Mostly finish knife tool

Closes #1945
This commit is contained in:
JannisX11 2024-04-05 18:36:18 +02:00
parent dad6dcfa1d
commit 7bf8c4482b
2 changed files with 50 additions and 6 deletions

View File

@ -125,8 +125,10 @@ class KnifeToolContext {
this.mesh.mesh.add(this.points_mesh); this.mesh.mesh.add(this.points_mesh);
this.mesh.mesh.add(this.lines_mesh); this.mesh.mesh.add(this.lines_mesh);
}
showToast() {
this.toast = Blockbench.showToastNotification({ this.toast = Blockbench.showToastNotification({
text: 'Using Knife Tool. Click here to apply!', text: tl('message.knife_tool.confirm', [Keybinds.extra.confirm.keybind.label]),
icon: BarItems.knife_tool.icon, icon: BarItems.knife_tool.icon,
click: () => { click: () => {
this.apply(); this.apply();
@ -210,14 +212,49 @@ class KnifeToolContext {
let last_point = this.points.last(); let last_point = this.points.last();
if (last_point && this.hover_point) { if (last_point && this.hover_point) {
let this_point = this.hover_point; let this_point = this.hover_point;
// Todo: Send error message when crossing faces let isSupported = (point_1, point_2) => {
let crossed_faces = (last_point.type == 'face' && this_point.type == 'face' && last_point.fkey != this_point.fkey) if (point_1.type == 'face' && point_2.type == 'face') {
return point_1.fkey == point_2.fkey;
}
if (point_1.type == 'face' && point_2.type == 'line') {
let face = this.mesh.faces[point_1.fkey];
return (face && face.vertices.includes(point_2.attached_line[0]) && face.vertices.includes(point_2.attached_line[1]));
}
if (point_1.type == 'face' && point_2.type == 'vertex') {
let face = this.mesh.faces[point_1.fkey];
return (face && face.vertices.includes(point_2.attached_vertex));
}
if (point_1.type != 'face' && point_2.type != 'face' && (point_1.type != point_2.type || point_1 == last_point)) {
let pointInFace = (point, vertices) => {
if (point.type == 'line') {
return vertices.includes(point.attached_line[0]) && vertices.includes(point.attached_line[1]);
} else {
return vertices.includes(point.attached_vertex)
}
}
for (let fkey in this.mesh.faces) {
let vertices = this.mesh.faces[fkey]?.vertices;
if (pointInFace(point_1, vertices) && pointInFace(point_2, vertices)) {
return true;
}
}
}
}
if (!isSupported(last_point, this_point) && !isSupported(this_point, last_point)) {
Blockbench.showQuickMessage('message.knife_tool.skipped_face', 2200);
}
} }
this.points.push(this.hover_point); this.points.push(this.hover_point);
this.hover_point = null; this.hover_point = null;
if (this.points.length == 1) this.showToast();
} }
apply() { apply() {
if (!this.mesh || !this.points.length) {
this.cancel();
return;
}
function intersectLinesIgnoreTouching(p1, p2, p3, p4) { function intersectLinesIgnoreTouching(p1, p2, p3, p4) {
let s1 = [ p2[0] - p1[0], p2[1] - p1[1] ]; let s1 = [ p2[0] - p1[0], p2[1] - p1[1] ];
let s2 = [ p4[0] - p3[0], p4[1] - p3[1] ]; let s2 = [ p4[0] - p3[0], p4[1] - p3[1] ];
@ -556,7 +593,7 @@ class KnifeToolContext {
} }
} }
} else { } else {
console.error('Knife tool: Failed to find face for edge', edge, nearest_vertices); //console.error('Knife tool: Failed to find face for edge', edge, nearest_vertices);
break; break;
} }
limiter++; limiter++;
@ -578,7 +615,7 @@ class KnifeToolContext {
this.mesh.mesh.remove(this.points_mesh); this.mesh.mesh.remove(this.points_mesh);
this.mesh.mesh.remove(this.lines_mesh); this.mesh.mesh.remove(this.lines_mesh);
delete this.mesh delete this.mesh
this.toast.delete(); if (this.toast) this.toast.delete();
KnifeToolContext.current = null; KnifeToolContext.current = null;
} }
static current = null; static current = null;
@ -1497,13 +1534,18 @@ BARS.defineActions(function() {
modes: ['edit'], modes: ['edit'],
condition: () => Modes.edit && Mesh.hasAny(), condition: () => Modes.edit && Mesh.hasAny(),
onCanvasMouseMove(data) { onCanvasMouseMove(data) {
if (!KnifeToolContext.current && Mesh.selected[0] && Mesh.selected.length == 1) {
KnifeToolContext.current = new KnifeToolContext(Mesh.selected[0]);
}
if (KnifeToolContext.current) { if (KnifeToolContext.current) {
KnifeToolContext.current.hover(data); KnifeToolContext.current.hover(data);
} }
}, },
onCanvasClick(data) { onCanvasClick(data) {
if (!data) return; if (!data) return;
if (!KnifeToolContext.current) KnifeToolContext.current = new KnifeToolContext(data.element); if (!KnifeToolContext.current && data.element instanceof Mesh) {
KnifeToolContext.current = new KnifeToolContext(data.element);
}
let context = KnifeToolContext.current; let context = KnifeToolContext.current;
context.addPoint(data); context.addPoint(data);
}, },

View File

@ -360,6 +360,8 @@
"message.meshes_and_box_uv": "Meshes are not compatible with Box UV. Go to File > Project... and switch to Per-face UV.", "message.meshes_and_box_uv": "Meshes are not compatible with Box UV. Go to File > Project... and switch to Per-face UV.",
"message.no_valid_elements": "No valid elements selected...", "message.no_valid_elements": "No valid elements selected...",
"message.palette_locked": "The palette is locked", "message.palette_locked": "The palette is locked",
"message.knife_tool.confirm": "Press %0 or click here to apply Knife Tool",
"message.knife_tool.skipped_face": "Cannot cut between different faces. Include the edges or vertices between them!",
"message.wireframe.enabled": "Wireframe view enabled", "message.wireframe.enabled": "Wireframe view enabled",
"message.wireframe.disabled": "Wireframe view disabled", "message.wireframe.disabled": "Wireframe view disabled",