diff --git a/src/kiri/main.js b/src/kiri/main.js
index 86acdb1d..9acaee49 100644
--- a/src/kiri/main.js
+++ b/src/kiri/main.js
@@ -3344,23 +3344,11 @@
let url = WIN.URL.createObjectURL(new Blob([data], {type: "octet/stream"}));
$('mod-any').innerHTML = `x`;
$('_dexport_').click();
- // fixes Chrome/iOS download, but loses name and breaks others
- // let reader = new FileReader();
- // let out = new Blob([data], {type: 'octet/stream'});
- // reader.onload = function(e){
- // window.location.href = reader.result;
- // }
- // reader.readAsDataURL(out);
}
// prevent safari from exiting full screen mode
DOC.onkeydown = function (evt) { if (evt.keyCode == 27) evt.preventDefault() }
- // K3DB.onIdle(function() {
- // upgrade on db idle. maybe delay init, too
- // console.log("k3db idle");
- // });
-
// run optional module functions NOW before kiri-init has run
if (Array.isArray(self.kirimod)) {
kirimod.forEach(function(mod) { mod(kiri.api) });
diff --git a/src/main/mesh.js b/src/main/mesh.js
index 8e6c2d8a..16be54df 100644
--- a/src/main/mesh.js
+++ b/src/main/mesh.js
@@ -7,6 +7,7 @@
let broker = gapp.broker;
let call = broker.send;
let dbindex = [ "admin", "space" ];
+let worker = moto.client.fn;
let { Quaternion, Vector3 } = THREE;
// set below. called once the DOM readyState = complete
@@ -160,13 +161,13 @@ function space_init(data) {
case 'KeyF':
return selection.floor().focus();
case 'KeyM':
- return selection.merge();
+ return api.tool.merge();
case 'KeyA':
- return selection.analyze();
+ return api.tool.analyze();
case 'KeyR':
- return selection.repair();
+ return api.tool.repair();
case 'KeyN':
- return selection.clean();
+ return api.tool.clean();
case 'KeyV':
return selection.focus();
case 'KeyW':
@@ -245,7 +246,7 @@ function space_init(data) {
}
]);
- // mouse hover/click handlers
+ // mouse hover/click handlers. required to enable model drag in space.js
space.mouse.downSelect((int, event) => {
return event && event.shiftKey ? api.objects() : undefined;
});
@@ -256,17 +257,17 @@ function space_init(data) {
if (model) {
let group = model.group;
let { ctrlKey, metaKey, shiftKey } = event;
- if (metaKey) {
+ if (shiftKey && metaKey) {
+ // find faces adjacent to point/line clicked
+ model.select(int.point, int.face);
+ } else if (metaKey) {
// set focus on intersected face
let { x, y, z } = int.point;
+ // y,z swap due to world rotation for orbit controls
api.focus({center: { x, y:-z, z:y }});
} else if (ctrlKey) {
- // lay flat when ctrl clicking a selected face
- let q = new Quaternion();
- // find intersecting point, look "up" on Z and rotate to face that
- q.setFromUnitVectors(int.face.normal, new Vector3(0,0,-1));
- group.qrotation(q);
- group.floor();
+ // rotate selected face towawrd z "floor"
+ group.faceDown(int.face.normal);
} else {
selection.toggle(shiftKey ? model : model.group);
}
diff --git a/src/mesh/api.js b/src/mesh/api.js
index a733326c..ca352fd2 100644
--- a/src/mesh/api.js
+++ b/src/mesh/api.js
@@ -39,6 +39,7 @@ let selection = {
return selected.length || strict ? selected.slice() : groups.slice();
},
+ // return selected groups + groups from selected models
groups(strict) {
let all = selection.list(strict);
let grp = all.filter(s => s instanceof mesh.group);
@@ -49,6 +50,7 @@ let selection = {
return grp;
},
+ // return selected models + models from selected groups
models(strict) {
let all = selection.list(strict);
let grp = all.filter(s => s instanceof mesh.group);
@@ -125,22 +127,6 @@ let selection = {
}
},
- analyze() {
- tool.analyze(selection.models());
- },
-
- repair() {
- tool.repair(selection.models());
- },
-
- clean() {
- tool.clean(selection.models());
- },
-
- merge() {
- tool.merge(selection.models());
- },
-
// update material selections
update() {
for (let group of groups) {
@@ -295,8 +281,15 @@ let file = {
},
};
+// return selection if models are invalid. can happen when called from
+// even bound to a button which delivers a PointEvent argument
+function fallback(models) {
+ return Array.isArray(models) ? models : selection.models();
+}
+
let tool = {
merge(models) {
+ models = fallback(models);
api.log.emit(`merging ${models.length} models`).pin();
worker.model_merge(models.map(m => {
return { id: m.id, matrix: m.matrix }
@@ -312,6 +305,7 @@ let tool = {
},
analyze(models) {
+ models = fallback(models);
api.log.emit('analyzing mesh(es)...').pin();
let promises = [];
let newmdl = [];
@@ -337,6 +331,7 @@ let tool = {
},
heal(models, opt = {}) {
+ models = fallback(models);
let promises = [];
for (let m of models) {
let p = worker.model_heal({
@@ -360,6 +355,7 @@ let tool = {
},
repair(models) {
+ models = fallback(models);
api.log.emit('repairing mesh(es)...').pin();
tool.heal(models, { merge: true }).then(() => {
api.log.emit('repair commplete').pin();
@@ -367,8 +363,8 @@ let tool = {
});
},
- clean(models) {
- api.log.emit('cleaning mesh(es)...').pin();
+ clean(models = selection.models()) {
+ models = fallback(models);
tool.heal(models, { merge: false }).then(() => {
api.log.emit('cleaning complete').pin();
api.selection.update();
diff --git a/src/mesh/build.js b/src/mesh/build.js
index 1edf9f98..e1a3db65 100644
--- a/src/mesh/build.js
+++ b/src/mesh/build.js
@@ -228,11 +228,11 @@ function ui_build() {
h.button({ _: 'wireframe', onclick() { api.wireframe() } }),
h.div({ class: "vsep" }),
h.button({ _: 'duplicate', onclick: api.selection.duplicate }),
- h.button({ _: 'merge', onclick: api.selection.merge }),
+ h.button({ _: 'merge', onclick: api.tool.merge }),
h.div({ class: "vsep" }),
- h.button({ _: 'analyze', onclick: api.selection.analyze }),
- h.button({ _: 'repair', onclick: api.selection.repair }),
- h.button({ _: 'clean', onclick: api.selection.clean }),
+ h.button({ _: 'analyze', onclick: api.tool.analyze }),
+ h.button({ _: 'repair', onclick: api.tool.repair }),
+ h.button({ _: 'clean', onclick: api.tool.clean }),
]),
]);
diff --git a/src/mesh/group.js b/src/mesh/group.js
index 396da67c..0a6d27aa 100644
--- a/src/mesh/group.js
+++ b/src/mesh/group.js
@@ -17,18 +17,19 @@ gapp.register("mesh.group", [
let mesh = self.mesh = self.mesh || {};
if (mesh.group) return;
+let { Quaternion, Group, Vector3 } = THREE;
let broker = gapp.broker;
let call = broker.send;
-
let space = moto.Space;
let worker = moto.client.fn;
+let lookUp = new Vector3(0,0,-1);
mesh.group = class MeshGroup extends mesh.object {
// @param group {MeshModel[]}
constructor(models = [], id, name) {
super(id);
- this.group3 = new THREE.Group();
+ this.group3 = new Group();
this.models = [];
this.name = name;
for (let model of models) {
@@ -88,6 +89,13 @@ mesh.group = class MeshGroup extends mesh.object {
return this;
}
+ // rotate model so face normal points toward floor
+ faceDown(normal) {
+ let q = new Quaternion().setFromUnitVectors(normal, lookUp);
+ this.qrotation(q);
+ this.floor();
+ }
+
promote() {
return this.centerModels().centerXY().floor();
}
diff --git a/src/mesh/model.js b/src/mesh/model.js
index 1aebea3f..0ca8d637 100644
--- a/src/mesh/model.js
+++ b/src/mesh/model.js
@@ -253,6 +253,21 @@ mesh.model = class MeshModel extends mesh.object {
mesh.util.defer(this.group.deferUBB);
}
+ // find adjacent faces to clicked point/line on a face
+ select(point, face) {
+ let geometry = new THREE.SphereGeometry( 0.5, 16, 16 );
+ let material = new MeshPhongMaterial( { color: 0x777777, transparent: true, opacity: 0.25 } );
+ let sphere = new Mesh( geometry, material );
+ let { x, y, z } = point;
+ sphere.position.set(x,y,z);
+ space.scene.add(sphere);
+ worker.model_locate({
+ id: this.id, x, y:-z, z:y, matrix: this.matrix
+ }).then(data => {
+ console.log('located', data);
+ });
+ }
+
};
})();
diff --git a/src/mesh/work.js b/src/mesh/work.js
index 2a5d2407..759ce8b1 100644
--- a/src/mesh/work.js
+++ b/src/mesh/work.js
@@ -33,6 +33,7 @@ function cacheUpdate(id, data) {
Object.assign(cache[id], data);
}
+// translate original mesh vertices into UI world view (PI/2 rotation on X)
function translate_encode(id, matrix) {
let rec = cache[id];
let geo = rec.geo.clone();
@@ -97,6 +98,26 @@ let model = {
return {
vertices: tool.unrolled().toFloat32(),
};
+ },
+
+ // given model and point, locate matching vertices, lines, and faces
+ locate(data) {
+ let { id, x, y, z, matrix } = data;
+ let arr = translate_encode(id, matrix);
+ let eps = 2;
+ for (let i=0, l=arr.length; i