Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: Source/platform/transforms/TransformOperations.cpp

Issue 328333003: Adding Blink-side 3d Box and Bounds calculations to TransformOperations (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) 2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 * 4 *
5 * This library is free software; you can redistribute it and/or 5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public 6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either 7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version. 8 * version 2 of the License, or (at your option) any later version.
9 * 9 *
10 * This library is distributed in the hope that it will be useful, 10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details. 13 * Library General Public License for more details.
14 * 14 *
15 * You should have received a copy of the GNU Library General Public License 15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to 16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA. 18 * Boston, MA 02110-1301, USA.
19 * 19 *
20 */ 20 */
21 21
22 #include "config.h" 22 #include "config.h"
23 #include "platform/transforms/TransformOperations.h" 23 #include "platform/transforms/TransformOperations.h"
24 24
25 #include "platform/geometry/FloatBox.h"
25 #include "platform/transforms/IdentityTransformOperation.h" 26 #include "platform/transforms/IdentityTransformOperation.h"
26 #include "platform/transforms/InterpolatedTransformOperation.h" 27 #include "platform/transforms/InterpolatedTransformOperation.h"
28 #include "platform/transforms/RotateTransformOperation.h"
27 #include <algorithm> 29 #include <algorithm>
28 30
29 using namespace std; 31 using namespace std;
30 32
31 namespace WebCore { 33 namespace WebCore {
32 34
35 const double kAngleEpsilon = 1e-4;
36
37 static inline void blendFloat(double& from, double to, double progress)
Ian Vollick 2014/06/16 15:23:37 Please switch this to the pre-existing blend fn yo
awoloszyn 2014/06/17 14:26:01 Done.
38 {
39 if (from != to)
40 from = from + (to - from) * progress;
41 }
42
33 TransformOperations::TransformOperations(bool makeIdentity) 43 TransformOperations::TransformOperations(bool makeIdentity)
34 { 44 {
35 if (makeIdentity) 45 if (makeIdentity)
36 m_operations.append(IdentityTransformOperation::create()); 46 m_operations.append(IdentityTransformOperation::create());
37 } 47 }
38 48
39 bool TransformOperations::operator==(const TransformOperations& o) const 49 bool TransformOperations::operator==(const TransformOperations& o) const
40 { 50 {
41 if (m_operations.size() != o.m_operations.size()) 51 if (m_operations.size() != o.m_operations.size())
42 return false; 52 return false;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 if (from == *this || (!from.size() && !size())) 112 if (from == *this || (!from.size() && !size()))
103 return *this; 113 return *this;
104 114
105 // If either list is empty, use blendByMatchingOperations which has special logic for this case. 115 // If either list is empty, use blendByMatchingOperations which has special logic for this case.
106 if (!from.size() || !size() || from.operationsMatch(*this)) 116 if (!from.size() || !size() || from.operationsMatch(*this))
107 return blendByMatchingOperations(from, progress); 117 return blendByMatchingOperations(from, progress);
108 118
109 return blendByUsingMatrixInterpolation(from, progress); 119 return blendByUsingMatrixInterpolation(from, progress);
110 } 120 }
111 121
122 static void findCandidatesInPlane(double px, double py, double nz, double* candi dates, int* numCandidates)
123 {
124 // The angle that this point is rotated with respect to the plane nz
125 double phi = atan2(px, py);
126
127 *numCandidates = 4;
128 candidates[0] = phi; // The element at 0deg (maximum x)
129
130 for (int i = 1; i < *numCandidates; ++i)
131 candidates[i] = candidates[i - 1] + M_PI_2; // every 90 deg
132 if (nz < 0.f) {
133 for (int i = 0; i < *numCandidates; ++i)
134 candidates[i] *= -1;
135 }
136 }
137
Ian Vollick 2014/06/16 15:23:37 A general comment here about how this method works
awoloszyn 2014/06/17 14:26:01 Done.
138 static void boundingBoxForArc(const FloatPoint3D& point, const RotateTransformOp eration& fromTransform, const RotateTransformOperation& toTransform, double minP rogress, double maxProgress, FloatBox& box)
139 {
140 double candidates[6];
141 int numCandidates = 0;
142
143 FloatPoint3D axis(fromTransform.x(), fromTransform.y(), fromTransform.z());
144 double fromDegrees = fromTransform.angle();
145 double toDegrees = toTransform.angle();
146
147 if (axis.dot(FloatPoint3D(toTransform.x(), toTransform.y(), toTransform.z()) ) < 0) {
Ian Vollick 2014/06/16 15:23:37 FloatPoint3D RotationTransformOperation::axis() wo
awoloszyn 2014/06/17 14:26:01 Done.
148 toDegrees *= -1;
Ian Vollick 2014/06/16 15:23:37 Nit: no braces on one-liners in blink. Here and el
awoloszyn 2014/06/17 14:26:01 Done.
149 }
150
151 blendFloat(fromDegrees, toTransform.angle(), minProgress);
152 blendFloat(toDegrees, fromTransform.angle(), 1.0 - maxProgress);
153 if (fromDegrees > toDegrees) {
154 std::swap(fromDegrees, toDegrees);
155 }
156
157 TransformationMatrix fromMatrix;
158 TransformationMatrix toMatrix;
159 fromMatrix.rotate3d(fromTransform.x(), fromTransform.y(), fromTransform.z(), fromDegrees);
160 toMatrix.rotate3d(fromTransform.x(), fromTransform.y(), fromTransform.z(), t oDegrees);
161
162 FloatPoint3D fromPoint = fromMatrix.mapPoint(point);
163 FloatPoint3D toPoint = toMatrix.mapPoint(point);
164
165 if (box.isEmpty()) {
166 box.setOrigin(fromPoint);
167 } else {
168 box.expandTo(fromPoint);
169 }
170
171 box.expandTo(toPoint);
172
173 switch (fromTransform.type()) {
174 case TransformOperation::RotateX:
175 findCandidatesInPlane(point.y(), point.z(), fromTransform.x(), candidate s, &numCandidates);
176 break;
177 case TransformOperation::RotateY:
178 findCandidatesInPlane(point.z(), point.x(), fromTransform.y(), candidate s, &numCandidates);
179 break;
180 case TransformOperation::RotateZ:
181 findCandidatesInPlane(point.x(), point.y(), fromTransform.z(), candidate s, &numCandidates);
182 break;
183 default:
184 {
185 FloatPoint3D normal = axis;
186 if (normal.isZero())
187 return;
188 normal.normalize();
189 FloatPoint3D origin;
190 FloatPoint3D toPoint = point - origin;
191 FloatPoint3D center = origin + normal*toPoint.dot(normal);
192 FloatPoint3D v1 = point - center;
193 if (v1.isZero())
194 return;
195
196 v1.normalize();
197 FloatPoint3D v2 = normal.cross(v1);
198 // v1 is the basis vector in the direction of the point.
199 // i.e. with a rotation of 0, v1 is our +x vector.
200 // v2 is a perpenticular basis vector of our plane (+y).
201
202 // Take the parametric equation of a circle.
203 // (x = r*cos(t); y = r*sin(t);
204 // We can treat that as a circle on the plane v1xv2
205 // From that we get the parametric equations for a circle on the
206 // plane in 3d space of
207 // x(t) = r*cos(t)*v1.x + r*sin(t)*v2.x + cx
208 // y(t) = r*cos(t)*v1.y + r*sin(t)*v2.y + cy
209 // z(t) = r*cos(t)*v1.z + r*sin(t)*v2.z + cz
210 // taking the derivative of (x, y, z) and solving for 0 gives us our
211 // maximum/minimum x, y, z values
212 // x'(t) = r*cos(t)*v2.x - r*sin(t)*v1.x = 0
213 // tan(t) = v2.x/v1.x
214 // t = atan2(v2.x, v1.x) + n*M_PI;
215
216 candidates[0] = atan2(v2.x(), v1.x());
217 candidates[1] = candidates[0] + M_PI;
218 candidates[2] = atan2(v2.y(), v1.y());
219 candidates[3] = candidates[2] + M_PI;
220 candidates[4] = atan2(v2.z(), v1.z());
221 candidates[5] = candidates[4] + M_PI;
222 numCandidates = 6;
223 }
224 break;
225 }
226
Ian Vollick 2014/06/16 15:23:37 Pls add comment that explains that this is where w
awoloszyn 2014/06/17 14:26:01 Done.
227 double minRadians = deg2rad(fromDegrees);
228 double maxRadians = deg2rad(toDegrees);
229 for (int i = 0; i < numCandidates; ++i) {
230 double radians = candidates[i];
231
232 while (radians < minRadians)
233 radians += 2.0 * M_PI;
234 while (radians > maxRadians)
235 radians -= 2.0 * M_PI;
236 if (radians < minRadians)
237 continue;
238
239 TransformationMatrix rotation;
240 rotation.rotate3d(axis.x(), axis.y(), axis.z(), rad2deg(radians));
241 box.expandTo(rotation.mapPoint(point));
242 }
243 }
244
245 static bool isEmptyAxis(const RotateTransformOperation& from)
Ian Vollick 2014/06/16 15:23:37 nuke.
awoloszyn 2014/06/17 14:26:01 Done.
246 {
247 double lengthSquared = from.x() * from.x() + from.y() * from.y() + from.z() * from.z();
248 return (lengthSquared < kAngleEpsilon);
249 }
250
251 static bool shareSameAxis(const RotateTransformOperation* from, const RotateTran sformOperation* to, double& x, double& y, double& z)
Ian Vollick 2014/06/16 15:23:37 ditto.
awoloszyn 2014/06/17 14:26:01 Done.
252 {
253 if (!from && !to) {
254 x = 0.f;
255 y = 0.f;
256 z = 1.f;
257 return true;
258 }
259
260 if (from && to) {
261 if (!from->isSameType(*to)) {
262 return false;
263 }
264 } else {
265 if (from) {
266 x = from->x();
267 y = from->y();
268 z = from->z();
269 return true;
270 }
271
272 x = to->x();
273 y = to->y();
274 z = to->z();
275 return true;
276 }
277
278 double fromSquared = from->x() * from->x() + from->y() * from->y() + from->z () * from->z();
279 double toSquared = to->x() * to->x() + to->y() * to->y() + to->z() * to->z();
280
281 if (fromSquared <= kAngleEpsilon || toSquared <= kAngleEpsilon) {
282 return false;
283 }
284
285 double dot = from->x() * to->x() + from->y() * to->y() + from->z() * to->z() ;
286 double error = std::abs(1 - (dot * dot) / (fromSquared * toSquared));
287
288 x = from->x();
289 y = from->y();
290 z = from->z();
291
292 return (error < kAngleEpsilon);
293 }
294
295 bool TransformOperations::blendedBoundsForBox(const FloatBox& box, const Transfo rmOperations& from, const double& minProgress, const double& maxProgress, FloatB ox* bounds) const
296 {
297
298 int fromSize = from.operations().size();
299 int toSize = operations().size();
300 int size = max(fromSize, toSize);
301
302 *bounds = box;
303 for (int i = size - 1; i >= 0; i--) {
304 RefPtr<TransformOperation> fromOperation = (i < fromSize)? from.operatio ns()[i]: static_cast<TransformOperation*>(0);
305 RefPtr<TransformOperation> toOperation = (i < toSize)? operations()[i]: static_cast<TransformOperation*>(0);
306 if (fromOperation && fromOperation->type() == TransformOperation::None) {
307 fromOperation = static_cast<TransformOperation*>(0);
308 }
309 if (toOperation && toOperation->type() == TransformOperation::None) {
310 toOperation = static_cast<TransformOperation*>(0);
311 }
312 TransformOperation::OperationType interpolationType = toOperation? toOpe ration->type():
313 fromOperation? fromOperation->type():
314 TransformOperation::None;
315 if (fromOperation && toOperation && !fromOperation->isCompatibleType(*to Operation.get())) {
316 continue;
317 }
318
319 switch (interpolationType) {
320 case TransformOperation::Identity:
321 bounds->expandTo(box);
322 continue;
323 case TransformOperation::Translate:
324 case TransformOperation::TranslateX:
325 case TransformOperation::TranslateY:
326 case TransformOperation::TranslateZ:
327 case TransformOperation::Translate3D:
328 case TransformOperation::Scale:
329 case TransformOperation::ScaleX:
330 case TransformOperation::ScaleY:
331 case TransformOperation::ScaleZ:
332 case TransformOperation::Scale3D:
333 case TransformOperation::Skew:
334 case TransformOperation::SkewX:
335 case TransformOperation::SkewY:
336 case TransformOperation::Perspective:
337 {
338 RefPtr<TransformOperation> fromTransform;
339 RefPtr<TransformOperation> toTransform;
340 if (!toOperation) {
341 fromTransform = fromOperation->blend(toOperation.get(), 1-mi nProgress, false);
342 toTransform = fromOperation->blend(toOperation.get(), 1-maxP rogress, false);
343 } else {
344 fromTransform = toOperation->blend(fromOperation.get(), minP rogress, false);
345 toTransform = toOperation->blend(fromOperation.get(), maxPro gress, false);
346 }
347 if (!fromTransform || !toTransform)
348 continue;
349 TransformationMatrix fromMatrix;
350 TransformationMatrix toMatrix;
351 fromTransform->apply(fromMatrix, FloatSize());
352 toTransform->apply(toMatrix, FloatSize());
353 FloatBox fromBox = *bounds;
354 FloatBox toBox = *bounds;
355 fromMatrix.transformBox(fromBox);
356 toMatrix.transformBox(toBox);
357 *bounds = fromBox;
358 bounds->expandTo(toBox);
359 continue;
360 }
361 case TransformOperation::Rotate: // This is also RotateZ
362 case TransformOperation::Rotate3D:
363 case TransformOperation::RotateX:
364 case TransformOperation::RotateY:
365 {
366 RefPtr<RotateTransformOperation> identityRotation;
367 const RotateTransformOperation* fromRotation = nullptr;
368 const RotateTransformOperation* toRotation = nullptr;
369 if (fromOperation) {
370 fromRotation = static_cast<const RotateTransformOperation*>( fromOperation.get());
371 if (isEmptyAxis(*fromRotation)) {
372 fromRotation = nullptr;
373 }
374 }
375
376 if (toOperation) {
377 toRotation = static_cast<const RotateTransformOperation*>(to Operation.get());
378 if (isEmptyAxis(*toRotation)) {
379 toRotation = nullptr;
380 }
381 }
382 double x = 0;
383 double y = 0;
384 double z = 0;
385 if (!shareSameAxis(fromRotation, toRotation, x, y, z)) {
386 return(false);
387 }
388
389 if (!fromRotation) {
390 identityRotation = RotateTransformOperation::create(x, y, z, 0, fromOperation? fromOperation->type(): toOperation->type());
391 fromRotation = identityRotation.get();
392 }
393
394 if (!toRotation) {
395 if (!identityRotation) {
396 identityRotation = RotateTransformOperation::create(x, y , z, 0, fromOperation? fromOperation->type(): toOperation->type());
397 }
398 toRotation = identityRotation.get();
399 }
400
401 FloatBox fromBox = *bounds;
402 bool first = true;
403 for (int i = 0; i < 8; i++) {
404 FloatBox boundsForArc;
405 FloatPoint3D corner(fromBox.x(), fromBox.y(), fromBox.z());
406 corner += FloatPoint3D(i & 1? fromBox.width() :0.f,
Ian Vollick 2014/06/16 15:23:38 nit: very inconsistent use of spaces around here.
awoloszyn 2014/06/17 14:26:01 I have no problems putting in the triply nested fo
407 i & 2? fromBox.height():0.f,
408 i & 4? fromBox.depth() :0.f);
409 boundingBoxForArc(corner, *fromRotation, *toRotation, minPro gress, maxProgress, boundsForArc);
410 if (first) {
411 *bounds = boundsForArc;
412 first = false;
413 } else {
414 bounds->expandTo(boundsForArc);
415 }
416 }
417 }
418 continue;
419 case TransformOperation::None:
420 continue;
421 case TransformOperation::Matrix:
422 case TransformOperation::Matrix3D:
423 case TransformOperation::Interpolated:
424 return(false);
425 }
426 }
427
428 return true;
429 }
430
431
112 TransformOperations TransformOperations::add(const TransformOperations& addend) const 432 TransformOperations TransformOperations::add(const TransformOperations& addend) const
113 { 433 {
114 TransformOperations result; 434 TransformOperations result;
115 result.m_operations = operations(); 435 result.m_operations = operations();
116 result.m_operations.appendVector(addend.operations()); 436 result.m_operations.appendVector(addend.operations());
117 return result; 437 return result;
118 } 438 }
119 439
120 } // namespace WebCore 440 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698