| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "cc/math_util.h" | |
| 6 | |
| 7 #include <cmath> | |
| 8 #include <limits> | |
| 9 | |
| 10 #include "base/values.h" | |
| 11 #include "ui/gfx/quad_f.h" | |
| 12 #include "ui/gfx/rect.h" | |
| 13 #include "ui/gfx/rect_conversions.h" | |
| 14 #include "ui/gfx/rect_f.h" | |
| 15 #include "ui/gfx/transform.h" | |
| 16 #include "ui/gfx/vector2d_f.h" | |
| 17 | |
| 18 namespace cc { | |
| 19 | |
| 20 const double MathUtil::PI_DOUBLE = 3.14159265358979323846; | |
| 21 const float MathUtil::PI_FLOAT = 3.14159265358979323846f; | |
| 22 const double MathUtil::EPSILON = 1e-9; | |
| 23 | |
| 24 static HomogeneousCoordinate projectHomogeneousPoint(const gfx::Transform& trans
form, const gfx::PointF& p) | |
| 25 { | |
| 26 // In this case, the layer we are trying to project onto is perpendicular to
ray | |
| 27 // (point p and z-axis direction) that we are trying to project. This happen
s when the | |
| 28 // layer is rotated so that it is infinitesimally thin, or when it is co-pla
nar with | |
| 29 // the camera origin -- i.e. when the layer is invisible anyway. | |
| 30 if (!transform.matrix().getDouble(2, 2)) | |
| 31 return HomogeneousCoordinate(0, 0, 0, 1); | |
| 32 | |
| 33 double x = p.x(); | |
| 34 double y = p.y(); | |
| 35 double z = -(transform.matrix().getDouble(2, 0) * x + transform.matrix().get
Double(2, 1) * y + transform.matrix().getDouble(2, 3)) / transform.matrix().getD
ouble(2, 2); | |
| 36 // implicit definition of w = 1; | |
| 37 | |
| 38 double outX = x * transform.matrix().getDouble(0, 0) + y * transform.matrix(
).getDouble(0, 1) + z * transform.matrix().getDouble(0, 2) + transform.matrix().
getDouble(0, 3); | |
| 39 double outY = x * transform.matrix().getDouble(1, 0) + y * transform.matrix(
).getDouble(1, 1) + z * transform.matrix().getDouble(1, 2) + transform.matrix().
getDouble(1, 3); | |
| 40 double outZ = x * transform.matrix().getDouble(2, 0) + y * transform.matrix(
).getDouble(2, 1) + z * transform.matrix().getDouble(2, 2) + transform.matrix().
getDouble(2, 3); | |
| 41 double outW = x * transform.matrix().getDouble(3, 0) + y * transform.matrix(
).getDouble(3, 1) + z * transform.matrix().getDouble(3, 2) + transform.matrix().
getDouble(3, 3); | |
| 42 | |
| 43 return HomogeneousCoordinate(outX, outY, outZ, outW); | |
| 44 } | |
| 45 | |
| 46 static HomogeneousCoordinate mapHomogeneousPoint(const gfx::Transform& transform
, const gfx::Point3F& p) | |
| 47 { | |
| 48 double x = p.x(); | |
| 49 double y = p.y(); | |
| 50 double z = p.z(); | |
| 51 // implicit definition of w = 1; | |
| 52 | |
| 53 double outX = x * transform.matrix().getDouble(0, 0) + y * transform.matrix(
).getDouble(0, 1) + z * transform.matrix().getDouble(0, 2) + transform.matrix().
getDouble(0, 3); | |
| 54 double outY = x * transform.matrix().getDouble(1, 0) + y * transform.matrix(
).getDouble(1, 1) + z * transform.matrix().getDouble(1, 2) + transform.matrix().
getDouble(1, 3); | |
| 55 double outZ = x * transform.matrix().getDouble(2, 0) + y * transform.matrix(
).getDouble(2, 1) + z * transform.matrix().getDouble(2, 2) + transform.matrix().
getDouble(2, 3); | |
| 56 double outW = x * transform.matrix().getDouble(3, 0) + y * transform.matrix(
).getDouble(3, 1) + z * transform.matrix().getDouble(3, 2) + transform.matrix().
getDouble(3, 3); | |
| 57 | |
| 58 return HomogeneousCoordinate(outX, outY, outZ, outW); | |
| 59 } | |
| 60 | |
| 61 static HomogeneousCoordinate computeClippedPointForEdge(const HomogeneousCoordin
ate& h1, const HomogeneousCoordinate& h2) | |
| 62 { | |
| 63 // Points h1 and h2 form a line in 4d, and any point on that line can be rep
resented | |
| 64 // as an interpolation between h1 and h2: | |
| 65 // p = (1-t) h1 + (t) h2 | |
| 66 // | |
| 67 // We want to compute point p such that p.w == epsilon, where epsilon is a s
mall | |
| 68 // non-zero number. (but the smaller the number is, the higher the risk of o
verflow) | |
| 69 // To do this, we solve for t in the following equation: | |
| 70 // p.w = epsilon = (1-t) * h1.w + (t) * h2.w | |
| 71 // | |
| 72 // Once paramter t is known, the rest of p can be computed via p = (1-t) h1
+ (t) h2. | |
| 73 | |
| 74 // Technically this is a special case of the following assertion, but its a
good idea to keep it an explicit sanity check here. | |
| 75 DCHECK(h2.w != h1.w); | |
| 76 // Exactly one of h1 or h2 (but not both) must be on the negative side of th
e w plane when this is called. | |
| 77 DCHECK(h1.shouldBeClipped() ^ h2.shouldBeClipped()); | |
| 78 | |
| 79 double w = 0.00001; // or any positive non-zero small epsilon | |
| 80 | |
| 81 double t = (w - h1.w) / (h2.w - h1.w); | |
| 82 | |
| 83 double x = (1-t) * h1.x + t * h2.x; | |
| 84 double y = (1-t) * h1.y + t * h2.y; | |
| 85 double z = (1-t) * h1.z + t * h2.z; | |
| 86 | |
| 87 return HomogeneousCoordinate(x, y, z, w); | |
| 88 } | |
| 89 | |
| 90 static inline void expandBoundsToIncludePoint(float& xmin, float& xmax, float& y
min, float& ymax, const gfx::PointF& p) | |
| 91 { | |
| 92 xmin = std::min(p.x(), xmin); | |
| 93 xmax = std::max(p.x(), xmax); | |
| 94 ymin = std::min(p.y(), ymin); | |
| 95 ymax = std::max(p.y(), ymax); | |
| 96 } | |
| 97 | |
| 98 static inline void addVertexToClippedQuad(const gfx::PointF& newVertex, gfx::Poi
ntF clippedQuad[8], int& numVerticesInClippedQuad) | |
| 99 { | |
| 100 clippedQuad[numVerticesInClippedQuad] = newVertex; | |
| 101 numVerticesInClippedQuad++; | |
| 102 } | |
| 103 | |
| 104 gfx::Rect MathUtil::mapClippedRect(const gfx::Transform& transform, const gfx::R
ect& srcRect) | |
| 105 { | |
| 106 return gfx::ToEnclosingRect(mapClippedRect(transform, gfx::RectF(srcRect))); | |
| 107 } | |
| 108 | |
| 109 gfx::RectF MathUtil::mapClippedRect(const gfx::Transform& transform, const gfx::
RectF& srcRect) | |
| 110 { | |
| 111 if (transform.IsIdentityOrTranslation()) | |
| 112 return srcRect + gfx::Vector2dF(static_cast<float>(transform.matrix().ge
tDouble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); | |
| 113 | |
| 114 // Apply the transform, but retain the result in homogeneous coordinates. | |
| 115 | |
| 116 double quad[4 * 2]; // input: 4 x 2D points | |
| 117 quad[0] = srcRect.x(); | |
| 118 quad[1] = srcRect.y(); | |
| 119 quad[2] = srcRect.right(); | |
| 120 quad[3] = srcRect.y(); | |
| 121 quad[4] = srcRect.right(); | |
| 122 quad[5] = srcRect.bottom(); | |
| 123 quad[6] = srcRect.x(); | |
| 124 quad[7] = srcRect.bottom(); | |
| 125 | |
| 126 double result[4 * 4]; // output: 4 x 4D homogeneous points | |
| 127 transform.matrix().map2(quad, 4, result); | |
| 128 | |
| 129 HomogeneousCoordinate hc0(result[0], result[1], result[2], result[3]); | |
| 130 HomogeneousCoordinate hc1(result[4], result[5], result[6], result[7]); | |
| 131 HomogeneousCoordinate hc2(result[8], result[9], result[10], result[11]); | |
| 132 HomogeneousCoordinate hc3(result[12], result[13], result[14], result[15]); | |
| 133 return computeEnclosingClippedRect(hc0, hc1, hc2, hc3); | |
| 134 } | |
| 135 | |
| 136 gfx::RectF MathUtil::projectClippedRect(const gfx::Transform& transform, const g
fx::RectF& srcRect) | |
| 137 { | |
| 138 if (transform.IsIdentityOrTranslation()) | |
| 139 return srcRect + gfx::Vector2dF(static_cast<float>(transform.matrix().ge
tDouble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); | |
| 140 | |
| 141 // Perform the projection, but retain the result in homogeneous coordinates. | |
| 142 gfx::QuadF q = gfx::QuadF(srcRect); | |
| 143 HomogeneousCoordinate h1 = projectHomogeneousPoint(transform, q.p1()); | |
| 144 HomogeneousCoordinate h2 = projectHomogeneousPoint(transform, q.p2()); | |
| 145 HomogeneousCoordinate h3 = projectHomogeneousPoint(transform, q.p3()); | |
| 146 HomogeneousCoordinate h4 = projectHomogeneousPoint(transform, q.p4()); | |
| 147 | |
| 148 return computeEnclosingClippedRect(h1, h2, h3, h4); | |
| 149 } | |
| 150 | |
| 151 void MathUtil::mapClippedQuad(const gfx::Transform& transform, const gfx::QuadF&
srcQuad, gfx::PointF clippedQuad[8], int& numVerticesInClippedQuad) | |
| 152 { | |
| 153 HomogeneousCoordinate h1 = mapHomogeneousPoint(transform, gfx::Point3F(srcQu
ad.p1())); | |
| 154 HomogeneousCoordinate h2 = mapHomogeneousPoint(transform, gfx::Point3F(srcQu
ad.p2())); | |
| 155 HomogeneousCoordinate h3 = mapHomogeneousPoint(transform, gfx::Point3F(srcQu
ad.p3())); | |
| 156 HomogeneousCoordinate h4 = mapHomogeneousPoint(transform, gfx::Point3F(srcQu
ad.p4())); | |
| 157 | |
| 158 // The order of adding the vertices to the array is chosen so that clockwise
/ counter-clockwise orientation is retained. | |
| 159 | |
| 160 numVerticesInClippedQuad = 0; | |
| 161 | |
| 162 if (!h1.shouldBeClipped()) | |
| 163 addVertexToClippedQuad(h1.cartesianPoint2d(), clippedQuad, numVerticesIn
ClippedQuad); | |
| 164 | |
| 165 if (h1.shouldBeClipped() ^ h2.shouldBeClipped()) | |
| 166 addVertexToClippedQuad(computeClippedPointForEdge(h1, h2).cartesianPoint
2d(), clippedQuad, numVerticesInClippedQuad); | |
| 167 | |
| 168 if (!h2.shouldBeClipped()) | |
| 169 addVertexToClippedQuad(h2.cartesianPoint2d(), clippedQuad, numVerticesIn
ClippedQuad); | |
| 170 | |
| 171 if (h2.shouldBeClipped() ^ h3.shouldBeClipped()) | |
| 172 addVertexToClippedQuad(computeClippedPointForEdge(h2, h3).cartesianPoint
2d(), clippedQuad, numVerticesInClippedQuad); | |
| 173 | |
| 174 if (!h3.shouldBeClipped()) | |
| 175 addVertexToClippedQuad(h3.cartesianPoint2d(), clippedQuad, numVerticesIn
ClippedQuad); | |
| 176 | |
| 177 if (h3.shouldBeClipped() ^ h4.shouldBeClipped()) | |
| 178 addVertexToClippedQuad(computeClippedPointForEdge(h3, h4).cartesianPoint
2d(), clippedQuad, numVerticesInClippedQuad); | |
| 179 | |
| 180 if (!h4.shouldBeClipped()) | |
| 181 addVertexToClippedQuad(h4.cartesianPoint2d(), clippedQuad, numVerticesIn
ClippedQuad); | |
| 182 | |
| 183 if (h4.shouldBeClipped() ^ h1.shouldBeClipped()) | |
| 184 addVertexToClippedQuad(computeClippedPointForEdge(h4, h1).cartesianPoint
2d(), clippedQuad, numVerticesInClippedQuad); | |
| 185 | |
| 186 DCHECK(numVerticesInClippedQuad <= 8); | |
| 187 } | |
| 188 | |
| 189 gfx::RectF MathUtil::computeEnclosingRectOfVertices(gfx::PointF vertices[], int
numVertices) | |
| 190 { | |
| 191 if (numVertices < 2) | |
| 192 return gfx::RectF(); | |
| 193 | |
| 194 float xmin = std::numeric_limits<float>::max(); | |
| 195 float xmax = -std::numeric_limits<float>::max(); | |
| 196 float ymin = std::numeric_limits<float>::max(); | |
| 197 float ymax = -std::numeric_limits<float>::max(); | |
| 198 | |
| 199 for (int i = 0; i < numVertices; ++i) | |
| 200 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, vertices[i]); | |
| 201 | |
| 202 return gfx::RectF(gfx::PointF(xmin, ymin), gfx::SizeF(xmax - xmin, ymax - ym
in)); | |
| 203 } | |
| 204 | |
| 205 gfx::RectF MathUtil::computeEnclosingClippedRect(const HomogeneousCoordinate& h1
, const HomogeneousCoordinate& h2, const HomogeneousCoordinate& h3, const Homoge
neousCoordinate& h4) | |
| 206 { | |
| 207 // This function performs clipping as necessary and computes the enclosing 2
d | |
| 208 // gfx::RectF of the vertices. Doing these two steps simultaneously allows u
s to avoid | |
| 209 // the overhead of storing an unknown number of clipped vertices. | |
| 210 | |
| 211 // If no vertices on the quad are clipped, then we can simply return the enc
losing rect directly. | |
| 212 bool somethingClipped = h1.shouldBeClipped() || h2.shouldBeClipped() || h3.s
houldBeClipped() || h4.shouldBeClipped(); | |
| 213 if (!somethingClipped) { | |
| 214 gfx::QuadF mappedQuad = gfx::QuadF(h1.cartesianPoint2d(), h2.cartesianPo
int2d(), h3.cartesianPoint2d(), h4.cartesianPoint2d()); | |
| 215 return mappedQuad.BoundingBox(); | |
| 216 } | |
| 217 | |
| 218 bool everythingClipped = h1.shouldBeClipped() && h2.shouldBeClipped() && h3.
shouldBeClipped() && h4.shouldBeClipped(); | |
| 219 if (everythingClipped) | |
| 220 return gfx::RectF(); | |
| 221 | |
| 222 | |
| 223 float xmin = std::numeric_limits<float>::max(); | |
| 224 float xmax = -std::numeric_limits<float>::max(); | |
| 225 float ymin = std::numeric_limits<float>::max(); | |
| 226 float ymax = -std::numeric_limits<float>::max(); | |
| 227 | |
| 228 if (!h1.shouldBeClipped()) | |
| 229 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, h1.cartesianPoint2d()
); | |
| 230 | |
| 231 if (h1.shouldBeClipped() ^ h2.shouldBeClipped()) | |
| 232 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, computeClippedPointFo
rEdge(h1, h2).cartesianPoint2d()); | |
| 233 | |
| 234 if (!h2.shouldBeClipped()) | |
| 235 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, h2.cartesianPoint2d()
); | |
| 236 | |
| 237 if (h2.shouldBeClipped() ^ h3.shouldBeClipped()) | |
| 238 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, computeClippedPointFo
rEdge(h2, h3).cartesianPoint2d()); | |
| 239 | |
| 240 if (!h3.shouldBeClipped()) | |
| 241 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, h3.cartesianPoint2d()
); | |
| 242 | |
| 243 if (h3.shouldBeClipped() ^ h4.shouldBeClipped()) | |
| 244 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, computeClippedPointFo
rEdge(h3, h4).cartesianPoint2d()); | |
| 245 | |
| 246 if (!h4.shouldBeClipped()) | |
| 247 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, h4.cartesianPoint2d()
); | |
| 248 | |
| 249 if (h4.shouldBeClipped() ^ h1.shouldBeClipped()) | |
| 250 expandBoundsToIncludePoint(xmin, xmax, ymin, ymax, computeClippedPointFo
rEdge(h4, h1).cartesianPoint2d()); | |
| 251 | |
| 252 return gfx::RectF(gfx::PointF(xmin, ymin), gfx::SizeF(xmax - xmin, ymax - ym
in)); | |
| 253 } | |
| 254 | |
| 255 gfx::QuadF MathUtil::mapQuad(const gfx::Transform& transform, const gfx::QuadF&
q, bool& clipped) | |
| 256 { | |
| 257 if (transform.IsIdentityOrTranslation()) { | |
| 258 gfx::QuadF mappedQuad(q); | |
| 259 mappedQuad += gfx::Vector2dF(static_cast<float>(transform.matrix().getDo
uble(0, 3)), static_cast<float>(transform.matrix().getDouble(1, 3))); | |
| 260 clipped = false; | |
| 261 return mappedQuad; | |
| 262 } | |
| 263 | |
| 264 HomogeneousCoordinate h1 = mapHomogeneousPoint(transform, gfx::Point3F(q.p1(
))); | |
| 265 HomogeneousCoordinate h2 = mapHomogeneousPoint(transform, gfx::Point3F(q.p2(
))); | |
| 266 HomogeneousCoordinate h3 = mapHomogeneousPoint(transform, gfx::Point3F(q.p3(
))); | |
| 267 HomogeneousCoordinate h4 = mapHomogeneousPoint(transform, gfx::Point3F(q.p4(
))); | |
| 268 | |
| 269 clipped = h1.shouldBeClipped() || h2.shouldBeClipped() || h3.shouldBeClipped
() || h4.shouldBeClipped(); | |
| 270 | |
| 271 // Result will be invalid if clipped == true. But, compute it anyway just in
case, to emulate existing behavior. | |
| 272 return gfx::QuadF(h1.cartesianPoint2d(), h2.cartesianPoint2d(), h3.cartesian
Point2d(), h4.cartesianPoint2d()); | |
| 273 } | |
| 274 | |
| 275 gfx::PointF MathUtil::mapPoint(const gfx::Transform& transform, const gfx::Point
F& p, bool& clipped) | |
| 276 { | |
| 277 HomogeneousCoordinate h = mapHomogeneousPoint(transform, gfx::Point3F(p)); | |
| 278 | |
| 279 if (h.w > 0) { | |
| 280 clipped = false; | |
| 281 return h.cartesianPoint2d(); | |
| 282 } | |
| 283 | |
| 284 // The cartesian coordinates will be invalid after dividing by w. | |
| 285 clipped = true; | |
| 286 | |
| 287 // Avoid dividing by w if w == 0. | |
| 288 if (!h.w) | |
| 289 return gfx::PointF(); | |
| 290 | |
| 291 // This return value will be invalid because clipped == true, but (1) users
of this | |
| 292 // code should be ignoring the return value when clipped == true anyway, and
(2) this | |
| 293 // behavior is more consistent with existing behavior of WebKit transforms i
f the user | |
| 294 // really does not ignore the return value. | |
| 295 return h.cartesianPoint2d(); | |
| 296 } | |
| 297 | |
| 298 gfx::Point3F MathUtil::mapPoint(const gfx::Transform& transform, const gfx::Poin
t3F& p, bool& clipped) | |
| 299 { | |
| 300 HomogeneousCoordinate h = mapHomogeneousPoint(transform, p); | |
| 301 | |
| 302 if (h.w > 0) { | |
| 303 clipped = false; | |
| 304 return h.cartesianPoint3d(); | |
| 305 } | |
| 306 | |
| 307 // The cartesian coordinates will be invalid after dividing by w. | |
| 308 clipped = true; | |
| 309 | |
| 310 // Avoid dividing by w if w == 0. | |
| 311 if (!h.w) | |
| 312 return gfx::Point3F(); | |
| 313 | |
| 314 // This return value will be invalid because clipped == true, but (1) users
of this | |
| 315 // code should be ignoring the return value when clipped == true anyway, and
(2) this | |
| 316 // behavior is more consistent with existing behavior of WebKit transforms i
f the user | |
| 317 // really does not ignore the return value. | |
| 318 return h.cartesianPoint3d(); | |
| 319 } | |
| 320 | |
| 321 gfx::QuadF MathUtil::projectQuad(const gfx::Transform& transform, const gfx::Qua
dF& q, bool& clipped) | |
| 322 { | |
| 323 gfx::QuadF projectedQuad; | |
| 324 bool clippedPoint; | |
| 325 projectedQuad.set_p1(projectPoint(transform, q.p1(), clippedPoint)); | |
| 326 clipped = clippedPoint; | |
| 327 projectedQuad.set_p2(projectPoint(transform, q.p2(), clippedPoint)); | |
| 328 clipped |= clippedPoint; | |
| 329 projectedQuad.set_p3(projectPoint(transform, q.p3(), clippedPoint)); | |
| 330 clipped |= clippedPoint; | |
| 331 projectedQuad.set_p4(projectPoint(transform, q.p4(), clippedPoint)); | |
| 332 clipped |= clippedPoint; | |
| 333 | |
| 334 return projectedQuad; | |
| 335 } | |
| 336 | |
| 337 gfx::PointF MathUtil::projectPoint(const gfx::Transform& transform, const gfx::P
ointF& p, bool& clipped) | |
| 338 { | |
| 339 HomogeneousCoordinate h = projectHomogeneousPoint(transform, p); | |
| 340 | |
| 341 if (h.w > 0) { | |
| 342 // The cartesian coordinates will be valid in this case. | |
| 343 clipped = false; | |
| 344 return h.cartesianPoint2d(); | |
| 345 } | |
| 346 | |
| 347 // The cartesian coordinates will be invalid after dividing by w. | |
| 348 clipped = true; | |
| 349 | |
| 350 // Avoid dividing by w if w == 0. | |
| 351 if (!h.w) | |
| 352 return gfx::PointF(); | |
| 353 | |
| 354 // This return value will be invalid because clipped == true, but (1) users
of this | |
| 355 // code should be ignoring the return value when clipped == true anyway, and
(2) this | |
| 356 // behavior is more consistent with existing behavior of WebKit transforms i
f the user | |
| 357 // really does not ignore the return value. | |
| 358 return h.cartesianPoint2d(); | |
| 359 } | |
| 360 | |
| 361 static inline float scaleOnAxis(double a, double b, double c) | |
| 362 { | |
| 363 return std::sqrt(a * a + b * b + c * c); | |
| 364 } | |
| 365 | |
| 366 gfx::Vector2dF MathUtil::computeTransform2dScaleComponents(const gfx::Transform&
transform, float fallbackValue) | |
| 367 { | |
| 368 if (transform.HasPerspective()) | |
| 369 return gfx::Vector2dF(fallbackValue, fallbackValue); | |
| 370 float xScale = scaleOnAxis(transform.matrix().getDouble(0, 0), transform.mat
rix().getDouble(1, 0), transform.matrix().getDouble(2, 0)); | |
| 371 float yScale = scaleOnAxis(transform.matrix().getDouble(0, 1), transform.mat
rix().getDouble(1, 1), transform.matrix().getDouble(2, 1)); | |
| 372 return gfx::Vector2dF(xScale, yScale); | |
| 373 } | |
| 374 | |
| 375 float MathUtil::smallestAngleBetweenVectors(gfx::Vector2dF v1, gfx::Vector2dF v2
) | |
| 376 { | |
| 377 double dotProduct = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length(); | |
| 378 // Clamp to compensate for rounding errors. | |
| 379 dotProduct = std::max(-1.0, std::min(1.0, dotProduct)); | |
| 380 return static_cast<float>(Rad2Deg(std::acos(dotProduct))); | |
| 381 } | |
| 382 | |
| 383 gfx::Vector2dF MathUtil::projectVector(gfx::Vector2dF source, gfx::Vector2dF des
tination) | |
| 384 { | |
| 385 float projectedLength = gfx::DotProduct(source, destination) / destination.L
engthSquared(); | |
| 386 return gfx::Vector2dF(projectedLength * destination.x(), projectedLength * d
estination.y()); | |
| 387 } | |
| 388 | |
| 389 scoped_ptr<base::Value> MathUtil::asValue(gfx::Size s) { | |
| 390 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); | |
| 391 res->SetDouble("width", s.width()); | |
| 392 res->SetDouble("height", s.height()); | |
| 393 return res.PassAs<base::Value>(); | |
| 394 } | |
| 395 | |
| 396 scoped_ptr<base::Value> MathUtil::asValue(gfx::PointF pt) { | |
| 397 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); | |
| 398 res->SetDouble("x", pt.x()); | |
| 399 res->SetDouble("y", pt.y()); | |
| 400 return res.PassAs<base::Value>(); | |
| 401 } | |
| 402 | |
| 403 scoped_ptr<base::Value> MathUtil::asValue(gfx::QuadF q) { | |
| 404 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); | |
| 405 res->Set("p1", asValue(q.p1()).release()); | |
| 406 res->Set("p2", asValue(q.p2()).release()); | |
| 407 res->Set("p3", asValue(q.p3()).release()); | |
| 408 res->Set("p4", asValue(q.p4()).release()); | |
| 409 return res.PassAs<base::Value>(); | |
| 410 } | |
| 411 | |
| 412 scoped_ptr<base::Value> MathUtil::asValueSafely(double value) { | |
| 413 return scoped_ptr<base::Value>(base::Value::CreateDoubleValue( | |
| 414 std::min(value, std::numeric_limits<double>::max()))); | |
| 415 } | |
| 416 | |
| 417 scoped_ptr<base::Value> MathUtil::asValueSafely(float value) { | |
| 418 return scoped_ptr<base::Value>(base::Value::CreateDoubleValue( | |
| 419 std::min(value, std::numeric_limits<float>::max()))); | |
| 420 } | |
| 421 | |
| 422 } // namespace cc | |
| OLD | NEW |