1<!DOCTYPE html>
2<!--
3Copyright (c) 2014 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7<link rel="import" href="/tracing/base/base.html">
8<link rel="import" href="/tracing/base/math.html">
9<script>
10'use strict';
11
12tr.exportTo('tr.b', function() {
13  var tmpVec2s = [];
14  for (var i = 0; i < 8; i++)
15    tmpVec2s[i] = vec2.create();
16
17  var tmpVec2a = vec4.create();
18  var tmpVec4a = vec4.create();
19  var tmpVec4b = vec4.create();
20  var tmpMat4 = mat4.create();
21  var tmpMat4b = mat4.create();
22
23  var p00 = vec2.createXY(0, 0);
24  var p10 = vec2.createXY(1, 0);
25  var p01 = vec2.createXY(0, 1);
26  var p11 = vec2.createXY(1, 1);
27
28  var lerpingVecA = vec2.create();
29  var lerpingVecB = vec2.create();
30  function lerpVec2(out, a, b, amt) {
31    vec2.scale(lerpingVecA, a, amt);
32    vec2.scale(lerpingVecB, b, 1 - amt);
33    vec2.add(out, lerpingVecA, lerpingVecB);
34    vec2.normalize(out, out);
35    return out;
36  }
37
38  /**
39   * @constructor
40   */
41  function Quad() {
42    this.p1 = vec2.create();
43    this.p2 = vec2.create();
44    this.p3 = vec2.create();
45    this.p4 = vec2.create();
46  }
47
48  Quad.fromXYWH = function(x, y, w, h) {
49    var q = new Quad();
50    vec2.set(q.p1, x, y);
51    vec2.set(q.p2, x + w, y);
52    vec2.set(q.p3, x + w, y + h);
53    vec2.set(q.p4, x, y + h);
54    return q;
55  }
56
57  Quad.fromRect = function(r) {
58    return new Quad.fromXYWH(
59        r.x, r.y,
60        r.width, r.height);
61  }
62
63  Quad.from4Vecs = function(p1, p2, p3, p4) {
64    var q = new Quad();
65    vec2.set(q.p1, p1[0], p1[1]);
66    vec2.set(q.p2, p2[0], p2[1]);
67    vec2.set(q.p3, p3[0], p3[1]);
68    vec2.set(q.p4, p4[0], p4[1]);
69    return q;
70  }
71
72  Quad.from8Array = function(arr) {
73    if (arr.length != 8)
74      throw new Error('Array must be 8 long');
75    var q = new Quad();
76    q.p1[0] = arr[0];
77    q.p1[1] = arr[1];
78    q.p2[0] = arr[2];
79    q.p2[1] = arr[3];
80    q.p3[0] = arr[4];
81    q.p3[1] = arr[5];
82    q.p4[0] = arr[6];
83    q.p4[1] = arr[7];
84    return q;
85  };
86
87  Quad.prototype = {
88    pointInside: function(point) {
89      return pointInImplicitQuad(point,
90                                 this.p1, this.p2, this.p3, this.p4);
91    },
92
93    boundingRect: function() {
94      var x0 = Math.min(this.p1[0], this.p2[0], this.p3[0], this.p4[0]);
95      var y0 = Math.min(this.p1[1], this.p2[1], this.p3[1], this.p4[1]);
96
97      var x1 = Math.max(this.p1[0], this.p2[0], this.p3[0], this.p4[0]);
98      var y1 = Math.max(this.p1[1], this.p2[1], this.p3[1], this.p4[1]);
99
100      return new tr.b.Rect.fromXYWH(x0, y0, x1 - x0, y1 - y0);
101    },
102
103    clone: function() {
104      var q = new Quad();
105      vec2.copy(q.p1, this.p1);
106      vec2.copy(q.p2, this.p2);
107      vec2.copy(q.p3, this.p3);
108      vec2.copy(q.p4, this.p4);
109      return q;
110    },
111
112    scale: function(s) {
113      var q = new Quad();
114      this.scaleFast(q, s);
115      return q;
116    },
117
118    scaleFast: function(dstQuad, s) {
119      vec2.copy(dstQuad.p1, this.p1, s);
120      vec2.copy(dstQuad.p2, this.p2, s);
121      vec2.copy(dstQuad.p3, this.p3, s);
122      vec2.copy(dstQuad.p3, this.p3, s);
123    },
124
125    isRectangle: function() {
126      // Simple rectangle check. Note: will not handle out-of-order components.
127      var bounds = this.boundingRect();
128      return (
129          bounds.x == this.p1[0] &&
130          bounds.y == this.p1[1] &&
131          bounds.width == this.p2[0] - this.p1[0] &&
132          bounds.y == this.p2[1] &&
133          bounds.width == this.p3[0] - this.p1[0] &&
134          bounds.height == this.p3[1] - this.p2[1] &&
135          bounds.x == this.p4[0] &&
136          bounds.height == this.p4[1] - this.p2[1]
137      );
138    },
139
140    projectUnitRect: function(rect) {
141      var q = new Quad();
142      this.projectUnitRectFast(q, rect);
143      return q;
144    },
145
146    projectUnitRectFast: function(dstQuad, rect) {
147      var v12 = tmpVec2s[0];
148      var v14 = tmpVec2s[1];
149      var v23 = tmpVec2s[2];
150      var v43 = tmpVec2s[3];
151      var l12, l14, l23, l43;
152
153      vec2.sub(v12, this.p2, this.p1);
154      l12 = vec2.length(v12);
155      vec2.scale(v12, v12, 1 / l12);
156
157      vec2.sub(v14, this.p4, this.p1);
158      l14 = vec2.length(v14);
159      vec2.scale(v14, v14, 1 / l14);
160
161      vec2.sub(v23, this.p3, this.p2);
162      l23 = vec2.length(v23);
163      vec2.scale(v23, v23, 1 / l23);
164
165      vec2.sub(v43, this.p3, this.p4);
166      l43 = vec2.length(v43);
167      vec2.scale(v43, v43, 1 / l43);
168
169      var b12 = tmpVec2s[0];
170      var b14 = tmpVec2s[1];
171      var b23 = tmpVec2s[2];
172      var b43 = tmpVec2s[3];
173      lerpVec2(b12, v12, v43, rect.y);
174      lerpVec2(b43, v12, v43, 1 - rect.bottom);
175      lerpVec2(b14, v14, v23, rect.x);
176      lerpVec2(b23, v14, v23, 1 - rect.right);
177
178      vec2.addTwoScaledUnitVectors(tmpVec2a,
179                                   b12, l12 * rect.x,
180                                   b14, l14 * rect.y);
181      vec2.add(dstQuad.p1, this.p1, tmpVec2a);
182
183      vec2.addTwoScaledUnitVectors(tmpVec2a,
184                                   b12, l12 * -(1.0 - rect.right),
185                                   b23, l23 * rect.y);
186      vec2.add(dstQuad.p2, this.p2, tmpVec2a);
187
188
189      vec2.addTwoScaledUnitVectors(tmpVec2a,
190                                   b43, l43 * -(1.0 - rect.right),
191                                   b23, l23 * -(1.0 - rect.bottom));
192      vec2.add(dstQuad.p3, this.p3, tmpVec2a);
193
194      vec2.addTwoScaledUnitVectors(tmpVec2a,
195                                   b43, l43 * rect.left,
196                                   b14, l14 * -(1.0 - rect.bottom));
197      vec2.add(dstQuad.p4, this.p4, tmpVec2a);
198    },
199
200    toString: function() {
201      return 'Quad(' +
202          vec2.toString(this.p1) + ', ' +
203          vec2.toString(this.p2) + ', ' +
204          vec2.toString(this.p3) + ', ' +
205          vec2.toString(this.p4) + ')';
206    }
207  };
208
209  function sign(p1, p2, p3) {
210    return (p1[0] - p3[0]) * (p2[1] - p3[1]) -
211        (p2[0] - p3[0]) * (p1[1] - p3[1]);
212  }
213
214  function pointInTriangle2(pt, p1, p2, p3) {
215    var b1 = sign(pt, p1, p2) < 0.0;
216    var b2 = sign(pt, p2, p3) < 0.0;
217    var b3 = sign(pt, p3, p1) < 0.0;
218    return ((b1 == b2) && (b2 == b3));
219  }
220
221  function pointInImplicitQuad(point, p1, p2, p3, p4) {
222    return pointInTriangle2(point, p1, p2, p3) ||
223        pointInTriangle2(point, p1, p3, p4);
224  }
225
226  return {
227    pointInTriangle2: pointInTriangle2,
228    pointInImplicitQuad: pointInImplicitQuad,
229    Quad: Quad
230  };
231});
232</script>
233