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#ifndef CC_BASE_MATH_UTIL_H_
6#define CC_BASE_MATH_UTIL_H_
7
8#include <algorithm>
9#include <cmath>
10#include <vector>
11
12#include "base/logging.h"
13#include "base/memory/scoped_ptr.h"
14#include "cc/base/cc_export.h"
15#include "ui/gfx/box_f.h"
16#include "ui/gfx/point3_f.h"
17#include "ui/gfx/point_f.h"
18#include "ui/gfx/size.h"
19#include "ui/gfx/transform.h"
20
21namespace base {
22class Value;
23namespace debug {
24class TracedValue;
25}
26}
27
28namespace gfx {
29class QuadF;
30class Rect;
31class RectF;
32class Transform;
33class Vector2dF;
34class Vector2d;
35}
36
37namespace cc {
38
39struct HomogeneousCoordinate {
40  HomogeneousCoordinate(SkMScalar x, SkMScalar y, SkMScalar z, SkMScalar w) {
41    vec[0] = x;
42    vec[1] = y;
43    vec[2] = z;
44    vec[3] = w;
45  }
46
47  bool ShouldBeClipped() const { return w() <= 0.0; }
48
49  gfx::PointF CartesianPoint2d() const {
50    if (w() == SK_MScalar1)
51      return gfx::PointF(x(), y());
52
53    // For now, because this code is used privately only by MathUtil, it should
54    // never be called when w == 0, and we do not yet need to handle that case.
55    DCHECK(w());
56    SkMScalar inv_w = SK_MScalar1 / w();
57    return gfx::PointF(x() * inv_w, y() * inv_w);
58  }
59
60  gfx::Point3F CartesianPoint3d() const {
61    if (w() == SK_MScalar1)
62      return gfx::Point3F(x(), y(), z());
63
64    // For now, because this code is used privately only by MathUtil, it should
65    // never be called when w == 0, and we do not yet need to handle that case.
66    DCHECK(w());
67    SkMScalar inv_w = SK_MScalar1 / w();
68    return gfx::Point3F(x() * inv_w, y() * inv_w, z() * inv_w);
69  }
70
71  SkMScalar x() const { return vec[0]; }
72  SkMScalar y() const { return vec[1]; }
73  SkMScalar z() const { return vec[2]; }
74  SkMScalar w() const { return vec[3]; }
75
76  SkMScalar vec[4];
77};
78
79class CC_EXPORT MathUtil {
80 public:
81  static const double kPiDouble;
82  static const float kPiFloat;
83
84  static double Deg2Rad(double deg) { return deg * kPiDouble / 180.0; }
85  static double Rad2Deg(double rad) { return rad * 180.0 / kPiDouble; }
86
87  static float Deg2Rad(float deg) { return deg * kPiFloat / 180.0f; }
88  static float Rad2Deg(float rad) { return rad * 180.0f / kPiFloat; }
89
90  static float Round(float f) {
91    return (f > 0.f) ? std::floor(f + 0.5f) : std::ceil(f - 0.5f);
92  }
93  static double Round(double d) {
94    return (d > 0.0) ? std::floor(d + 0.5) : std::ceil(d - 0.5);
95  }
96
97  template <typename T> static T ClampToRange(T value, T min, T max) {
98    return std::min(std::max(value, min), max);
99  }
100
101  // Background: Existing transform code does not do the right thing in
102  // MapRect / MapQuad / ProjectQuad when there is a perspective projection that
103  // causes one of the transformed vertices to go to w < 0. In those cases, it
104  // is necessary to perform clipping in homogeneous coordinates, after applying
105  // the transform, before dividing-by-w to convert to cartesian coordinates.
106  //
107  // These functions return the axis-aligned rect that encloses the correctly
108  // clipped, transformed polygon.
109  static gfx::Rect MapEnclosingClippedRect(const gfx::Transform& transform,
110                                           const gfx::Rect& rect);
111  static gfx::RectF MapClippedRect(const gfx::Transform& transform,
112                                   const gfx::RectF& rect);
113  static gfx::Rect ProjectEnclosingClippedRect(const gfx::Transform& transform,
114                                               const gfx::Rect& rect);
115  static gfx::RectF ProjectClippedRect(const gfx::Transform& transform,
116                                       const gfx::RectF& rect);
117
118  // This function is only valid when the transform preserves 2d axis
119  // alignment and the resulting rect will not be clipped.
120  static gfx::Rect MapEnclosedRectWith2dAxisAlignedTransform(
121      const gfx::Transform& transform,
122      const gfx::Rect& rect);
123
124  // Returns an array of vertices that represent the clipped polygon. After
125  // returning, indexes from 0 to num_vertices_in_clipped_quad are valid in the
126  // clipped_quad array. Note that num_vertices_in_clipped_quad may be zero,
127  // which means the entire quad was clipped, and none of the vertices in the
128  // array are valid.
129  static void MapClippedQuad(const gfx::Transform& transform,
130                             const gfx::QuadF& src_quad,
131                             gfx::PointF clipped_quad[8],
132                             int* num_vertices_in_clipped_quad);
133  static bool MapClippedQuad3d(const gfx::Transform& transform,
134                               const gfx::QuadF& src_quad,
135                               gfx::Point3F clipped_quad[8],
136                               int* num_vertices_in_clipped_quad);
137
138  static gfx::RectF ComputeEnclosingRectOfVertices(const gfx::PointF vertices[],
139                                                   int num_vertices);
140  static gfx::RectF ComputeEnclosingClippedRect(
141      const HomogeneousCoordinate& h1,
142      const HomogeneousCoordinate& h2,
143      const HomogeneousCoordinate& h3,
144      const HomogeneousCoordinate& h4);
145
146  // NOTE: These functions do not do correct clipping against w = 0 plane, but
147  // they correctly detect the clipped condition via the boolean clipped.
148  static gfx::QuadF MapQuad(const gfx::Transform& transform,
149                            const gfx::QuadF& quad,
150                            bool* clipped);
151  static gfx::QuadF MapQuad3d(const gfx::Transform& transform,
152                              const gfx::QuadF& q,
153                              gfx::Point3F* p,
154                              bool* clipped);
155  static gfx::PointF MapPoint(const gfx::Transform& transform,
156                              const gfx::PointF& point,
157                              bool* clipped);
158  static gfx::Point3F MapPoint(const gfx::Transform&,
159                               const gfx::Point3F&,
160                               bool* clipped);
161  static gfx::QuadF ProjectQuad(const gfx::Transform& transform,
162                                const gfx::QuadF& quad,
163                                bool* clipped);
164  static gfx::PointF ProjectPoint(const gfx::Transform& transform,
165                                  const gfx::PointF& point,
166                                  bool* clipped);
167  // Identical to the above function, but coerces the homogeneous coordinate to
168  // a 3d rather than a 2d point.
169  static gfx::Point3F ProjectPoint3D(const gfx::Transform& transform,
170                                     const gfx::PointF& point,
171                                     bool* clipped);
172
173  static gfx::Vector2dF ComputeTransform2dScaleComponents(const gfx::Transform&,
174                                                          float fallbackValue);
175
176  // Makes a rect that has the same relationship to input_outer_rect as
177  // scale_inner_rect has to scale_outer_rect. scale_inner_rect should be
178  // contained within scale_outer_rect, and likewise the rectangle that is
179  // returned will be within input_outer_rect at a similar relative, scaled
180  // position.
181  static gfx::RectF ScaleRectProportional(const gfx::RectF& input_outer_rect,
182                                          const gfx::RectF& scale_outer_rect,
183                                          const gfx::RectF& scale_inner_rect);
184
185  // Returns the smallest angle between the given two vectors in degrees.
186  // Neither vector is assumed to be normalized.
187  static float SmallestAngleBetweenVectors(const gfx::Vector2dF& v1,
188                                           const gfx::Vector2dF& v2);
189
190  // Projects the |source| vector onto |destination|. Neither vector is assumed
191  // to be normalized.
192  static gfx::Vector2dF ProjectVector(const gfx::Vector2dF& source,
193                                      const gfx::Vector2dF& destination);
194
195  // Conversion to value.
196  static scoped_ptr<base::Value> AsValue(const gfx::Size& s);
197  static scoped_ptr<base::Value> AsValue(const gfx::Rect& r);
198  static bool FromValue(const base::Value*, gfx::Rect* out_rect);
199  static scoped_ptr<base::Value> AsValue(const gfx::PointF& q);
200
201  static void AddToTracedValue(const gfx::Size& s,
202                               base::debug::TracedValue* res);
203  static void AddToTracedValue(const gfx::SizeF& s,
204                               base::debug::TracedValue* res);
205  static void AddToTracedValue(const gfx::Rect& r,
206                               base::debug::TracedValue* res);
207  static void AddToTracedValue(const gfx::PointF& q,
208                               base::debug::TracedValue* res);
209  static void AddToTracedValue(const gfx::Point3F&,
210                               base::debug::TracedValue* res);
211  static void AddToTracedValue(const gfx::Vector2d& v,
212                               base::debug::TracedValue* res);
213  static void AddToTracedValue(const gfx::Vector2dF& v,
214                               base::debug::TracedValue* res);
215  static void AddToTracedValue(const gfx::QuadF& q,
216                               base::debug::TracedValue* res);
217  static void AddToTracedValue(const gfx::RectF& rect,
218                               base::debug::TracedValue* res);
219  static void AddToTracedValue(const gfx::Transform& transform,
220                               base::debug::TracedValue* res);
221  static void AddToTracedValue(const gfx::BoxF& box,
222                               base::debug::TracedValue* res);
223
224  // Returns a base::Value representation of the floating point value.
225  // If the value is inf, returns max double/float representation.
226  static double AsDoubleSafely(double value);
227  static float AsFloatSafely(float value);
228};
229
230}  // namespace cc
231
232#endif  // CC_BASE_MATH_UTIL_H_
233