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 pub fn as_2d_scale_offset(&self) -> Option<ScaleOffset> {
184 self.kind.as_2d_scale_offset()
185 }
186}
187
188
189#[derive(Clone, Debug)]
190pub struct SpaceSnapper {
191 ref_spatial_node_index: SpatialNodeIndex,
192 current_target_spatial_node_index: SpatialNodeIndex,
193 snapping_transform: Option<ScaleOffset>,
194 raster_pixel_scale: RasterPixelScale,
195}
196
197impl SpaceSnapper {
198 pub fn new(
199 ref_spatial_node_index: SpatialNodeIndex,
200 raster_pixel_scale: RasterPixelScale,
201 ) -> Self {
202 SpaceSnapper {
203 ref_spatial_node_index,
204 current_target_spatial_node_index: SpatialNodeIndex::INVALID,
205 snapping_transform: None,
206 raster_pixel_scale,
207 }
208 }
209
210 pub fn set_target_spatial_node<S: SpatialNodeContainer>(
211 &mut self,
212 target_node_index: SpatialNodeIndex,
213 spatial_tree: &S,
214 ) {
215 if target_node_index == self.current_target_spatial_node_index {
216 return
217 }
218
219 let ref_snap = spatial_tree.get_node_info(self.ref_spatial_node_index).snapping_transform;
220 let target_snap = spatial_tree.get_node_info(target_node_index).snapping_transform;
221
222 self.current_target_spatial_node_index = target_node_index;
223 self.snapping_transform = match (ref_snap, target_snap) {
224 (Some(ref ref_scale_offset), Some(ref target_scale_offset)) => {
225 Some(target_scale_offset
226 .pre_scale(self.raster_pixel_scale.0)
227 .then(&ref_scale_offset.inverse())
228 )
229 }
230 _ => None,
231 };
232 }
233
234 pub fn snap_rect<F>(&self, rect: &Box2D<f32, F>) -> Box2D<f32, F> where F: fmt::Debug {
235 debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID);
236 match self.snapping_transform {
237 Some(ref scale_offset) => {
238 let snapped_device_rect: DeviceRect = scale_offset.map_rect(rect).snap();
239 scale_offset.unmap_rect(&snapped_device_rect)
240 }
241 None => *rect,
242 }
243 }
244
245 pub fn snap_point<F>(&self, point: &Point2D<f32, F>) -> Point2D<f32, F> where F: fmt::Debug {
246 debug_assert!(self.current_target_spatial_node_index != SpatialNodeIndex::INVALID);
247 match self.snapping_transform {
248 Some(ref scale_offset) => {
249 let snapped_device_vector: DevicePoint = scale_offset.map_point(point).snap();
250 scale_offset.unmap_point(&snapped_device_vector)
251 }
252 None => *point,
253 }
254 }
255}