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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: Source/platform/transforms/TransformOperations.cpp
diff --git a/Source/platform/transforms/TransformOperations.cpp b/Source/platform/transforms/TransformOperations.cpp
index a0664f7d71439d9f48642e4150e4e74c81ba613d..fa837af386a9c9627bd7b8cb72deb97deba0fa86 100644
--- a/Source/platform/transforms/TransformOperations.cpp
+++ b/Source/platform/transforms/TransformOperations.cpp
@@ -22,14 +22,24 @@
#include "config.h"
#include "platform/transforms/TransformOperations.h"
+#include "platform/geometry/FloatBox.h"
#include "platform/transforms/IdentityTransformOperation.h"
#include "platform/transforms/InterpolatedTransformOperation.h"
+#include "platform/transforms/RotateTransformOperation.h"
#include <algorithm>
using namespace std;
namespace WebCore {
+const double kAngleEpsilon = 1e-4;
+
+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.
+{
+ if (from != to)
+ from = from + (to - from) * progress;
+}
+
TransformOperations::TransformOperations(bool makeIdentity)
{
if (makeIdentity)
@@ -109,6 +119,316 @@ TransformOperations TransformOperations::blend(const TransformOperations& from,
return blendByUsingMatrixInterpolation(from, progress);
}
+static void findCandidatesInPlane(double px, double py, double nz, double* candidates, int* numCandidates)
+{
+ // The angle that this point is rotated with respect to the plane nz
+ double phi = atan2(px, py);
+
+ *numCandidates = 4;
+ candidates[0] = phi; // The element at 0deg (maximum x)
+
+ for (int i = 1; i < *numCandidates; ++i)
+ candidates[i] = candidates[i - 1] + M_PI_2; // every 90 deg
+ if (nz < 0.f) {
+ for (int i = 0; i < *numCandidates; ++i)
+ candidates[i] *= -1;
+ }
+}
+
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.
+static void boundingBoxForArc(const FloatPoint3D& point, const RotateTransformOperation& fromTransform, const RotateTransformOperation& toTransform, double minProgress, double maxProgress, FloatBox& box)
+{
+ double candidates[6];
+ int numCandidates = 0;
+
+ FloatPoint3D axis(fromTransform.x(), fromTransform.y(), fromTransform.z());
+ double fromDegrees = fromTransform.angle();
+ double toDegrees = toTransform.angle();
+
+ 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.
+ 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.
+ }
+
+ blendFloat(fromDegrees, toTransform.angle(), minProgress);
+ blendFloat(toDegrees, fromTransform.angle(), 1.0 - maxProgress);
+ if (fromDegrees > toDegrees) {
+ std::swap(fromDegrees, toDegrees);
+ }
+
+ TransformationMatrix fromMatrix;
+ TransformationMatrix toMatrix;
+ fromMatrix.rotate3d(fromTransform.x(), fromTransform.y(), fromTransform.z(), fromDegrees);
+ toMatrix.rotate3d(fromTransform.x(), fromTransform.y(), fromTransform.z(), toDegrees);
+
+ FloatPoint3D fromPoint = fromMatrix.mapPoint(point);
+ FloatPoint3D toPoint = toMatrix.mapPoint(point);
+
+ if (box.isEmpty()) {
+ box.setOrigin(fromPoint);
+ } else {
+ box.expandTo(fromPoint);
+ }
+
+ box.expandTo(toPoint);
+
+ switch (fromTransform.type()) {
+ case TransformOperation::RotateX:
+ findCandidatesInPlane(point.y(), point.z(), fromTransform.x(), candidates, &numCandidates);
+ break;
+ case TransformOperation::RotateY:
+ findCandidatesInPlane(point.z(), point.x(), fromTransform.y(), candidates, &numCandidates);
+ break;
+ case TransformOperation::RotateZ:
+ findCandidatesInPlane(point.x(), point.y(), fromTransform.z(), candidates, &numCandidates);
+ break;
+ default:
+ {
+ FloatPoint3D normal = axis;
+ if (normal.isZero())
+ return;
+ normal.normalize();
+ FloatPoint3D origin;
+ FloatPoint3D toPoint = point - origin;
+ FloatPoint3D center = origin + normal*toPoint.dot(normal);
+ FloatPoint3D v1 = point - center;
+ if (v1.isZero())
+ return;
+
+ v1.normalize();
+ FloatPoint3D v2 = normal.cross(v1);
+ // v1 is the basis vector in the direction of the point.
+ // i.e. with a rotation of 0, v1 is our +x vector.
+ // v2 is a perpenticular basis vector of our plane (+y).
+
+ // Take the parametric equation of a circle.
+ // (x = r*cos(t); y = r*sin(t);
+ // We can treat that as a circle on the plane v1xv2
+ // From that we get the parametric equations for a circle on the
+ // plane in 3d space of
+ // x(t) = r*cos(t)*v1.x + r*sin(t)*v2.x + cx
+ // y(t) = r*cos(t)*v1.y + r*sin(t)*v2.y + cy
+ // z(t) = r*cos(t)*v1.z + r*sin(t)*v2.z + cz
+ // taking the derivative of (x, y, z) and solving for 0 gives us our
+ // maximum/minimum x, y, z values
+ // x'(t) = r*cos(t)*v2.x - r*sin(t)*v1.x = 0
+ // tan(t) = v2.x/v1.x
+ // t = atan2(v2.x, v1.x) + n*M_PI;
+
+ candidates[0] = atan2(v2.x(), v1.x());
+ candidates[1] = candidates[0] + M_PI;
+ candidates[2] = atan2(v2.y(), v1.y());
+ candidates[3] = candidates[2] + M_PI;
+ candidates[4] = atan2(v2.z(), v1.z());
+ candidates[5] = candidates[4] + M_PI;
+ numCandidates = 6;
+ }
+ break;
+ }
+
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.
+ double minRadians = deg2rad(fromDegrees);
+ double maxRadians = deg2rad(toDegrees);
+ for (int i = 0; i < numCandidates; ++i) {
+ double radians = candidates[i];
+
+ while (radians < minRadians)
+ radians += 2.0 * M_PI;
+ while (radians > maxRadians)
+ radians -= 2.0 * M_PI;
+ if (radians < minRadians)
+ continue;
+
+ TransformationMatrix rotation;
+ rotation.rotate3d(axis.x(), axis.y(), axis.z(), rad2deg(radians));
+ box.expandTo(rotation.mapPoint(point));
+ }
+}
+
+static bool isEmptyAxis(const RotateTransformOperation& from)
Ian Vollick 2014/06/16 15:23:37 nuke.
awoloszyn 2014/06/17 14:26:01 Done.
+{
+ double lengthSquared = from.x() * from.x() + from.y() * from.y() + from.z() * from.z();
+ return (lengthSquared < kAngleEpsilon);
+}
+
+static bool shareSameAxis(const RotateTransformOperation* from, const RotateTransformOperation* to, double& x, double& y, double& z)
Ian Vollick 2014/06/16 15:23:37 ditto.
awoloszyn 2014/06/17 14:26:01 Done.
+{
+ if (!from && !to) {
+ x = 0.f;
+ y = 0.f;
+ z = 1.f;
+ return true;
+ }
+
+ if (from && to) {
+ if (!from->isSameType(*to)) {
+ return false;
+ }
+ } else {
+ if (from) {
+ x = from->x();
+ y = from->y();
+ z = from->z();
+ return true;
+ }
+
+ x = to->x();
+ y = to->y();
+ z = to->z();
+ return true;
+ }
+
+ double fromSquared = from->x() * from->x() + from->y() * from->y() + from->z() * from->z();
+ double toSquared = to->x() * to->x() + to->y() * to->y() + to->z() * to->z();
+
+ if (fromSquared <= kAngleEpsilon || toSquared <= kAngleEpsilon) {
+ return false;
+ }
+
+ double dot = from->x() * to->x() + from->y() * to->y() + from->z() * to->z();
+ double error = std::abs(1 - (dot * dot) / (fromSquared * toSquared));
+
+ x = from->x();
+ y = from->y();
+ z = from->z();
+
+ return (error < kAngleEpsilon);
+}
+
+bool TransformOperations::blendedBoundsForBox(const FloatBox& box, const TransformOperations& from, const double& minProgress, const double& maxProgress, FloatBox* bounds) const
+{
+
+ int fromSize = from.operations().size();
+ int toSize = operations().size();
+ int size = max(fromSize, toSize);
+
+ *bounds = box;
+ for (int i = size - 1; i >= 0; i--) {
+ RefPtr<TransformOperation> fromOperation = (i < fromSize)? from.operations()[i]: static_cast<TransformOperation*>(0);
+ RefPtr<TransformOperation> toOperation = (i < toSize)? operations()[i]: static_cast<TransformOperation*>(0);
+ if (fromOperation && fromOperation->type() == TransformOperation::None) {
+ fromOperation = static_cast<TransformOperation*>(0);
+ }
+ if (toOperation && toOperation->type() == TransformOperation::None) {
+ toOperation = static_cast<TransformOperation*>(0);
+ }
+ TransformOperation::OperationType interpolationType = toOperation? toOperation->type():
+ fromOperation? fromOperation->type():
+ TransformOperation::None;
+ if (fromOperation && toOperation && !fromOperation->isCompatibleType(*toOperation.get())) {
+ continue;
+ }
+
+ switch (interpolationType) {
+ case TransformOperation::Identity:
+ bounds->expandTo(box);
+ continue;
+ case TransformOperation::Translate:
+ case TransformOperation::TranslateX:
+ case TransformOperation::TranslateY:
+ case TransformOperation::TranslateZ:
+ case TransformOperation::Translate3D:
+ case TransformOperation::Scale:
+ case TransformOperation::ScaleX:
+ case TransformOperation::ScaleY:
+ case TransformOperation::ScaleZ:
+ case TransformOperation::Scale3D:
+ case TransformOperation::Skew:
+ case TransformOperation::SkewX:
+ case TransformOperation::SkewY:
+ case TransformOperation::Perspective:
+ {
+ RefPtr<TransformOperation> fromTransform;
+ RefPtr<TransformOperation> toTransform;
+ if (!toOperation) {
+ fromTransform = fromOperation->blend(toOperation.get(), 1-minProgress, false);
+ toTransform = fromOperation->blend(toOperation.get(), 1-maxProgress, false);
+ } else {
+ fromTransform = toOperation->blend(fromOperation.get(), minProgress, false);
+ toTransform = toOperation->blend(fromOperation.get(), maxProgress, false);
+ }
+ if (!fromTransform || !toTransform)
+ continue;
+ TransformationMatrix fromMatrix;
+ TransformationMatrix toMatrix;
+ fromTransform->apply(fromMatrix, FloatSize());
+ toTransform->apply(toMatrix, FloatSize());
+ FloatBox fromBox = *bounds;
+ FloatBox toBox = *bounds;
+ fromMatrix.transformBox(fromBox);
+ toMatrix.transformBox(toBox);
+ *bounds = fromBox;
+ bounds->expandTo(toBox);
+ continue;
+ }
+ case TransformOperation::Rotate: // This is also RotateZ
+ case TransformOperation::Rotate3D:
+ case TransformOperation::RotateX:
+ case TransformOperation::RotateY:
+ {
+ RefPtr<RotateTransformOperation> identityRotation;
+ const RotateTransformOperation* fromRotation = nullptr;
+ const RotateTransformOperation* toRotation = nullptr;
+ if (fromOperation) {
+ fromRotation = static_cast<const RotateTransformOperation*>(fromOperation.get());
+ if (isEmptyAxis(*fromRotation)) {
+ fromRotation = nullptr;
+ }
+ }
+
+ if (toOperation) {
+ toRotation = static_cast<const RotateTransformOperation*>(toOperation.get());
+ if (isEmptyAxis(*toRotation)) {
+ toRotation = nullptr;
+ }
+ }
+ double x = 0;
+ double y = 0;
+ double z = 0;
+ if (!shareSameAxis(fromRotation, toRotation, x, y, z)) {
+ return(false);
+ }
+
+ if (!fromRotation) {
+ identityRotation = RotateTransformOperation::create(x, y, z, 0, fromOperation? fromOperation->type(): toOperation->type());
+ fromRotation = identityRotation.get();
+ }
+
+ if (!toRotation) {
+ if (!identityRotation) {
+ identityRotation = RotateTransformOperation::create(x, y, z, 0, fromOperation? fromOperation->type(): toOperation->type());
+ }
+ toRotation = identityRotation.get();
+ }
+
+ FloatBox fromBox = *bounds;
+ bool first = true;
+ for (int i = 0; i < 8; i++) {
+ FloatBox boundsForArc;
+ FloatPoint3D corner(fromBox.x(), fromBox.y(), fromBox.z());
+ 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
+ i & 2? fromBox.height():0.f,
+ i & 4? fromBox.depth() :0.f);
+ boundingBoxForArc(corner, *fromRotation, *toRotation, minProgress, maxProgress, boundsForArc);
+ if (first) {
+ *bounds = boundsForArc;
+ first = false;
+ } else {
+ bounds->expandTo(boundsForArc);
+ }
+ }
+ }
+ continue;
+ case TransformOperation::None:
+ continue;
+ case TransformOperation::Matrix:
+ case TransformOperation::Matrix3D:
+ case TransformOperation::Interpolated:
+ return(false);
+ }
+ }
+
+ return true;
+}
+
+
TransformOperations TransformOperations::add(const TransformOperations& addend) const
{
TransformOperations result;

Powered by Google App Engine
This is Rietveld 408576698