1use std::fmt;
9
10use euclid::{Transform3D, Box2D, Point2D, Vector2D};
11
12use api::units::*;
13use crate::spatial_tree::{SpatialTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace, SpatialNodeContainer};
14use crate::util::project_rect;
15use crate::util::{MatrixHelpers, ScaleOffset, RectHelpers, PointHelpers};
16
17
18#[derive(Debug, Clone)]
19pub struct SpaceMapper<F, T> {
20 kind: CoordinateSpaceMapping<F, T>,
21 pub ref_spatial_node_index: SpatialNodeIndex,
22 pub current_target_spatial_node_index: SpatialNodeIndex,
23 pub bounds: Box2D<f32, T>,
24 visible_face: VisibleFace,
25}
26
27impl<F, T> SpaceMapper<F, T> where F: fmt::Debug {
28 pub fn new(
29 ref_spatial_node_index: SpatialNodeIndex,
30 bounds: Box2D<f32, T>,
31 ) -> Self {
32 SpaceMapper {
33 kind: CoordinateSpaceMapping::Local,
34 ref_spatial_node_index,
35 current_target_spatial_node_index: ref_spatial_node_index,
36 bounds,
37 visible_face: VisibleFace::Front,
38 }
39 }
40
41 pub fn new_with_target(
42 ref_spatial_node_index: SpatialNodeIndex,
43 target_node_index: SpatialNodeIndex,
44 bounds: Box2D<f32, T>,
45 spatial_tree: &SpatialTree,
46 ) -> Self {
47 let mut mapper = Self::new(ref_spatial_node_index, bounds);
48 mapper.set_target_spatial_node(target_node_index, spatial_tree);
49 mapper
50 }
51
52 pub fn set_target_spatial_node(
53 &mut self,
54 target_node_index: SpatialNodeIndex,
55 spatial_tree: &SpatialTree,
56 ) {
57 if target_node_index == self.current_target_spatial_node_index {
58 return
59 }
60
61 let ref_spatial_node = spatial_tree.get_spatial_node(self.ref_spatial_node_index);
62 let target_spatial_node = spatial_tree.get_spatial_node(target_node_index);
63 self.visible_face = VisibleFace::Front;
64
65 self.kind = if self.ref_spatial_node_index == target_node_index {
66 CoordinateSpaceMapping::Local
67 } else if ref_spatial_node.coordinate_system_id == target_spatial_node.coordinate_system_id {
68 let scale_offset = target_spatial_node.content_transform
69 .then(&ref_spatial_node.content_transform.inverse());
70 CoordinateSpaceMapping::ScaleOffset(scale_offset)
71 } else {
72 let transform = spatial_tree
73 .get_relative_transform_with_face(
74 target_node_index,
75 self.ref_spatial_node_index,
76 Some(&mut self.visible_face),
77 )
78 .into_transform()
79 .with_source::<F>()
80 .with_destination::<T>();
81 CoordinateSpaceMapping::Transform(transform)
82 };
83
84 self.current_target_spatial_node_index = target_node_index;
85 }
86
87 pub fn get_transform(&self) -> Transform3D<f32, F, T> {
88 match self.kind {
89 CoordinateSpaceMapping::Local => {
90 Transform3D::identity()
91 }
92 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
93 scale_offset.to_transform()
94 }
95 CoordinateSpaceMapping::Transform(transform) => {
96 transform
97 }
98 }
99 }
100
101 pub fn unmap(&self, rect: &Box2D<f32, T>) -> Option<Box2D<f32, F>> {
102 match self.kind {
103 CoordinateSpaceMapping::Local => {
104 Some(rect.cast_unit())
105 }
106 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
107 Some(scale_offset.unmap_rect(rect))
108 }
109 CoordinateSpaceMapping::Transform(ref transform) => {
110 transform.inverse_rect_footprint(rect)
111 }
112 }
113 }
114
115 pub fn map(&self, rect: &Box2D<f32, F>) -> Option<Box2D<f32, T>> {
116 match self.kind {
117 CoordinateSpaceMapping::Local => {
118 Some(rect.cast_unit())
119 }
120 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
121 Some(scale_offset.map_rect(rect))
122 }
123 CoordinateSpaceMapping::Transform(ref transform) => {
124 match project_rect(transform, rect, &self.bounds) {
125 Some(bounds) => {
126 Some(bounds)
127 }
128 None => {
129 warn!("parent relative transform can't transform the primitive rect for {:?}", rect);
130 None
131 }
132 }
133 }
134 }
135 }
136
137 pub fn map_inner_bounds(&self, rect: &Box2D<f32, F>) -> Option<Box2D<f32, T>> {
139 match self.kind {
140 CoordinateSpaceMapping::Local => {
141 Some(rect.cast_unit())
142 }
143 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
144 Some(scale_offset.map_rect(rect))
145 }
146 CoordinateSpaceMapping::Transform(..) => {
147 return None;
150 }
151 }
152 }
153
154 pub fn map_point(&self, p: Point2D<f32, F>) -> Option<Point2D<f32, T>> {
156 match self.kind {
157 CoordinateSpaceMapping::Local => {
158 Some(p.cast_unit())
159 }
160 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
161 Some(scale_offset.map_point(&p))
162 }
163 CoordinateSpaceMapping::Transform(ref transform) => {
164 transform.transform_point2d(p)
165 }
166 }
167 }
168
169 pub fn map_vector(&self, v: Vector2D<f32, F>) -> Vector2D<f32, T> {
170 match self.kind {
171 CoordinateSpaceMapping::Local => {
172 v.cast_unit()
173 }
174 CoordinateSpaceMapping::ScaleOffset(ref scale_offset) => {
175 scale_offset.map_vector(&v)
176 }
177 CoordinateSpaceMapping::Transform(ref transform) => {
178 transform.transform_vector2d(v)
179 }
180 }
181 }
182}
183
184
185#[derive(Clone, Debug)]
186pub struct SpaceSnapper {
187 ref_spatial_node_index: SpatialNodeIndex,
188 current_target_spatial_node_index: SpatialNodeIndex,
189 snapping_transform: Option<ScaleOffset>,
190 raster_pixel_scale: RasterPixelScale,
191}
192
193impl SpaceSnapper {
194 pub fn new(
195 ref_spatial_node_index: SpatialNodeIndex,
196 raster_pixel_scale: RasterPixelScale,
197 ) -> Self {
198 SpaceSnapper {
199 ref_spatial_node_index,
200 current_target_spatial_node_index: SpatialNodeIndex::INVALID,
201 snapping_transform: None,
202 raster_pixel_scale,
203 }
204 }
205
206 pub fn new_with_target<S: SpatialNodeContainer>(
207 ref_spatial_node_index: SpatialNodeIndex,
208 target_node_index: SpatialNodeIndex,
209 raster_pixel_scale: RasterPixelScale,
210 spatial_tree: &S,
211 ) -> Self {
212 let mut snapper = SpaceSnapper {
213 ref_spatial_node_index,
214 current_target_spatial_node_index: SpatialNodeIndex::INVALID,
215 snapping_transform: None,
216 raster_pixel_scale,
217 };
218
219 snapper.set_target_spatial_node(target_node_index, spatial_tree);
220 snapper
221 }
222
223 pub fn set_target_spatial_node<S: SpatialNodeContainer>(
224 &mut self,
225 target_node_index: SpatialNodeIndex,
226 spatial_tree: &S,
227 ) {
228 if target_node_index == self.current_target_spatial_node_index {
229 return
230 }
231
232 let ref_snap = spatial_tree.get_node_info(self.ref_spatial_node_index).snapping_transform;
233 let target_snap = spatial_tree.get_node_info(target_node_index).snapping_transform;
234
235 self.current_target_spatial_node_index = target_node_index;
236 self.snapping_transform = match (ref_snap, target_snap) {
237 (Some(ref ref_scale_offset), Some(ref target_scale_offset)) => {
238 Some(target_scale_offset
239 .pre_scale(self.raster_pixel_scale.0)
240 .then(&ref_scale_offset.inverse())
241 )
242 }
243 _ => None,
244 };
245 }
246
247 pub fn snap_rect<F>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, F> where F: fmt::Debug {
248 debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID);
249 match self.snapping_transform {
250 Some(ref scale_offset) => {
251 let snapped_device_rect: DeviceRect = scale_offset.map_rect(rect).snap();
252 scale_offset.unmap_rect(&snapped_device_rect)
253 }
254 None => *rect,
255 }
256 }
257
258 pub fn snap_point<F>(&self, point: &Point2D<f32, F>) -> Point2D<f32, F> where F: fmt::Debug {
259 debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID);
260 match self.snapping_transform {
261 Some(ref scale_offset) => {
262 let snapped_device_vector : DevicePoint = scale_offset.map_point(point).snap();
263 scale_offset.unmap_point(&snapped_device_vector)
264 }
265 None => *point,
266 }
267 }
268}