swap in manifold for jscad/modeling
This commit is contained in:
parent
a6382ea1d7
commit
95edfc1ea9
8 changed files with 171 additions and 56 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -3,5 +3,6 @@ tmp
|
|||
.DS_Store
|
||||
node_modules
|
||||
package-lock.json
|
||||
app.json
|
||||
logs/*
|
||||
data/*
|
||||
|
|
|
|||
1
app.js
1
app.js
|
|
@ -420,7 +420,6 @@ const script = {
|
|||
"&main/mesh"
|
||||
],
|
||||
mesh_work : [
|
||||
"ext/jscad",
|
||||
"&mesh/work"
|
||||
],
|
||||
mesh_pool : [
|
||||
|
|
|
|||
4
bin/npm-post
Executable file
4
bin/npm-post
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
( curl https://static.grid.space/gapp/manifold.js > src/ext/manifold.js ) > /dev/null 2>&1
|
||||
( curl https://static.grid.space/gapp/manifold.wasm > src/wasm/manifold.wasm ) > /dev/null 2>&1
|
||||
|
|
@ -29,7 +29,6 @@
|
|||
"connect": "^3.7.0",
|
||||
"earcut": "^2.2.3",
|
||||
"express-useragent": "^1.0.13",
|
||||
"@jscad/modeling": "^2.9.5",
|
||||
"jszip": "^3.7.1",
|
||||
"moment": "^2.24.0",
|
||||
"pixi.js": "^4.8.9",
|
||||
|
|
@ -38,5 +37,11 @@
|
|||
"uglify-js": "3.14.5",
|
||||
"validator": ">=13.7.0",
|
||||
"ws": "^7.5.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gridspace/app-server": "^0.0.7"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "bin/npm-post"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
114
src/add/manifold.js
Normal file
114
src/add/manifold.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/** Copyright Stewart Allen -- All Rights Reserved */
|
||||
|
||||
"use strict";
|
||||
|
||||
const testing = false;
|
||||
|
||||
// dep: ext.manifold
|
||||
gapp.register("add.manifold", [], (root, exports) => {
|
||||
Module.onRuntimeInitialized = () => {
|
||||
Module.setup();
|
||||
|
||||
if (testing) {
|
||||
// let c = Module.cube([1,1,1], true);
|
||||
let c = Module.sphere(10, 100);
|
||||
let l = 1000;
|
||||
let cm = c.getMesh();
|
||||
let md = c.getMeshDirect();
|
||||
console.log({ c, cm, md });
|
||||
|
||||
console.time('getMesh');
|
||||
for (let i=0; i<l; i++) c.getMesh();
|
||||
console.timeEnd('getMesh');
|
||||
|
||||
console.time(`getMeshDirect`);
|
||||
for (let i=0; i<l; i++) c.getMeshDirect({ mode: 0 });
|
||||
console.timeEnd(`getMeshDirect`);
|
||||
|
||||
console.time(`getMeshDirect`);
|
||||
for (let i=0; i<l; i++) c.getMeshDirect({ mode: 1 });
|
||||
console.timeEnd(`getMeshDirect`);
|
||||
|
||||
console.time(`getMeshDirect`);
|
||||
for (let i=0; i<l; i++) c.getMeshDirect({ mode: 2 });
|
||||
console.timeEnd(`getMeshDirect`);
|
||||
}
|
||||
};
|
||||
|
||||
function indexVertices(pos) {
|
||||
mesh.log(`indexing ${pos.length/3} vertices`);
|
||||
let ipos = 0;
|
||||
const index = [];
|
||||
const vertices = [];
|
||||
const cache = {};
|
||||
const temp = { x: 0, y: 0, z: 0 };
|
||||
for (let i=0, length = pos.length; i<length; ) {
|
||||
temp.x = pos[i++];
|
||||
temp.y = pos[i++];
|
||||
temp.z = pos[i++];
|
||||
let key = [
|
||||
((temp.x * 100000) | 0),
|
||||
((temp.y * 100000) | 0),
|
||||
((temp.z * 100000) | 0)
|
||||
].join('');
|
||||
let ip = cache[key];
|
||||
if (ip >= 0) {
|
||||
index.push(ip);
|
||||
} else {
|
||||
index.push(ipos);
|
||||
cache[key] = (ipos++);
|
||||
vertices.push(temp.x, temp.y, temp.z);
|
||||
}
|
||||
}
|
||||
return { index, vertices };
|
||||
}
|
||||
|
||||
function pos2mesh(pos) {
|
||||
const { index, vertices } = indexVertices(pos);
|
||||
const mesh = {
|
||||
vertPos: new Module.Vector_vec3(),
|
||||
triVerts: new Module.Vector_ivec3(),
|
||||
vertNormal: new Module.Vector_vec3(),
|
||||
halfedgeTangent: new Module.Vector_vec4()
|
||||
};
|
||||
for (let i = 0, l = vertices.length; i < l; ) {
|
||||
mesh.vertPos.push_back({
|
||||
x: vertices[i++],
|
||||
y: vertices[i++],
|
||||
z: vertices[i++]
|
||||
});
|
||||
}
|
||||
for (let i = 0, l = index.length; i < l; ) {
|
||||
mesh.triVerts.push_back([ index[i++], index[i++], index[i++] ]);
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
function mesh2pos(mesh) {
|
||||
const { vertPos, triVerts } = mesh;
|
||||
const vertices = new Float32Array(triVerts.length * 9);
|
||||
for (let i = 0, t = 0, l = triVerts.length; t < l; t++) {
|
||||
let tri = triVerts[t];
|
||||
let vert = vertPos[tri[0]]; // X
|
||||
vertices[i++] = vert[0];
|
||||
vertices[i++] = vert[1];
|
||||
vertices[i++] = vert[2];
|
||||
vert = vertPos[tri[1]]; // Y
|
||||
vertices[i++] = vert[0];
|
||||
vertices[i++] = vert[1];
|
||||
vertices[i++] = vert[2];
|
||||
vert = vertPos[tri[2]]; // Z
|
||||
vertices[i++] = vert[0];
|
||||
vertices[i++] = vert[1];
|
||||
vertices[i++] = vert[2];
|
||||
}
|
||||
return vertices;
|
||||
}
|
||||
|
||||
exports({
|
||||
indexVertices,
|
||||
pos2mesh,
|
||||
mesh2pos
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -3,76 +3,57 @@
|
|||
"use strict";
|
||||
|
||||
// dep: geo.base
|
||||
// jscad dep injected in app so it comes before everything else
|
||||
// dep: add.manifold
|
||||
gapp.register("geo.csg", [], (root, exports) => {
|
||||
|
||||
const { base } = root;
|
||||
const debug = false;
|
||||
const debug = true;
|
||||
|
||||
const CSG = {
|
||||
|
||||
// accepts 2 or more arguments with threejs vertex position arrays
|
||||
union() {
|
||||
if (debug) {
|
||||
console.log(JSON.stringify([ ...arguments ]));
|
||||
mesh.log(`manifold.union ${arguments.length} meshes`);
|
||||
const args = [...arguments].map(a => new Module.Manifold(a));
|
||||
const result = Module.union(...args);
|
||||
const output = result.getMesh();
|
||||
for (let m of [ ...args, result ]) {
|
||||
m.delete();
|
||||
}
|
||||
let union = jscadModeling.booleans.union(...arguments);
|
||||
if (debug) {
|
||||
console.log(JSON.stringify(union));
|
||||
}
|
||||
return union;
|
||||
return output;
|
||||
},
|
||||
|
||||
// accepts 2 or more arguments with threejs vertex position arrays
|
||||
// the fist argument is the target mesh. the rest are negatives
|
||||
subtract() {
|
||||
return jscadModeling.booleans.subtract(...arguments);
|
||||
mesh.log(`manifold.subtract ${arguments.length} meshes`);
|
||||
const args = [...arguments].map(a => new Module.Manifold(a));
|
||||
const result = Module.difference(...args);
|
||||
const output = result.getMesh();
|
||||
for (let m of [ ...args, result ]) {
|
||||
m.delete();
|
||||
}
|
||||
return output;
|
||||
},
|
||||
|
||||
// accepts 2 or more arguments with threejs vertex position arrays
|
||||
intersect() {
|
||||
return jscadModeling.booleans.intersect(...arguments);
|
||||
mesh.log(`manifold.intersect ${arguments.length} meshes`);
|
||||
const args = [...arguments].map(a => new Module.Manifold(a));
|
||||
const result = Module.intersection(...args);
|
||||
const output = result.getMesh();
|
||||
for (let m of [ ...args, result ]) {
|
||||
m.delete();
|
||||
}
|
||||
return output;
|
||||
},
|
||||
|
||||
toPositionArray(geom) {
|
||||
if (!geom || geom.length === 0) {
|
||||
return [].toFloat32();
|
||||
}
|
||||
const out = [];
|
||||
const poly = jscadModeling.geometries.geom3
|
||||
.toPolygons(geom)
|
||||
.map(p => p.vertices);
|
||||
for (let p of poly) {
|
||||
let p0 = p[0];
|
||||
for (let i = 0; i<p.length - 2; i++) {
|
||||
out.push(p0, p[i+1], p[i+2]);
|
||||
}
|
||||
}
|
||||
return out.flat().toFloat32();
|
||||
// return geom.polygons
|
||||
// .map(p => p.vertices.flat())
|
||||
// .map(a => base.util.triangulate(a, undefined, 3))
|
||||
// .flat().toFloat32();
|
||||
return add.manifold.mesh2pos(geom);
|
||||
},
|
||||
|
||||
// Construct a CSG from a THREE Geometry BufferAttribute array (or similar)
|
||||
fromPositionArray(array) {
|
||||
const polys = [];
|
||||
if (debug) {
|
||||
array = [...array].map(v => v.round(3));
|
||||
}
|
||||
for (let i=0, l=array.length; i<l; ) {
|
||||
polys.push([ [
|
||||
array[i++],
|
||||
array[i++],
|
||||
array[i++],
|
||||
],[
|
||||
array[i++],
|
||||
array[i++],
|
||||
array[i++],
|
||||
],[
|
||||
array[i++],
|
||||
array[i++],
|
||||
array[i++],
|
||||
] ]);
|
||||
}
|
||||
return jscadModeling.geometries.geom3.fromPoints(polys);
|
||||
return add.manifold.pos2mesh(array);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ function fallback(models, strict) {
|
|||
const tool = {
|
||||
merge(models) {
|
||||
models = fallback(models);
|
||||
if (models.length <= 1) {
|
||||
if (models.length < 2) {
|
||||
return api.log.emit('nothing to merge');
|
||||
}
|
||||
api.log.emit(`merging ${models.length} models`).pin();
|
||||
|
|
@ -391,6 +391,9 @@ const tool = {
|
|||
|
||||
union(models) {
|
||||
models = fallback(models);
|
||||
if (models.length < 2) {
|
||||
return api.log.emit('nothing to union');
|
||||
}
|
||||
api.log.emit(`union ${models.length} models`).pin();
|
||||
worker.model_union(models.map(m => {
|
||||
return { id: m.id, matrix: m.matrix }
|
||||
|
|
@ -407,6 +410,9 @@ const tool = {
|
|||
|
||||
intersect(models) {
|
||||
models = fallback(models);
|
||||
if (models.length < 2) {
|
||||
return api.log.emit('nothing to intersect');
|
||||
}
|
||||
api.log.emit(`intersect ${models.length} models`).pin();
|
||||
worker.model_intersect(models.map(m => {
|
||||
return { id: m.id, matrix: m.matrix }
|
||||
|
|
@ -423,6 +429,9 @@ const tool = {
|
|||
|
||||
subtract(models) {
|
||||
models = fallback(models);
|
||||
if (models.length < 2) {
|
||||
return api.log.emit('nothing to subtract');
|
||||
}
|
||||
api.log.emit(`subtract ${models.length} models`).pin();
|
||||
worker.model_subtract(models.map(m => {
|
||||
return { id: m.id, matrix: m.matrix, tool: m.tool() }
|
||||
|
|
@ -695,9 +704,9 @@ const prefs = {
|
|||
select: []
|
||||
},
|
||||
normals: {
|
||||
length: 0.5,
|
||||
color_lite: 0xff0000,
|
||||
color_dark: 0x00ffff
|
||||
length: 0.25,
|
||||
color_lite: 0xffff00,
|
||||
color_dark: 0xffff00,
|
||||
},
|
||||
surface: {
|
||||
radians: 0.1,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ function log(msg) {
|
|||
return worker.publish("mesh.log", msg);
|
||||
}
|
||||
|
||||
mesh.log = log;
|
||||
|
||||
function cacheUpdate(id, data) {
|
||||
Object.assign(cache[id], data);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue