2021-12-29 16:49:15 -05:00
|
|
|
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
|
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
|
|
2021-12-29 21:52:24 -05:00
|
|
|
gapp.register("mesh.model", [
|
2021-12-31 13:26:07 -05:00
|
|
|
"add.array", // dep: add.array
|
2021-12-29 16:49:15 -05:00
|
|
|
"add.three", // dep: add.three
|
|
|
|
|
"moto.license", // dep: moto.license
|
2021-12-31 13:26:07 -05:00
|
|
|
"mesh.object", // dep: mesh.object
|
2021-12-30 22:59:46 -05:00
|
|
|
"mesh.group", // dep: mesh.group
|
2022-01-11 20:02:29 -05:00
|
|
|
"mesh.util", // dep: mesh.util
|
2022-01-01 12:12:57 -05:00
|
|
|
"mesh.api", // dep: mesh.api
|
2021-12-29 16:49:15 -05:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
let mesh = self.mesh = self.mesh || {};
|
2021-12-29 21:52:24 -05:00
|
|
|
if (mesh.model) return;
|
2021-12-29 16:49:15 -05:00
|
|
|
|
2022-01-03 17:13:50 -05:00
|
|
|
let mapp = mesh;
|
2022-01-02 14:25:28 -05:00
|
|
|
let space = moto.Space;
|
|
|
|
|
let worker = moto.client.fn;
|
2022-01-12 11:46:10 -05:00
|
|
|
let { MeshPhongMaterial, MeshBasicMaterial } = THREE;
|
|
|
|
|
let { BufferGeometry, BufferAttribute, DoubleSide, Mesh } = THREE;
|
2022-01-02 14:25:28 -05:00
|
|
|
|
2021-12-29 21:52:24 -05:00
|
|
|
/** default materials **/
|
2021-12-31 17:14:55 -05:00
|
|
|
let materials = mesh.material = {
|
2022-01-13 11:59:26 -05:00
|
|
|
// model unselected
|
|
|
|
|
normal: new MeshPhongMaterial({
|
2022-01-12 11:46:10 -05:00
|
|
|
side: DoubleSide,
|
2021-12-29 17:20:17 -05:00
|
|
|
transparent: true,
|
|
|
|
|
shininess: 100,
|
2022-01-05 17:58:37 -05:00
|
|
|
specular: 0x202020,
|
2021-12-29 17:20:17 -05:00
|
|
|
color: 0xffff00,
|
|
|
|
|
opacity: 1
|
2021-12-31 17:14:55 -05:00
|
|
|
}),
|
2022-01-13 11:59:26 -05:00
|
|
|
// model selected
|
|
|
|
|
select: new MeshPhongMaterial({
|
|
|
|
|
side: DoubleSide,
|
|
|
|
|
transparent: true,
|
|
|
|
|
shininess: 100,
|
|
|
|
|
specular: 0x202020,
|
|
|
|
|
color: 0x00ee00,
|
|
|
|
|
opacity: 1
|
|
|
|
|
}),
|
|
|
|
|
// face selected (for groups ranges)
|
|
|
|
|
face: new MeshPhongMaterial({
|
2022-01-12 11:46:10 -05:00
|
|
|
side: DoubleSide,
|
2021-12-31 17:14:55 -05:00
|
|
|
transparent: true,
|
|
|
|
|
shininess: 100,
|
2022-01-05 17:58:37 -05:00
|
|
|
specular: 0x202020,
|
2022-01-13 12:59:18 -05:00
|
|
|
color: 0xee0000,
|
2021-12-31 17:14:55 -05:00
|
|
|
opacity: 1
|
2022-01-03 21:14:36 -05:00
|
|
|
}),
|
2022-01-12 11:46:10 -05:00
|
|
|
wireframe: new MeshBasicMaterial({
|
|
|
|
|
side: DoubleSide,
|
2022-01-03 21:14:36 -05:00
|
|
|
wireframe: true,
|
2022-01-14 14:14:13 -05:00
|
|
|
color: 0x0,
|
|
|
|
|
transparent: true,
|
|
|
|
|
opacity: 0.5
|
2022-01-03 21:14:36 -05:00
|
|
|
}),
|
2021-12-29 17:20:17 -05:00
|
|
|
};
|
|
|
|
|
|
2021-12-29 21:52:24 -05:00
|
|
|
/** 3D model rendered on plaform **/
|
2021-12-31 13:26:07 -05:00
|
|
|
mesh.model = class MeshModel extends mesh.object {
|
2022-01-03 17:13:50 -05:00
|
|
|
constructor(data, id) {
|
|
|
|
|
super(id);
|
2022-01-05 09:29:27 -05:00
|
|
|
let { file, mesh, vertices, indices, normals } = data;
|
2021-12-29 16:49:15 -05:00
|
|
|
|
|
|
|
|
if (!mesh) {
|
|
|
|
|
dbug.error(`'${file}' missing mesh data`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 21:39:09 -05:00
|
|
|
// remove file name extensions
|
|
|
|
|
let text = file || '';
|
|
|
|
|
let dot = text.lastIndexOf('.');
|
|
|
|
|
if (dot > 0) file = text.substring(0, dot);
|
|
|
|
|
|
2022-01-13 11:59:26 -05:00
|
|
|
// create local materials
|
|
|
|
|
this.mats = {
|
|
|
|
|
normal: materials.normal.clone(),
|
|
|
|
|
select: materials.select.clone(),
|
|
|
|
|
face: materials.face.clone()
|
|
|
|
|
};
|
|
|
|
|
|
2022-01-13 20:23:48 -05:00
|
|
|
// information about selected faces, lines, and vertices
|
|
|
|
|
// vertex compound keys are sorted least index to greatest
|
|
|
|
|
this.sel = {
|
|
|
|
|
faces: [], // first index into vertices
|
|
|
|
|
lines: {}, // key = vertex-vertex, val = [ faces ]
|
|
|
|
|
verts: {}, // key = x-y-z, val = { faces:[], sphere }
|
|
|
|
|
};
|
|
|
|
|
|
2022-01-02 21:39:09 -05:00
|
|
|
this.file = file || 'unnamed';
|
2022-01-05 09:29:27 -05:00
|
|
|
this.load(mesh || vertices, indices, normals);
|
2021-12-29 17:20:17 -05:00
|
|
|
}
|
|
|
|
|
|
2022-01-05 17:58:37 -05:00
|
|
|
get type() {
|
2022-01-02 14:25:28 -05:00
|
|
|
return "model";
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 17:58:37 -05:00
|
|
|
get object() {
|
2021-12-31 13:26:07 -05:00
|
|
|
return this.mesh;
|
2021-12-30 22:59:46 -05:00
|
|
|
}
|
|
|
|
|
|
2022-01-08 21:00:19 -05:00
|
|
|
get matrix() {
|
|
|
|
|
return this.mesh.matrixWorld.elements;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-11 14:41:49 -05:00
|
|
|
// return new group containing just this model in world coordinates
|
|
|
|
|
duplicate() {
|
|
|
|
|
worker.model_duplicate({
|
2022-01-08 21:00:19 -05:00
|
|
|
matrix: this.matrix,
|
2022-01-01 22:39:49 -05:00
|
|
|
id: this.id
|
2021-12-31 22:11:20 -05:00
|
|
|
}).then(data => {
|
2022-01-11 18:41:49 -05:00
|
|
|
mesh.api.group.new([new mesh.model({
|
2022-01-11 14:41:49 -05:00
|
|
|
file: `${this.file}-dup`,
|
2022-01-07 14:39:32 -05:00
|
|
|
mesh: data
|
2022-01-12 15:55:09 -05:00
|
|
|
})]).select();
|
2021-12-31 22:11:20 -05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 09:29:27 -05:00
|
|
|
load(vertices, indices, normals) {
|
2022-01-12 11:46:10 -05:00
|
|
|
let geo = new BufferGeometry();
|
|
|
|
|
geo.setAttribute('position', new BufferAttribute(vertices, 3));
|
|
|
|
|
if (indices) geo.setIndex(new BufferAttribute(indices, 1));
|
2022-01-05 09:29:27 -05:00
|
|
|
if (!normals) geo.computeVertexNormals();
|
2022-01-13 11:59:26 -05:00
|
|
|
let meh = this.mesh = new Mesh(geo, [
|
|
|
|
|
this.mats.normal,
|
|
|
|
|
this.mats.face
|
|
|
|
|
]);
|
|
|
|
|
geo.addGroup(0, Infinity, 0);
|
2021-12-29 17:20:17 -05:00
|
|
|
meh.receiveShadow = true;
|
|
|
|
|
meh.castShadow = true;
|
|
|
|
|
meh.renderOrder = 1;
|
2022-01-06 09:38:04 -05:00
|
|
|
// sets fallback opacity for wireframe toggle
|
|
|
|
|
this.opacity(1);
|
2022-01-01 00:04:35 -05:00
|
|
|
// this ref allows clicks to be traced to models and groups
|
|
|
|
|
meh.model = this;
|
2022-01-13 21:17:35 -05:00
|
|
|
// persist in db so it can be restored on page load
|
|
|
|
|
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
|
2022-01-02 00:40:43 -05:00
|
|
|
// sync data to worker
|
2022-01-02 14:25:28 -05:00
|
|
|
worker.model_load({id: this.id, name: this.file, vertices, indices});
|
2021-12-29 16:49:15 -05:00
|
|
|
}
|
2021-12-29 23:52:48 -05:00
|
|
|
|
2022-01-05 09:29:27 -05:00
|
|
|
reload(vertices, indices, normals) {
|
2022-01-11 14:41:49 -05:00
|
|
|
let was = this.wireframe(false);
|
2022-01-04 08:15:26 -05:00
|
|
|
let geo = this.mesh.geometry;
|
2022-01-12 11:46:10 -05:00
|
|
|
geo.setAttribute('position', new BufferAttribute(vertices, 3));
|
2022-01-04 08:15:26 -05:00
|
|
|
geo.setAttribute('normal', undefined);
|
2022-01-12 11:46:10 -05:00
|
|
|
if (indices) geo.setIndex(new BufferAttribute(indices, 1));
|
2022-01-04 17:42:19 -05:00
|
|
|
geo.attributes.position.needsUpdate = true;
|
2022-01-05 09:29:27 -05:00
|
|
|
if (!normals) geo.computeVertexNormals();
|
2022-01-13 21:17:35 -05:00
|
|
|
// persist in db so it can be restored on page load
|
|
|
|
|
mapp.db.space.put(this.id, { file: this.file, mesh: vertices });
|
2022-01-04 17:42:19 -05:00
|
|
|
// sync data to worker
|
2022-01-04 08:15:26 -05:00
|
|
|
worker.model_load({id: this.id, name: this.name, vertices, indices});
|
2022-01-11 14:41:49 -05:00
|
|
|
// restore wireframe state
|
|
|
|
|
this.wireframe(was);
|
2022-01-04 08:15:26 -05:00
|
|
|
}
|
2022-01-04 01:11:13 -05:00
|
|
|
|
2021-12-29 23:52:48 -05:00
|
|
|
get group() {
|
|
|
|
|
return this._group;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set group(gv) {
|
2021-12-30 22:59:46 -05:00
|
|
|
if (gv && this._group && this._group !== gv) {
|
|
|
|
|
throw "models can only belong to one group";
|
2021-12-29 23:52:48 -05:00
|
|
|
}
|
|
|
|
|
this._group = gv;
|
|
|
|
|
}
|
2021-12-30 22:59:46 -05:00
|
|
|
|
2022-01-05 21:16:18 -05:00
|
|
|
get attributes() {
|
|
|
|
|
return this.mesh.geometry.attributes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get vertices() {
|
2022-01-05 22:09:49 -05:00
|
|
|
return this.attributes.position.count;
|
2022-01-05 21:16:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get faces() {
|
|
|
|
|
return this.vertices / 3;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-11 14:41:49 -05:00
|
|
|
// todo -- put model into its own group
|
|
|
|
|
ungroup() {
|
|
|
|
|
// get current world coordinates
|
|
|
|
|
let { mid } = meh.getBoundingBox();
|
|
|
|
|
// transform mesh into world coordinates
|
|
|
|
|
// move mesh to origin
|
|
|
|
|
// create and add to group
|
|
|
|
|
// move group center back to original center
|
|
|
|
|
geo.moveMesh(-mid.x, -mid.y, -mid.z);
|
|
|
|
|
geo.computeBoundingBox();
|
|
|
|
|
this.move(mid.x, mid.y, mid.z);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-13 11:59:26 -05:00
|
|
|
// get, set, or toggle visibility of model and wireframe
|
2022-01-06 09:38:04 -05:00
|
|
|
visible(bool) {
|
|
|
|
|
if (bool === undefined) {
|
|
|
|
|
return this.mesh.visible;
|
|
|
|
|
}
|
|
|
|
|
if (bool.toggle) {
|
|
|
|
|
return this.visible(!this.mesh.visible);
|
|
|
|
|
}
|
|
|
|
|
this.mesh.visible = bool;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-13 11:59:26 -05:00
|
|
|
// get, set, or toggle selection of model (coloring)
|
|
|
|
|
select(bool) {
|
|
|
|
|
if (bool === undefined) {
|
|
|
|
|
return this.mesh.material[0] === this.mats.normal;
|
|
|
|
|
}
|
|
|
|
|
if (bool.toggle) {
|
|
|
|
|
return this.select(!this.select());
|
|
|
|
|
}
|
|
|
|
|
this.mesh.material[0] = bool ? this.mats.select : this.mats.normal;
|
|
|
|
|
return bool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// return selected state
|
|
|
|
|
selected() {
|
|
|
|
|
return this.select();
|
2022-01-06 09:38:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
opacity(ov, opt = {}) {
|
2021-12-30 23:23:45 -05:00
|
|
|
let mat = this.mesh.material;
|
|
|
|
|
if (ov === undefined) {
|
2022-01-13 11:59:26 -05:00
|
|
|
return mat[0].opacity;
|
2021-12-30 23:23:45 -05:00
|
|
|
}
|
2022-01-06 09:38:04 -05:00
|
|
|
if (ov.restore) {
|
|
|
|
|
ov = this._op;
|
|
|
|
|
} else if (ov.temp !== undefined) {
|
|
|
|
|
ov = ov.temp;
|
|
|
|
|
} else {
|
|
|
|
|
this._op = ov;
|
|
|
|
|
}
|
2022-01-13 11:59:26 -05:00
|
|
|
for (let m of Object.values(this.mats)) {
|
|
|
|
|
if (ov <= 0.0) {
|
|
|
|
|
m.transparent = false;
|
|
|
|
|
m.opacity = 1;
|
|
|
|
|
m.visible = false;
|
|
|
|
|
} else {
|
|
|
|
|
m.transparent = true;
|
|
|
|
|
m.opacity = ov;
|
|
|
|
|
m.visible = true;
|
|
|
|
|
}
|
2021-12-30 23:23:45 -05:00
|
|
|
}
|
2022-01-02 14:25:28 -05:00
|
|
|
space.update();
|
2021-12-30 23:23:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wireframe(bool, opt = {}) {
|
2022-01-14 14:14:13 -05:00
|
|
|
let was = this._wire ? true : false;
|
2021-12-30 23:28:36 -05:00
|
|
|
if (bool === undefined) {
|
2022-01-14 14:14:13 -05:00
|
|
|
return was ? {
|
2021-12-30 23:28:36 -05:00
|
|
|
enabled: true,
|
2022-01-06 09:38:04 -05:00
|
|
|
opacity: this.opacity(),
|
2022-01-14 14:14:13 -05:00
|
|
|
color: was ? this._wire.material.color : undefined,
|
2021-12-30 23:28:36 -05:00
|
|
|
} : {
|
|
|
|
|
enabled: false
|
|
|
|
|
};
|
|
|
|
|
}
|
2022-01-01 13:43:35 -05:00
|
|
|
if (bool.toggle) {
|
2022-01-14 14:14:13 -05:00
|
|
|
bool = !was;
|
2022-01-01 13:43:35 -05:00
|
|
|
}
|
2022-01-14 14:14:13 -05:00
|
|
|
// no change
|
2022-01-12 01:09:34 -05:00
|
|
|
if (was === bool) {
|
|
|
|
|
return was;
|
|
|
|
|
}
|
2022-01-14 14:14:13 -05:00
|
|
|
if (was) {
|
2021-12-30 23:23:45 -05:00
|
|
|
this.mesh.remove(this._wire);
|
|
|
|
|
this._wire = undefined;
|
2022-01-06 09:38:04 -05:00
|
|
|
this.opacity({restore: true});
|
2021-12-30 23:23:45 -05:00
|
|
|
}
|
|
|
|
|
if (bool) {
|
2022-01-12 11:46:10 -05:00
|
|
|
this._wire = new Mesh(this.mesh.geometry.shallowClone(), materials.wireframe);
|
2021-12-30 23:23:45 -05:00
|
|
|
this.mesh.add(this._wire);
|
2022-01-13 11:59:26 -05:00
|
|
|
this.opacity({temp: opt.opacity || 0.15});
|
2021-12-30 23:23:45 -05:00
|
|
|
}
|
2022-01-02 14:25:28 -05:00
|
|
|
space.update();
|
2022-01-11 14:41:49 -05:00
|
|
|
return was;
|
2021-12-30 23:23:45 -05:00
|
|
|
}
|
|
|
|
|
|
2022-01-14 14:14:13 -05:00
|
|
|
normals(bool) {
|
|
|
|
|
let was = this._norm ? true : false;
|
|
|
|
|
if (bool === undefined) {
|
|
|
|
|
return was;
|
|
|
|
|
}
|
|
|
|
|
if (bool.toggle) {
|
|
|
|
|
bool = !was;
|
|
|
|
|
}
|
|
|
|
|
// no change
|
|
|
|
|
if (was === bool) {
|
|
|
|
|
return was;
|
|
|
|
|
}
|
|
|
|
|
if (was) {
|
|
|
|
|
this.mesh.remove(this._norm);
|
|
|
|
|
this._norm = undefined;
|
|
|
|
|
}
|
|
|
|
|
if (bool) {
|
|
|
|
|
this.mesh.add(this._norm = mesh.util.faceNormals(this.mesh, { size: 0.5 }));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 22:59:46 -05:00
|
|
|
remove() {
|
2022-01-02 00:40:43 -05:00
|
|
|
if (arguments.length === 0) {
|
|
|
|
|
// direct call requires pass through group
|
2022-01-03 17:13:50 -05:00
|
|
|
this.group.remove(this);
|
|
|
|
|
this.group = undefined;
|
|
|
|
|
this.removed = 'pending';
|
2022-01-02 00:40:43 -05:00
|
|
|
} else {
|
2022-01-09 21:05:14 -05:00
|
|
|
// manage lifecycle with worker, mesh app caches, etc
|
|
|
|
|
this.destroy();
|
2022-01-03 17:13:50 -05:00
|
|
|
// tag removed for debugging
|
|
|
|
|
this.removed = 'complete';
|
2022-01-02 00:40:43 -05:00
|
|
|
}
|
2021-12-30 22:59:46 -05:00
|
|
|
}
|
2022-01-08 22:42:57 -05:00
|
|
|
|
|
|
|
|
updateBoundsBox() {
|
2022-01-13 12:59:18 -05:00
|
|
|
if (this.group) {
|
|
|
|
|
mesh.util.defer(this.group.deferUBB);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-13 20:23:48 -05:00
|
|
|
clearSelections() {
|
2022-01-13 21:17:35 -05:00
|
|
|
// clear face selections (since they've been deleted);
|
|
|
|
|
this.sel.faces = [];
|
|
|
|
|
this.updateSelections();
|
2022-01-13 20:23:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deleteSelections(mode) {
|
|
|
|
|
let { geometry } = this.mesh;
|
|
|
|
|
let { groups } = geometry;
|
|
|
|
|
let { array } = geometry.attributes.position;
|
|
|
|
|
let newtot = 0;
|
|
|
|
|
// filter to unselected groups
|
|
|
|
|
groups = groups.filter(g => g.materialIndex === 0);
|
|
|
|
|
for (let group of groups) {
|
|
|
|
|
let start = group.start * 3;
|
|
|
|
|
let count = group.count * 3;
|
|
|
|
|
newtot += group.count < Infinity ? count : array.length - start;
|
|
|
|
|
}
|
|
|
|
|
// nothing to do if new length is the same
|
|
|
|
|
if (newtot === array.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let newverts = new Float32Array(newtot);
|
|
|
|
|
let pos = 0;
|
|
|
|
|
// copy back unselected faces
|
|
|
|
|
for (let group of groups) {
|
|
|
|
|
let start = group.start * 3;
|
|
|
|
|
let count = group.count * 3;
|
|
|
|
|
if (count === Infinity) count = array.length - start;
|
|
|
|
|
let slice = array.slice(start, start + count);
|
|
|
|
|
newverts.set(slice, pos);
|
|
|
|
|
pos += count;
|
|
|
|
|
}
|
|
|
|
|
this.reload(newverts);
|
|
|
|
|
// clear face selections (since they've been deleted);
|
|
|
|
|
this.sel.faces = [];
|
|
|
|
|
this.updateSelections();
|
|
|
|
|
|
|
|
|
|
// let { modes } = mesh.api;
|
|
|
|
|
// switch (mode) {
|
|
|
|
|
// case modes.face:
|
|
|
|
|
// console.log('delete selected faces');
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateSelections() {
|
|
|
|
|
let faces = this.sel.faces;
|
2022-01-13 12:59:18 -05:00
|
|
|
let groups = [];
|
|
|
|
|
if (faces && faces.length) {
|
|
|
|
|
faces = faces.sort((a,b) => a - b).slice();
|
|
|
|
|
let first = faces.shift();
|
|
|
|
|
if (first > 0) {
|
|
|
|
|
groups.push({ start: 0, count: first, mat: 0 });
|
|
|
|
|
}
|
|
|
|
|
let range = { start: first, count: 1, mat: 1 };
|
|
|
|
|
groups.push(range);
|
|
|
|
|
for (let face of faces) {
|
|
|
|
|
if (face === range.start + range.count) {
|
|
|
|
|
range.count++;
|
|
|
|
|
} else {
|
|
|
|
|
groups.push(range = { start: range.start + range.count, count: face - range.start - range.count });
|
|
|
|
|
groups.push(range = { start: face, count: 1, mat: 1 });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
groups.push({ start: range.start + range.count, count: Infinity });
|
|
|
|
|
} else {
|
|
|
|
|
groups.push({ start: 0, count: Infinity });
|
|
|
|
|
}
|
|
|
|
|
let geo = this.mesh.geometry;
|
|
|
|
|
geo.clearGroups();
|
|
|
|
|
for (let group of groups) {
|
|
|
|
|
geo.addGroup(group.start*3, group.count*3, group.mat || 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toggleSelectedFaces(toggle = []) {
|
2022-01-13 20:23:48 -05:00
|
|
|
let faces = this.sel.faces;
|
2022-01-13 12:59:18 -05:00
|
|
|
for (let t of toggle) {
|
|
|
|
|
faces.remove(t) || faces.addOnce(t);
|
|
|
|
|
}
|
2022-01-13 20:23:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toggleSelectedVertices(vert) {
|
|
|
|
|
if (Array.isArray(vert)) {
|
|
|
|
|
for (let e of vert) {
|
|
|
|
|
this.toggleSelectedVertices(e);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let sel = this.sel;
|
|
|
|
|
let key = [x,y,z].map(v => v.round(5)).join('-');
|
|
|
|
|
let rec = sel.verts[key];
|
|
|
|
|
if (rec) {
|
|
|
|
|
delete sel.verts[key];
|
|
|
|
|
space.scene.remove(rec.sphere);
|
|
|
|
|
} else {
|
|
|
|
|
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 );
|
|
|
|
|
sphere.position.set(x, y, z);
|
|
|
|
|
space.scene.add(sphere);
|
|
|
|
|
sel.verts[key] = {
|
|
|
|
|
sphere,
|
|
|
|
|
faces,
|
|
|
|
|
verts
|
|
|
|
|
};
|
|
|
|
|
}
|
2022-01-08 22:42:57 -05:00
|
|
|
}
|
|
|
|
|
|
2022-01-12 23:02:08 -05:00
|
|
|
// find adjacent faces to clicked point/line on a face
|
2022-01-13 11:59:26 -05:00
|
|
|
find(point, face) {
|
2022-01-12 23:02:08 -05:00
|
|
|
let { x, y, z } = point;
|
2022-01-12 23:19:24 -05:00
|
|
|
let { a, b, c } = face;
|
|
|
|
|
worker.model_select({
|
|
|
|
|
id: this.id, x, y:-z, z:y, a, b, c, matrix: this.matrix
|
2022-01-12 23:02:08 -05:00
|
|
|
}).then(data => {
|
2022-01-13 20:23:48 -05:00
|
|
|
let { faces, edges, verts, point } = data;
|
2022-01-13 21:17:35 -05:00
|
|
|
// console.log({data});
|
2022-01-13 20:23:48 -05:00
|
|
|
// this.toggleSelectedVertices(verts);
|
2022-01-13 12:59:18 -05:00
|
|
|
this.toggleSelectedFaces(faces);
|
2022-01-13 20:23:48 -05:00
|
|
|
this.updateSelections();
|
2022-01-12 23:02:08 -05:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-29 16:49:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
})();
|