added cylinder selection
This commit is contained in:
parent
f21d8b19fe
commit
f3174b681d
4 changed files with 165 additions and 49 deletions
|
|
@ -421,7 +421,11 @@ CAM.init = function(kiri, api) {
|
|||
};
|
||||
|
||||
func.opAddHelical = () => {
|
||||
func.opAdd(popOp.helical.new());
|
||||
func.traceDone();
|
||||
func.surfaceDone();
|
||||
let rec = popOp.helical.new();
|
||||
rec.cylinders = { /* widget.id: [ faces... ] */ };
|
||||
func.opAdd(rec);
|
||||
};
|
||||
|
||||
// TAB/TRACE BUTTON HANDLERS
|
||||
|
|
@ -1086,6 +1090,7 @@ CAM.init = function(kiri, api) {
|
|||
func.traceDone();
|
||||
func.surfaceDone();
|
||||
func.selectHolesDone();
|
||||
func.helicalDone();
|
||||
};
|
||||
api.event.on("cam.trace.clear", func.traceClear = () => {
|
||||
func.traceDone();
|
||||
|
|
@ -1355,27 +1360,64 @@ CAM.init = function(kiri, api) {
|
|||
});
|
||||
};
|
||||
|
||||
let helicalOn = false;
|
||||
func.selectHelical = () => {
|
||||
|
||||
console.log("select helical")
|
||||
|
||||
|
||||
CAM.cylinderFaces((progress,msg)=>{
|
||||
api.show.progress(progress,msg)
|
||||
},(data)=>{
|
||||
|
||||
console.log(data)
|
||||
|
||||
func.selectHelicalDone(data);
|
||||
})
|
||||
|
||||
|
||||
console.log("select helical",{helicalOn})
|
||||
if (helicalOn) {
|
||||
return func.surfaceDone();
|
||||
}
|
||||
func.clearPops();
|
||||
alert = api.show.alert("analyzing surfaces...", 1000);
|
||||
let cylinders = poppedRec.cylinders;
|
||||
|
||||
CAM.surface_prep(currentIndex * RAD2DEG, () => {
|
||||
api.hide.alert(alert);
|
||||
alert = api.show.alert("[esc] cancels surface selection");
|
||||
for (let [wid, arr] of Object.entries(cylinders)) {
|
||||
let widget = api.widgets.forid(wid);
|
||||
if (widget && arr.length)
|
||||
for (let faceid of arr) {
|
||||
CAM.cylinderToggle(widget, faceid, faceids => {
|
||||
cylinders[widget.id] = faceids;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
helicalOn = hoveredOp;
|
||||
helicalOn.classList.add("editing");
|
||||
api.feature.on_mouse_up = (obj, ev) => {
|
||||
let { face } = obj;
|
||||
let min = Math.min(face.a, face.b, face.c);
|
||||
let faceid = min / 3;
|
||||
let widget = lastWidget = obj.object.widget;
|
||||
CAM.cylinderToggle(widget, faceid, ({faces,error}) => {
|
||||
if (error) {
|
||||
api.show.alert(error,3000);
|
||||
return;
|
||||
}
|
||||
cylinders[widget.id] = faces;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
func.selectHelicalDone = () =>{
|
||||
|
||||
console.log("select helical done")
|
||||
func.helicalDone = () =>{
|
||||
if (!(helicalOn && poppedRec && poppedRec.cylinders)) {
|
||||
return;
|
||||
}
|
||||
let {cylinders} = poppedRec;
|
||||
for (let wid of Object.keys(cylinders)) {
|
||||
let widget = api.widgets.forid(wid);
|
||||
if (widget) {
|
||||
CAM.cylinderClear(widget);
|
||||
} else {
|
||||
delete cylinders[wid];
|
||||
}
|
||||
}
|
||||
api.hide.alert(alert);
|
||||
api.feature.on_mouse_up = undefined;
|
||||
helicalOn.classList.remove("editing");
|
||||
helicalOn = false;
|
||||
console.log("helicalOn set to false")
|
||||
}
|
||||
|
||||
// COMMON TAB/TRACE EVENT HANDLERS
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ kiri.load(api => {
|
|||
widget.selectFaces(Object.values(widget._surfaces).flat());
|
||||
};
|
||||
|
||||
CAM.cylinder_show = function(widget) {
|
||||
widget.selectFaces(Object.values(widget._cylinders).flat());
|
||||
};
|
||||
|
||||
|
||||
CAM.surface_toggle = function(widget, face, radians, ondone) {
|
||||
let surfaces = widget._surfaces = widget._surfaces || {};
|
||||
for (let [root, faces] of Object.entries(surfaces)) {
|
||||
|
|
@ -108,28 +113,31 @@ kiri.load(api => {
|
|||
|
||||
}
|
||||
|
||||
CAM.cylinderToggle = (widget, face, radians, onDone) => {
|
||||
let surfaces = widget._cylinders = widget._cylinders || {};
|
||||
for (let [root, faces] of Object.entries(surfaces)) {
|
||||
if (faces.contains(face)) {
|
||||
CAM.cylinderToggle = (widget, face, onDone) => {
|
||||
let cyls = widget._cylinders = widget._cylinders || {};
|
||||
for (let [root, faces] of Object.entries(cyls)) {
|
||||
if (faces.contains(face)) { // if a face group contains the selected face
|
||||
// delete this face group
|
||||
delete surfaces[root];
|
||||
CAM.surface_show(widget);
|
||||
ondone(Object.keys(surfaces).map(v => parseInt(v)));
|
||||
delete cyls[root];
|
||||
CAM.cylinder_show(widget);
|
||||
onDone(Object.keys(cyls).map(v => parseInt(v)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
kiri.client.send("cam_surface_find", { id: widget.id, face, radians }, faces => {
|
||||
if (faces.length) {
|
||||
surfaces[face] = faces;
|
||||
CAM.surface_show(widget);
|
||||
//send
|
||||
kiri.client.send("cam_cylinder_find", { id: widget.id, face }, ({faces,error}) => {
|
||||
if (faces?.length) {
|
||||
cyls[face] = faces;
|
||||
CAM.cylinder_show(widget);
|
||||
}
|
||||
ondone(Object.keys(surfaces).map(v => parseInt(v)));
|
||||
|
||||
onDone({faces:Object.keys(cyls).map(v => parseInt(v)),error});
|
||||
});
|
||||
}
|
||||
|
||||
CAM.cylinderClear = (onProgress, onDone) => {
|
||||
|
||||
CAM.cylinderClear = (widget) => {
|
||||
widget.selectFaces([]);
|
||||
widget._cylinders = {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -143,10 +151,7 @@ kiri.load(api => {
|
|||
}
|
||||
};
|
||||
|
||||
CAM.surface_find = function(widget, faces, radians) {
|
||||
CAM.surface_prep(widget);
|
||||
return widget.tool.findConnectedSurface(faces, radians || 0, 0.0);
|
||||
};
|
||||
|
||||
|
||||
kiri.worker.cam_surfaces = function(data, send) {
|
||||
const { settings, index } = data;
|
||||
|
|
@ -215,19 +220,14 @@ kiri.load(api => {
|
|||
} } )));
|
||||
}
|
||||
|
||||
kiri.worker.cam_cylinder_faces = async function(data,send){
|
||||
const { settings, rec } = data;
|
||||
const widgets = Object.values(kiri.worker.cache);
|
||||
console.log("hi from the worker")
|
||||
|
||||
for (let [i,widget] of widgets.entries() ) {
|
||||
CAM.surface_prep(widget);
|
||||
if (await CAM.cylinders(settings, widget,)) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
kiri.worker.cam_cylinder_find = async function(data,send){
|
||||
const { id, face, settings } = data;
|
||||
const widget = kiri.worker.cache[id];
|
||||
try{
|
||||
const faces = CAM.cylinder_find(widget, face);
|
||||
send.done({faces});
|
||||
}catch(error){
|
||||
send.done({error});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -568,6 +568,16 @@ CAM.cylinders = async (settings, widget, opts) => {
|
|||
return Array.from(cylinderTriangles.values())
|
||||
}
|
||||
|
||||
CAM.surface_find = function(widget, faces, radians) {
|
||||
CAM.surface_prep(widget);
|
||||
return widget.tool.findConnectedSurface(faces, radians || 0, 0.0);
|
||||
};
|
||||
|
||||
CAM.cylinder_find = (widget, face)=>{
|
||||
CAM.surface_prep(widget);
|
||||
return widget.tool.findCylinderSurface(face);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a list of holes in the model based on the given diameter.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -238,6 +238,8 @@ mesh.tool = class MeshTool {
|
|||
fn++;
|
||||
}
|
||||
}
|
||||
//faces are the normals in groups of 6 [nx,]
|
||||
|
||||
this.indexed = {
|
||||
faces, sides, sideExt
|
||||
};
|
||||
|
|
@ -304,6 +306,68 @@ mesh.tool = class MeshTool {
|
|||
return faces;
|
||||
}
|
||||
|
||||
findCylinderSurface(face){
|
||||
face = Number(face)
|
||||
|
||||
const radianTolerance = 8 * (Math.PI/180);
|
||||
//helper function
|
||||
const dissimilar = (a,b,c) => a!==b && a!==c && b!==c
|
||||
|
||||
let found = {}
|
||||
let out = [face]
|
||||
const {vertices}= this
|
||||
const {faces} = this.getIndex();
|
||||
|
||||
const zs = [vertices[face*3+2],vertices[face*3+5],vertices[face*3+8]]
|
||||
.map(z => Math.round(z*1000)/1000)
|
||||
|
||||
if(dissimilar(...zs)){
|
||||
throw "face must have only 2 Z values"
|
||||
}else if(Math.abs( faces[face * 6 + 2] > 1e-6 )){
|
||||
throw "face's normal must be perpendicular to Z axis"
|
||||
}
|
||||
const lowZ = Math.min(zs)
|
||||
const highZ = Math.max(zs)
|
||||
|
||||
const checked = {};
|
||||
const check = [face]
|
||||
found[face] = 1;
|
||||
while (check.length) {
|
||||
const face = check.shift();
|
||||
const froot = face * 6;
|
||||
const vroot = face * 9
|
||||
|
||||
// filter faces to those perpendicular to +z axis
|
||||
if ( Math.abs( faces[froot + 2] > 1e-6 )) continue;
|
||||
//filter faces with verts don't share the z values of the first face
|
||||
if(
|
||||
!(vertices[vroot + 2] !== lowZ || vertices[vroot + 2] !== highZ) &&
|
||||
!(vertices[vroot + 5] !== lowZ || vertices[vroot + 5] !== highZ) &&
|
||||
!(vertices[vroot + 8] !== lowZ || vertices[vroot + 8] !== highZ)
|
||||
) continue;
|
||||
|
||||
const fadj = this.getAdjacentFaces(face);
|
||||
for (let f of fadj) {
|
||||
if (found[f] || checked[f]) {
|
||||
continue;
|
||||
}
|
||||
const aroot = f * 6;
|
||||
let sum = 0;
|
||||
for (let i=0; i<3; i++) {
|
||||
sum += Math.pow(faces[froot + i] - faces[aroot + i], 2);
|
||||
}
|
||||
const fn = Math.sqrt(sum);
|
||||
if (fn <= radianTolerance) {
|
||||
out.push(f);
|
||||
check.push(f)
|
||||
checked[f] = 1;
|
||||
found[f] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// given a list of faces (indices), return an array of closed
|
||||
// polylines that represent the outlines of each discrete island
|
||||
generateOutlines(list) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue