Download editor/src/messages/tool/common_functionality/compass_rose.rs from openfree/graphite2: direct link, hf CLI and curl.
- Browser
- Download file 3.47 kB
-
https://huggingface.co/spaces/openfree/graphite2/resolve/main/editor/src/messages/tool/common_functionality/compass_rose.rs
- Command line
-
hf download hf://spaces/openfree/graphite2/editor/src/messages/tool/common_functionality/compass_rose.rs
-
curl -L -o compass_rose.rs https://huggingface.co/spaces/openfree/graphite2/resolve/main/editor/src/messages/tool/common_functionality/compass_rose.rs
3.47 kB
| use crate::consts::{COMPASS_ROSE_ARROW_CLICK_TARGET_ANGLE, COMPASS_ROSE_HOVER_RING_DIAMETER, COMPASS_ROSE_RING_INNER_DIAMETER}; | |
| use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; | |
| use crate::messages::prelude::DocumentMessageHandler; | |
| use glam::{DAffine2, DVec2}; | |
| use std::f64::consts::FRAC_PI_2; | |
| pub struct CompassRose { | |
| compass_center: DVec2, | |
| } | |
| impl CompassRose { | |
| fn get_layer_pivot_transform(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> DAffine2 { | |
| let [min, max] = document.metadata().nonzero_bounding_box(layer); | |
| let bounds_transform = DAffine2::from_translation(min) * DAffine2::from_scale(max - min); | |
| let layer_transform = document.metadata().transform_to_viewport(layer); | |
| layer_transform * bounds_transform | |
| } | |
| pub fn refresh_position(&mut self, document: &DocumentMessageHandler) { | |
| let selected_nodes = document.network_interface.selected_nodes(); | |
| let mut layers = selected_nodes.selected_visible_and_unlocked_layers(&document.network_interface); | |
| let Some(first) = layers.next() else { return }; | |
| let count = layers.count() + 1; | |
| let transform = if count == 1 { | |
| Self::get_layer_pivot_transform(first, document) | |
| } else { | |
| let [min, max] = document.selected_visible_and_unlock_layers_bounding_box_viewport().unwrap_or([DVec2::ZERO, DVec2::ONE]); | |
| DAffine2::from_translation(min) * DAffine2::from_scale(max - min) | |
| }; | |
| self.compass_center = transform.transform_point2(DVec2::splat(0.5)); | |
| } | |
| pub fn compass_rose_position(&self) -> DVec2 { | |
| self.compass_center | |
| } | |
| pub fn compass_rose_state(&self, mouse: DVec2, angle: f64) -> CompassRoseState { | |
| const COMPASS_ROSE_RING_INNER_RADIUS_SQUARED: f64 = (COMPASS_ROSE_RING_INNER_DIAMETER / 2.) * (COMPASS_ROSE_RING_INNER_DIAMETER / 2.); | |
| const COMPASS_ROSE_HOVER_RING_RADIUS_SQUARED: f64 = (COMPASS_ROSE_HOVER_RING_DIAMETER / 2.) * (COMPASS_ROSE_HOVER_RING_DIAMETER / 2.); | |
| let compass_distance_squared = mouse.distance_squared(self.compass_center); | |
| if !(COMPASS_ROSE_RING_INNER_RADIUS_SQUARED..COMPASS_ROSE_HOVER_RING_RADIUS_SQUARED).contains(&compass_distance_squared) { | |
| return CompassRoseState::None; | |
| } | |
| let angle = (mouse - self.compass_center).angle_to(DVec2::from_angle(angle)).abs(); | |
| let resolved_angle = (FRAC_PI_2 - angle).abs(); | |
| let angular_width = COMPASS_ROSE_ARROW_CLICK_TARGET_ANGLE.to_radians(); | |
| if resolved_angle < angular_width { | |
| CompassRoseState::AxisY | |
| } else if resolved_angle > (FRAC_PI_2 - angular_width) { | |
| CompassRoseState::AxisX | |
| } else { | |
| CompassRoseState::Ring | |
| } | |
| } | |
| } | |
| pub enum CompassRoseState { | |
| Ring, | |
| AxisX, | |
| AxisY, | |
| None, | |
| } | |
| impl CompassRoseState { | |
| pub fn can_grab(&self) -> bool { | |
| matches!(self, Self::Ring | Self::AxisX | Self::AxisY) | |
| } | |
| pub fn is_ring(&self) -> bool { | |
| matches!(self, Self::Ring) | |
| } | |
| pub fn axis_type(&self) -> Option<Axis> { | |
| match self { | |
| CompassRoseState::AxisX => Some(Axis::X), | |
| CompassRoseState::AxisY => Some(Axis::Y), | |
| CompassRoseState::Ring => Some(Axis::None), | |
| _ => None, | |
| } | |
| } | |
| } | |
| pub enum Axis { | |
| None, | |
| X, | |
| Y, | |
| } | |
| impl Axis { | |
| pub fn is_constraint(&self) -> bool { | |
| matches!(self, Self::X | Self::Y) | |
| } | |
| } | |
| impl From<Axis> for DVec2 { | |
| fn from(value: Axis) -> Self { | |
| match value { | |
| Axis::X => DVec2::X, | |
| Axis::Y => DVec2::Y, | |
| Axis::None => DVec2::ZERO, | |
| } | |
| } | |
| } | |