mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
3D and Materials: Perspective runs 0° to 160°, as documented
The public 3D and Materials panel options give Perspective as 0° to 160°
("how close or far the object appears"); it was a 0–100 % strength, for
Revolve, Extrude & Bevel, Inflate and Rotate alike.
- The eye stands where a sphere about the object's centre, √3 times its
half size (the box around it fits inside), fills that angle of the
view: 0° is none, wider brings the eye nearer, and at 160° it is just
outside the sphere, never inside the object. The documentation doesn't
say how the angle places the eye; docs/three-d.md says this is our
reading.
- `perspectiveAngle` (degrees) replaces `perspective` (%). A strength from
an earlier file or script is read as the angle that shows exactly the
same view: sin(angle / 2) = √3 × strength / 4, 100 % about 51.3°. An
angle given too wins. effect.setParams turns a stored strength into the
angle before applying new values. The parameter description names
`perspective` as the earlier form, so effect.apply and effect.setParams
still take it under the key check of #1592. Old and new code draw the four effects identically at 0, 25,
60 and 100 % (bounds equal to 1e-9).
- The dialogs' Perspective fields run 0–160°.
# Conflicts:
# docs/target-app-parity.md
This commit is contained in:
1 parent
a3357121fb
commit
39db6abfce
16 files changed
+231
-49
No files matched your search
@@ -311,8 +311,8 @@ fn set_params(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
&& visible != Some(false)
|
||||
{
|
||||
let mut prospective = effects::merged_params(&e.id, &e.params);
|
||||
if let (Some(cur), Some(new)) = (prospective.as_object_mut(), params.as_object()) {
|
||||
cur.extend(new.clone());
|
||||
if let (Some(cur), Value::Object(new)) = (prospective.as_object_mut(), effects::upgrade_params(&e.id, ¶ms)) {
|
||||
cur.extend(new);
|
||||
}
|
||||
if e.id == effects::REVOLVE {
|
||||
effects::validate_revolve(n, &prospective).map_err(|e| bad(C, e))?;
|
||||
@@ -323,14 +323,15 @@ fn set_params(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
let ids = edit_effects(s, p, item, C, "Effect Options", &format!("{C}: no effect at index {index}"), |fx| {
|
||||
let Some(e) = fx.get_mut(index) else { return false };
|
||||
if let (Value::Object(new), cur) = (¶ms, &mut e.params) {
|
||||
if let (Value::Object(new), cur) = (effects::upgrade_params(&e.id, ¶ms), &mut e.params) {
|
||||
if !cur.is_object() {
|
||||
*cur = effects::merged_params(&e.id, &Value::Null);
|
||||
}
|
||||
// Earlier parameters (a Perspective strength) take their current form first, so the
|
||||
// new values replace them and the rest is kept.
|
||||
*cur = effects::upgrade_params(&e.id, cur);
|
||||
if let Value::Object(m) = cur {
|
||||
for (k, v) in new {
|
||||
m.insert(k.clone(), v.clone());
|
||||
}
|
||||
m.extend(new);
|
||||
}
|
||||
}
|
||||
if let Some(v) = visible {
|
||||
@@ -602,6 +603,30 @@ mod tests {
|
||||
assert!(err.to_string().contains("requires a path"), "{err}");
|
||||
}
|
||||
|
||||
/// Scripts from before the Perspective angle give `perspective` as a 0–100 % strength: it is
|
||||
/// stored as the angle that shows the same view, and a later angle replaces an earlier strength.
|
||||
#[test]
|
||||
fn an_earlier_perspective_strength_is_set_as_its_angle() {
|
||||
let (mut s, id) = session_with_rect();
|
||||
s.execute("effect.apply", &json!({"effect": effects::EXTRUDE, "ids": [id.0], "item": null, "params": {"perspective": 60}})).unwrap();
|
||||
let params = |s: &Session| node(s, id).appearance.effects[0].params.clone();
|
||||
let angle_of = |pct: f64| effects::merged_params(effects::EXTRUDE, &json!({"perspective": pct}))["perspectiveAngle"].as_f64().unwrap();
|
||||
let angle = angle_of(60.0);
|
||||
assert!((angle - 30.12).abs() < 0.01, "{angle}");
|
||||
assert!(
|
||||
params(&s).get("perspective").is_none() && (params(&s)["perspectiveAngle"].as_f64().unwrap() - angle).abs() < 1e-12,
|
||||
"{}",
|
||||
params(&s)
|
||||
);
|
||||
s.execute("effect.setParams", &json!({"index": 0, "params": {"perspective": 100}, "ids": [id.0], "item": null})).unwrap();
|
||||
assert!((params(&s)["perspectiveAngle"].as_f64().unwrap() - angle_of(100.0)).abs() < 1e-12);
|
||||
// A file of then: the strength stored; setting an angle replaces it.
|
||||
std::sync::Arc::make_mut(&mut s.doc_mut().unwrap().doc).node_mut(id).unwrap().appearance.effects[0].params =
|
||||
json!({"depth": 50, "perspective": 60});
|
||||
s.execute("effect.setParams", &json!({"index": 0, "params": {"perspectiveAngle": 120}, "ids": [id.0], "item": null})).unwrap();
|
||||
assert_eq!(params(&s), json!({"depth": 50, "perspectiveAngle": 120}));
|
||||
}
|
||||
|
||||
fn effects_for_test(s: &Session, id: NodeId) -> vectorcraft_doc::Node {
|
||||
effects::revolve_art(&node(s, id)).unwrap()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user