OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/transform_util.h" | 5 #include "ui/gfx/transform_util.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/logging.h" | |
10 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
11 #include "ui/gfx/point.h" | 12 #include "ui/gfx/point.h" |
13 #include "ui/gfx/point3_f.h" | |
14 #include "ui/gfx/rect.h" | |
12 | 15 |
13 namespace gfx { | 16 namespace gfx { |
14 | 17 |
15 namespace { | 18 namespace { |
16 | 19 |
17 SkMScalar Length3(SkMScalar v[3]) { | 20 SkMScalar Length3(SkMScalar v[3]) { |
18 double vd[3] = {SkMScalarToDouble(v[0]), SkMScalarToDouble(v[1]), | 21 double vd[3] = {SkMScalarToDouble(v[0]), SkMScalarToDouble(v[1]), |
19 SkMScalarToDouble(v[2])}; | 22 SkMScalarToDouble(v[2])}; |
20 return SkDoubleToMScalar( | 23 return SkDoubleToMScalar( |
21 std::sqrt(vd[0] * vd[0] + vd[1] * vd[1] + vd[2] * vd[2])); | 24 std::sqrt(vd[0] * vd[0] + vd[1] * vd[1] + vd[2] * vd[2])); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
101 return false; | 104 return false; |
102 | 105 |
103 SkMScalar scale = 1.0 / m.get(3, 3); | 106 SkMScalar scale = 1.0 / m.get(3, 3); |
104 for (int i = 0; i < 4; i++) | 107 for (int i = 0; i < 4; i++) |
105 for (int j = 0; j < 4; j++) | 108 for (int j = 0; j < 4; j++) |
106 m.set(i, j, m.get(i, j) * scale); | 109 m.set(i, j, m.get(i, j) * scale); |
107 | 110 |
108 return true; | 111 return true; |
109 } | 112 } |
110 | 113 |
114 void BuildPerspectiveMatrix(SkMatrix44* matrix, | |
115 const DecomposedTransform& decomp) { | |
116 matrix->setIdentity(); | |
117 | |
118 for (int i = 0; i < 4; i++) | |
119 matrix->setDouble(3, i, decomp.perspective[i]); | |
120 } | |
121 | |
122 void BuildTranslationMatrix(SkMatrix44 * matrix, | |
123 const DecomposedTransform& decomp) { | |
124 matrix->setTranslate(SkDoubleToMScalar(decomp.translate[0]), | |
danakj
2013/10/21 15:28:42
I find it a bit odd reading this that you have all
avallee
2013/10/21 15:55:55
Removed the pointers, makes it easier to read.
Ad
| |
125 SkDoubleToMScalar(decomp.translate[1]), | |
126 SkDoubleToMScalar(decomp.translate[2])); | |
127 } | |
128 | |
129 SkMatrix44 BuildSnappedTranslationMatrix(DecomposedTransform decomp) { | |
130 SkMatrix44 translation_matrix(SkMatrix44::kUninitialized_Constructor); | |
131 decomp.translate[0] = | |
132 std::floor(decomp.translate[0] + SkDoubleToMScalar(0.5)); | |
133 decomp.translate[1] = | |
134 std::floor(decomp.translate[1] + SkDoubleToMScalar(0.5)); | |
135 decomp.translate[2] = | |
136 std::floor(decomp.translate[2] + SkDoubleToMScalar(0.5)); | |
137 BuildTranslationMatrix(&translation_matrix, decomp); | |
138 return translation_matrix; | |
139 } | |
140 | |
141 void BuildRotationMatrix(SkMatrix44* matrix, | |
142 const DecomposedTransform& decomp) { | |
143 double x = decomp.quaternion[0]; | |
144 double y = decomp.quaternion[1]; | |
145 double z = decomp.quaternion[2]; | |
146 double w = decomp.quaternion[3]; | |
147 | |
148 matrix->set3x3(1.0 - 2.0 * (y * y + z * z), | |
149 2.0 * (x * y + z * w), | |
150 2.0 * (x * z - y * w), | |
151 2.0 * (x * y - z * w), | |
152 1.0 - 2.0 * (x * x + z * z), | |
153 2.0 * (y * z + x * w), | |
154 2.0 * (x * z + y * w), | |
155 2.0 * (y * z - x * w), | |
156 1.0 - 2.0 * (x * x + y * y)); | |
157 } | |
158 | |
159 SkMatrix44 BuildSnappedRotationMatrix(const DecomposedTransform& decomp) { | |
160 // Create snapped rotation. | |
161 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); | |
162 BuildRotationMatrix(&rotation_matrix, decomp); | |
163 for (int i = 0; i < 3; ++i) { | |
164 for (int j = 0; j < 3; ++j) { | |
165 SkMScalar value = rotation_matrix.get(i, j); | |
166 // Snap values to -1, 0 or 1. | |
167 if (value < -0.5f) { | |
168 value = -1.0f; | |
169 } else if (value > 0.5f) { | |
170 value = 1.0f; | |
171 } else { | |
172 value = 0.0f; | |
173 } | |
174 rotation_matrix.set(i, j, value); | |
175 } | |
176 } | |
177 return rotation_matrix; | |
178 } | |
179 | |
180 void BuildSkewMatrix(SkMatrix44* matrix, const DecomposedTransform& decomp) { | |
181 matrix->setIdentity(); | |
182 | |
183 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); | |
184 if (decomp.skew[2]) { | |
185 temp.setDouble(1, 2, decomp.skew[2]); | |
186 matrix->preConcat(temp); | |
187 } | |
188 | |
189 if (decomp.skew[1]) { | |
190 temp.setDouble(1, 2, 0); | |
191 temp.setDouble(0, 2, decomp.skew[1]); | |
192 matrix->preConcat(temp); | |
193 } | |
194 | |
195 if (decomp.skew[0]) { | |
196 temp.setDouble(0, 2, 0); | |
197 temp.setDouble(0, 1, decomp.skew[0]); | |
198 matrix->preConcat(temp); | |
199 } | |
200 } | |
201 | |
202 void BuildScaleMatrix(SkMatrix44* matrix, const DecomposedTransform& decomp) { | |
203 matrix->setIdentity(); | |
204 matrix->setScale(SkDoubleToMScalar(decomp.scale[0]), | |
205 SkDoubleToMScalar(decomp.scale[1]), | |
206 SkDoubleToMScalar(decomp.scale[2])); | |
207 } | |
208 | |
209 SkMatrix44 BuildSnappedScaleMatrix(DecomposedTransform decomp) { | |
210 SkMatrix44 scale_matrix(SkMatrix44::kUninitialized_Constructor); | |
211 decomp.scale[0] = std::floor(decomp.scale[0] + SkDoubleToMScalar(0.5)); | |
212 decomp.scale[1] = std::floor(decomp.scale[1] + SkDoubleToMScalar(0.5)); | |
213 decomp.scale[2] = std::floor(decomp.scale[2] + SkDoubleToMScalar(0.5)); | |
214 BuildScaleMatrix(&scale_matrix, decomp); | |
215 return scale_matrix; | |
216 } | |
217 | |
218 Transform ComposeTransform(const SkMatrix44& perspective, | |
219 const SkMatrix44& translation, | |
220 const SkMatrix44& rotation, | |
221 const SkMatrix44& skew, | |
222 const SkMatrix44& scale) { | |
223 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); | |
224 | |
225 matrix.preConcat(perspective); | |
226 matrix.preConcat(translation); | |
227 matrix.preConcat(rotation); | |
228 matrix.preConcat(skew); | |
229 matrix.preConcat(scale); | |
230 | |
231 Transform to_return; | |
232 to_return.matrix() = matrix; | |
233 return to_return; | |
234 } | |
235 | |
236 bool CheckViewportPointMapsWithinAPixel(const Point& point, | |
danakj
2013/10/21 15:28:42
bikeshed: WithinOnePixel
avallee
2013/10/21 15:55:55
Yeah, was mostly shortening to make the call sits
| |
237 const Transform& transform) { | |
danakj
2013/10/21 15:28:42
git cl format
| |
238 Point3F point_original, point_transformed; | |
239 point_original = point_transformed = Point3F(point); | |
240 | |
241 // Can't use TransformRect here since it would give us the axis-aligned | |
242 // bounding rect of the 4 points in the initial rectable which is not what we | |
243 // want. | |
244 transform.TransformPoint(&point_transformed); | |
245 | |
246 if ((point_transformed - point_original).Length() > 1.f) { | |
247 // The changed distance should not be more than 1 pixel. | |
248 return false; | |
249 } | |
250 return true; | |
251 } | |
252 | |
253 bool CheckTransformsMapsIntViewportWithinAPixel(const Rect& viewport, | |
254 const Transform& original, | |
255 const Transform& snapped) { | |
256 | |
257 Transform original_inv(Transform::kSkipInitialization); | |
258 bool invertible = true; | |
259 invertible &= original.GetInverse(&original_inv); | |
260 DCHECK(invertible) << "Non-invertible transform, cannot snap."; | |
261 | |
262 Transform combined = snapped * original_inv; | |
263 | |
264 return CheckViewportPointMapsWithinAPixel(viewport.origin(), combined) && | |
265 CheckViewportPointMapsWithinAPixel(viewport.top_right(), combined) && | |
266 CheckViewportPointMapsWithinAPixel(viewport.bottom_left(), combined) && | |
267 CheckViewportPointMapsWithinAPixel(viewport.bottom_right(), combined); | |
268 } | |
269 | |
111 } // namespace | 270 } // namespace |
112 | 271 |
113 Transform GetScaleTransform(const Point& anchor, float scale) { | 272 Transform GetScaleTransform(const Point& anchor, float scale) { |
114 Transform transform; | 273 Transform transform; |
115 transform.Translate(anchor.x() * (1 - scale), | 274 transform.Translate(anchor.x() * (1 - scale), |
116 anchor.y() * (1 - scale)); | 275 anchor.y() * (1 - scale)); |
117 transform.Scale(scale, scale); | 276 transform.Scale(scale, scale); |
118 return transform; | 277 return transform; |
119 } | 278 } |
120 | 279 |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 if (row[0][2] > row[2][0]) | 422 if (row[0][2] > row[2][0]) |
264 decomp->quaternion[1] = -decomp->quaternion[1]; | 423 decomp->quaternion[1] = -decomp->quaternion[1]; |
265 if (row[1][0] > row[0][1]) | 424 if (row[1][0] > row[0][1]) |
266 decomp->quaternion[2] = -decomp->quaternion[2]; | 425 decomp->quaternion[2] = -decomp->quaternion[2]; |
267 | 426 |
268 return true; | 427 return true; |
269 } | 428 } |
270 | 429 |
271 // Taken from http://www.w3.org/TR/css3-transforms/. | 430 // Taken from http://www.w3.org/TR/css3-transforms/. |
272 Transform ComposeTransform(const DecomposedTransform& decomp) { | 431 Transform ComposeTransform(const DecomposedTransform& decomp) { |
273 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); | 432 SkMatrix44 perspective(SkMatrix44::kUninitialized_Constructor); |
274 for (int i = 0; i < 4; i++) | 433 BuildPerspectiveMatrix(&perspective, decomp); |
275 matrix.set(3, i, decomp.perspective[i]); | |
276 | 434 |
277 matrix.preTranslate( | 435 SkMatrix44 translation(SkMatrix44::kUninitialized_Constructor); |
278 decomp.translate[0], decomp.translate[1], decomp.translate[2]); | 436 BuildTranslationMatrix(&translation, decomp); |
279 | 437 |
280 SkMScalar x = decomp.quaternion[0]; | 438 SkMatrix44 rotation(SkMatrix44::kUninitialized_Constructor); |
281 SkMScalar y = decomp.quaternion[1]; | 439 BuildRotationMatrix(&rotation, decomp); |
282 SkMScalar z = decomp.quaternion[2]; | |
283 SkMScalar w = decomp.quaternion[3]; | |
284 | 440 |
285 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); | 441 SkMatrix44 skew(SkMatrix44::kUninitialized_Constructor); |
286 rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), | 442 BuildSkewMatrix(&skew, decomp); |
287 2.0 * (x * y + z * w), | |
288 2.0 * (x * z - y * w), | |
289 2.0 * (x * y - z * w), | |
290 1.0 - 2.0 * (x * x + z * z), | |
291 2.0 * (y * z + x * w), | |
292 2.0 * (x * z + y * w), | |
293 2.0 * (y * z - x * w), | |
294 1.0 - 2.0 * (x * x + y * y)); | |
295 | 443 |
296 matrix.preConcat(rotation_matrix); | 444 SkMatrix44 scale(SkMatrix44::kUninitialized_Constructor); |
445 BuildScaleMatrix(&scale, decomp); | |
297 | 446 |
298 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); | 447 return ComposeTransform(perspective, translation, rotation, skew, scale); |
299 if (decomp.skew[2]) { | 448 } |
300 temp.set(1, 2, decomp.skew[2]); | 449 |
301 matrix.preConcat(temp); | 450 bool SnapTransform(Transform* out, |
451 const Transform& transform, | |
452 const Rect& viewport) { | |
453 DecomposedTransform decomp; | |
454 DecomposeTransform(&decomp, transform); | |
455 | |
456 SkMatrix44 rotation_matrix = BuildSnappedRotationMatrix(decomp); | |
457 SkMatrix44 translation = BuildSnappedTranslationMatrix(decomp); | |
458 SkMatrix44 scale = BuildSnappedScaleMatrix(decomp); | |
459 | |
460 // Rebuild matrices for other unchanged components. | |
461 SkMatrix44 perspective(SkMatrix44::kUninitialized_Constructor); | |
462 BuildPerspectiveMatrix(&perspective, decomp); | |
463 | |
464 // Completely ignore the skew. | |
465 SkMatrix44 skew(SkMatrix44::kIdentity_Constructor); | |
466 | |
467 // Get full tranform | |
468 Transform snapped = | |
469 ComposeTransform(perspective, translation, rotation_matrix, skew, scale); | |
470 | |
471 // Verify that viewport is not moved unnaturally. | |
472 bool snappable = | |
473 CheckTransformsMapsIntViewportWithinAPixel(viewport, transform, snapped); | |
474 if (snappable) { | |
475 *out = snapped; | |
302 } | 476 } |
303 | 477 return snappable; |
304 if (decomp.skew[1]) { | |
305 temp.set(1, 2, 0); | |
306 temp.set(0, 2, decomp.skew[1]); | |
307 matrix.preConcat(temp); | |
308 } | |
309 | |
310 if (decomp.skew[0]) { | |
311 temp.set(0, 2, 0); | |
312 temp.set(0, 1, decomp.skew[0]); | |
313 matrix.preConcat(temp); | |
314 } | |
315 | |
316 matrix.preScale(decomp.scale[0], decomp.scale[1], decomp.scale[2]); | |
317 | |
318 Transform to_return; | |
319 to_return.matrix() = matrix; | |
320 return to_return; | |
321 } | 478 } |
322 | 479 |
323 std::string DecomposedTransform::ToString() const { | 480 std::string DecomposedTransform::ToString() const { |
324 return base::StringPrintf( | 481 return base::StringPrintf( |
325 "translate: %+0.4f %+0.4f %+0.4f\n" | 482 "translate: %+0.4f %+0.4f %+0.4f\n" |
326 "scale: %+0.4f %+0.4f %+0.4f\n" | 483 "scale: %+0.4f %+0.4f %+0.4f\n" |
327 "skew: %+0.4f %+0.4f %+0.4f\n" | 484 "skew: %+0.4f %+0.4f %+0.4f\n" |
328 "perspective: %+0.4f %+0.4f %+0.4f %+0.4f\n" | 485 "perspective: %+0.4f %+0.4f %+0.4f %+0.4f\n" |
329 "quaternion: %+0.4f %+0.4f %+0.4f %+0.4f\n", | 486 "quaternion: %+0.4f %+0.4f %+0.4f %+0.4f\n", |
330 translate[0], | 487 translate[0], |
331 translate[1], | 488 translate[1], |
332 translate[2], | 489 translate[2], |
333 scale[0], | 490 scale[0], |
334 scale[1], | 491 scale[1], |
335 scale[2], | 492 scale[2], |
336 skew[0], | 493 skew[0], |
337 skew[1], | 494 skew[1], |
338 skew[2], | 495 skew[2], |
339 perspective[0], | 496 perspective[0], |
340 perspective[1], | 497 perspective[1], |
341 perspective[2], | 498 perspective[2], |
342 perspective[3], | 499 perspective[3], |
343 quaternion[0], | 500 quaternion[0], |
344 quaternion[1], | 501 quaternion[1], |
345 quaternion[2], | 502 quaternion[2], |
346 quaternion[3]); | 503 quaternion[3]); |
347 } | 504 } |
348 | 505 |
349 } // namespace ui | 506 } // namespace ui |
OLD | NEW |