mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 21:57:04 +00:00
Merge pull request #7762 from dotCooCoo/feat/3d-classic-track-cube
3D (Classic): the track cube turns the object on the Rotation tab
This commit is contained in:
@@ -262,7 +262,8 @@ fn extrude_controls(ui: &mut egui::Ui, d: &mut Dialog, unit: Unit) {
|
||||
});
|
||||
}
|
||||
|
||||
/// Rotation presets, rotation and perspective for Extrude & Bevel, Inflate and Rotate.
|
||||
/// Rotation presets, rotation and perspective for Extrude & Bevel, Inflate and Rotate, and the
|
||||
/// classic 3D effects, which have the track cube below the presets.
|
||||
fn view_controls(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
heading(ui, tl!("Rotation"));
|
||||
let names = [
|
||||
@@ -296,6 +297,9 @@ fn view_controls(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
d.fields.extend([("rotationX".into(), json!(x)), ("rotationY".into(), json!(y)), ("rotationZ".into(), json!(z))]);
|
||||
}
|
||||
});
|
||||
if vectorcraft_effects::is_classic_three_d(&d.str("__effect")) {
|
||||
super::three_d_classic::track_cube(ui, d);
|
||||
}
|
||||
for (key, name) in [("rotationX", tl!("Rotation X")), ("rotationY", tl!("Rotation Y")), ("rotationZ", tl!("Rotation Z"))] {
|
||||
number(ui, d, key, name, (-180.0, 180.0), "°", 2, None);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,11 @@ impl Harness {
|
||||
self.ctx.read_response(Id::unique(id)).unwrap().rect
|
||||
}
|
||||
|
||||
/// The open dialog's track cube.
|
||||
fn cube_id(&self) -> Id {
|
||||
super::super::three_d_classic::cube_id(&self.app.ui.dialog.as_ref().unwrap().kind)
|
||||
}
|
||||
|
||||
fn click(&mut self, p: Pos2) {
|
||||
self.frame(vec![Event::PointerMoved(p), button(p, true)]);
|
||||
self.frame(vec![button(p, false)]);
|
||||
@@ -460,6 +465,88 @@ fn classic_rotate_shows_its_options_and_applies_as_one_step() {
|
||||
assert_eq!(h.app.session.doc().unwrap().doc, before);
|
||||
}
|
||||
|
||||
/// The classic effects' track cube: a drag on its face turns the object live and the presets show
|
||||
/// Custom, Escape during a drag puts the angles back, the ring turns Z alone, the arrow keys turn
|
||||
/// it with the keyboard focus, and OK keeps it all as one undo step. The newer effects have no cube.
|
||||
#[test]
|
||||
fn the_track_cube_turns_the_classic_effects_live_in_one_undo_step() {
|
||||
use vectorcraft_effects::{CLASSIC_EXTRUDE, CLASSIC_REVOLVE, CLASSIC_ROTATE, EXTRUDE, ROTATE};
|
||||
let square = "M100 100 L200 100 L200 200 L100 200 Z";
|
||||
for effect in [EXTRUDE, ROTATE] {
|
||||
let mut h = Harness::with(square, effect, vec2(1400.0, 1000.0));
|
||||
h.app.ui.dialog.as_mut().unwrap().fields.insert("__tab".into(), json!("rotation"));
|
||||
h.settle();
|
||||
assert!(!h.texts.iter().any(|(t, _)| t == "Track cube"), "{effect} has no track cube");
|
||||
}
|
||||
for effect in [CLASSIC_EXTRUDE, CLASSIC_REVOLVE] {
|
||||
let mut h = Harness::with(square, effect, vec2(1400.0, 1000.0));
|
||||
h.app.ui.dialog.as_mut().unwrap().fields.insert("__tab".into(), json!("rotation"));
|
||||
h.settle();
|
||||
h.rect("Track cube");
|
||||
}
|
||||
let mut h = Harness::with(square, CLASSIC_ROTATE, vec2(1400.0, 1000.0));
|
||||
let before = h.app.session.doc().unwrap().doc.clone();
|
||||
h.settle();
|
||||
h.rect("Off-Axis Front");
|
||||
let start = ["rotationX", "rotationY", "rotationZ"].map(|k| h.value(k));
|
||||
let cube = h.ctx.read_response(h.cube_id()).unwrap().rect;
|
||||
// A face, dragged right: the object turns, the document previews it, and the preset is Custom.
|
||||
h.drag(cube.center(), vec2(30.0, 0.0));
|
||||
let turned = ["rotationX", "rotationY", "rotationZ"].map(|k| h.value(k));
|
||||
assert_ne!(turned, start, "the drag turned the object");
|
||||
h.rect("Custom");
|
||||
let fx = |h: &Harness| {
|
||||
let state = h.app.session.doc().unwrap();
|
||||
state.doc.node(state.selection.objects[0]).unwrap().appearance.effects[0].params.clone()
|
||||
};
|
||||
assert_eq!(fx(&h)["rotationY"].as_f64(), Some(turned[1]), "the preview follows the cube");
|
||||
// Escape during a drag puts the angles back and keeps the dialog open.
|
||||
let p = cube.center();
|
||||
h.frame(vec![Event::PointerMoved(p), button(p, true)]);
|
||||
h.frame(vec![Event::PointerMoved(p + vec2(0.0, 30.0))]);
|
||||
h.frame(vec![Event::PointerMoved(p + vec2(0.0, 40.0))]);
|
||||
assert_ne!(h.value("rotationX"), turned[0]);
|
||||
h.frame(vec![Event::Key { key: egui::Key::Escape, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }]);
|
||||
h.frame(vec![button(p + vec2(0.0, 40.0), false)]);
|
||||
h.settle();
|
||||
assert!(h.app.ui.dialog.is_some(), "Escape ends the drag, not the dialog");
|
||||
assert_eq!(["rotationX", "rotationY", "rotationZ"].map(|k| h.value(k)), turned);
|
||||
// The ring turns in the screen plane: Z alone.
|
||||
let top = pos2(cube.center().x, cube.center().y - 53.5);
|
||||
h.drag(top, vec2(12.0, 2.0));
|
||||
assert_eq!((h.value("rotationX"), h.value("rotationY")), (turned[0], turned[1]));
|
||||
assert!(h.value("rotationZ") > turned[2], "clockwise: {} -> {}", turned[2], h.value("rotationZ"));
|
||||
// With the keyboard focus (the drags gave it), Right turns about the screen's vertical axis.
|
||||
let z = h.value("rotationZ");
|
||||
assert!(h.ctx.memory(|m| m.has_focus(h.cube_id())), "the drag gave the cube the keyboard focus");
|
||||
h.frame(vec![Event::Key { key: egui::Key::PageUp, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }]);
|
||||
h.settle();
|
||||
assert!((h.value("rotationZ") - (z - 1.0)).abs() < 0.011, "Page Up turns 1° counterclockwise");
|
||||
let y = h.value("rotationY");
|
||||
h.frame(vec![Event::Key { key: egui::Key::ArrowRight, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }]);
|
||||
h.settle();
|
||||
assert_ne!(h.value("rotationY"), y, "Right turns the cube");
|
||||
let last = h.value("rotationZ");
|
||||
dialogs::confirm(&mut h.app).unwrap();
|
||||
assert_eq!(fx(&h)["rotationZ"].as_f64(), Some(last));
|
||||
h.app.run("edit.undo", json!({})).unwrap();
|
||||
assert_eq!(h.app.session.doc().unwrap().doc, before);
|
||||
}
|
||||
|
||||
/// A mixed rotation (the 3D and Materials panel's selected effects differ) leaves the cube off.
|
||||
#[test]
|
||||
fn the_track_cube_is_off_while_a_rotation_is_mixed() {
|
||||
use vectorcraft_effects::CLASSIC_ROTATE;
|
||||
let mut h = Harness::with("M100 100 L200 100 L200 200 L100 200 Z", CLASSIC_ROTATE, vec2(1400.0, 1000.0));
|
||||
h.app.ui.dialog.as_mut().unwrap().fields.insert("rotationX".into(), Value::Null);
|
||||
h.settle();
|
||||
let cube = h.ctx.read_response(h.cube_id()).unwrap().rect;
|
||||
h.drag(cube.center(), vec2(30.0, 0.0));
|
||||
let d = h.app.ui.dialog.as_ref().unwrap();
|
||||
assert_eq!(d.fields.get("rotationX"), Some(&Value::Null));
|
||||
assert!(!h.ctx.read_response(h.cube_id()).unwrap().sense.senses_drag());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn extrude_bevel_options_enable_with_a_bevel_shape() {
|
||||
let mut h = Harness::with("M100 100 L200 100 L200 200 L100 200 Z", vectorcraft_effects::EXTRUDE, vec2(1400.0, 1000.0));
|
||||
|
||||
@@ -42,8 +42,10 @@ fn drag_id() -> Id {
|
||||
Id::unique("revolve-gizmo-drag")
|
||||
}
|
||||
|
||||
/// Is a rotation or light gesture in progress, on the artboard or on the classic 3D effects' track
|
||||
/// cube?
|
||||
pub(crate) fn dragging(ctx: &egui::Context) -> bool {
|
||||
ctx.data(|m| m.get_temp::<Drag>(drag_id())).is_some()
|
||||
ctx.data(|m| m.get_temp::<Drag>(drag_id())).is_some() || super::three_d_classic::cube_dragging(ctx)
|
||||
}
|
||||
|
||||
pub(super) fn clear(ctx: &egui::Context) {
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
//! The track cube's rotations, grips and gestures.
|
||||
use super::*;
|
||||
use egui::pos2;
|
||||
use vectorcraft_effects::ROTATION_PRESETS;
|
||||
|
||||
const SAMPLES: [[f64; 3]; 6] =
|
||||
[[0.0, 0.0, 0.0], [-21.88, -23.4, 9.06], [27.0, -39.0, 53.0], [170.0, 10.0, -95.5], [-120.0, 75.0, 33.0], [45.0, -35.26, 30.0]];
|
||||
|
||||
fn close(a: [f64; 3], b: [f64; 3]) -> bool {
|
||||
a.iter().zip(b).all(|(a, b)| tidy(a - b).abs() < 0.011)
|
||||
}
|
||||
|
||||
fn same_rotation(a: M3, b: M3) -> bool {
|
||||
a.iter().flatten().zip(b.iter().flatten()).all(|(a, b)| (a - b).abs() < 1e-3)
|
||||
}
|
||||
|
||||
/// The cube turns as the 3D effects turn the art: each object axis lands where the effects' own
|
||||
/// view rotation puts it.
|
||||
#[test]
|
||||
fn the_cube_rotates_as_the_effects_do() {
|
||||
for angles in SAMPLES {
|
||||
let m = rotation(angles);
|
||||
let view = vectorcraft_three_d::Revolve { rotation_x: angles[0], rotation_y: angles[1], rotation_z: angles[2], ..Default::default() };
|
||||
for (axis, p) in view.view_axes().into_iter().enumerate() {
|
||||
assert!((m[0][axis] - p.x).abs() < 1e-9 && (m[1][axis] - p.y).abs() < 1e-9, "{angles:?} axis {axis}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reading the angles back gives the same angles, presets included, Back's 180° and the gimbal
|
||||
/// positions Left and Right (Y at ±90°) among them.
|
||||
#[test]
|
||||
fn angles_read_back_as_they_were_set() {
|
||||
for angles in SAMPLES.into_iter().chain(ROTATION_PRESETS.iter().map(|(_, a)| *a)) {
|
||||
let back = angles_of(rotation(angles), angles);
|
||||
assert!(close(back, angles), "{angles:?} read back as {back:?}");
|
||||
assert!(same_rotation(rotation(back), rotation(angles)));
|
||||
}
|
||||
assert_eq!(angles_of(rotation([0.0, 180.0, 0.0]), [0.0, 180.0, 0.0]), [0.0, 180.0, 0.0], "Back stays Back, not -180°");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn angles_stay_in_the_fields_range_to_a_hundredth() {
|
||||
assert_eq!(tidy(180.0), 180.0);
|
||||
assert_eq!(tidy(-180.0), 180.0);
|
||||
assert_eq!(tidy(190.004), -170.0);
|
||||
assert_eq!(tidy(-0.001), 0.0);
|
||||
assert!(tidy(-0.001).is_sign_positive());
|
||||
}
|
||||
|
||||
fn drag(grip: Grip, angles: [f64; 3], from: Pos2, to: Pos2, shift: bool) -> [f64; 3] {
|
||||
let mut g =
|
||||
CubeDrag { grip, matrix: rotation(angles), origin: from, last: from, lock: None, fields: Default::default(), pass: 0, owner: Id::NULL };
|
||||
// In five steps, as a pointer moves.
|
||||
let mut near = angles;
|
||||
for k in 1..=5 {
|
||||
let p = from + (to - from) * (k as f32 / 5.0);
|
||||
g.matrix = drag_turn(&mut g, p, pos2(0.0, 0.0), shift);
|
||||
g.last = p;
|
||||
near = angles_of(g.matrix, near);
|
||||
}
|
||||
near
|
||||
}
|
||||
|
||||
/// The ring turns in the screen plane, which the effects apply last: only Z changes, by the angle
|
||||
/// swept, clockwise on the screen.
|
||||
#[test]
|
||||
fn the_ring_turns_z_only() {
|
||||
for angles in SAMPLES {
|
||||
let after = drag(Grip::Ring, angles, pos2(0.0, -53.0), pos2(53.0, 0.0), false);
|
||||
assert!(close(after, [angles[0], angles[1], angles[2] + 90.0]), "{angles:?} -> {after:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// An edge turns about its own object axis. The effects turn X first, so an X edge changes X alone.
|
||||
#[test]
|
||||
fn an_x_edge_turns_x_only_and_other_edges_keep_their_axis() {
|
||||
let start = [-21.88, -23.4, 9.06];
|
||||
let after = drag(Grip::Edge(0), start, pos2(0.0, 0.0), pos2(0.0, -40.0), false);
|
||||
assert!((after[0] - start[0]).abs() > 5.0, "X turned: {after:?}");
|
||||
assert!((after[1] - start[1]).abs() < 0.02 && (after[2] - start[2]).abs() < 0.02, "Y and Z kept: {after:?}");
|
||||
for axis in 0..3 {
|
||||
let after = drag(Grip::Edge(axis), start, pos2(0.0, 0.0), pos2(30.0, -30.0), false);
|
||||
let (m0, m1) = (rotation(start), rotation(after));
|
||||
let column = |m: M3| [m[0][axis], m[1][axis], m[2][axis]];
|
||||
let (a, b) = (column(m0), column(m1));
|
||||
assert!(a.iter().zip(b).all(|(a, b)| (a - b).abs() < 1e-3), "axis {axis} stays put: {a:?} {b:?}");
|
||||
assert!(!same_rotation(m0, m1), "axis {axis}: the cube turned");
|
||||
}
|
||||
}
|
||||
|
||||
/// A face drag across the screen turns about the screen's vertical axis, the front toward the
|
||||
/// drag; Shift keeps a slanted drag to that axis.
|
||||
#[test]
|
||||
fn a_face_drag_turns_the_front_toward_the_pointer_and_shift_keeps_one_axis() {
|
||||
let front = [0.0, 0.0, 0.0];
|
||||
let right = drag(Grip::Face, front, pos2(0.0, 0.0), pos2(40.0, 0.0), false);
|
||||
assert!(close(right, [0.0, 20.0, 0.0]), "{right:?}");
|
||||
// The front (+Z) turns toward +X.
|
||||
assert!(rotation(right)[0][2] > 0.3);
|
||||
let down = drag(Grip::Face, front, pos2(0.0, 0.0), pos2(0.0, 40.0), false);
|
||||
assert!(close(down, [-20.0, 0.0, 0.0]), "{down:?}");
|
||||
assert!(rotation(down)[1][2] > 0.3, "the front turns down");
|
||||
let slanted = drag(Grip::Face, front, pos2(0.0, 0.0), pos2(40.0, 12.0), true);
|
||||
assert!(close(slanted, [0.0, 20.0, 0.0]), "Shift across: {slanted:?}");
|
||||
let steep = drag(Grip::Face, front, pos2(0.0, 0.0), pos2(10.0, -40.0), true);
|
||||
assert!(close(steep, [20.0, 0.0, 0.0]), "Shift up: {steep:?}");
|
||||
let free = drag(Grip::Face, front, pos2(0.0, 0.0), pos2(40.0, 12.0), false);
|
||||
assert!(free[0].abs() > 1.0, "without Shift a slanted drag also tilts: {free:?}");
|
||||
}
|
||||
|
||||
/// A gesture ends when the cube stops being drawn during it (its dialog closed, or the Rotation tab
|
||||
/// was left), so Escape is not held back for a cube that is no longer there.
|
||||
#[test]
|
||||
fn a_drag_ends_when_the_cube_is_no_longer_drawn() {
|
||||
let ctx = egui::Context::default();
|
||||
let run = |draw: &mut dyn FnMut(&mut egui::Ui)| ctx.run_ui(Default::default(), draw).textures_delta.clear();
|
||||
run(&mut |ui| {
|
||||
let pass = ui.ctx().cumulative_pass_nr();
|
||||
let drag = CubeDrag {
|
||||
grip: Grip::Face,
|
||||
matrix: rotation([0.0; 3]),
|
||||
origin: Pos2::ZERO,
|
||||
last: Pos2::ZERO,
|
||||
lock: None,
|
||||
fields: Default::default(),
|
||||
pass,
|
||||
owner: Id::NULL,
|
||||
};
|
||||
ui.data_mut(|m| m.insert_temp(cube_drag_id(), drag));
|
||||
assert!(cube_dragging(ui.ctx()));
|
||||
});
|
||||
assert!(cube_dragging(&ctx), "the next pass still sees the gesture");
|
||||
for _ in 0..2 {
|
||||
run(&mut |_| {});
|
||||
}
|
||||
assert!(!cube_dragging(&ctx), "two passes without the cube end the gesture");
|
||||
}
|
||||
|
||||
/// With the 3D and Materials panel and a 3D dialog both showing a cube, a gesture on one cube is
|
||||
/// left alone by the other: Escape there does not put the first cube's settings into it.
|
||||
#[test]
|
||||
fn a_cube_leaves_a_gesture_on_the_other_cube_alone() {
|
||||
let ctx = egui::Context::default();
|
||||
let mut d = Dialog::new("effect", json!({ "rotationX": 10.0, "rotationY": 0.0, "rotationZ": 0.0 }));
|
||||
let escape = egui::Event::Key { key: egui::Key::Escape, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE };
|
||||
let input = egui::RawInput { events: vec![escape], ..Default::default() };
|
||||
let mut out = ctx.run_ui(input, |ui| {
|
||||
let pass = ui.ctx().cumulative_pass_nr();
|
||||
let other = CubeDrag {
|
||||
grip: Grip::Face,
|
||||
matrix: rotation([50.0, 0.0, 0.0]),
|
||||
origin: Pos2::ZERO,
|
||||
last: Pos2::ZERO,
|
||||
lock: None,
|
||||
fields: json!({ "rotationX": 50.0, "rotationY": 0.0, "rotationZ": 0.0 }).as_object().cloned().unwrap_or_default(),
|
||||
pass,
|
||||
owner: cube_id(crate::panels::three_d::ID),
|
||||
};
|
||||
assert_ne!(cube_id(crate::panels::three_d::ID), cube_id(&d.kind), "each cube has its own focus");
|
||||
ui.data_mut(|m| m.insert_temp(cube_drag_id(), other));
|
||||
track_cube(ui, &mut d);
|
||||
});
|
||||
out.textures_delta.clear();
|
||||
assert_eq!(d.f64("rotationX", 0.0), 10.0, "the dialog keeps its own rotation");
|
||||
// The button is up in that pass, and the other cube, drawn later, still has the release to handle.
|
||||
assert!(ctx.data(|m| m.get_temp::<CubeDrag>(cube_drag_id())).is_some(), "the other cube's gesture is still there");
|
||||
}
|
||||
|
||||
/// The centre is on the front face, the ring's band on the ring, and an edge's middle on that edge.
|
||||
#[test]
|
||||
fn grips_follow_what_is_under_the_pointer() {
|
||||
let m = rotation([-21.88, -23.4, 9.06]);
|
||||
let center = pos2(100.0, 100.0);
|
||||
assert_eq!(grip_at(m, center, center), Grip::Face);
|
||||
assert_eq!(grip_at(m, center, center + vec2(0.0, -(RING_IN + RING_OUT) / 2.0)), Grip::Ring);
|
||||
for (i, j, axis) in edges().filter(|&(i, _, axis)| edge_visible(m, i, axis)) {
|
||||
let middle = corner(m, center, i) + (corner(m, center, j) - corner(m, center, i)) * 0.5;
|
||||
assert_eq!(grip_at(m, center, middle), Grip::Edge(axis), "edge {i}-{j}");
|
||||
}
|
||||
// Facing front: four faces are edge-on and hidden, so only the front's edges show.
|
||||
let m = rotation([0.0, 0.0, 0.0]);
|
||||
assert_eq!(edges().filter(|&(i, _, axis)| edge_visible(m, i, axis)).count(), 4);
|
||||
}
|
||||
@@ -2,14 +2,16 @@
|
||||
//! compact 3D dialog: the extrude and bevel options, or the revolve options, on the Object tab
|
||||
//! (Rotate (Classic) has none), and the surface with its lights, highlight, blend steps, shading
|
||||
//! color and Preserve Spot Colors on the Lighting tab. Position (presets, rotation, perspective) is the Rotation tab every 3D
|
||||
//! effect shares.
|
||||
//! effect shares; the classic effects add the track cube to it ([`track_cube`]).
|
||||
|
||||
use egui::{Color32, Id, Pos2, Rect, Sense, Stroke, Vec2, vec2};
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_doc::Unit;
|
||||
use vectorcraft_effects::{CLASSIC_EXTRUDE, CLASSIC_REVOLVE, CLASSIC_ROTATE};
|
||||
|
||||
use super::revolve::{c3, choice, heading, label, light_list, light_record, number, reset_dot, selected_light, store_selected, toggle};
|
||||
use crate::state::Dialog;
|
||||
use crate::theme::Tokens;
|
||||
|
||||
/// Depth and cap, then the bevel: its shape, its height and whether it is added around the shape
|
||||
/// or carved into it.
|
||||
@@ -113,3 +115,403 @@ fn shading_custom(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// The settings the track cube turns, as every 3D effect names them.
|
||||
const ROTATION_KEYS: [&str; 3] = ["rotationX", "rotationY", "rotationZ"];
|
||||
/// The track cube's box side, its cube's half edge, and its ring's inner and outer radius (points).
|
||||
const CUBE_BOX: f32 = 124.0;
|
||||
const CUBE_HALF: f32 = 25.0;
|
||||
const RING_IN: f32 = 47.0;
|
||||
const RING_OUT: f32 = 60.0;
|
||||
/// How far an edge reaches for the pointer (points).
|
||||
const EDGE_REACH: f32 = 5.0;
|
||||
/// Degrees one point of pointer movement turns the cube.
|
||||
const DEGREES_PER_POINT: f64 = 0.5;
|
||||
|
||||
/// A 3×3 rotation, rows first.
|
||||
type M3 = [[f64; 3]; 3];
|
||||
|
||||
/// The rotation that X, Y and Z angles in degrees make, as the 3D effects apply them: X first, then
|
||||
/// Y, then Z, in view space (x right, y down, z toward the viewer).
|
||||
fn rotation(angles: [f64; 3]) -> M3 {
|
||||
let [(sx, cx), (sy, cy), (sz, cz)] = angles.map(|a| a.to_radians().sin_cos());
|
||||
[[cz * cy, cz * sy * sx - sz * cx, cz * sy * cx + sz * sx], [sz * cy, sz * sy * sx + cz * cx, sz * sy * cx - cz * sx], [-sy, cy * sx, cy * cx]]
|
||||
}
|
||||
|
||||
fn multiply(a: M3, b: M3) -> M3 {
|
||||
std::array::from_fn(|i| std::array::from_fn(|j| (0..3).map(|k| a[i][k] * b[k][j]).sum()))
|
||||
}
|
||||
|
||||
/// The unit vector along axis `axis` (0 X, 1 Y, 2 Z).
|
||||
fn unit(axis: usize) -> [f64; 3] {
|
||||
std::array::from_fn(|i| if i == axis { 1.0 } else { 0.0 })
|
||||
}
|
||||
|
||||
/// A turn of `degrees` about the unit vector `axis`.
|
||||
fn turn(axis: [f64; 3], degrees: f64) -> M3 {
|
||||
let (s, c) = degrees.to_radians().sin_cos();
|
||||
let t = 1.0 - c;
|
||||
let [x, y, z] = axis;
|
||||
[
|
||||
[t * x * x + c, t * x * y - s * z, t * x * z + s * y],
|
||||
[t * x * y + s * z, t * y * y + c, t * y * z - s * x],
|
||||
[t * x * z - s * y, t * y * z + s * x, t * z * z + c],
|
||||
]
|
||||
}
|
||||
|
||||
/// An angle as the rotation fields hold it: above -180° up to 180°, to a hundredth of a degree.
|
||||
fn tidy(degrees: f64) -> f64 {
|
||||
let wrapped = 180.0 - (180.0 - degrees).rem_euclid(360.0);
|
||||
(wrapped * 100.0).round() / 100.0 + 0.0
|
||||
}
|
||||
|
||||
/// The X, Y and Z angles of rotation `m`. Of the two sets of angles that make it, the one nearest
|
||||
/// `near` (so a turn moves the fields as little as it can); with Y at ±90°, where X and Z turn about
|
||||
/// the same axis, X keeps its value from `near`.
|
||||
fn angles_of(m: M3, near: [f64; 3]) -> [f64; 3] {
|
||||
let y = (-m[2][0]).clamp(-1.0, 1.0).asin().to_degrees();
|
||||
let candidates = if m[2][1].hypot(m[2][2]) < 1e-9 {
|
||||
let x = near[0];
|
||||
let z = if y > 0.0 { x - m[0][1].atan2(m[1][1]).to_degrees() } else { (-m[0][1]).atan2(m[1][1]).to_degrees() - x };
|
||||
[Some([x, y, z]), None]
|
||||
} else {
|
||||
let x = m[2][1].atan2(m[2][2]).to_degrees();
|
||||
let z = m[1][0].atan2(m[0][0]).to_degrees();
|
||||
[Some([x, y, z]), Some([x + 180.0, 180.0 - y, z + 180.0])]
|
||||
};
|
||||
let distance = |a: &[f64; 3]| a.iter().zip(near).map(|(a, b)| tidy(a - b).abs()).sum::<f64>();
|
||||
candidates.into_iter().flatten().min_by(|a, b| distance(a).total_cmp(&distance(b))).unwrap_or(near).map(tidy)
|
||||
}
|
||||
|
||||
/// Where corner `i` of the cube (bit 0 for +X, bit 1 for +Y, bit 2 for +Z) is drawn.
|
||||
fn corner(m: M3, center: Pos2, i: usize) -> Pos2 {
|
||||
let p: [f64; 3] = std::array::from_fn(|b| if i >> b & 1 == 1 { 1.0 } else { -1.0 });
|
||||
let v: [f64; 3] = std::array::from_fn(|r| (0..3).map(|k| m[r][k] * p[k]).sum());
|
||||
center + vec2(v[0] as f32, v[1] as f32) * CUBE_HALF
|
||||
}
|
||||
|
||||
/// The corners of the face square to `axis` on its positive or negative side, in order round it.
|
||||
fn face_corners(axis: usize, positive: bool) -> [usize; 4] {
|
||||
let (b, c) = (1 << ((axis + 1) % 3), 1 << ((axis + 2) % 3));
|
||||
let side = if positive { 1 << axis } else { 0 };
|
||||
[0, b, b | c, c].map(|k| side | k)
|
||||
}
|
||||
|
||||
/// Does the face square to `axis` on that side face the viewer?
|
||||
fn face_visible(m: M3, axis: usize, positive: bool) -> bool {
|
||||
m[2][axis] * if positive { 1.0 } else { -1.0 } > 1e-6
|
||||
}
|
||||
|
||||
/// The 12 edges: (from corner, to corner, the object axis it runs along).
|
||||
fn edges() -> impl Iterator<Item = (usize, usize, usize)> {
|
||||
(0..3).flat_map(|axis| (0..8).filter(move |i| i >> axis & 1 == 0).map(move |i| (i, i | 1 << axis, axis)))
|
||||
}
|
||||
|
||||
/// Is the edge from corner `i` along `axis` on a face the viewer sees?
|
||||
fn edge_visible(m: M3, i: usize, axis: usize) -> bool {
|
||||
[(axis + 1) % 3, (axis + 2) % 3].into_iter().any(|other| face_visible(m, other, i >> other & 1 == 1))
|
||||
}
|
||||
|
||||
/// What a press on the track cube takes hold of.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum Grip {
|
||||
/// A face: a free turn, or with Shift about the screen's horizontal or vertical axis.
|
||||
Face,
|
||||
/// An edge: a turn about the object axis the edge runs along.
|
||||
Edge(usize),
|
||||
/// The ring round the cube: a turn in the plane of the screen.
|
||||
Ring,
|
||||
}
|
||||
|
||||
/// The z of the cross product of two screen vectors: positive when `b` is clockwise from `a`.
|
||||
fn cross(a: Vec2, b: Vec2) -> f32 {
|
||||
a.x * b.y - a.y * b.x
|
||||
}
|
||||
|
||||
fn segment_distance(p: Pos2, a: Pos2, b: Pos2) -> f32 {
|
||||
let line = b - a;
|
||||
let t = ((p - a).dot(line) / line.length_sq().max(1e-6)).clamp(0.0, 1.0);
|
||||
p.distance(a + line * t)
|
||||
}
|
||||
|
||||
/// What the pointer at `p` takes hold of on a cube drawn at `m` about `center`: the nearest edge
|
||||
/// within reach, else a face, else the ring, else (in the box's corners) a face's free turn.
|
||||
fn grip_at(m: M3, center: Pos2, p: Pos2) -> Grip {
|
||||
let edge = edges()
|
||||
.filter(|&(i, _, axis)| edge_visible(m, i, axis))
|
||||
.map(|(i, j, axis)| (segment_distance(p, corner(m, center, i), corner(m, center, j)), axis))
|
||||
.filter(|(distance, _)| *distance <= EDGE_REACH)
|
||||
.min_by(|a, b| a.0.total_cmp(&b.0));
|
||||
if let Some((_, axis)) = edge {
|
||||
return Grip::Edge(axis);
|
||||
}
|
||||
let on_face = (0..3).flat_map(|axis| [(axis, true), (axis, false)]).filter(|&(axis, side)| face_visible(m, axis, side)).any(|(axis, side)| {
|
||||
let points = face_corners(axis, side).map(|i| corner(m, center, i));
|
||||
let sides: [f32; 4] = std::array::from_fn(|k| cross(points[(k + 1) % 4] - points[k], p - points[k]));
|
||||
sides.iter().all(|s| *s >= 0.0) || sides.iter().all(|s| *s <= 0.0)
|
||||
});
|
||||
let distance = p.distance(center);
|
||||
if !on_face && (RING_IN - 3.0..=RING_OUT + 3.0).contains(&distance) { Grip::Ring } else { Grip::Face }
|
||||
}
|
||||
|
||||
/// The turn in degrees, clockwise on the screen, from `from` to `to` about `center`.
|
||||
fn sweep(from: Pos2, to: Pos2, center: Pos2) -> f64 {
|
||||
let (a, b) = (from - center, to - center);
|
||||
if a.length() < 2.0 || b.length() < 2.0 {
|
||||
return 0.0;
|
||||
}
|
||||
f64::from(cross(a, b)).atan2(f64::from(a.dot(b))).to_degrees()
|
||||
}
|
||||
|
||||
/// A track cube gesture in progress.
|
||||
#[derive(Clone)]
|
||||
struct CubeDrag {
|
||||
grip: Grip,
|
||||
/// The rotation so far, kept unrounded so a long drag does not drift.
|
||||
matrix: M3,
|
||||
origin: Pos2,
|
||||
last: Pos2,
|
||||
/// With Shift, the screen axis the drag keeps to (0 X, 1 Y), chosen once it has moved 3 points.
|
||||
lock: Option<usize>,
|
||||
/// The settings before the gesture, which Escape puts back.
|
||||
fields: serde_json::Map<String, Value>,
|
||||
/// The last pass that drew the cube during the gesture.
|
||||
pass: u64,
|
||||
/// The cube the gesture started on. The 3D and Materials panel and a 3D dialog can each show
|
||||
/// a cube at the same time, and only this one follows the gesture.
|
||||
owner: Id,
|
||||
}
|
||||
|
||||
impl CubeDrag {
|
||||
/// Was the cube drawn in this pass or the one before? When it was not (its dialog closed, or
|
||||
/// the Rotation tab or the panel was left during the drag), the gesture is over.
|
||||
fn live(&self, pass: u64) -> bool {
|
||||
self.pass.saturating_add(1) >= pass
|
||||
}
|
||||
}
|
||||
|
||||
/// The track cube of the dialog or panel of kind `kind`. The 3D and Materials panel and a 3D
|
||||
/// dialog can show a cube at the same time, each with its own keyboard focus.
|
||||
pub(super) fn cube_id(kind: &str) -> Id {
|
||||
Id::unique(("three-d-track-cube", kind))
|
||||
}
|
||||
|
||||
fn cube_drag_id() -> Id {
|
||||
Id::unique("three-d-track-cube-drag")
|
||||
}
|
||||
|
||||
/// Is a track cube gesture in progress?
|
||||
pub(super) fn cube_dragging(ctx: &egui::Context) -> bool {
|
||||
let pass = ctx.cumulative_pass_nr();
|
||||
ctx.data(|m| m.get_temp::<CubeDrag>(cube_drag_id())).is_some_and(|g| g.live(pass))
|
||||
}
|
||||
|
||||
/// The rotation after the pointer moves from `drag.last` to `p` on a cube about `center`.
|
||||
fn drag_turn(drag: &mut CubeDrag, p: Pos2, center: Pos2, shift: bool) -> M3 {
|
||||
let m = drag.matrix;
|
||||
let delta = p - drag.last;
|
||||
let (mut dx, mut dy) = (f64::from(delta.x), f64::from(delta.y));
|
||||
match drag.grip {
|
||||
Grip::Face => {
|
||||
if shift {
|
||||
let total = p - drag.origin;
|
||||
if drag.lock.is_none() && total.length() >= 3.0 {
|
||||
drag.lock = Some(usize::from(total.x.abs() >= total.y.abs()));
|
||||
}
|
||||
match drag.lock {
|
||||
// Across the screen turns about its vertical (Y) axis, up and down about X.
|
||||
Some(1) => dy = 0.0,
|
||||
Some(_) => dx = 0.0,
|
||||
None => return m,
|
||||
}
|
||||
}
|
||||
let length = dx.hypot(dy);
|
||||
if length < 1e-9 {
|
||||
return m;
|
||||
}
|
||||
// The front follows the pointer: right turns it toward +X, down toward +Y.
|
||||
multiply(turn([-dy / length, dx / length, 0.0], length * DEGREES_PER_POINT), m)
|
||||
}
|
||||
Grip::Ring => multiply(turn(unit(2), sweep(drag.last, p, center)), m),
|
||||
Grip::Edge(axis) => {
|
||||
let w = [m[0][axis], m[1][axis], m[2][axis]];
|
||||
let across = w[0].hypot(w[1]);
|
||||
// An axis pointing at the viewer turns like the ring, on the side it points to.
|
||||
let degrees =
|
||||
if w[2].abs() > 0.9 { sweep(drag.last, p, center) * w[2].signum() } else { (dx * w[1] - dy * w[0]) / across * DEGREES_PER_POINT };
|
||||
multiply(m, turn(unit(axis), degrees))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The track cube on the Rotation tab of Extrude & Bevel (Classic), Revolve (Classic) and Rotate
|
||||
/// (Classic): a cube drawn at the current X, Y and Z rotation (the object's front blue, its top and
|
||||
/// bottom light gray, its sides mid gray and its back dark gray) inside a ring.
|
||||
///
|
||||
/// Dragging a face turns the object freely; with Shift the turn keeps to the screen's vertical axis
|
||||
/// (a drag across) or its horizontal axis (a drag up or down), whichever the drag follows first.
|
||||
/// Dragging an edge turns it about the object axis the edge runs along (X red, Y green, Z blue; the
|
||||
/// edge takes its axis's color while hovered or dragged), and dragging in the ring turns it in the
|
||||
/// plane of the screen. Escape during a drag puts the angles back. With the keyboard focus, the
|
||||
/// arrow keys turn it about the screen's axes and Page Up and Page Down in the screen plane, 1° a
|
||||
/// press (15° with Shift). The angles go to `rotationX`, `rotationY` and `rotationZ` only when they
|
||||
/// change, and the dialog's preview applies them; OK records them as one undo step. The cube is off
|
||||
/// while a rotation setting is mixed (the 3D and Materials panel's selected effects differ).
|
||||
pub(super) fn track_cube(ui: &mut egui::Ui, d: &mut Dialog) {
|
||||
let defaults = vectorcraft_effects::default_params(&d.str("__effect")).unwrap_or(json!({}));
|
||||
let mixed = ROTATION_KEYS.iter().any(|k| d.fields.get(*k).is_some_and(Value::is_null));
|
||||
let now = ROTATION_KEYS.map(|k| d.f64(k, defaults.get(k).and_then(Value::as_f64).unwrap_or(0.0)));
|
||||
let mut next = None;
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 6.0;
|
||||
let name = tl!("Track cube");
|
||||
label(ui, name);
|
||||
let (rect, _) = ui.allocate_exact_size(Vec2::splat(CUBE_BOX), Sense::hover());
|
||||
let enabled = ui.is_enabled() && !mixed;
|
||||
let id = cube_id(&d.kind);
|
||||
let resp = ui.interact(rect, id, if enabled { Sense::click_and_drag() } else { Sense::hover() });
|
||||
let center = rect.center();
|
||||
let value = format!("X {:.2}°, Y {:.2}°, Z {:.2}°", now[0], now[1], now[2]);
|
||||
resp.widget_info(|| egui::WidgetInfo {
|
||||
current_text_value: Some(value.clone()),
|
||||
..egui::WidgetInfo::labeled(egui::Role::Slider, enabled, name)
|
||||
});
|
||||
if enabled
|
||||
&& resp.drag_started()
|
||||
&& let Some(origin) = ui.input(|i| i.pointer.press_origin())
|
||||
{
|
||||
// A value being typed ends first; the cube then takes the keyboard focus below.
|
||||
ui.ctx().memory_mut(|m| m.stop_text_input());
|
||||
let matrix = rotation(now);
|
||||
let pass = ui.ctx().cumulative_pass_nr();
|
||||
let drag = CubeDrag {
|
||||
grip: grip_at(matrix, center, origin),
|
||||
matrix,
|
||||
origin,
|
||||
last: origin,
|
||||
lock: None,
|
||||
fields: d.fields.clone(),
|
||||
pass,
|
||||
owner: id,
|
||||
};
|
||||
ui.data_mut(|m| m.insert_temp(cube_drag_id(), drag));
|
||||
}
|
||||
if enabled && (resp.drag_started() || resp.clicked()) {
|
||||
resp.request_focus();
|
||||
}
|
||||
let pass = ui.ctx().cumulative_pass_nr();
|
||||
// A gesture on the other cube (the panel's or the dialog's) is left to that cube.
|
||||
let mut drag = ui.data(|m| m.get_temp::<CubeDrag>(cube_drag_id())).filter(|g| g.owner == id);
|
||||
if drag.as_ref().is_some_and(|g| !g.live(pass)) {
|
||||
ui.data_mut(|m| m.remove::<CubeDrag>(cube_drag_id()));
|
||||
drag = None;
|
||||
}
|
||||
if let Some(current) = &mut drag {
|
||||
current.pass = pass;
|
||||
if ui.input_mut(|i| i.consume_key(i.modifiers, egui::Key::Escape)) {
|
||||
d.fields = current.fields.clone();
|
||||
d.fields.remove(super::form::PREVIEWED);
|
||||
ui.data_mut(|m| m.remove::<CubeDrag>(cube_drag_id()));
|
||||
drag = None;
|
||||
} else {
|
||||
if let Some(p) = resp.interact_pointer_pos() {
|
||||
let shift = ui.input(|i| i.modifiers.shift);
|
||||
current.matrix = drag_turn(current, p, center, shift);
|
||||
current.last = p;
|
||||
next = Some(angles_of(current.matrix, now));
|
||||
}
|
||||
ui.data_mut(|m| m.insert_temp(cube_drag_id(), current.clone()));
|
||||
}
|
||||
}
|
||||
// Only this cube's gesture ends here; the other cube may still have the release to handle.
|
||||
if drag.is_some() && (resp.drag_stopped() || !ui.input(|i| i.pointer.primary_down())) {
|
||||
ui.data_mut(|m| m.remove::<CubeDrag>(cube_drag_id()));
|
||||
}
|
||||
if enabled && resp.has_focus() {
|
||||
use egui::{Key, Modifiers};
|
||||
ui.memory_mut(|m| {
|
||||
m.set_focus_lock_filter(id, egui::EventFilter { horizontal_arrows: true, vertical_arrows: true, ..Default::default() })
|
||||
});
|
||||
let mut m = rotation(now);
|
||||
let mut turned = false;
|
||||
for (key, axis, sign) in [
|
||||
(Key::ArrowRight, 1, 1.0),
|
||||
(Key::ArrowLeft, 1, -1.0),
|
||||
(Key::ArrowUp, 0, 1.0),
|
||||
(Key::ArrowDown, 0, -1.0),
|
||||
(Key::PageDown, 2, 1.0),
|
||||
(Key::PageUp, 2, -1.0),
|
||||
] {
|
||||
// Shift first: a key without modifiers also matches the key with Shift.
|
||||
for (modifiers, step) in [(Modifiers::SHIFT, 15.0), (Modifiers::NONE, 1.0)] {
|
||||
while ui.input_mut(|i| i.consume_key(modifiers, key)) {
|
||||
m = multiply(turn(unit(axis), sign * step), m);
|
||||
turned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if turned {
|
||||
next = Some(angles_of(m, now));
|
||||
}
|
||||
}
|
||||
let shown = next.unwrap_or(now);
|
||||
let hovered = drag.as_ref().map(|g| g.grip).or_else(|| resp.hover_pos().filter(|_| enabled).map(|p| grip_at(rotation(shown), center, p)));
|
||||
if enabled && (resp.hovered() || drag.is_some()) {
|
||||
ui.ctx().set_cursor_icon(match (hovered, drag.is_some()) {
|
||||
(Some(Grip::Edge(_)), _) => egui::CursorIcon::ResizeHorizontal,
|
||||
(_, true) => egui::CursorIcon::Grabbing,
|
||||
_ => egui::CursorIcon::Grab,
|
||||
});
|
||||
}
|
||||
paint_cube(ui, rect, rotation(shown), hovered, enabled, resp.has_focus());
|
||||
resp.on_hover_text(tl!("Drag a face, an edge or the ring to rotate. Shift turns about one screen axis."));
|
||||
});
|
||||
if let Some(angles) = next
|
||||
&& angles.iter().zip(now).any(|(a, b)| (a - b).abs() > 1e-9)
|
||||
{
|
||||
for (key, angle) in ROTATION_KEYS.into_iter().zip(angles) {
|
||||
d.fields.insert(key.into(), json!(angle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws the track cube at rotation `m` in `rect`, with the grip under the pointer or in hand lit.
|
||||
fn paint_cube(ui: &egui::Ui, rect: Rect, m: M3, active: Option<Grip>, enabled: bool, focused: bool) {
|
||||
let t = Tokens::get(ui.ctx());
|
||||
let fade = |c: Color32| if enabled { c } else { c.gamma_multiply(0.4) };
|
||||
let painter = ui.painter_at(rect);
|
||||
let center = rect.center();
|
||||
painter.rect_filled(rect, 2.0, t.input);
|
||||
let ring = if active == Some(Grip::Ring) { 0.6 } else { 0.3 };
|
||||
painter.circle_stroke(center, (RING_IN + RING_OUT) / 2.0, Stroke::new(RING_OUT - RING_IN, fade(t.axis_z.gamma_multiply(ring))));
|
||||
// Front blue; top and bottom light, sides mid and back dark gray. Only faces turned to the
|
||||
// viewer are drawn, and on a cube those never overlap.
|
||||
for (axis, side) in (0..3).flat_map(|axis| [(axis, true), (axis, false)]) {
|
||||
if !face_visible(m, axis, side) {
|
||||
continue;
|
||||
}
|
||||
let fill = match (axis, side) {
|
||||
(2, true) => t.axis_z,
|
||||
(2, false) => Color32::from_gray(90),
|
||||
(1, _) => Color32::from_gray(205),
|
||||
_ => Color32::from_gray(155),
|
||||
};
|
||||
let points: Vec<Pos2> = face_corners(axis, side).iter().map(|&i| corner(m, center, i)).collect();
|
||||
painter.add(egui::Shape::convex_polygon(points, fade(fill), Stroke::NONE));
|
||||
}
|
||||
let colors = [t.axis_x, t.axis_y, t.axis_z];
|
||||
for (i, j, axis) in edges() {
|
||||
if !edge_visible(m, i, axis) {
|
||||
continue;
|
||||
}
|
||||
let lit = active == Some(Grip::Edge(axis));
|
||||
let stroke = if lit { Stroke::new(2.5, fade(colors[axis])) } else { Stroke::new(1.0, fade(t.text_dim)) };
|
||||
painter.line_segment([corner(m, center, i), corner(m, center, j)], stroke);
|
||||
}
|
||||
let border = if focused { t.accent } else { t.input_border };
|
||||
painter.rect_stroke(rect, 2.0, Stroke::new(1.0, border), egui::StrokeKind::Inside);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests_track_cube.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -5191,6 +5191,8 @@ effect Soft Меко
|
||||
Step up or down Стъпка нагоре или надолу
|
||||
Drag values or labels. Double-click a value to type. Плъзнете стойности или етикети. Кликнете двукратно върху стойност за въвеждане.
|
||||
Drag rings to rotate. Shift snaps to 15°. Плъзнете пръстените за завъртане. Shift прилепва към 15°.
|
||||
Track cube Куб за завъртане
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Плъзнете стена, ръб или пръстена за завъртане. Shift завърта около една ос на екрана.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Плъзнете светлината или нейните пръстени. Shift прилепва към 15°.
|
||||
Keep visible surfaces only when expanding Запазване само на видимите повърхности при разширяване
|
||||
Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces. Изрязване на закритата геометрия при разширяване на оформлението. Живият преглед запазва цялата повърхност. Прозрачните бои и повърхности, надвишаващи границите на видимост, запазват всички лица.
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1035,6 +1035,8 @@
|
||||
Step up or down Korak gore ili dolje
|
||||
Drag values or labels. Double-click a value to type. Prevucite vrijednosti ili oznake. Dvostruki klik na vrijednost za upis.
|
||||
Drag rings to rotate. Shift snaps to 15°. Prevucite prstenove za rotaciju. Shift hvata na 15°.
|
||||
Track cube Kocka za rotaciju
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Prevucite stranu, ivicu ili prsten za rotaciju. Shift rotira oko jedne ose ekrana.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Prevucite svjetlo ili njegove prstenove. Shift hvata na 15°.
|
||||
lighting Light Svjetlo
|
||||
Keep visible surfaces only when expanding Pri proširivanju zadrži samo vidljive površine
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1347,6 +1347,8 @@ antiAlias Sharp Nítid
|
||||
Drag out from a corner, or click two straight lines, then click to place. Arrossega cap enfora des d’una cantonada, o fes clic en dues línies rectes i després fes clic per col·locar-ho.
|
||||
Drag out from a segment, or click two points, then click to place. Arrossega cap enfora des d’un segment, o fes clic en dos punts i després fes clic per col·locar-ho.
|
||||
Drag rings to rotate. Shift snaps to 15°. Arrossega els anells per girar. La tecla Maj ajusta a 15°.
|
||||
Track cube Cub de rotació
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Arrossega una cara, una aresta o l'anell per girar. La tecla Maj gira al voltant d'un eix de la pantalla.
|
||||
Drag the art to move it on the paper Arrossega la il·lustració per moure-la sobre el paper
|
||||
Drag the light, or its rings. Shift snaps to 15°. Arrossega el llum o els seus anells. La tecla Maj ajusta a 15°.
|
||||
Drag to float as a toolbar Arrossega per surar com a barra d’eines
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1057,6 +1057,8 @@
|
||||
Step up or down O krok nahoru nebo dolů
|
||||
Drag values or labels. Double-click a value to type. Upravte hodnoty přetažením čísel nebo popisků. Dvojím kliknutím na hodnotu ji zadáte.
|
||||
Drag rings to rotate. Shift snaps to 15°. Otáčejte přetažením prstenců. Shift nastaví kroky po 15°.
|
||||
Track cube Otočná krychle
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Otáčejte přetažením stěny, hrany nebo prstence. Shift otáčí kolem jedné osy obrazovky.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Přetáhněte světlo nebo jeho prstence. Shift nastaví kroky po 15°.
|
||||
lighting Light Světlo
|
||||
Keep visible surfaces only when expanding Při rozložení ponechat pouze viditelné povrchy
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1600,6 +1600,8 @@
|
||||
Reset all Revolve settings to their defaults. Nulstil alle indstillinger for omdrejning til standardværdierne.
|
||||
Drag values or labels. Double-click a value to type. Træk i værdier eller etiketter. Dobbeltklik på en værdi for at indtaste.
|
||||
Drag rings to rotate. Shift snaps to 15°. Træk i ringe for at rotere. Shift fastgør til 15°.
|
||||
Track cube Rotationsterning
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Træk i en flade, en kant eller ringen for at rotere. Shift roterer om én skærmakse.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Træk i lyset eller dets ringe. Shift fastgør til 15°.
|
||||
lighting Light Lys
|
||||
Keep visible surfaces only when expanding Behold kun synlige flader ved udvidelse
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5530,6 +5530,8 @@ theme Appearance Erscheinungsbild
|
||||
# 3D and Materials › Revolve: its options dialog and gizmos.
|
||||
Axis side Achsenseite
|
||||
Drag rings to rotate. Shift snaps to 15°. Ziehen Sie die Ringe, um zu drehen. Mit Shift in 15°-Schritten.
|
||||
Track cube Rotationswürfel
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Ziehen Sie eine Fläche, eine Kante oder den Ring, um zu drehen. Mit Shift um eine Bildschirmachse.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Ziehen Sie das Licht oder seine Ringe. Mit Shift in 15°-Schritten.
|
||||
lighting Light Licht
|
||||
Drag values or labels. Double-click a value to type. Ziehen Sie Werte oder Beschriftungen. Doppelklicken Sie auf einen Wert, um ihn einzugeben.
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5432,6 +5432,8 @@ digits Malayalam Μαλαγιάλαμ
|
||||
Step up or down Ένα βήμα πάνω ή κάτω
|
||||
Drag values or labels. Double-click a value to type. Σύρετε τιμές ή ετικέτες. Κάντε διπλό κλικ σε μια τιμή για πληκτρολόγηση.
|
||||
Drag rings to rotate. Shift snaps to 15°. Σύρετε τους δακτυλίους για περιστροφή. Με Shift γίνεται προσκόλληση ανά 15°.
|
||||
Track cube Κύβος περιστροφής
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Σύρετε μια έδρα, μια ακμή ή τον δακτύλιο για περιστροφή. Με Shift η περιστροφή γίνεται γύρω από έναν άξονα της οθόνης.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Σύρετε την πηγή φωτός ή τους δακτυλίους της. Με Shift γίνεται προσκόλληση ανά 15°.
|
||||
Keep visible surfaces only when expanding Διατήρηση μόνο ορατών επιφανειών κατά την ανάπτυξη
|
||||
Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces. Αποκοπή καλυμμένης γεωμετρίας κατά την Ανάπτυξη εμφάνισης. Η ζωντανή προεπισκόπηση διατηρεί ολόκληρη την επιφάνεια. Διαφανή γεμίσματα και επιφάνειες που υπερβαίνουν τα όρια ορατότητας διατηρούν όλες τις έδρες.
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5552,6 +5552,8 @@ axis Both Ambos
|
||||
Step up or down Subir o bajar un paso
|
||||
Drag values or labels. Double-click a value to type. Arrastra los valores o las etiquetas. Haz doble clic en un valor para escribir.
|
||||
Drag rings to rotate. Shift snaps to 15°. Arrastra los anillos para girar. Shift ajusta a pasos de 15°.
|
||||
Track cube Cubo de rotación
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Arrastra una cara, una arista o el anillo para girar. Shift gira sobre un eje de la pantalla.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Arrastra la luz o sus anillos. Shift ajusta a pasos de 15°.
|
||||
lighting Light Luz
|
||||
Keep visible surfaces only when expanding Conservar solo superficies visibles al expandir
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -1038,6 +1038,8 @@
|
||||
Step up or down Askel ylös tai alas
|
||||
Drag values or labels. Double-click a value to type. Vedä arvoja tai nimiöitä. Kirjoita arvo kaksoisnapsauttamalla.
|
||||
Drag rings to rotate. Shift snaps to 15°. Kierrä vetämällä renkaita. Vaihto kohdistaa 15°:n välein.
|
||||
Track cube Kiertokuutio
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Kierrä vetämällä tahkoa, särmää tai rengasta. Vaihto kiertää yhden näytön akselin ympäri.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Vedä valoa tai sen renkaita. Vaihto kohdistaa 15°:n välein.
|
||||
lighting Light Valo
|
||||
Keep visible surfaces only when expanding Säilytä laajennettaessa vain näkyvät pinnat
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5546,6 +5546,8 @@ effect Soft Doux
|
||||
Step up or down Augmenter ou diminuer d’un cran
|
||||
Drag values or labels. Double-click a value to type. Faites glisser les valeurs ou les libellés. Double-cliquez sur une valeur pour la saisir.
|
||||
Drag rings to rotate. Shift snaps to 15°. Faites glisser les anneaux pour tourner. Maj contraint par pas de 15°.
|
||||
Track cube Cube de rotation
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Faites glisser une face, une arête ou l'anneau pour tourner. Maj fait tourner autour d'un axe de l'écran.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Faites glisser la lumière ou ses anneaux. Maj contraint par pas de 15°.
|
||||
Keep visible surfaces only when expanding Conserver uniquement les surfaces visibles lors de la décomposition
|
||||
Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces. Découpe la géométrie masquée lors de la décomposition de l’aspect. L’aperçu conserve toute la surface. Les peintures transparentes et les surfaces dépassant les limites de visibilité conservent toutes les faces.
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1067,6 +1067,8 @@
|
||||
Drag art or swatches here, or use + to add the selection's colors and text styles. અહીં આર્ટ અથવા સ્વેચ ખેંચો, અથવા પસંદગીના રંગો અને ટેક્સ્ટ સ્ટાઇલ ઉમેરવા + વાપરો.
|
||||
Drag onto art to apply this appearance આ દેખાવ લાગુ કરવા આર્ટ પર ખેંચો
|
||||
Drag rings to rotate. Shift snaps to 15°. ફેરવવા રિંગ્સ ખેંચો. Shift 15° પર સ્નેપ કરે છે.
|
||||
Track cube ફેરવવાનો ઘન
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. ફેરવવા ફલક, ધાર અથવા રિંગ ખેંચો. Shift સ્ક્રીનની એક અક્ષની આસપાસ ફેરવે છે.
|
||||
Drag the art to move it on the paper કાગળ પર ખસેડવા આર્ટ ખેંચો
|
||||
Drag the light, or its rings. Shift snaps to 15°. લાઇટ અથવા તેની રિંગ્સ ખેંચો. Shift 15° પર સ્નેપ કરે છે.
|
||||
Drag to float as a toolbar ટૂલબાર તરીકે ફ્લોટ કરવા ખેંચો
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 72 and column 5.
|
@@ -1508,6 +1508,8 @@ antiAlias Sharp शार्प
|
||||
Drag out from a corner, or click two straight lines, then click to place. एक कोने से बाहर खींचें, या दो सीधी रेखाओं पर क्लिक करें, फिर जगह पर क्लिक करें।
|
||||
Drag out from a segment, or click two points, then click to place. एक खंड से बाहर खींचें, या दो बिंदुओं पर क्लिक करें, फिर जगह पर क्लिक करें।
|
||||
Drag rings to rotate. Shift snaps to 15°. घुमाने के लिए रिंग ड्रैग करें। Shift से 15° पर स्नैप होता है।
|
||||
Track cube घुमाने का घन
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. घुमाने के लिए फलक, किनारा या रिंग ड्रैग करें। Shift से स्क्रीन के एक अक्ष के चारों ओर घूमता है।
|
||||
Drag the art to move it on the paper इसे कागज पर स्थानांतरित करने के लिए कला को खींचें
|
||||
Drag the light, or its rings. Shift snaps to 15°. लाइट या उसकी रिंग ड्रैग करें। Shift से 15° पर स्नैप होता है।
|
||||
Drag to float as a toolbar एक टूलबार के रूप में तैरने के लिए खींचें
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1208,6 +1208,8 @@ font-technology Variable Változó
|
||||
Drag art, colors and text styles here to reuse them across documents. Libraries are stored on this machine — no account required. Húzz ide grafikát, színeket és szövegstílusokat, hogy más dokumentumokban is használhasd őket. A könyvtárak ezen a gépen tárolódnak, fiók nem kell hozzájuk.
|
||||
Drag onto art to apply this appearance Grafikára húzva alkalmazza ezt a megjelenést
|
||||
Drag rings to rotate. Shift snaps to 15°. Forgatáshoz húzd a gyűrűket. Shift: illesztés 15°-onként.
|
||||
Track cube Forgatókocka
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Forgatáshoz húzz egy lapot, egy élt vagy a gyűrűt. Shift: forgatás egy képernyőtengely körül.
|
||||
Drag the art to move it on the paper Húzd a grafikát a papíron való áthelyezéshez
|
||||
Drag the light, or its rings. Shift snaps to 15°. Húzd a fényt vagy a gyűrűit. Shift: illesztés 15°-onként.
|
||||
Drag to float as a toolbar Húzd el, hogy önálló eszköztárként lebegjen
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -976,6 +976,8 @@
|
||||
Reset all Revolve settings to their defaults. Atur ulang semua pengaturan Revolusi ke defaultnya.
|
||||
Drag values or labels. Double-click a value to type. Seret nilai atau label. Klik dua kali pada nilai untuk mengetik.
|
||||
Drag rings to rotate. Shift snaps to 15°. Seret cincin untuk memutar. Shift mengunci ke kelipatan 15°.
|
||||
Track cube Kubus putar
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Seret sisi, tepi, atau cincin untuk memutar. Shift memutar pada satu sumbu layar.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Seret cahaya atau cincinnya. Shift mengunci ke kelipatan 15°.
|
||||
lighting Light Cahaya
|
||||
Keep visible surfaces only when expanding Pertahankan hanya permukaan yang terlihat saat memperluas
|
||||
|
||||
|
@@ -5593,6 +5593,8 @@ effect Regular Normale
|
||||
Step up or down Aumenta o riduci di un passo
|
||||
Drag values or labels. Double-click a value to type. Trascina i valori o le etichette. Fai doppio clic su un valore per digitarlo.
|
||||
Drag rings to rotate. Shift snaps to 15°. Trascina gli anelli per ruotare. Shift usa incrementi di 15°.
|
||||
Track cube Cubo di rotazione
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Trascina una faccia, uno spigolo o l'anello per ruotare. Shift ruota attorno a un asse dello schermo.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Trascina la luce o i suoi anelli. Shift usa incrementi di 15°.
|
||||
lighting Light Luce
|
||||
Keep visible surfaces only when expanding Mantieni solo le superfici visibili durante l’espansione
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5636,6 +5636,8 @@ effect Vertical 垂直
|
||||
Step up or down 1 段階ずつ増減
|
||||
Drag values or labels. Double-click a value to type. 数値やラベルをドラッグして調整。数値をダブルクリックすると入力できます。
|
||||
Drag rings to rotate. Shift snaps to 15°. リングをドラッグして回転。Shiftで15°刻みに調整。
|
||||
Track cube 回転キューブ
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. 面、辺、またはリングをドラッグして回転。Shiftで画面の1つの軸を中心に回転。
|
||||
Drag the light, or its rings. Shift snaps to 15°. ライトやリングをドラッグ。Shiftで15°刻みに調整。
|
||||
lighting Light ライト
|
||||
Keep visible surfaces only when expanding アピアランス分割時に見える面だけを保持
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -3027,6 +3027,8 @@
|
||||
Reset all Revolve settings to their defaults. ბრუნვის ყველა პარამეტრის ნაგულისხმევზე დაბრუნება.
|
||||
Drag values or labels. Double-click a value to type. გადაათრიეთ მნიშვნელობები ან წარწერები. მნიშვნელობის ასაკრეფად ორჯერ დაწკაპეთ.
|
||||
Drag rings to rotate. Shift snaps to 15°. შესაბრუნებლად გადაათრიეთ რგოლები. Shift მიაბამს 15°-ის ჯერად კუთხეებზე.
|
||||
Track cube შემობრუნების კუბი
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. შესაბრუნებლად გადაათრიეთ წახნაგი, წიბო ან რგოლი. Shift აბრუნებს ეკრანის ერთი ღერძის გარშემო.
|
||||
Drag the light, or its rings. Shift snaps to 15°. გადაათრიეთ სინათლე ან მისი რგოლები. Shift მიაბამს 15°-ის ჯერად კუთხეებზე.
|
||||
lighting Light სინათლე
|
||||
Keep visible surfaces only when expanding გაშლისას მხოლოდ ხილული ზედაპირების შენარჩუნება
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5557,6 +5557,8 @@ effect Vertical 세로
|
||||
Step up or down 한 단계 올리기 또는 내리기
|
||||
Drag values or labels. Double-click a value to type. 값이나 레이블을 드래그하세요. 값을 더블클릭하면 입력할 수 있습니다.
|
||||
Drag rings to rotate. Shift snaps to 15°. 링을 드래그해 회전하세요. Shift를 누르면 15°씩 스냅됩니다.
|
||||
Track cube 회전 큐브
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. 면, 모서리 또는 링을 드래그해 회전하세요. Shift를 누르면 화면의 한 축을 중심으로 회전합니다.
|
||||
Drag the light, or its rings. Shift snaps to 15°. 조명이나 링을 드래그하세요. Shift를 누르면 15°씩 스냅됩니다.
|
||||
lighting Light 광원
|
||||
Keep visible surfaces only when expanding 확장 시 보이는 표면만 유지
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1496,6 +1496,8 @@
|
||||
Reset all Revolve settings to their defaults. Stelt alle draai-instellingen opnieuw in op de standaardwaarden.
|
||||
Drag values or labels. Double-click a value to type. Sleep waarden of labels. Dubbelklik op een waarde om te typen.
|
||||
Drag rings to rotate. Shift snaps to 15°. Sleep de ringen om te roteren. Shift lijnt uit op 15°.
|
||||
Track cube Rotatiekubus
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Sleep een vlak, een rand of de ring om te roteren. Shift roteert om één schermas.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Sleep het licht of de ringen ervan. Shift lijnt uit op 15°.
|
||||
lighting Light Licht
|
||||
Keep visible surfaces only when expanding Alleen zichtbare oppervlakken behouden bij het uitbreiden
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -995,6 +995,8 @@
|
||||
Step up or down Zwiększ lub zmniejsz o krok
|
||||
Drag values or labels. Double-click a value to type. Przeciągaj wartości lub etykiety. Kliknij dwukrotnie wartość, aby ją wpisać.
|
||||
Drag rings to rotate. Shift snaps to 15°. Przeciągaj pierścienie, aby obracać. Shift przyciąga co 15°.
|
||||
Track cube Kostka obrotu
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Przeciągnij ścianę, krawędź lub pierścień, aby obracać. Shift obraca wokół jednej osi ekranu.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Przeciągaj światło lub jego pierścienie. Shift przyciąga co 15°.
|
||||
lighting Light Światło
|
||||
Keep visible surfaces only when expanding Przy rozszerzaniu zachowaj tylko widoczne powierzchnie
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -3564,6 +3564,8 @@ imageTrace Outline Contorno
|
||||
Step up or down Aumentar ou diminuir um passo
|
||||
Drag values or labels. Double-click a value to type. Arraste os valores ou rótulos. Clique duas vezes em um valor para digitá-lo.
|
||||
Drag rings to rotate. Shift snaps to 15°. Arraste os anéis para girar. Shift ajusta em incrementos de 15°.
|
||||
Track cube Cubo de rotação
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Arraste uma face, uma aresta ou o anel para girar. Shift gira em torno de um eixo da tela.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Arraste a luz ou seus anéis. Shift ajusta em incrementos de 15°.
|
||||
lighting Light Luz
|
||||
Keep visible surfaces only when expanding Manter apenas as superfícies visíveis ao expandir
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5591,6 +5591,8 @@ axis Both Оба
|
||||
Step up or down Шаг вверх или вниз
|
||||
Drag values or labels. Double-click a value to type. Перетаскивайте значения или подписи. Для ввода дважды щёлкните значение.
|
||||
Drag rings to rotate. Shift snaps to 15°. Перетаскивайте кольца для вращения. Shift задаёт шаг 15°.
|
||||
Track cube Куб вращения
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Перетащите грань, ребро или кольцо для вращения. Shift вращает вокруг одной оси экрана.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Перетаскивайте источник света или кольца. Shift задаёт шаг 15°.
|
||||
lighting Light Свет
|
||||
Keep visible surfaces only when expanding При разборе сохранять только видимые поверхности
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5456,6 +5456,8 @@ effect Soft Mjuk
|
||||
Step up or down Ett steg upp eller ned
|
||||
Drag values or labels. Double-click a value to type. Dra i värden eller etiketter. Dubbelklicka på ett värde för att skriva.
|
||||
Drag rings to rotate. Shift snaps to 15°. Dra i ringarna för att rotera. Shift fäster i steg om 15°.
|
||||
Track cube Rotationskub
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Dra i en sida, en kant eller ringen för att rotera. Shift roterar runt en skärmaxel.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Dra i ljuset eller dess ringar. Shift fäster i steg om 15°.
|
||||
Keep visible surfaces only when expanding Behåll endast synliga ytor vid expandering
|
||||
Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces. Trimma dold geometri vid Expandera utseende. Live-förhandsgranskningen behåller hela ytan. Transparenta färger och ytor som överskrider synlighetsgränserna behåller alla sidoytor.
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5328,6 +5328,8 @@ effect Soft Yumuşak
|
||||
Reset all Revolve settings to their defaults. Tüm Revolve ayarlarını varsayılan değerlerine sıfırlayın.
|
||||
Drag values or labels. Double-click a value to type. Değerleri veya etiketleri sürükleyin. Yazmak için bir değeri çift tıklayın.
|
||||
Drag rings to rotate. Shift snaps to 15°. Döndürmek için halkaları sürükleyin. Kaydırma 15°'ye sabitlenir.
|
||||
Track cube Döndürme küpü
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Döndürmek için bir yüzü, kenarı veya halkayı sürükleyin. Shift tek bir ekran ekseni etrafında döndürür.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Işığı veya halkalarını sürükleyin. Kaydırma 15°'ye sabitlenir.
|
||||
Keep visible surfaces only when expanding Görünür yüzeyleri yalnızca genişletirken koruyun
|
||||
Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces. Görünümü Genişlet'te kapsanan geometriyi kırpın. Canlı önizleme tüm yüzeyi korur. Şeffaf boyalar ve görünürlük sınırlarını aşan yüzeyler tüm yüzleri korur.
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5573,6 +5573,8 @@ axis Both Обидві
|
||||
Step up or down Крок угору або вниз
|
||||
Drag values or labels. Double-click a value to type. Перетягуйте значення або підписи. Двічі клацніть значення, щоб увести його.
|
||||
Drag rings to rotate. Shift snaps to 15°. Перетягуйте кільця для обертання. Shift задає крок 15°.
|
||||
Track cube Куб обертання
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Перетягніть грань, ребро або кільце для обертання. Shift обертає навколо однієї осі екрана.
|
||||
Drag the light, or its rings. Shift snaps to 15°. Перетягуйте джерело світла або його кільця. Shift задає крок 15°.
|
||||
Keep visible surfaces only when expanding Під час розгортання зберігати лише видимі поверхні
|
||||
Trim covered geometry on Expand Appearance. Live preview keeps the full surface. Transparent paints and surfaces exceeding visibility limits retain all faces. Обрізає приховану геометрію під час розгортання оформлення. Попередній перегляд зберігає всю поверхню. Прозорі заливки та поверхні, що перевищують обмеження видимості, зберігають усі грані.
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -1100,6 +1100,8 @@ font-technology Variable Biến thiên
|
||||
Drag art, colors and text styles here to reuse them across documents. Libraries are stored on this machine — no account required. Kéo tác phẩm, màu và kiểu chữ vào đây để tái sử dụng trong các tài liệu. Thư viện được lưu trên máy này — không cần tài khoản.
|
||||
Drag onto art to apply this appearance Kéo lên tác phẩm để áp dụng diện mạo này
|
||||
Drag rings to rotate. Shift snaps to 15°. Kéo vòng để xoay. Shift khớp ở 15°.
|
||||
Track cube Khối xoay
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. Kéo một mặt, một cạnh hoặc vòng để xoay. Shift xoay quanh một trục màn hình.
|
||||
Drag the art to move it on the paper Kéo tác phẩm để di chuyển trên trang
|
||||
Drag the light, or its rings. Shift snaps to 15°. Kéo đèn hoặc vòng của nó. Shift khớp ở 15°.
|
||||
Drag to float as a toolbar Kéo để thả nổi thanh công cụ
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 205 and column 5.
|
@@ -5853,6 +5853,8 @@ effect Vertical 垂直
|
||||
Step up or down 逐级增减
|
||||
Drag values or labels. Double-click a value to type. 拖动数值或标签。双击数值即可输入。
|
||||
Drag rings to rotate. Shift snaps to 15°. 拖动圆环旋转。按住 Shift 以 15° 为步长调整。
|
||||
Track cube 旋转立方体
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. 拖动面、边或圆环进行旋转。按住 Shift 绕一个屏幕轴旋转。
|
||||
Drag the light, or its rings. Shift snaps to 15°. 拖动光源或圆环。按住 Shift 以 15° 为步长调整。
|
||||
lighting Light 光源
|
||||
Keep visible surfaces only when expanding 扩展时仅保留可见表面
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5689,6 +5689,8 @@ effect Soft 柔和
|
||||
Step up or down 逐級增減
|
||||
Drag values or labels. Double-click a value to type. 拖曳數值或標籤。按兩下數值即可輸入。
|
||||
Drag rings to rotate. Shift snaps to 15°. 拖曳圓環旋轉。按住 Shift 以 15° 為間距調整。
|
||||
Track cube 旋轉立方體
|
||||
Drag a face, an edge or the ring to rotate. Shift turns about one screen axis. 拖曳面、邊或圓環進行旋轉。按住 Shift 繞一個螢幕軸旋轉。
|
||||
Drag the light, or its rings. Shift snaps to 15°. 拖曳光源或圓環。按住 Shift 以 15° 為間距調整。
|
||||
lighting Light 光源
|
||||
Keep visible surfaces only when expanding 展開時僅保留可見表面
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -181,7 +181,7 @@ VectorCraft choices; an original approximation, never compared with another appl
|
||||
| Revolve | initial: live, editable profile, rotation and light gizmos, default-on Cap with continuous curved rims, smooth vector shading and round seam joins, overlapping faces drawn in the order of their depths where they overlap, SVG/PDF output, Expand Appearance ([revolve.md](revolve.md), #846) |
|
||||
| Extrude & Bevel, Inflate, Rotate | initial: live, round seam joins, depth, twist, taper, solid or hollow caps, five original bevel shapes, Inflate volume, both sides, twist, taper and cap, Rotate of every fill and stroke, groups and layers turned about one shared axis (#4506), contours that cross, touch or overlap merged first ([three-d.md](three-d.md)), Position presets, rotation and light gizmos, SVG/PDF output, Expand Appearance ([three-d.md](three-d.md)) |
|
||||
| Materials panel, lighting, ray-traced render | Window › 3D and Materials panel with the object types (Plane, Extrude, Revolve, Inflate) and the Object, Rotation and Lighting settings of the applied effect, Render Settings › Wireframe, which draws the live effect as the edges of its faces, and Quick Actions › Expand as Wireframes ([three-d.md](three-d.md#3d-and-materials-panel)); one to ten directional lights with per-light Color (opaque RGB, white by default), Intensity, Rotation, Height, Softness and neutral Ambient Light, Revolve and colored Inflate use smooth vector shading; Extrude & Bevel and Rotate retain planar shading; original Standard, Diffuse, Top Left and Right lighting rigs; hard-edged shadows behind or below the object from the first light ([three-d.md](three-d.md#shadows)); the Materials tab's Graphics, document symbols mapped onto Extrude & Bevel's caps and onto a plane, moved with an artboard handle, and wrapped around Revolve's side ([three-d.md](three-d.md#graphics)); no base materials, graphics on Inflate or on Extrude & Bevel's walls and bevels, soft shadows or ray tracing |
|
||||
| 3D (Classic): Extrude & Bevel, Revolve, Rotate | Extrude & Bevel (Classic) initial: live, round seam joins, Extrude Depth, Cap, five original bevel shapes with Height and Bevel Extent In or Out, Position presets and rotation gizmo, Perspective, Wireframe, No Shading, Diffuse and Plastic surfaces with one to ten lights, Light Intensity, Ambient Light, Highlight Intensity and Size, Blend Steps, Black, Custom or no Shading Color, Draw Hidden Faces ([create 3D objects](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/create-3d-objects.html)); Revolve (Classic) initial: live, round seam joins, Angle, Cap, Offset from the left or right edge, Position presets and rotation gizmo, Perspective, the same four surfaces, lights, highlight, Blend Steps and Shading Color, groups and layers revolved about one shared axis (same page); Rotate (Classic) initial: live, round seam joins, every fill and stroke turned as one plane, Position presets and rotation gizmo, Perspective, No Shading and Diffuse surfaces with lights, Ambient Light, Blend Steps and Shading Color ([rotate objects in 3D](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/rotate-objects-in-3d.html)); Preserve Spot Colors in all three, unavailable with a Custom Shading Color ([Preserve Spot Color](https://help.adobe.com/archive/en_US/illustrator/cs5/illustrator_cs5_help.pdf#page=260)); Map Art: none |
|
||||
| 3D (Classic): Extrude & Bevel, Revolve, Rotate | Extrude & Bevel (Classic) initial: live, round seam joins, Extrude Depth, Cap, five original bevel shapes with Height and Bevel Extent In or Out, Position presets and rotation gizmo, Perspective, Wireframe, No Shading, Diffuse and Plastic surfaces with one to ten lights, Light Intensity, Ambient Light, Highlight Intensity and Size, Blend Steps, Black, Custom or no Shading Color, Draw Hidden Faces ([create 3D objects](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/create-3d-objects.html)); Revolve (Classic) initial: live, round seam joins, Angle, Cap, Offset from the left or right edge, Position presets and rotation gizmo, Perspective, the same four surfaces, lights, highlight, Blend Steps and Shading Color, groups and layers revolved about one shared axis (same page); Rotate (Classic) initial: live, round seam joins, every fill and stroke turned as one plane, Position presets and rotation gizmo, Perspective, No Shading and Diffuse surfaces with lights, Ambient Light, Blend Steps and Shading Color ([rotate objects in 3D](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/rotate-objects-in-3d.html)); Preserve Spot Colors in all three, unavailable with a Custom Shading Color ([Preserve Spot Color](https://help.adobe.com/archive/en_US/illustrator/cs5/illustrator_cs5_help.pdf#page=260)); all three: the track cube (face, edge, Shift and ring drags, keyboard steps; [three-d.md](three-d.md#track-cube)); Map Art: none |
|
||||
| Turntable (30.0 beta) | none |
|
||||
| Export 3D objects (OBJ, USDA, glTF) | initial: Asset Export's Export 3D Object collects an object with Extrude & Bevel, Revolve, Inflate or Rotate as a 3D asset, and Export writes its solids as a USDA (the default), USDZ, glTF or OBJ mesh with a material in each solid's paint color (`assets.add3D`, `assets.set3DFormat`, `assets.export3D`); no textures, map art or shading ([3D export help](https://helpx.adobe.com/illustrator/desktop/special-effects-styles/create-3d-graphics/export-3d-vector-artwork.html)) |
|
||||
|
||||
|
||||
+25
-2
@@ -275,6 +275,29 @@ of an isometric view (each visible axis foreshortened equally). These are our ow
|
||||
each view; the dialog shows a preset's name when the angles match it and **Custom** otherwise. The new effects
|
||||
open at Off-Axis Front.
|
||||
|
||||
## Track cube
|
||||
|
||||
The Rotation tab of Extrude & Bevel (Classic), Revolve (Classic) and Rotate (Classic) has a track cube below the
|
||||
presets, drawn at the current X, Y and Z rotation inside a ring
|
||||
([set 3D rotation position options](https://web.archive.org/web/20220911143322/https://helpx.adobe.com/pdf/cs6/illustrator_reference.pdf#page=249)):
|
||||
|
||||
- Dragging a face turns the object freely. With Shift, a drag across turns it about the screen's vertical axis and a
|
||||
drag up or down about its horizontal axis, whichever the drag follows first.
|
||||
- Dragging an edge turns it about the object axis that edge runs along. The edge under the pointer shows its axis's
|
||||
color: red for X, green for Y, blue for Z.
|
||||
- Dragging in the ring turns it in the plane of the screen.
|
||||
- The front face is blue, the top and bottom are light gray, the sides are mid gray and the back is dark gray, as
|
||||
the help page above describes, along with the red, green and blue axis edges.
|
||||
- Escape during a drag puts the angles back. With the keyboard focus, the arrow keys turn it about the screen's
|
||||
horizontal and vertical axes, and Page Up and Page Down turn it in the screen plane, 1° a press or 15° with Shift.
|
||||
|
||||
The drag changes the effect's `rotationX`, `rotationY` and `rotationZ` and previews live; X, Y and Z and the
|
||||
presets follow it (**Custom** off a preset). OK keeps the change as one undo step. The angles stay between -180°
|
||||
and 180°: of the two sets of angles that give the same turn, the cube writes the one nearest the current values.
|
||||
In the 3D and Materials panel, a drag is one undo step when the pointer is released, and the cube is off while the
|
||||
selected effects hold different rotations. The cube's 0.5° per point of drag, Escape during a drag and its keyboard
|
||||
steps are VectorCraft's own.
|
||||
|
||||
## Perspective
|
||||
|
||||
**Perspective** runs 0° to 160°, as the public panel options give it ("how close or far the object appears"),
|
||||
@@ -555,8 +578,8 @@ out, perspective). No Adobe software, assets, presets or bevel shapes were used.
|
||||
face that darkens gets black over it, multiplied and overprinting, so a spot color stays on its own plate. The
|
||||
checkbox is unavailable while Shading Color is Custom
|
||||
([Preserve Spot Color](https://help.adobe.com/archive/en_US/illustrator/cs5/illustrator_cs5_help.pdf#page=260)); how
|
||||
the faces are shaded with it is VectorCraft's own. The track cube, map art, Turntable and 3D export are separate,
|
||||
unbuilt items.
|
||||
the faces are shaded with it is VectorCraft's own. Their Rotation tab has the track cube
|
||||
([Track cube](#track-cube)). Map art, Turntable and 3D export are separate, unbuilt items.
|
||||
|
||||
Release measurements and a repeatable CLI scene are in [3D lighting performance](3d-lighting-performance.md).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user