refactor widget as class. patch engine, frame, cli

This commit is contained in:
Stewart Allen 2022-02-18 12:08:08 -05:00
commit 74d3d8752c
9 changed files with 300 additions and 306 deletions

4
app.js
View file

@ -404,6 +404,7 @@ const script = {
"geo/mesh", "geo/mesh",
// "moto/broker", // "moto/broker",
"kiri/pack", "kiri/pack",
"kiri/utils",
"kiri/slice", "kiri/slice",
"kiri/layers", "kiri/layers",
"kiri-mode/fdm/fill", "kiri-mode/fdm/fill",
@ -453,6 +454,7 @@ const script = {
"geo/slicer", "geo/slicer",
"kiri-mode/fdm/driver", "kiri-mode/fdm/driver",
"kiri-mode/fdm/slice", "kiri-mode/fdm/slice",
"kiri/utils",
"kiri/slice", "kiri/slice",
"kiri/layers", "kiri/layers",
"kiri/widget", "kiri/widget",
@ -472,6 +474,7 @@ const script = {
"geo/base", "geo/base",
"geo/point", "geo/point",
"geo/points", "geo/points",
"geo/paths",
"geo/slope", "geo/slope",
"geo/line", "geo/line",
"geo/bounds", "geo/bounds",
@ -481,6 +484,7 @@ const script = {
"load/obj", "load/obj",
"load/stl", "load/stl",
"kiri/conf", "kiri/conf",
"kiri/utils",
"kiri/client", "kiri/client",
"kiri/slice", "kiri/slice",
"kiri/layers", "kiri/layers",

View file

@ -1,6 +1,7 @@
[ [
"main/gapp", "main/gapp",
"moto/license", "moto/license",
"moto/broker",
"main/kiri", "main/kiri",
"ext/three", "ext/three",
"ext/pngjs", "ext/pngjs",
@ -13,18 +14,22 @@
"geo/base", "geo/base",
"geo/point", "geo/point",
"geo/points", "geo/points",
"geo/paths",
"geo/slope", "geo/slope",
"geo/line", "geo/line",
"geo/bounds", "geo/bounds",
"geo/polygons", "geo/polygons",
"geo/polygon", "geo/polygon",
"geo/gyroid", "geo/gyroid",
"geo/slicer",
"load/obj",
"load/stl",
"kiri/conf", "kiri/conf",
"kiri/pack", "kiri/pack",
"kiri/client", "kiri/client",
"kiri/engine", "kiri/engine",
"kiri/utils",
"kiri/slice", "kiri/slice",
"kiri/slicer",
"kiri/layers", "kiri/layers",
"kiri-mode/fdm/fill", "kiri-mode/fdm/fill",
"kiri-mode/fdm/driver", "kiri-mode/fdm/driver",
@ -48,5 +53,4 @@
"kiri/print", "kiri/print",
"kiri/codec", "kiri/codec",
"kiri/worker", "kiri/worker",
"load/stl"
] ]

View file

@ -2,7 +2,7 @@
"use strict"; "use strict";
kiri.load(function() { self.kiri.load(function() {
let KIRI = self.kiri, let KIRI = self.kiri,
CAM = KIRI.driver.CAM, CAM = KIRI.driver.CAM,

View file

@ -4,7 +4,7 @@
(function() { (function() {
const { base, kiri } = self; const { base, kiri, noop } = self;
const { driver, fill, fill_fixed, newSlice, utils } = kiri; const { driver, fill, fill_fixed, newSlice, utils } = kiri;
const { config, polygons, util, newPoint } = base; const { config, polygons, util, newPoint } = base;
const { fillArea } = polygons; const { fillArea } = polygons;

View file

@ -56,9 +56,8 @@ let exports_save = exports,
gapp = {}, gapp = {},
geo = {}, geo = {},
self = this.self = { self = this.self = {
THREE,
gapp, gapp,
kiri: { driver: {}, loader: [] }, THREE,
location: { hostname: 'local', port: 0, protocol: 'fake' }, location: { hostname: 'local', port: 0, protocol: 'fake' },
postMessage: (msg) => { postMessage: (msg) => {
self.kiri.client.onmessage({data:msg}); self.kiri.client.onmessage({data:msg});

View file

@ -399,7 +399,7 @@
} }
} }
if (data.load) { if (data.load) {
platformLoad(data.load, (verts, widget) => { api.platform.load(data.load, (verts, widget) => {
send({event: "loaded", data: [ widget.id ]}); send({event: "loaded", data: [ widget.id ]});
}) })
}; };
@ -2044,7 +2044,7 @@
function loadFile() { function loadFile() {
$('load-file').onchange = function(event) { $('load-file').onchange = function(event) {
console.log(event); console.log(event);
platformLoadFiles(event.target.files); api.platform.load_files(event.target.files);
}; };
$('load-file').click(); $('load-file').click();
// alert2("drag/drop STL files onto platform to import\nreload page to return to last saved state"); // alert2("drag/drop STL files onto platform to import\nreload page to return to last saved state");

View file

@ -793,7 +793,7 @@ const platform = api.platform = {
show_axes: space.platform.showAxes, show_axes: space.platform.showAxes,
show_volume: space.platform.showVolume, show_volume: space.platform.showVolume,
top_z() { return topZ }, top_z() { return topZ },
clear() { clearWorkspace(); saveWorkspace(true) } clear() { api.space.clear(); api.space.save(true) }
}; };
})(); })();

View file

@ -46,6 +46,26 @@ function js2o(s,def) {
} }
} }
// split 24 bit color into [ r, g, b ]
function rgb(c) {
return [ (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff ];
}
// return 24 bit color from [ r, g, b ] array
function a2c(a) {
return (a[0] << 16) | (a[1] << 8) | a[0];
}
// average two color arrays with weighting @ return 24 bit color
function avgc(c1, c2, w = 3) {
let r1 = rgb(c1);
let r2 = rgb(c2);
let d = (w + 2);
return ((r1[0] * w + r2[0]) / d) << 16
| ((r1[1] * w + r2[1]) / d) << 8
| ((r1[2] * w + r2[2]) / d);
}
function areEqual(o1, o2) { function areEqual(o1, o2) {
if (o1 == o2) return true; if (o1 == o2) return true;
if (Array.isArray(o1) && Array.isArray(o2)) { if (Array.isArray(o1) && Array.isArray(o2)) {
@ -76,6 +96,9 @@ kiri.utils = {
ajax, ajax,
o2js, o2js,
js2o, js2o,
avgc,
rgb,
a2c
}; };
})(); })();

View file

@ -7,20 +7,17 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
if (self.kiri.Widget) return; if (self.kiri.Widget) return;
const { base, kiri } = self; const { base, kiri } = self;
const { driver } = kiri; const { api, driver, utils } = kiri;
const { config, util, polygons } = base; const { config, util, polygons } = base;
const { Mesh, newPoint, verticesToPoints } = base; const { Mesh, newPoint, verticesToPoints } = base;
const { inRange, time } = util; const { inRange, time } = util;
const { rgb, avgc } = utils;
const POLY = polygons; const POLY = polygons;
const PRO = Widget.prototype;
const solid_opacity = 1.0; const solid_opacity = 1.0;
const groups = [];
let nextId = 0, let nextId = 0;
groups = [];
kiri.Widget = Widget;
kiri.newWidget = newWidget;
function newWidget(id,group) { return new Widget(id,group) } function newWidget(id,group) { return new Widget(id,group) }
@ -28,121 +25,8 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
function index() { return catalog().index } function index() { return catalog().index }
/** ****************************************************************** class Widget {
* Group helpers constructor(id, group) {
******************************************************************* */
const Group = Widget.Groups = {
list: () => {
return groups.slice()
},
merge: (widgets) => {
let grps = widgets.map(w => w.group).uniq();
if (grps.length > 1) {
let root = grps.shift();
let rpos = root[0].track.pos;
for (let grp of grps) {
for (let w of grp) {
let wpos = w.track.pos;
w.group = root;
w.moveMesh(rpos.x - wpos.x, rpos.y - wpos.y, rpos.z - wpos.z);
w._move(rpos.x, rpos.y, rpos.z, true);
root.push(w);
}
groups.splice(groups.indexOf(grp),1);
}
}
},
split: (widgets) => {
for (let group of widgets.map(w => w.group).uniq()) {
groups.splice(groups.indexOf(group),1);
for (let widget of group) {
let nugroup = Group.forid(widget.id);
nugroup.push(widget);
widget.group = nugroup;
}
}
},
forid: function(id) {
for (let i=0; i<groups.length; i++) {
if (groups[i].id === id) return groups[i];
}
let group = [];
group.id = id;
groups.push(group);
return group;
},
remove: function(widget) {
groups.slice().forEach(group => {
let pos = group.indexOf(widget);
if (pos >= 0) {
group.splice(pos,1);
}
if (group.length === 0) {
pos = groups.indexOf(group);
groups.splice(pos,1);
}
});
},
blocks: function() {
return groups.map(group => {
return {
w: group[0].track.box.w,
h: group[0].track.box.h,
move: (x,y,z,abs) => {
group.forEach(widget => {
widget.mesh.material.visible = true;
widget._move(x, y, z, abs);
});
}
};
});
},
loadDone: function() {
groups.forEach(group => {
if (!group.centered) {
group[0].center();
group.centered = true;
}
});
},
bounds: function(group) {
let bounds = null;
group.forEach(widget => {
let wb = widget.mesh.getBoundingBox(true);
if (bounds) {
bounds = bounds.union(wb);
} else {
bounds = wb;
}
});
return bounds;
},
clear: function() {
groups.length = 0;
}
};
// class Widget {
// constructor(id, group) {
//
// }
// }
/**
* @params {String} [id]
* @constructor
*/
function Widget(id, group) {
this.id = id || new Date().getTime().toString(36)+(nextId++); this.id = id || new Date().getTime().toString(36)+(nextId++);
this.grouped = group ? true : false; this.grouped = group ? true : false;
this.group = group || []; this.group = group || [];
@ -209,69 +93,24 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
this.support = false; this.support = false;
} }
/** ****************************************************************** saveToCatalog(filename) {
* Widget Class Functions
******************************************************************* */
Widget.loadFromCatalog = function(filename, ondone) {
catalog().getFile(filename, function(data) {
let widget = newWidget().loadVertices(data);
widget.meta.file = filename;
ondone(widget);
});
};
Widget.loadFromState = function(id, ondone, move) {
index().get('ws-save-'+id, function(data) {
if (data) {
let vertices = data.geo || data,
indices = data.ind || undefined,
track = data.track || undefined,
group = data.group || id,
anno = data.anno || undefined,
widget = newWidget(id, Group.forid(group)),
meta = data.meta || widget.meta,
ptr = widget.loadVertices({vertices, indices});
widget.meta = meta;
widget.anno = anno || widget.anno;
// restore widget position if specified
if (move && track && track.pos) {
widget.track = track;
widget.move(track.pos.x, track.pos.y, track.pos.z, true);
}
ondone(ptr);
} else {
ondone(null);
}
});
};
Widget.deleteFromState = function(id,ondone) {
index().remove('ws-save-'+id, ondone);
};
/** ******************************************************************
* Widget Prototype Functions
******************************************************************* */
PRO.saveToCatalog = function(filename) {
if (this.grouped) { if (this.grouped) {
return this; return this;
} }
let widget = this; const widget = this;
let time = time(); const mark = time();
widget.meta.file = filename; widget.meta.file = filename;
widget.meta.save = time; widget.meta.save = mark;
catalog().putFile(filename, this.getGeoVertices(true), function(vertices) { catalog().putFile(filename, this.getGeoVertices(true), vertices => {
if (vertices && vertices.length) { if (vertices && vertices.length) {
console.log("saving decimated mesh ["+vertices.length+"] time ["+(time()-time)+"]"); console.log("saving decimated mesh ["+vertices.length+"] time ["+(time()-mark)+"]");
widget.loadVertices(vertices); widget.loadVertices(vertices);
} }
}); });
return this; return this;
}; }
PRO.saveState = function(ondone) { saveState(ondone) {
if (!ondone) { if (!ondone) {
clearTimeout(this._save_timer); clearTimeout(this._save_timer);
this._save_timer = setTimeout(() => { this._save_timer = setTimeout(() => {
@ -280,7 +119,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
}, 1500); }, 1500);
return; return;
} }
let widget = this; const widget = this;
index().put('ws-save-'+this.id, { index().put('ws-save-'+this.id, {
geo: widget.getGeoVertices(false), geo: widget.getGeoVertices(false),
ind: widget.getGeoIndices(), ind: widget.getGeoIndices(),
@ -288,13 +127,13 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
group: this.group.id, group: this.group.id,
meta: this.meta, meta: this.meta,
anno: this.annotations() anno: this.annotations()
}, function(result) { }, result => {
widget.meta.saved = time(); widget.meta.saved = time();
if (ondone) ondone(); if (ondone) ondone();
}); });
}; }
PRO.annotations = function() { annotations() {
let o = Object.clone(this.anno); let o = Object.clone(this.anno);
if (o.support) { if (o.support) {
// clear out THREE.Box temps // clear out THREE.Box temps
@ -303,14 +142,14 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
} }
} }
return o; return o;
}; }
/** /**
* *
* @param {Float32Array} vertices * @param {Float32Array} vertices
* @returns {Widget} * @returns {Widget}
*/ */
PRO.loadVertices = function(data, options = { index: false }) { loadVertices(data, options = { index: false }) {
let vertices, let vertices,
indices, indices,
autoscale = false; autoscale = false;
@ -369,19 +208,21 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
this.points = null; this.points = null;
return this.loadGeometry(geo); return this.loadGeometry(geo);
} }
}; }
PRO.loadData = PRO.loadVertices; loadData() {
return this.loadVertices(...arguments);
}
PRO.setModified = function() { setModified() {
this.modified = true; this.modified = true;
if (this.mesh && this.mesh.geometry) { if (this.mesh && this.mesh.geometry) {
// this fixes ray intersections after the mesh is modified // this fixes ray intersections after the mesh is modified
this.mesh.geometry.boundingSphere = null; this.mesh.geometry.boundingSphere = null;
} }
}; }
PRO.indexGeo = function() { indexGeo() {
let indices = this.getGeoIndices(); let indices = this.getGeoIndices();
if (!indices) { if (!indices) {
let mesh = new Mesh({vertices: this.getGeoVertices()}); let mesh = new Mesh({vertices: this.getGeoVertices()});
@ -389,9 +230,9 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
indices = Uint32Array.from(mesh.faces.map(v => v/3)); indices = Uint32Array.from(mesh.faces.map(v => v/3));
this.loadData({vertices, indices}); this.loadData({vertices, indices});
} }
}; }
PRO.heal = function(debug, refresh) { heal(debug, refresh) {
if (debug) { if (debug) {
let mesh = this.debugMesh().heal(); let mesh = this.debugMesh().heal();
let verts = mesh.vertices; let verts = mesh.vertices;
@ -437,22 +278,22 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
resolve(this.modified); resolve(this.modified);
}, refresh); }, refresh);
}); });
}; }
PRO.debugMesh = function(precision) { debugMesh(precision) {
return new base.Mesh({precision, vertices: this.getVertices().array}); return new base.Mesh({precision, vertices: this.getVertices().array});
}; }
PRO.getVertices = function() { getVertices() {
return this.mesh.geometry.attributes.position; return this.mesh.geometry.attributes.position;
}; }
/** /**
* @param {THREE.Geometry} geometry * @param {THREE.Geometry} geometry
* @returns {Widget} * @returns {Widget}
*/ */
PRO.loadGeometry = function(geometry) { loadGeometry(geometry) {
let mesh = new THREE.Mesh( const mesh = new THREE.Mesh(
geometry, geometry,
new THREE.MeshPhongMaterial({ new THREE.MeshPhongMaterial({
color: 0xffff00, color: 0xffff00,
@ -474,25 +315,25 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
// invalidates points cache (like any scale/rotation) // invalidates points cache (like any scale/rotation)
this.center(true); this.center(true);
return this; return this;
}; }
PRO.groupBounds = function() { groupBounds() {
return Group.bounds(this.group); return Group.bounds(this.group);
}; }
/** /**
* @param {Point[]} points * @param {Point[]} points
* @returns {Widget} * @returns {Widget}
*/ */
PRO.setPoints = function(points) { setPoints(points) {
this.points = points || null; this.points = points || null;
return this; return this;
}; }
/** /**
* remove slice data and their views * remove slice data and their views
*/ */
PRO.clearSlices = function() { clearSlices() {
let slices = this.slices, let slices = this.slices,
mesh = this.mesh; mesh = this.mesh;
if (slices && mesh && mesh.remove) { if (slices && mesh && mesh.remove) {
@ -501,25 +342,12 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
}); });
} }
this.slices = null; this.slices = null;
};
function rgb(c) {
return [ c >> 16, (c >> 8) & 0xff , c & 0xff ];
}
function avgc(c1, c2, w) {
let r1 = rgb(c1);
let r2 = rgb(c2);
let d = (w + 2);
return ((r1[0] * w + r2[0]) / d) << 16
| ((r1[1] * w + r2[1]) / d) << 8
| ((r1[2] * w + r2[2]) / d);
} }
/** /**
* @param {number} color * @param {number} color
*/ */
PRO.setColor = function(color, settings, save = true) { setColor(color, settings, save = true) {
if (settings) { if (settings) {
console.trace('legacy call with settings'); console.trace('legacy call with settings');
} }
@ -531,17 +359,17 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
} }
let material = this.mesh.material; let material = this.mesh.material;
material.color.set(this.meta.disabled ? avgc(0x888888, color, 3) : color); material.color.set(this.meta.disabled ? avgc(0x888888, color, 3) : color);
}; }
PRO.getColor = function() { getColor() {
return this.color; return this.color;
}; }
/** /**
* @param {number} value * @param {number} value
*/ */
PRO.setOpacity = function(value) { setOpacity(value) {
let mesh = this.mesh; const mesh = this.mesh;
if (value <= 0.0) { if (value <= 0.0) {
mesh.material.transparent = solid_opacity < 1.0; mesh.material.transparent = solid_opacity < 1.0;
mesh.material.opacity = solid_opacity; mesh.material.opacity = solid_opacity;
@ -551,12 +379,12 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
mesh.material.opacity = value; mesh.material.opacity = value;
mesh.material.visible = true; mesh.material.visible = true;
} }
}; }
/** /**
* center geometry bottom (on platform) at 0,0,0 * center geometry bottom (on platform) at 0,0,0
*/ */
PRO.center = function(init) { center(init) {
let bb = init ? this.mesh.getBoundingBox(true) : this.groupBounds(), let bb = init ? this.mesh.getBoundingBox(true) : this.groupBounds(),
bm = bb.min.clone(), bm = bb.min.clone(),
bM = bb.max.clone(), bM = bb.max.clone(),
@ -572,13 +400,13 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
}); });
} }
return this; return this;
}; }
/** /**
* called by center() and Group.center() * called by center() and Group.center()
* todo use new prototype.moveMesh() * todo use new prototype.moveMesh()
*/ */
PRO.moveMesh = function(x, y, z) { moveMesh(x, y, z) {
let gap = this.mesh.geometry.attributes.position, let gap = this.mesh.geometry.attributes.position,
pa = gap.array; pa = gap.array;
// center point array on 0,0,0 // center point array on 0,0,0
@ -599,14 +427,14 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
// invalidate cached points // invalidate cached points
this.points = null; this.points = null;
this.setModified(); this.setModified();
}; }
/** /**
* moves top of widget to given Z * moves top of widget to given Z
* *
* @param {number} z position * @param {number} z position
*/ */
PRO.setTopZ = function(z) { setTopZ(z) {
let mesh = this.mesh, let mesh = this.mesh,
pos = this.track.pos, pos = this.track.pos,
ltz = this.last_top_z || {}, ltz = this.last_top_z || {},
@ -626,20 +454,20 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
}; };
this.modified |= (ltz.pz !== ntz.pz || ltz.mpz !== ntz.mpz); this.modified |= (ltz.pz !== ntz.pz || ltz.mpz !== ntz.mpz);
this.last_top_z = ntz; this.last_top_z = ntz;
}; }
PRO.cutZ = function(dist) { cutZ(dist) {
this.track.zcut = dist; this.track.zcut = dist;
this.setTopZ(); this.setTopZ();
}; }
PRO.move = function(x, y, z, abs) { move(x, y, z, abs) {
this.group.forEach(w => { this.group.forEach(w => {
w._move(x, y, z, abs); w._move(x, y, z, abs);
}); });
}; }
PRO._move = function(x, y, z, abs) { _move(x, y, z, abs) {
let mesh = this.mesh, let mesh = this.mesh,
pos = this.track.pos, pos = this.track.pos,
zcut = this.track.zcut || 0; zcut = this.track.zcut || 0;
@ -660,18 +488,18 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
} }
if (x || y || z) { if (x || y || z) {
this.setModified(); this.setModified();
kiri.api.event.emit('widget.move', {widget: this, pos}); api.event.emit('widget.move', {widget: this, pos});
}
} }
};
PRO.scale = function(x, y, z) { scale(x, y, z) {
this.group.forEach(w => { this.group.forEach(w => {
w._scale(x, y, z); w._scale(x, y, z);
}); });
this.center(); this.center();
}; }
PRO._scale = function(x, y, z) { _scale(x, y, z) {
let mesh = this.mesh, let mesh = this.mesh,
scale = this.track.scale; scale = this.track.scale;
this.bounds = null; this.bounds = null;
@ -682,22 +510,22 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
scale.y *= (y || 1.0); scale.y *= (y || 1.0);
scale.z *= (z || 1.0); scale.z *= (z || 1.0);
this.setModified(); this.setModified();
}; }
PRO.rotate = function(x, y, z, temp) { rotate(x, y, z, temp) {
this.group.forEach(w => { this.group.forEach(w => {
w._rotate(x, y, z, temp); w._rotate(x, y, z, temp);
}); });
this.center(false); this.center(false);
}; }
PRO.rotateRaw = function(x, y, z, temp) { rotateRaw(x, y, z, temp) {
this.group.forEach(w => { this.group.forEach(w => {
w._rotate(x, y, z, temp); w._rotate(x, y, z, temp);
}); });
}; }
PRO._rotate = function(x, y, z, temp) { _rotate(x, y, z, temp) {
if (!temp) { if (!temp) {
this.bounds = null; this.bounds = null;
this.setWireframe(false); this.setWireframe(false);
@ -719,25 +547,25 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
rot.z += (z || 0); rot.z += (z || 0);
} }
this.setModified(); this.setModified();
}; }
PRO.unrotate = function() { unrotate() {
this.roto.reverse().forEach(m => { this.roto.reverse().forEach(m => {
this.mesh.geometry.applyMatrix4(m.clone().invert()); this.mesh.geometry.applyMatrix4(m.clone().invert());
}); });
this.roto = []; this.roto = [];
this.center(); this.center();
this.setModified(); this.setModified();
}; }
PRO.mirror = function() { mirror() {
this.group.forEach(w => { this.group.forEach(w => {
w._mirror(); w._mirror();
}); });
this.center(); this.center();
}; }
PRO._mirror = function() { _mirror() {
this.clearSlices(); this.clearSlices();
this.setWireframe(false); this.setWireframe(false);
let geo = this.mesh.geometry, ot = this.track; let geo = this.mesh.geometry, ot = this.track;
@ -748,7 +576,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
for (let i=0; i<count; i++) { for (let i=0; i<count; i++) {
arr[i*3] = -arr[i*3]; arr[i*3] = -arr[i*3];
} }
// invert face vertices // invert face vertex order
for (let i=0; i<count; i+=3) { for (let i=0; i<count; i+=3) {
let x = arr[i*3+0]; let x = arr[i*3+0];
let y = arr[i*3+1]; let y = arr[i*3+1];
@ -766,9 +594,9 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
ot.mirror = !ot.mirror; ot.mirror = !ot.mirror;
this.setModified(); this.setModified();
this.points = null; this.points = null;
}; }
PRO.getGeoVertices = function(unroll) { getGeoVertices(unroll) {
let geo = this.mesh.geometry; let geo = this.mesh.geometry;
let pos = geo.getAttribute('position').array; let pos = geo.getAttribute('position').array;
if (geo.index && unroll !== false) { if (geo.index && unroll !== false) {
@ -787,14 +615,14 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
} else { } else {
return pos; return pos;
} }
}; }
PRO.getGeoIndices = function() { getGeoIndices() {
let indices = this.mesh.geometry.index; let indices = this.mesh.geometry.index;
return indices ? indices.array : undefined; return indices ? indices.array : undefined;
}; }
PRO.iterPoints = function() { iterPoints() {
let verts = this.getGeoVertices(); let verts = this.getGeoVertices();
let index = 0; let index = 0;
let count = verts.length; let count = verts.length;
@ -807,9 +635,9 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
} }
} } } }
}; };
}; }
PRO.getPoints = function() { getPoints() {
if (!this.points) { if (!this.points) {
// convert and cache points from geometry vertices // convert and cache points from geometry vertices
this.points = verticesToPoints(this.getGeoVertices(), { this.points = verticesToPoints(this.getGeoVertices(), {
@ -817,17 +645,17 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
}); });
} }
return this.points; return this.points;
}; }
PRO.getBoundingBox = function(refresh) { getBoundingBox(refresh) {
if (!this.bounds || refresh) { if (!this.bounds || refresh) {
this.bounds = new THREE.Box3(); this.bounds = new THREE.Box3();
this.bounds.setFromPoints(this.getPoints()); this.bounds.setFromPoints(this.getPoints());
} }
return this.bounds; return this.bounds;
}; }
PRO.getPositionBox = function() { getPositionBox() {
let bounds = this.getBoundingBox().clone(); let bounds = this.getBoundingBox().clone();
let pos = this.track.pos; let pos = this.track.pos;
bounds.min.x += pos.x; bounds.min.x += pos.x;
@ -835,29 +663,24 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
bounds.min.y += pos.y; bounds.min.y += pos.y;
bounds.max.y += pos.y; bounds.max.y += pos.y;
return bounds; return bounds;
}; }
PRO.isModified = function() { isModified() {
return this.modified; return this.modified;
}; }
PRO.getExtruder = function(settings) { getExtruder(settings) {
if (settings) { if (settings) {
console.trace('legacy call with settings'); console.trace('legacy call with settings');
} }
return this.anno.extruder || 0; return this.anno.extruder || 0;
// if (settings && settings.widget) { }
// let rec = settings.widget[this.id];
// return rec && rec.extruder >= 0 ? rec.extruder : 0;
// }
// return 0;
};
// allow worker code to run in same memspace as client // allow worker code to run in same memspace as client
PRO.setInWorker = function() { setInWorker() {
this.inWorker = true; this.inWorker = true;
return this; return this;
}; }
/** /**
* processes points into facets, then into slices * processes points into facets, then into slices
@ -872,7 +695,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
* @params {Function} [ondone] * @params {Function} [ondone]
* @params {Function} [onupdate] * @params {Function} [onupdate]
*/ */
PRO.slice = function(settings, ondone, onupdate) { slice(settings, ondone, onupdate) {
let widget = this; let widget = this;
let startTime = time(); let startTime = time();
@ -943,12 +766,12 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
// discard point cache // discard point cache
widget.points = undefined; widget.points = undefined;
}; }
/** /**
* render to provided stack * render to provided stack
*/ */
PRO.render = function(stack) { render(stack) {
const mark = Date.now(); const mark = Date.now();
this.slices.forEach(slice => { this.slices.forEach(slice => {
if (slice.layers) { if (slice.layers) {
@ -956,10 +779,10 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
} }
}); });
return Date.now() - mark; return Date.now() - mark;
}; }
PRO.setWireframe = function(set, color, opacity) { setWireframe(set, color, opacity) {
if (!(kiri.api && kiri.api.conf)) { if (!(api && api.conf)) {
// missing api features in engine mode // missing api features in engine mode
return; return;
} }
@ -971,7 +794,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
this.wire = null; this.wire = null;
} }
if (set) { if (set) {
let dark = kiri.api.conf.get().controller.dark; let dark = api.space.is_dark();
let mat = new THREE.MeshBasicMaterial({ let mat = new THREE.MeshBasicMaterial({
wireframe: true, wireframe: true,
color: dark ? 0xaaaaaa : 0, color: dark ? 0xaaaaaa : 0,
@ -981,7 +804,7 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
let wire = widget.wire = new THREE.Mesh(mesh.geometry.shallowClone(), mat); let wire = widget.wire = new THREE.Mesh(mesh.geometry.shallowClone(), mat);
mesh.add(wire); mesh.add(wire);
} }
if (kiri.api.view.get() === kiri.consts.VIEWS.ARRANGE) { if (api.view.is_arrange()) {
this.setColor(this.color); this.setColor(this.color);
} else { } else {
this.setColor(0x888888,undefined,false); this.setColor(0x888888,undefined,false);
@ -989,14 +812,155 @@ console.log/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
if (opacity !== undefined) { if (opacity !== undefined) {
widget.setOpacity(opacity); widget.setOpacity(opacity);
} }
}; }
PRO.show = function() { show() {
this.mesh.visible = true; this.mesh.visible = true;
}
hide() {
this.mesh.visible = false;
}
}
// Widget Grouping API
const Group = Widget.Groups = {
list() {
return groups.slice()
},
merge(widgets) {
let grps = widgets.map(w => w.group).uniq();
if (grps.length > 1) {
let root = grps.shift();
let rpos = root[0].track.pos;
for (let grp of grps) {
for (let w of grp) {
let wpos = w.track.pos;
w.group = root;
w.moveMesh(rpos.x - wpos.x, rpos.y - wpos.y, rpos.z - wpos.z);
w._move(rpos.x, rpos.y, rpos.z, true);
root.push(w);
}
groups.splice(groups.indexOf(grp),1);
}
}
},
split(widgets) {
for (let group of widgets.map(w => w.group).uniq()) {
groups.splice(groups.indexOf(group),1);
for (let widget of group) {
let nugroup = Group.forid(widget.id);
nugroup.push(widget);
widget.group = nugroup;
}
}
},
forid(id) {
for (let i=0; i<groups.length; i++) {
if (groups[i].id === id) return groups[i];
}
let group = [];
group.id = id;
groups.push(group);
return group;
},
remove(widget) {
groups.slice().forEach(group => {
let pos = group.indexOf(widget);
if (pos >= 0) {
group.splice(pos,1);
}
if (group.length === 0) {
pos = groups.indexOf(group);
groups.splice(pos,1);
}
});
},
blocks() {
return groups.map(group => {
return {
w: group[0].track.box.w,
h: group[0].track.box.h,
move: (x,y,z,abs) => {
group.forEach(widget => {
widget.mesh.material.visible = true;
widget._move(x, y, z, abs);
});
}
};
});
},
loadDone() {
groups.forEach(group => {
if (!group.centered) {
group[0].center();
group.centered = true;
}
});
},
bounds(group) {
let bounds = null;
group.forEach(widget => {
let wb = widget.mesh.getBoundingBox(true);
if (bounds) {
bounds = bounds.union(wb);
} else {
bounds = wb;
}
});
return bounds;
},
clear() {
groups.length = 0;
}
}; };
PRO.hide = function() { Widget.loadFromCatalog = function(filename, ondone) {
this.mesh.visible = false; catalog().getFile(filename, function(data) {
let widget = newWidget().loadVertices(data);
widget.meta.file = filename;
ondone(widget);
});
}; };
Widget.loadFromState = function(id, ondone, move) {
index().get('ws-save-'+id, function(data) {
if (data) {
let vertices = data.geo || data,
indices = data.ind || undefined,
track = data.track || undefined,
group = data.group || id,
anno = data.anno || undefined,
widget = newWidget(id, Group.forid(group)),
meta = data.meta || widget.meta,
ptr = widget.loadVertices({vertices, indices});
widget.meta = meta;
widget.anno = anno || widget.anno;
// restore widget position if specified
if (move && track && track.pos) {
widget.track = track;
widget.move(track.pos.x, track.pos.y, track.pos.z, true);
}
ondone(ptr);
} else {
ondone(null);
}
});
};
Widget.deleteFromState = function(id,ondone) {
index().remove('ws-save-'+id, ondone);
};
kiri.Widget = Widget;
kiri.newWidget = newWidget;
})(); })();