missing edges module
This commit is contained in:
parent
4261d2eea9
commit
06b0974940
1 changed files with 207 additions and 0 deletions
207
src/mesh/edges.js
Normal file
207
src/mesh/edges.js
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
|
||||
|
||||
/**
|
||||
* facet edge selecetor. allows for creating new facets
|
||||
* when two connected edges share a single point.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// dep: moto.space
|
||||
gapp.register("mesh.edges", [], (root, exports) => {
|
||||
|
||||
const { Line2, LineMaterial, LineGeometry, Vector3, Group } = THREE;
|
||||
const { base, mesh, moto } = root;
|
||||
const { space } = moto;
|
||||
const { newPoint } = base;
|
||||
|
||||
let isActive;
|
||||
let hovered;
|
||||
let selected = [];
|
||||
|
||||
// hovered edge object
|
||||
let geo, mat, obj = new Line2(
|
||||
geo = new LineGeometry(),
|
||||
mat = new LineMaterial({
|
||||
linewidth: 6,
|
||||
color: 0x88ff00,
|
||||
alphaToCoverage: false,
|
||||
})
|
||||
|
||||
);
|
||||
|
||||
// split functions
|
||||
let edges = {
|
||||
active() {
|
||||
return isActive ? true : false;
|
||||
},
|
||||
|
||||
start() {
|
||||
if (isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { api } = mesh;
|
||||
|
||||
isActive = true;
|
||||
selected.length = 0;
|
||||
obj.visible = false;
|
||||
|
||||
space.scene.add(obj);
|
||||
|
||||
// enable temp mode
|
||||
let state = edges.state = { obj };
|
||||
let models = state.models = api.selection.models();
|
||||
let meshes = models.map(m => m.mesh);
|
||||
|
||||
// find closest facet edge to hover location
|
||||
space.mouse.onHover((int, event, ints) => {
|
||||
if (!event) {
|
||||
obj.visible = false;
|
||||
return meshes;
|
||||
}
|
||||
if (event.buttons) {
|
||||
return;
|
||||
}
|
||||
|
||||
obj.visible = true;
|
||||
|
||||
let { point, face, object } = int;
|
||||
let side = edges.closest_edge(point, face, object);
|
||||
let { p0, p1 } = side;
|
||||
let verts = side.verts = [ p0.x, -p0.z, p0.y, p1.x, -p1.z, p1.y ];
|
||||
geo.setPositions(verts);
|
||||
hovered = { object, face, side };
|
||||
});
|
||||
isActive = true;
|
||||
},
|
||||
|
||||
end() {
|
||||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
let space = moto.space;
|
||||
space.scene.remove(obj);
|
||||
space.scene.remove(edges.selected);
|
||||
space.mouse.onHover(undefined);
|
||||
isActive = edges.state = undefined;
|
||||
mesh.api.selection.update();
|
||||
},
|
||||
|
||||
async add() {
|
||||
if (selected.length === 2 && selected[0].object === selected[1].object) {
|
||||
let verts = selected.map(s => [ s.side.p0, s.side.p1 ]).flat();
|
||||
// clean up floating point cruft for comparison
|
||||
for (let v of verts) {
|
||||
v.x = v.x.round(3);
|
||||
v.y = v.y.round(3);
|
||||
v.z = v.z.round(3);
|
||||
}
|
||||
// sort points so dups show up next to each other
|
||||
let sort = verts.sort((a,b) => {
|
||||
if (a.x !== b.x) {
|
||||
return a.x - b.x;
|
||||
} else if (a.y !== b.y) {
|
||||
return a.y - b.y;
|
||||
} else {
|
||||
return a.z - b.z;
|
||||
}
|
||||
}).filter((point, index, arr) => {
|
||||
return index === 0 ||
|
||||
point.x !== arr[index - 1].x ||
|
||||
point.y !== arr[index - 1].y ||
|
||||
point.z !== arr[index - 1].z;
|
||||
});
|
||||
let model = selected[0].object.model;
|
||||
if (verts.length === 3) {
|
||||
await model.duplicate({ append: [
|
||||
sort[0].x, -sort[0].z, sort[0].y,
|
||||
sort[1].x, -sort[1].z, sort[1].y,
|
||||
sort[2].x, -sort[2].z, sort[2].y,
|
||||
]});
|
||||
model.remove();
|
||||
} else if (verts.length === 4) {
|
||||
await model.duplicate({ append: [
|
||||
verts[0].x, -verts[0].z, verts[0].y,
|
||||
verts[1].x, -verts[1].z, verts[1].y,
|
||||
verts[2].x, -verts[2].z, verts[2].y,
|
||||
verts[1].x, -verts[1].z, verts[1].y,
|
||||
verts[2].x, -verts[2].z, verts[2].y,
|
||||
verts[3].x, -verts[3].z, verts[3].y,
|
||||
]});
|
||||
model.remove();
|
||||
}
|
||||
// refresh object target cache
|
||||
edges.end();
|
||||
edges.start();
|
||||
}
|
||||
},
|
||||
|
||||
clear() {
|
||||
selected.length = 0;
|
||||
space.scene.remove(edges.selected);
|
||||
},
|
||||
|
||||
select() {
|
||||
space.scene.remove(edges.selected);
|
||||
|
||||
const { object, face, side } = hovered;
|
||||
let add = true;
|
||||
for (let i=0; i<selected.length; i++) {
|
||||
let s = selected[i];
|
||||
let { p0, p1 } = s.side;
|
||||
let sp = newPoint(
|
||||
(p0.x + p1.x) / 2,
|
||||
(p0.y + p1.y) / 2,
|
||||
(p0.z + p1.z) / 2,
|
||||
);
|
||||
let tp = newPoint(
|
||||
(side.p0.x + side.p1.x) / 2,
|
||||
(side.p0.y + side.p1.y) / 2,
|
||||
(side.p0.z + side.p1.z) / 2,
|
||||
);
|
||||
// because two faces can share edges that don't match
|
||||
// we compare midpoints of the line segments for a match
|
||||
let pd = sp.distTo3D(tp);
|
||||
if (s.object === object && Math.abs(pd) < 0.0001) {
|
||||
selected.splice(i,1);
|
||||
add = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add) {
|
||||
selected.push(hovered);
|
||||
}
|
||||
|
||||
const group = edges.selected = new Group();
|
||||
space.scene.add(edges.selected);
|
||||
|
||||
for (let sel of selected) {
|
||||
let geo = new LineGeometry();
|
||||
let line = new Line2( geo, new LineMaterial({
|
||||
linewidth: 4,
|
||||
color: 0x0088ff,
|
||||
alphaToCoverage: false,
|
||||
}) );
|
||||
geo.setPositions(sel.side.verts);
|
||||
group.add(line);
|
||||
}
|
||||
},
|
||||
|
||||
closest_edge(point, face, object) {
|
||||
let { position } = object.geometry.attributes;
|
||||
let matrix = object.matrixWorld;
|
||||
point = newPoint(point.x, point.y, point.z);
|
||||
let v0 = new Vector3(position.getX(face.a), position.getY(face.a), position.getZ(face.a)).applyMatrix4(matrix);
|
||||
let v1 = new Vector3(position.getX(face.b), position.getY(face.b), position.getZ(face.b)).applyMatrix4(matrix);
|
||||
let v2 = new Vector3(position.getX(face.c), position.getY(face.c), position.getZ(face.c)).applyMatrix4(matrix);
|
||||
let l0 = { p0:v0, p1:v1, d:point.distToLine3D(v0, v1), v:[face.a,face.b].sort() };
|
||||
let l1 = { p0:v1, p1:v2, d:point.distToLine3D(v1, v2), v:[face.b,face.c].sort() };
|
||||
let l2 = { p0:v2, p1:v0, d:point.distToLine3D(v2, v0), v:[face.c,face.a].sort() };
|
||||
return [ l0, l1, l2 ].sort((a,b) => a.d - b.d)[0];
|
||||
}
|
||||
}
|
||||
|
||||
exports(edges);
|
||||
|
||||
});
|
||||
Loading…
Reference in a new issue