use super::camera::{Bounds, Camera};
use super::{Event, View};
const COAST: f64 = 0.3;
const GLIDE: f64 = 0.1;
#[derive(Default)]
pub(crate) struct Rig {
anchor: [f64; 3],
pan: [f64; 2],
turn: [f64; 2],
zoom: f64,
flight: Option<Flight>,
pub(crate) orbit: f64,
pub(crate) bounds: Option<Bounds>,
}
struct Flight {
from: Camera,
to: Camera,
start: f64,
seconds: f64,
}
impl Rig {
pub(crate) fn easing(&self) -> bool {
self.flight.is_some() || self.owed()
}
fn owed(&self) -> bool {
self.pan != [0.0; 2] || self.turn != [0.0; 2] || self.zoom != 0.0
}
pub(crate) fn hold(&mut self) {
self.pan = [0.0; 2];
self.turn = [0.0; 2];
self.zoom = 0.0;
self.flight = None;
}
pub(crate) fn owe(&mut self, anchor: [f64; 3], pan: [f64; 2], turn: [f64; 2], zoom: f64) {
self.flight = None;
self.anchor = anchor;
self.pan = [self.pan[0] + pan[0], self.pan[1] + pan[1]];
self.turn = [self.turn[0] + turn[0], self.turn[1] + turn[1]];
self.zoom += zoom;
}
pub(crate) fn fling(&mut self, anchor: [f64; 3], pan: [f64; 2], turn: [f64; 2]) {
self.owe(anchor, pan.map(|v| v * COAST), turn.map(|v| v * COAST), 0.0);
}
pub(crate) fn fly(&mut self, from: Camera, to: Camera, start: f64, seconds: f64) {
self.hold();
self.flight = Some(Flight { from, to, start, seconds });
}
}
impl View {
pub(super) fn steer(&mut self, camera: Camera) {
let camera = match &self.rig.bounds {
Some(bounds) => camera.within(bounds),
None => camera,
};
self.move_camera(camera);
}
pub(super) fn advance(&mut self, dt: f64) {
if let Some(flight) = &self.rig.flight {
let eased = self.clock.eased(flight.start, flight.seconds);
let camera = flight.from.ease(&flight.to, eased, &self.scene.space);
if self.clock.done(flight.start, flight.seconds) {
self.rig.flight = None;
}
self.move_camera(camera);
}
if dt <= 0.0 {
return;
}
if self.rig.owed() {
let moves = self.moves();
let coast = if moves { 1.0 - (-dt / COAST).exp() } else { 1.0 };
let glide = if moves { 1.0 - (-dt / GLIDE).exp() } else { 1.0 };
let (pan, turn, zoom) =
(self.rig.pan.map(|v| v * coast), self.rig.turn.map(|v| v * coast), self.rig.zoom * glide);
let anchor = self.rig.anchor;
let view = self.projected();
let mut camera = self.camera.panned(&view, anchor, pan);
camera = camera.turned(&self.projected_with(&camera), anchor, turn);
camera = camera.zoomed(&self.projected_with(&camera), anchor, zoom);
let settle = |v: f64, least: f64| if v.abs() < least { 0.0 } else { v };
self.rig.pan = [settle(self.rig.pan[0] - pan[0], 0.05), settle(self.rig.pan[1] - pan[1], 0.05)];
self.rig.turn = [settle(self.rig.turn[0] - turn[0], 0.01), settle(self.rig.turn[1] - turn[1], 0.01)];
self.rig.zoom = settle(self.rig.zoom - zoom, 1e-4);
self.steer(camera);
}
if self.rig.orbit != 0.0 && matches!(self.camera, Camera::Map { .. }) && self.moves() {
let Camera::Map { center, .. } = self.camera else { return };
let view = self.projected();
let camera = self.camera.turned(&view, center, [self.rig.orbit * dt, 0.0]);
self.move_camera(camera);
}
}
pub(super) fn move_camera(&mut self, camera: Camera) {
if self.place_camera(camera) {
self.events.tell(Event::Camera(camera));
}
}
pub(super) fn place_camera(&mut self, camera: Camera) -> bool {
if camera == self.camera {
return false;
}
self.camera = camera;
self.fitting.plot_due = true;
self.gestures.keys.stale();
for shown in &mut self.marks {
let channels =
shown.channels_reading(crate::expr::compile::Deps::CAMERA | crate::expr::compile::Deps::POINTER);
shown.dirty_rows(channels, None);
}
self.wake();
true
}
}