complete basic gerber import conversion to mesh for milling traces
This commit is contained in:
parent
fdfea41a48
commit
8b215460a1
6 changed files with 65 additions and 30 deletions
|
|
@ -233,6 +233,8 @@ Float32Array.prototype.toShared = function() {
|
||||||
return newvert;
|
return newvert;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Float32Array.prototype.toFloat32 = function() { return this };
|
||||||
|
|
||||||
String.prototype.reverse = function() {
|
String.prototype.reverse = function() {
|
||||||
return this.split('').reverse().join('');
|
return this.split('').reverse().join('');
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,14 @@ gapp.register("geo.csg", [], (root, exports) => {
|
||||||
const { base, ext } = root;
|
const { base, ext } = root;
|
||||||
const debug = true;
|
const debug = true;
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
if (root?.mesh?.log) {
|
||||||
|
root.mesh.log(...arguments)
|
||||||
|
} else if (root.debug === true) {
|
||||||
|
console.log(...arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const CSG = {
|
const CSG = {
|
||||||
// accepts 2 or more arguments with threejs vertex position arrays
|
// accepts 2 or more arguments with threejs vertex position arrays
|
||||||
union() {
|
union() {
|
||||||
|
|
@ -27,7 +35,7 @@ const CSG = {
|
||||||
},
|
},
|
||||||
|
|
||||||
moduleOp(name, op) {
|
moduleOp(name, op) {
|
||||||
mesh.log(`${name} ${arguments.length} meshes`);
|
log(`${name} ${arguments.length} meshes`);
|
||||||
const args = [...arguments].slice(2).map(a => new Instance.Manifold(a));
|
const args = [...arguments].slice(2).map(a => new Instance.Manifold(a));
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
throw "missing one or more meshes";
|
throw "missing one or more meshes";
|
||||||
|
|
@ -80,7 +88,7 @@ const CSG = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function indexVertices(pos) {
|
function indexVertices(pos) {
|
||||||
mesh.log(`indexing ${pos.length/3} vertices`);
|
log(`indexing ${pos.length/3} vertices`);
|
||||||
let ipos = 0;
|
let ipos = 0;
|
||||||
const index = [];
|
const index = [];
|
||||||
const vertices = [];
|
const vertices = [];
|
||||||
|
|
|
||||||
|
|
@ -1852,39 +1852,42 @@ class Polygon {
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn 2d polygon into a 2.5D ribbon extruded in Z
|
// turn 2d polygon into a 2.5D ribbon extruded in Z
|
||||||
ribbonZ(z = 1) {
|
ribbonZ(z = 1, zadd = 0, rev) {
|
||||||
let poly = this.clone().setClockwise();
|
let poly = this.clone().setClockwise();
|
||||||
let faces = [];
|
let faces = [];
|
||||||
let points = poly.points;
|
let points = poly.points;
|
||||||
let length = points.length;
|
let length = points.length;
|
||||||
|
if (rev) {
|
||||||
|
points = points.slice().reverse();
|
||||||
|
}
|
||||||
for (let i=0; i<length; i++) {
|
for (let i=0; i<length; i++) {
|
||||||
let p0 = points[i];
|
let p0 = points[i];
|
||||||
let p1 = points[(i + 1) % length];
|
let p1 = points[(i + 1) % length];
|
||||||
faces.push(p0.x, p0.y, p0.z);
|
faces.push(p0.x, p0.y, p0.z + zadd);
|
||||||
faces.push(p1.x, p1.y, p0.z);
|
faces.push(p1.x, p1.y, p1.z + z + zadd);
|
||||||
faces.push(p1.x, p1.y, p1.z + z);
|
faces.push(p1.x, p1.y, p0.z + zadd);
|
||||||
faces.push(p0.x, p0.y, p0.z);
|
faces.push(p0.x, p0.y, p0.z + zadd);
|
||||||
faces.push(p1.x, p1.y, p1.z + z);
|
faces.push(p0.x, p0.y, p0.z + z + zadd);
|
||||||
faces.push(p0.x, p0.y, p0.z + z);
|
faces.push(p1.x, p1.y, p1.z + z + zadd);
|
||||||
}
|
}
|
||||||
return faces;
|
return faces;
|
||||||
}
|
}
|
||||||
|
|
||||||
// extrude poly (with inner voids) into 3d mesh
|
// extrude poly (with inner voids) into 3d mesh
|
||||||
extrude(z = 1) {
|
extrude(z = 1, zadd = 0) {
|
||||||
let obj = [];
|
let obj = [];
|
||||||
let earcut = this.earcut();
|
let earcut = this.earcut();
|
||||||
for (let poly of earcut) {
|
for (let poly of earcut) {
|
||||||
for (let point of poly.points) {
|
for (let point of poly.points) {
|
||||||
obj.push(point.x, point.y, z);
|
obj.push(point.x, point.y, z + zadd);
|
||||||
}
|
}
|
||||||
for (let point of poly.points.reverse()) {
|
for (let point of poly.points.reverse()) {
|
||||||
obj.push(point.x, point.y, 0);
|
obj.push(point.x, point.y, zadd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
obj.appendAll(this.ribbonZ(z));
|
obj.appendAll(this.ribbonZ(z, zadd));
|
||||||
for (let inner of this.inner || []) {
|
for (let inner of this.inner || []) {
|
||||||
obj.appendAll(inner.ribbonZ(z));
|
obj.appendAll(inner.ribbonZ(z, zadd, true));
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,10 +116,10 @@ CAM.init = function(kiri, api) {
|
||||||
updateStock();
|
updateStock();
|
||||||
}
|
}
|
||||||
|
|
||||||
api.event.on("cam.parse.gerber", gerber => {
|
api.event.on("cam.parse.gerber", opts => {
|
||||||
const { open, closed, circs, rects } = load.GBR.parse(gerber);
|
const { data, mesh } = opts;
|
||||||
const widget = api.widgets.all()[0];
|
const { open, closed, circs, rects } = load.GBR.parse(data);
|
||||||
const stack = new kiri.Stack(widget.mesh);
|
const stack = new kiri.Stack(mesh || moto.space.world.newGroup());
|
||||||
const layers = new kiri.Layers();
|
const layers = new kiri.Layers();
|
||||||
for (let poly of open) {
|
for (let poly of open) {
|
||||||
layers.setLayer("open", {line: 0xff8800}, false).addPoly(poly);
|
layers.setLayer("open", {line: 0xff8800}, false).addPoly(poly);
|
||||||
|
|
|
||||||
|
|
@ -819,17 +819,21 @@ function platformLoadFiles(files, group) {
|
||||||
} else {
|
} else {
|
||||||
odon();
|
odon();
|
||||||
}
|
}
|
||||||
} else if (isgbr && api.conf.get().controller.devel) {
|
} else if (isgbr) {
|
||||||
if (api.mode.is_cam()) {
|
if (api.conf.get().controller.devel) {
|
||||||
api.event.emit('cam.parse.gerber', e.target.result);
|
api.event.emit('cam.parse.gerber', { data: e.target.result });
|
||||||
} else {
|
} else {
|
||||||
let mesh = load.GBR.toMesh(e.target.result);
|
let mesh = load.GBR.toMesh(e.target.result);
|
||||||
platform.add(
|
let wid;
|
||||||
|
platform.add(wid =
|
||||||
newWidget(undefined, group)
|
newWidget(undefined, group)
|
||||||
.loadVertices(mesh.toFloat32(), true)
|
.loadVertices(mesh, true)
|
||||||
.saveToCatalog(e.target.file.name)
|
.saveToCatalog(e.target.file.name)
|
||||||
);
|
);
|
||||||
// api.alerts.show('Gerber import not availabe in this device mode');
|
if (api.mode.is_cam()) {
|
||||||
|
// attach raw illustration
|
||||||
|
api.event.emit('cam.parse.gerber', { data: e.target.result, mesh: wid.mesh });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (is3mf) {
|
} else if (is3mf) {
|
||||||
let odon = function(models) {
|
let odon = function(models) {
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,42 @@
|
||||||
// use: geo.polygon
|
// use: geo.polygon
|
||||||
// use: geo.polygons
|
// use: geo.polygons
|
||||||
// use: ext.gerber
|
// use: ext.gerber
|
||||||
|
// use: geo.csg
|
||||||
gapp.register("load.gbr", (root, exports) => {
|
gapp.register("load.gbr", (root, exports) => {
|
||||||
|
|
||||||
const { load } = root;
|
const { load } = root;
|
||||||
|
const POLYS = base.polygons;
|
||||||
|
const CSG = base.CSG;
|
||||||
|
|
||||||
load.GBR = {
|
load.GBR = {
|
||||||
parse,
|
parse,
|
||||||
toMesh
|
toMesh
|
||||||
};
|
};
|
||||||
|
|
||||||
function toMesh(text, opt = { z: 3 }) {
|
function toMesh(text, opt = { z: 1 }) {
|
||||||
const { open, closed, circs, rects } = parse(text);
|
const { open, closed, circs, rects } = parse(text);
|
||||||
|
|
||||||
const nest = base.polygons.nest([...closed, ...circs, ...rects], true);
|
const nest = base.polygons.nest([...closed, ...circs, ...rects], true);
|
||||||
console.log({ nest });
|
|
||||||
const obj = [];
|
const flat = POLYS.flatten(nest, [], true);
|
||||||
for (let poly of nest) {
|
const z0 = opt.z || opt.z0 || 1;
|
||||||
obj.appendAll(poly.extrude(opt.z || 3));
|
const z1 = opt.z1 || 0.25;
|
||||||
|
|
||||||
|
const top = [];
|
||||||
|
for (let poly of flat.filter(p => p.depth === 0)) {
|
||||||
|
top.push(poly.extrude(z0));
|
||||||
}
|
}
|
||||||
return obj;
|
|
||||||
|
const mid = [];
|
||||||
|
for (let poly of flat.filter(p => p.depth === 1)) {
|
||||||
|
mid.push(poly.extrude(z1, z0 - z1));
|
||||||
|
}
|
||||||
|
|
||||||
|
const topMesh = CSG.fromPositionArray(top[0]);
|
||||||
|
const midMesh = mid.map(v => CSG.fromPositionArray(v));
|
||||||
|
const subMesh = CSG.subtract(topMesh, ...midMesh);
|
||||||
|
|
||||||
|
return CSG.toPositionArray(subMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse(text) {
|
function parse(text) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue