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
3// found in the LICENSE file.
4
5#include "ui/gfx/geometry/quad_f.h"
6
7#include <limits>
8
9#include "base/strings/stringprintf.h"
10
11namespace gfx {
12
13void QuadF::operator=(const RectF& rect) {
14  p1_ = PointF(rect.x(), rect.y());
15  p2_ = PointF(rect.right(), rect.y());
16  p3_ = PointF(rect.right(), rect.bottom());
17  p4_ = PointF(rect.x(), rect.bottom());
18}
19
20std::string QuadF::ToString() const {
21  return base::StringPrintf("%s;%s;%s;%s",
22                            p1_.ToString().c_str(),
23                            p2_.ToString().c_str(),
24                            p3_.ToString().c_str(),
25                            p4_.ToString().c_str());
26}
27
28static inline bool WithinEpsilon(float a, float b) {
29  return std::abs(a - b) < std::numeric_limits<float>::epsilon();
30}
31
32bool QuadF::IsRectilinear() const {
33  return
34      (WithinEpsilon(p1_.x(), p2_.x()) && WithinEpsilon(p2_.y(), p3_.y()) &&
35       WithinEpsilon(p3_.x(), p4_.x()) && WithinEpsilon(p4_.y(), p1_.y())) ||
36      (WithinEpsilon(p1_.y(), p2_.y()) && WithinEpsilon(p2_.x(), p3_.x()) &&
37       WithinEpsilon(p3_.y(), p4_.y()) && WithinEpsilon(p4_.x(), p1_.x()));
38}
39
40bool QuadF::IsCounterClockwise() const {
41  // This math computes the signed area of the quad. Positive area
42  // indicates the quad is clockwise; negative area indicates the quad is
43  // counter-clockwise. Note carefully: this is backwards from conventional
44  // math because our geometric space uses screen coordiantes with y-axis
45  // pointing downards.
46  // Reference: http://mathworld.wolfram.com/PolygonArea.html
47
48  // Up-cast to double so this cannot overflow.
49  double determinant1 = static_cast<double>(p1_.x()) * p2_.y()
50      - static_cast<double>(p2_.x()) * p1_.y();
51  double determinant2 = static_cast<double>(p2_.x()) * p3_.y()
52      - static_cast<double>(p3_.x()) * p2_.y();
53  double determinant3 = static_cast<double>(p3_.x()) * p4_.y()
54      - static_cast<double>(p4_.x()) * p3_.y();
55  double determinant4 = static_cast<double>(p4_.x()) * p1_.y()
56      - static_cast<double>(p1_.x()) * p4_.y();
57
58  return determinant1 + determinant2 + determinant3 + determinant4 < 0;
59}
60
61static inline bool PointIsInTriangle(const PointF& point,
62                                     const PointF& r1,
63                                     const PointF& r2,
64                                     const PointF& r3) {
65  // Compute the barycentric coordinates (u, v, w) of |point| relative to the
66  // triangle (r1, r2, r3) by the solving the system of equations:
67  //   1) point = u * r1 + v * r2 + w * r3
68  //   2) u + v + w = 1
69  // This algorithm comes from Christer Ericson's Real-Time Collision Detection.
70
71  Vector2dF r31 = r1 - r3;
72  Vector2dF r32 = r2 - r3;
73  Vector2dF r3p = point - r3;
74
75  float denom = r32.y() * r31.x() - r32.x() * r31.y();
76  float u = (r32.y() * r3p.x() - r32.x() * r3p.y()) / denom;
77  float v = (r31.x() * r3p.y() - r31.y() * r3p.x()) / denom;
78  float w = 1.f - u - v;
79
80  // Use the barycentric coordinates to test if |point| is inside the
81  // triangle (r1, r2, r2).
82  return (u >= 0) && (v >= 0) && (w >= 0);
83}
84
85bool QuadF::Contains(const PointF& point) const {
86  return PointIsInTriangle(point, p1_, p2_, p3_)
87      || PointIsInTriangle(point, p1_, p3_, p4_);
88}
89
90void QuadF::Scale(float x_scale, float y_scale) {
91  p1_.Scale(x_scale, y_scale);
92  p2_.Scale(x_scale, y_scale);
93  p3_.Scale(x_scale, y_scale);
94  p4_.Scale(x_scale, y_scale);
95}
96
97void QuadF::operator+=(const Vector2dF& rhs) {
98  p1_ += rhs;
99  p2_ += rhs;
100  p3_ += rhs;
101  p4_ += rhs;
102}
103
104void QuadF::operator-=(const Vector2dF& rhs) {
105  p1_ -= rhs;
106  p2_ -= rhs;
107  p3_ -= rhs;
108  p4_ -= rhs;
109}
110
111QuadF operator+(const QuadF& lhs, const Vector2dF& rhs) {
112  QuadF result = lhs;
113  result += rhs;
114  return result;
115}
116
117QuadF operator-(const QuadF& lhs, const Vector2dF& rhs) {
118  QuadF result = lhs;
119  result -= rhs;
120  return result;
121}
122
123}  // namespace gfx
124