add gbr to loader classes
This commit is contained in:
parent
9adfe33cfb
commit
fdfea41a48
8 changed files with 179 additions and 129 deletions
|
|
@ -1851,8 +1851,8 @@ class Polygon {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn 2d polygon into closed 3d mesh faces
|
// turn 2d polygon into a 2.5D ribbon extruded in Z
|
||||||
extrude(z = 1) {
|
ribbonZ(z = 1) {
|
||||||
let poly = this.clone().setClockwise();
|
let poly = this.clone().setClockwise();
|
||||||
let faces = [];
|
let faces = [];
|
||||||
let points = poly.points;
|
let points = poly.points;
|
||||||
|
|
@ -1870,6 +1870,25 @@ class Polygon {
|
||||||
return faces;
|
return faces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extrude poly (with inner voids) into 3d mesh
|
||||||
|
extrude(z = 1) {
|
||||||
|
let obj = [];
|
||||||
|
let earcut = this.earcut();
|
||||||
|
for (let poly of earcut) {
|
||||||
|
for (let point of poly.points) {
|
||||||
|
obj.push(point.x, point.y, z);
|
||||||
|
}
|
||||||
|
for (let point of poly.points.reverse()) {
|
||||||
|
obj.push(point.x, point.y, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.appendAll(this.ribbonZ(z));
|
||||||
|
for (let inner of this.inner || []) {
|
||||||
|
obj.appendAll(inner.ribbonZ(z));
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
// split long straight lines into segments no longer than max
|
// split long straight lines into segments no longer than max
|
||||||
// and return a new polygon
|
// and return a new polygon
|
||||||
segment(max = 1) {
|
segment(max = 1) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
// dep: kiri-mode.cam.driver
|
// dep: kiri-mode.cam.driver
|
||||||
// use: kiri-mode.cam.animate
|
// use: kiri-mode.cam.animate
|
||||||
// use: kiri-mode.cam.animate2
|
// use: kiri-mode.cam.animate2
|
||||||
|
// use: load.gbr
|
||||||
gapp.register("kiri-mode.cam.client", [], (root, exports) => {
|
gapp.register("kiri-mode.cam.client", [], (root, exports) => {
|
||||||
|
|
||||||
const { base, kiri } = root;
|
const { base, kiri } = root;
|
||||||
|
|
@ -116,102 +117,7 @@ CAM.init = function(kiri, api) {
|
||||||
}
|
}
|
||||||
|
|
||||||
api.event.on("cam.parse.gerber", gerber => {
|
api.event.on("cam.parse.gerber", gerber => {
|
||||||
let fact = 1000000;
|
const { open, closed, circs, rects } = load.GBR.parse(gerber);
|
||||||
let tools = {};
|
|
||||||
let tool;
|
|
||||||
let poly;
|
|
||||||
let polys = [];
|
|
||||||
let circs = [];
|
|
||||||
let rects = [];
|
|
||||||
let last = {};
|
|
||||||
let bounds = base.newBounds();
|
|
||||||
let p = TracespaceParser.createParser();
|
|
||||||
p.feed(gerber);
|
|
||||||
let r = p.results();
|
|
||||||
let c = r.children
|
|
||||||
.filter(c => {
|
|
||||||
switch (c.type) {
|
|
||||||
case 'toolDefinition':
|
|
||||||
tools[c.code] = c.shape;
|
|
||||||
break;
|
|
||||||
case 'toolChange':
|
|
||||||
tool = { code: c.code, shape: tools[c.code] };
|
|
||||||
break;
|
|
||||||
case 'graphic':
|
|
||||||
c.tool = tool;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
.map(r => {
|
|
||||||
return {
|
|
||||||
type: r.graphic,
|
|
||||||
tool: r.tool,
|
|
||||||
x: parseInt(r.coordinates.x),
|
|
||||||
y: parseInt(r.coordinates.y)
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.map(r => {
|
|
||||||
const { x, y, tool, type } = r;
|
|
||||||
const pos = { x:x/fact, y:y/fact, z: 0};
|
|
||||||
bounds.update(pos);
|
|
||||||
switch (type) {
|
|
||||||
case 'move':
|
|
||||||
if (true && poly && last.x === x && last.y === y && last.tool === tool) {
|
|
||||||
// console.log('continuation');
|
|
||||||
} else {
|
|
||||||
poly = base.newPolygon().setOpen().add(pos.x, pos.y, 0);
|
|
||||||
poly.tool = tool;
|
|
||||||
polys.push(poly);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'segment':
|
|
||||||
poly.add(pos.x, pos.y, 0);
|
|
||||||
break;
|
|
||||||
case 'shape':
|
|
||||||
poly = undefined;
|
|
||||||
let { shape } = tool;
|
|
||||||
switch (shape.type) {
|
|
||||||
case 'obround':
|
|
||||||
if (shape.xSize === shape.ySize) {
|
|
||||||
circs.push(base.newPolygon().centerCircle(pos, shape.xSize / 2, 20));
|
|
||||||
} else {
|
|
||||||
console.log('TODO', shape);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'circle':
|
|
||||||
circs.push(base.newPolygon().centerCircle(pos, shape.diameter / 2, 20));
|
|
||||||
break;
|
|
||||||
case 'rectangle':
|
|
||||||
rects.push(base.newPolygon().centerRectangle(pos, shape.xSize, shape.ySize));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
console.log('TODO', shape);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last = { x, y, tool };
|
|
||||||
return r;
|
|
||||||
});
|
|
||||||
const { minx, maxx, miny, maxy } = bounds;
|
|
||||||
for (let poly of [...polys, ...circs, ...rects]) {
|
|
||||||
poly.move({
|
|
||||||
x: -((maxx-minx)/2 + minx),
|
|
||||||
y: -((maxy-miny)/2 + miny),
|
|
||||||
z: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const open = [];
|
|
||||||
const closed = [];
|
|
||||||
for (let poly of polys) {
|
|
||||||
if (poly.appearsClosed()) {
|
|
||||||
closed.push(...poly.simplify());
|
|
||||||
} else {
|
|
||||||
open.push(poly);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log({ open, closed, circs, rects });
|
|
||||||
const widget = api.widgets.all()[0];
|
const widget = api.widgets.all()[0];
|
||||||
const stack = new kiri.Stack(widget.mesh);
|
const stack = new kiri.Stack(widget.mesh);
|
||||||
const layers = new kiri.Layers();
|
const layers = new kiri.Layers();
|
||||||
|
|
@ -228,7 +134,6 @@ CAM.init = function(kiri, api) {
|
||||||
layers.setLayer("rects", {line: 0x0000ff}, false).addPoly(poly);
|
layers.setLayer("rects", {line: 0x0000ff}, false).addPoly(poly);
|
||||||
}
|
}
|
||||||
stack.addLayers(layers);
|
stack.addLayers(layers);
|
||||||
console.log(r, tools);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
api.event.on("widget.add", widget => {
|
api.event.on("widget.add", widget => {
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ const POLY = polygons;
|
||||||
|
|
||||||
let debug = self.debug === true,
|
let debug = self.debug === true,
|
||||||
ccvalue = this.navigator ? navigator.hardwareConcurrency || 0 : 0,
|
ccvalue = this.navigator ? navigator.hardwareConcurrency || 0 : 0,
|
||||||
concurrent = self.Worker && ccvalue > 3 ? ccvalue - 1 : 0,
|
concurrent = Math.min(4, self.Worker && ccvalue > 3 ? ccvalue - 1 : 0),
|
||||||
current = self.worker = {
|
current = self.worker = {
|
||||||
print: null,
|
print: null,
|
||||||
snap: null,
|
snap: null,
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
// dep: kiri.selection
|
// dep: kiri.selection
|
||||||
// use: kiri.tools
|
// use: kiri.tools
|
||||||
// use: kiri.pack
|
// use: kiri.pack
|
||||||
// use: ext.gerber
|
|
||||||
gapp.register("kiri.init", [], (root, exports) => {
|
gapp.register("kiri.init", [], (root, exports) => {
|
||||||
|
|
||||||
const { base, kiri } = root;
|
const { base, kiri } = root;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
// dep: load.stl
|
// dep: load.stl
|
||||||
// dep: load.obj
|
// dep: load.obj
|
||||||
// dep: load.3mf
|
// dep: load.3mf
|
||||||
|
// dep: load.gbr
|
||||||
// use: kiri-mode.cam.tool
|
// use: kiri-mode.cam.tool
|
||||||
gapp.register("kiri.platform", [], (root, exports) => {
|
gapp.register("kiri.platform", [], (root, exports) => {
|
||||||
|
|
||||||
|
|
@ -753,18 +754,18 @@ function platformLoadFiles(files, group) {
|
||||||
const file = files[i],
|
const file = files[i],
|
||||||
reader = new FileReader(),
|
reader = new FileReader(),
|
||||||
lower = files[i].name.toLowerCase(),
|
lower = files[i].name.toLowerCase(),
|
||||||
israw = lower.indexOf(".raw") > 0 || lower.indexOf('.') < 0,
|
israw = lower.endsWith(".raw") || lower.indexOf('.') < 0,
|
||||||
isstl = lower.indexOf(".stl") > 0,
|
isstl = lower.endsWith(".stl"),
|
||||||
isobj = lower.indexOf(".obj") > 0,
|
isobj = lower.endsWith(".obj"),
|
||||||
is3mf = lower.indexOf(".3mf") > 0,
|
is3mf = lower.endsWith(".3mf"),
|
||||||
issvg = lower.indexOf(".svg") > 0,
|
issvg = lower.endsWith(".svg"),
|
||||||
ispng = lower.indexOf(".png") > 0,
|
ispng = lower.endsWith(".png"),
|
||||||
isjpg = lower.indexOf(".jpg") > 0,
|
isjpg = lower.endsWith(".jpg"),
|
||||||
isgcode = lower.indexOf(".gcode") > 0 || lower.indexOf(".nc") > 0,
|
isgcode = lower.endsWith(".gcode") || lower.endsWith(".nc"),
|
||||||
isset = lower.indexOf(".b64") > 0 || lower.indexOf(".km") > 0,
|
isset = lower.endsWith(".b64") || lower.endsWith(".km"),
|
||||||
iskmz = lower.indexOf(".kmz") > 0,
|
iskmz = lower.endsWith(".kmz"),
|
||||||
isini = lower.indexOf(".ini") > 0,
|
isini = lower.endsWith(".ini"),
|
||||||
isgrb = lower.indexOf(".grb");
|
isgbr = lower.endsWith(".gbr");
|
||||||
reader.file = files[i];
|
reader.file = files[i];
|
||||||
reader.onloadend = function(e) {
|
reader.onloadend = function(e) {
|
||||||
function load_dec() {
|
function load_dec() {
|
||||||
|
|
@ -818,11 +819,17 @@ function platformLoadFiles(files, group) {
|
||||||
} else {
|
} else {
|
||||||
odon();
|
odon();
|
||||||
}
|
}
|
||||||
} else if (isgrb && api.conf.get().controller.devel) {
|
} else if (isgbr && api.conf.get().controller.devel) {
|
||||||
if (api.mode.is_cam()) {
|
if (api.mode.is_cam()) {
|
||||||
api.event.emit('cam.parse.gerber', e.target.result);
|
api.event.emit('cam.parse.gerber', e.target.result);
|
||||||
} else {
|
} else {
|
||||||
api.alerts.show('Gerber import not availabe in this device mode');
|
let mesh = load.GBR.toMesh(e.target.result);
|
||||||
|
platform.add(
|
||||||
|
newWidget(undefined, group)
|
||||||
|
.loadVertices(mesh.toFloat32(), true)
|
||||||
|
.saveToCatalog(e.target.file.name)
|
||||||
|
);
|
||||||
|
// api.alerts.show('Gerber import not availabe in this device mode');
|
||||||
}
|
}
|
||||||
} else if (is3mf) {
|
} else if (is3mf) {
|
||||||
let odon = function(models) {
|
let odon = function(models) {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ if (load.File) return;
|
||||||
// dep: load.svg
|
// dep: load.svg
|
||||||
// dep: load.url
|
// dep: load.url
|
||||||
// dep: load.png
|
// dep: load.png
|
||||||
|
// dep: load.gbr
|
||||||
gapp.register('load.file', []);
|
gapp.register('load.file', []);
|
||||||
|
|
||||||
const types = {
|
const types = {
|
||||||
|
|
@ -48,6 +49,10 @@ const types = {
|
||||||
resolve({ mesh: data, file });
|
resolve({ mesh: data, file });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
gbr(data, file, resolve, reject, opt = {}) {
|
||||||
|
resolve([{ mesh: load.GBR.toMesh(data).toFloat32(), file }])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
128
src/load/gbr.js
Normal file
128
src/load/gbr.js
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||||
|
|
||||||
|
// use: geo.bounds
|
||||||
|
// use: geo.polygon
|
||||||
|
// use: geo.polygons
|
||||||
|
// use: ext.gerber
|
||||||
|
gapp.register("load.gbr", (root, exports) => {
|
||||||
|
|
||||||
|
const { load } = root;
|
||||||
|
|
||||||
|
load.GBR = {
|
||||||
|
parse,
|
||||||
|
toMesh
|
||||||
|
};
|
||||||
|
|
||||||
|
function toMesh(text, opt = { z: 3 }) {
|
||||||
|
const { open, closed, circs, rects } = parse(text);
|
||||||
|
const nest = base.polygons.nest([...closed, ...circs, ...rects], true);
|
||||||
|
console.log({ nest });
|
||||||
|
const obj = [];
|
||||||
|
for (let poly of nest) {
|
||||||
|
obj.appendAll(poly.extrude(opt.z || 3));
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse(text) {
|
||||||
|
let fact = 1000000;
|
||||||
|
let tools = {};
|
||||||
|
let tool;
|
||||||
|
let poly;
|
||||||
|
let polys = [];
|
||||||
|
let circs = [];
|
||||||
|
let rects = [];
|
||||||
|
let last = {};
|
||||||
|
let bounds = base.newBounds();
|
||||||
|
let p = TracespaceParser.createParser();
|
||||||
|
p.feed(text);
|
||||||
|
let r = p.results();
|
||||||
|
let c = r.children
|
||||||
|
.filter(c => {
|
||||||
|
switch (c.type) {
|
||||||
|
case 'toolDefinition':
|
||||||
|
tools[c.code] = c.shape;
|
||||||
|
break;
|
||||||
|
case 'toolChange':
|
||||||
|
tool = { code: c.code, shape: tools[c.code] };
|
||||||
|
break;
|
||||||
|
case 'graphic':
|
||||||
|
c.tool = tool;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.map(r => {
|
||||||
|
return {
|
||||||
|
type: r.graphic,
|
||||||
|
tool: r.tool,
|
||||||
|
x: parseInt(r.coordinates.x),
|
||||||
|
y: parseInt(r.coordinates.y)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.map(r => {
|
||||||
|
const { x, y, tool, type } = r;
|
||||||
|
const pos = { x:x/fact, y:y/fact, z: 0};
|
||||||
|
bounds.update(pos);
|
||||||
|
switch (type) {
|
||||||
|
case 'move':
|
||||||
|
if (true && poly && last.x === x && last.y === y && last.tool === tool) {
|
||||||
|
// console.log('continuation');
|
||||||
|
} else {
|
||||||
|
poly = base.newPolygon().setOpen().add(pos.x, pos.y, 0);
|
||||||
|
poly.tool = tool;
|
||||||
|
polys.push(poly);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'segment':
|
||||||
|
poly.add(pos.x, pos.y, 0);
|
||||||
|
break;
|
||||||
|
case 'shape':
|
||||||
|
poly = undefined;
|
||||||
|
let { shape } = tool;
|
||||||
|
switch (shape.type) {
|
||||||
|
case 'obround':
|
||||||
|
if (shape.xSize === shape.ySize) {
|
||||||
|
circs.push(base.newPolygon().centerCircle(pos, shape.xSize / 2, 20));
|
||||||
|
} else {
|
||||||
|
console.log('TODO', shape);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'circle':
|
||||||
|
circs.push(base.newPolygon().centerCircle(pos, shape.diameter / 2, 20));
|
||||||
|
break;
|
||||||
|
case 'rectangle':
|
||||||
|
rects.push(base.newPolygon().centerRectangle(pos, shape.xSize, shape.ySize));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log('TODO', shape);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = { x, y, tool };
|
||||||
|
return r;
|
||||||
|
});
|
||||||
|
const { minx, maxx, miny, maxy } = bounds;
|
||||||
|
for (let poly of [...polys, ...circs, ...rects]) {
|
||||||
|
poly.move({
|
||||||
|
x: -((maxx-minx)/2 + minx),
|
||||||
|
y: -((maxy-miny)/2 + miny),
|
||||||
|
z: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const open = [];
|
||||||
|
const closed = [];
|
||||||
|
for (let poly of polys) {
|
||||||
|
if (poly.appearsClosed()) {
|
||||||
|
closed.push(...poly.simplify());
|
||||||
|
} else {
|
||||||
|
open.push(poly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// const nest = base.polygons.nest([...closed, ...circs, ...rects], true);
|
||||||
|
// console.log({ nest });
|
||||||
|
return { open, closed, circs, rects };
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
@ -74,20 +74,7 @@ function parse(text, opt = { soup: true }) {
|
||||||
|
|
||||||
let z = parseFloat(depth.value);
|
let z = parseFloat(depth.value);
|
||||||
for (let poly of nest) {
|
for (let poly of nest) {
|
||||||
let obj = [];
|
let obj = poly.extrude(z);
|
||||||
let earcut = poly.earcut();
|
|
||||||
for (let poly of earcut) {
|
|
||||||
for (let point of poly.points) {
|
|
||||||
obj.push(point.x, point.y, z);
|
|
||||||
}
|
|
||||||
for (let point of poly.points.reverse()) {
|
|
||||||
obj.push(point.x, point.y, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
obj.appendAll(poly.extrude(z));
|
|
||||||
for (let inner of poly.inner || []) {
|
|
||||||
obj.appendAll(inner.extrude(z));
|
|
||||||
}
|
|
||||||
objs.push(obj);
|
objs.push(obj);
|
||||||
// invert y
|
// invert y
|
||||||
for (let i=1, l=obj.length; i<l; i += 3) {
|
for (let i=1, l=obj.length; i<l; i += 3) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue