complete parametric scaling with axis grouping. angles in degrees
This commit is contained in:
parent
833e6367e7
commit
03a9eb396f
4 changed files with 79 additions and 38 deletions
|
|
@ -440,6 +440,11 @@ let prefs = {
|
||||||
map: {
|
map: {
|
||||||
info: {},
|
info: {},
|
||||||
mode: modes.object,
|
mode: modes.object,
|
||||||
|
edit: {
|
||||||
|
scale_group_X: true,
|
||||||
|
scale_group_Y: true,
|
||||||
|
scale_group_Z: true
|
||||||
|
},
|
||||||
space: {
|
space: {
|
||||||
wire: false,
|
wire: false,
|
||||||
grid: true,
|
grid: true,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ if (mesh.build) return;
|
||||||
let broker = gapp.broker;
|
let broker = gapp.broker;
|
||||||
let call = broker.send;
|
let call = broker.send;
|
||||||
let { api, util } = mesh;
|
let { api, util } = mesh;
|
||||||
|
let rad = 180 / Math.PI;
|
||||||
let und = undefined;
|
let und = undefined;
|
||||||
|
|
||||||
broker.listeners({
|
broker.listeners({
|
||||||
|
|
@ -297,14 +298,14 @@ function ui_build() {
|
||||||
let [ pos, rot ] = side;
|
let [ pos, rot ] = side;
|
||||||
return h.div({ class: "grid"}, [
|
return h.div({ class: "grid"}, [
|
||||||
h.div({ _: "" }),
|
h.div({ _: "" }),
|
||||||
h.div({ _: X, class: "top", id: root ? [ root, l, X ] : und }),
|
h.div({ _: X, class: "top noselect", id: root ? [ root, l, X ] : und }),
|
||||||
h.div({ _: Y, class: "top", id: root ? [ root, l, Y ] : und }),
|
h.div({ _: Y, class: "top noselect", id: root ? [ root, l, Y ] : und }),
|
||||||
h.div({ _: Z, class: "top", id: root ? [ root, l, Z ] : und }),
|
h.div({ _: Z, class: "top noselect", id: root ? [ root, l, Z ] : und }),
|
||||||
h.div({ _: side[0], class: "side" }),
|
h.div({ _: side[0], class: "side noselect" }),
|
||||||
h.label({ _: v1[0], id: root ? [ root, v, X, pos ] : und }),
|
h.label({ _: v1[0], id: root ? [ root, v, X, pos ] : und }),
|
||||||
h.label({ _: v1[1], id: root ? [ root, v, Y, pos ] : und }),
|
h.label({ _: v1[1], id: root ? [ root, v, Y, pos ] : und }),
|
||||||
h.label({ _: v1[2], id: root ? [ root, v, Z, pos ] : und }),
|
h.label({ _: v1[2], id: root ? [ root, v, Z, pos ] : und }),
|
||||||
h.div({ _: side[1], class: "side" }),
|
h.div({ _: side[1], class: "side noselect" }),
|
||||||
h.label({ _: v2[0], id: root ? [ root, v, X, rot ] : und }),
|
h.label({ _: v2[0], id: root ? [ root, v, X, rot ] : und }),
|
||||||
h.label({ _: v2[1], id: root ? [ root, v, Y, rot ] : und }),
|
h.label({ _: v2[1], id: root ? [ root, v, Y, rot ] : und }),
|
||||||
h.label({ _: v2[2], id: root ? [ root, v, Z, rot ] : und }),
|
h.label({ _: v2[2], id: root ? [ root, v, Z, rot ] : und }),
|
||||||
|
|
@ -350,7 +351,7 @@ function ui_build() {
|
||||||
|
|
||||||
// return function bound to field editing clicks
|
// return function bound to field editing clicks
|
||||||
// builds a modal dialog that updates the object and field
|
// builds a modal dialog that updates the object and field
|
||||||
function field_edit(title, get, set) {
|
function field_edit(title, set) {
|
||||||
return function(ev) {
|
return function(ev) {
|
||||||
let onclick = (ev) => {
|
let onclick = (ev) => {
|
||||||
let tempval = parseFloat($('tempval').value);
|
let tempval = parseFloat($('tempval').value);
|
||||||
|
|
@ -359,8 +360,7 @@ function ui_build() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let g of api.selection.groups()) {
|
for (let g of api.selection.groups()) {
|
||||||
let old = get(g);
|
set(g, tempval);
|
||||||
set(g, tempval, old);
|
|
||||||
g.floor(mesh.group);
|
g.floor(mesh.group);
|
||||||
defer_selection(); // update ui
|
defer_selection(); // update ui
|
||||||
}
|
}
|
||||||
|
|
@ -410,7 +410,7 @@ function ui_build() {
|
||||||
let g_id = s_grp.map(g => g.id).join(' ');
|
let g_id = s_grp.map(g => g.id).join(' ');
|
||||||
let h_grp = sblock('group', g_id, grid(
|
let h_grp = sblock('group', g_id, grid(
|
||||||
util.extract(g_pos, map),
|
util.extract(g_pos, map),
|
||||||
util.extract(g_rot, map),
|
util.extract(g_rot).map(r => (r * rad).round(2).toFixed(map.fixed)),
|
||||||
und, und, 'group'
|
und, und, 'group'
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
@ -461,44 +461,68 @@ function ui_build() {
|
||||||
[ group_val_X_rot, group_val_Y_rot, group_val_Z_rot ].forEach(e => {
|
[ group_val_X_rot, group_val_Y_rot, group_val_Z_rot ].forEach(e => {
|
||||||
e.classList.add('editable');
|
e.classList.add('editable');
|
||||||
});
|
});
|
||||||
group_val_X_rot.onclick = field_edit('x rotation', group => {
|
group_val_X_rot.onclick = field_edit('x rotation', (group, val) => {
|
||||||
return group.rotation();
|
let r = group.rotation();
|
||||||
}, (group, val, old) => {
|
group.rotation(val/rad, r.y, r.z);
|
||||||
group.rotation(val, old.y, old.z);
|
|
||||||
});
|
});
|
||||||
group_val_Y_rot.onclick = field_edit('y rotation', group => {
|
group_val_Y_rot.onclick = field_edit('y rotation', (group, val) => {
|
||||||
return group.rotation();
|
let r = group.rotation();
|
||||||
}, (group, val, old) => {
|
group.rotation(r.x, val/rad, r.z);
|
||||||
group.rotation(old.x, val, old.z);
|
|
||||||
});
|
});
|
||||||
group_val_Z_rot.onclick = field_edit('z rotation', group => {
|
group_val_Z_rot.onclick = field_edit('z rotation', (group, val) => {
|
||||||
return group.rotation();
|
let r = group.rotation();
|
||||||
}, (group, val, old) => {
|
group.rotation(r.x, r.y, val/rad);
|
||||||
group.rotation(old.x, old.y, val);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// bind scale editable fields
|
// bind scale editable fields
|
||||||
|
let pedit = prefs.map.edit;
|
||||||
let { span_val_X_size, span_val_Y_size, span_val_Z_size } = bound;
|
let { span_val_X_size, span_val_Y_size, span_val_Z_size } = bound;
|
||||||
[ span_val_X_size, span_val_Y_size, span_val_Z_size ].forEach(e => {
|
[ span_val_X_size, span_val_Y_size, span_val_Z_size ].forEach(e => {
|
||||||
e.classList.add('editable');
|
e.classList.add('editable');
|
||||||
});
|
});
|
||||||
span_val_X_size.onclick = field_edit('x size', group => {
|
let axgrp = {};
|
||||||
return group.scale();
|
// activate axis grouping toggles
|
||||||
}, (group, val, old) => {
|
[ "X", "Y", "Z" ].forEach(axis => {
|
||||||
val = val / group.bounds.dim.x;
|
let prefkey = `scale_group_${axis}`;
|
||||||
group.scale(val, old.y, old.z);
|
let agv = axgrp[axis] = pedit[prefkey];
|
||||||
|
let lbl = bound[`span_lbl_${axis}`];
|
||||||
|
lbl.classList.add('editable');
|
||||||
|
if (agv) {
|
||||||
|
lbl.classList.add('grouped');
|
||||||
|
} else {
|
||||||
|
bound[`span_lbl_${axis}`].classList.add('ungrouped');
|
||||||
|
}
|
||||||
|
lbl.onclick = () => {
|
||||||
|
pedit[prefkey] = !agv;
|
||||||
|
defer_selection(); // update ui
|
||||||
|
};
|
||||||
});
|
});
|
||||||
span_val_Y_size.onclick = field_edit('y size', group => {
|
span_val_X_size.onclick = field_edit('x size', (group, val) => {
|
||||||
return group.scale();
|
let dim = group.bounds.dim;
|
||||||
}, (group, val, old) => {
|
let rel = val / dim.x;
|
||||||
val = val / group.bounds.dim.y;
|
if (axgrp.X) {
|
||||||
group.scale(old.x, val, old.z);
|
group.scale(rel, axgrp.Y ? rel : 1, axgrp.Z ? rel : 1);
|
||||||
|
} else {
|
||||||
|
group.scale(rel, 1, 1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
span_val_Z_size.onclick = field_edit('z size', group => {
|
span_val_Y_size.onclick = field_edit('y size', (group, val) => {
|
||||||
return group.scale();
|
let dim = group.bounds.dim;
|
||||||
}, (group, val, old) => {
|
let rel = val / dim.y;
|
||||||
val = val / group.bounds.dim.z;
|
if (axgrp.Y) {
|
||||||
group.scale(old.x, old.y, val);
|
group.scale(axgrp.X ? rel : 1, rel, axgrp.Z ? rel : 1);
|
||||||
|
} else {
|
||||||
|
group.scale(1, rel, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
span_val_Z_size.onclick = field_edit('z size', (group, val) => {
|
||||||
|
let dim = group.bounds.dim;
|
||||||
|
let rel = val / dim.z;
|
||||||
|
if (axgrp.Z) {
|
||||||
|
group.scale(axgrp.X ? rel : 1, axgrp.Y ? rel : 1, rel);
|
||||||
|
} else {
|
||||||
|
group.scale(1, 1, rel);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let pmap = prefs.map.info;
|
let pmap = prefs.map.info;
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ let util = mesh.util = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// extract object fields into an array with optional rounding
|
||||||
extract(object, opt = {}) {
|
extract(object, opt = {}) {
|
||||||
let field = opt.fields || ['x', 'y', 'z'];
|
let field = opt.fields || ['x', 'y', 'z'];
|
||||||
let array = [];
|
let array = [];
|
||||||
|
|
@ -150,6 +151,7 @@ let util = mesh.util = {
|
||||||
return array;
|
return array;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// for an array of maps, return the average of all named fields in a new map
|
||||||
average(array, opt = {}) {
|
average(array, opt = {}) {
|
||||||
let fields = opt.fields || ['x', 'y', 'z'];
|
let fields = opt.fields || ['x', 'y', 'z'];
|
||||||
let avg = {};
|
let avg = {};
|
||||||
|
|
|
||||||
|
|
@ -505,6 +505,14 @@ button.selected:hover {
|
||||||
grid: min-content 1fr / min-content 1fr;
|
grid: min-content 1fr / min-content 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid .ungrouped {
|
||||||
|
background-color: rgba(128,128,128,0.5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid .ungrouped:hover {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
.tempedit {
|
.tempedit {
|
||||||
gap: 3px;
|
gap: 3px;
|
||||||
}
|
}
|
||||||
|
|
@ -514,9 +522,11 @@ button.selected:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable {
|
.editable {
|
||||||
background-color: rgba(0,128,255,0.2) !important;
|
color: #05a;
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.editable:hover {
|
.editable:hover {
|
||||||
|
color: #000;
|
||||||
background-color: rgba(0,128,255,0.5) !important;
|
background-color: rgba(0,128,255,0.5) !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue