1 /**************************************************************************
2 *
3 * Copyright 2010, 2011 BMW Car IT GmbH
4 * Copyright (C) 2011 DENSO CORPORATION and Robert Bosch Car Multimedia Gmbh
5 *
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h>
24 #include "WLEyes.h"
25
26 #define EYE_X(n) ((n) * 2.0)
27 #define EYE_Y(n) (0.0)
28 #define EYE_OFFSET (0.1) /* padding between eyes */
29 #define EYE_THICK (0.175) /* thickness of eye rim */
30 #define BALL_DIAM (0.3)
31 #define BALL_PAD (0.175)
32 #define EYE_DIAM (2.0 - (EYE_THICK + EYE_OFFSET) * 2)
33 #define BALL_DIST ((EYE_DIAM - BALL_DIAM) / 2.0 - BALL_PAD)
34
35 //#define W_MIN_X (-1.0 + EYE_OFFSET)
36 //#define W_MAX_X ( 3.0 - EYE_OFFSET)
37 //#define W_MIN_Y (-1.0 + EYE_OFFSET)
38 //#define W_MAX_Y ( 1.0 - EYE_OFFSET)
39 #define W_MIN_X (-1.05 + EYE_OFFSET)
40 #define W_MAX_X ( 3.05 - EYE_OFFSET)
41 #define W_MIN_Y (-1.05 + EYE_OFFSET)
42 #define W_MAX_Y ( 1.05 - EYE_OFFSET)
43
44 #define TPOINT_NONE (-1000) /* special value meaning "not yet set" */
45 #define TPointEqual(a, b) ((a).x == (b).x && (a).y == (b).y)
46 #define XPointEqual(a, b) ((a).x == (b).x && (a).y == (b).y)
47 #define AngleBetween(A, A0, A1) (A0 <= A1 ? A0 <= A && A <= A1 : \
48 A0 <= A || A <= A1)
49
50 //////////////////////////////////////////////////////////////////////////////
51
52 static void
SetTransform(Transform * t,int xx1,int xx2,int xy1,int xy2,float tx1,float tx2,float ty1,float ty2)53 SetTransform(Transform* t, int xx1, int xx2, int xy1, int xy2,
54 float tx1, float tx2, float ty1, float ty2)
55 {
56 t->mx = ((float) xx2 - xx1) / (tx2 - tx1);
57 t->bx = ((float) xx1) - t->mx * tx1;
58 t->my = ((float) xy2 - xy1) / (ty2 - ty1);
59 t->by = ((float) xy1) - t->my * ty1;
60 }
61
62 static void
Trectangle(const Transform * t,const TRectangle * i,TRectangle * o)63 Trectangle(const Transform *t, const TRectangle *i, TRectangle *o)
64 {
65 o->x = t->mx * i->x + t->bx;
66 o->y = t->my * i->y + t->by;
67 o->width = t->mx * i->width;
68 o->height = t->my * i->height;
69 if (o->width < 0) {
70 o->x += o->width;
71 o->width = -o->width;
72 }
73 if (o->height < 0) {
74 o->y += o->height;
75 o->height = -o->height;
76 }
77 }
78
79 static TPoint
ComputePupil(int num,TPoint mouse,const TRectangle * screen)80 ComputePupil(int num, TPoint mouse, const TRectangle* screen)
81 {
82 float cx, cy;
83 float dist;
84 float angle;
85 float dx, dy;
86 float cosa, sina;
87 TPoint ret;
88
89 cx = EYE_X(num); dx = mouse.x - cx;
90 cy = EYE_Y(num); dy = mouse.y - cy;
91 if (dx == 0 && dy == 0);
92 else {
93 angle = atan2 ((float) dy, (float) dx);
94 cosa = cos (angle);
95 sina = sin (angle);
96 dist = BALL_DIST;
97 if (screen)
98 {
99 /* use distance mapping */
100 float x0, y0, x1, y1;
101 float a[4];
102 x0 = screen->x - cx;
103 y0 = screen->y - cy;
104 x1 = x0 + screen->width;
105 y1 = y0 + screen->height;
106 a[0] = atan2(y0, x0);
107 a[1] = atan2(y1, x0);
108 a[2] = atan2(y1, x1);
109 a[3] = atan2(y0, x1);
110 if (AngleBetween(angle, a[0], a[1]))
111 {
112 /* left */
113 dist *= dx / x0;
114 }
115 else if (AngleBetween(angle, a[1], a[2]))
116 {
117 /* bottom */
118 dist *= dy / y1;
119 }
120 else if (AngleBetween(angle, a[2], a[3]))
121 {
122 /* right */
123 dist *= dx / x1;
124 }
125 else if (AngleBetween(angle, a[3], a[0]))
126 {
127 /* top */
128 dist *= dy / y0;
129 }
130 if (dist > BALL_DIST)
131 dist = BALL_DIST;
132 }
133 if (dist > hypot ((double) dx, (double) dy)) {
134 cx += dx;
135 cy += dy;
136 } else {
137 cx += dist * cosa;
138 cy += dist * sina;
139 }
140 }
141 ret.x = cx;
142 ret.y = -cy;
143 return ret;
144 }
145
146 static void
CreateEllipsePoints(const float & centerX,const float & centerY,const float & diam,const Transform & trans,int & nPoint,TPoint * & points)147 CreateEllipsePoints(const float& centerX, const float& centerY,
148 const float& diam, const Transform& trans,
149 int& nPoint, TPoint*& points)
150 {
151 int n, i;
152 float hd, c, s, sx, sy, x, y, px, py;
153
154 const TRectangle tpos = {
155 centerX - diam * 0.5f,
156 centerY - diam * 0.5f,
157 diam, diam };
158 TRectangle pos;
159
160 Trectangle(&trans, &tpos, &pos);
161
162 pos.x = pos.x + pos.width * 0.5;
163 pos.y = pos.y + pos.height * 0.5;
164
165 hd = hypot(pos.width, pos.height) * 0.5;
166 n = (M_PI / acos(hd / (hd + 1.0))) + 0.5;
167 if (n < 2) n = 2;
168
169 c = cos(M_PI / n);
170 s = sin(M_PI / n);
171 sx = -(pos.width * s) / pos.height;
172 sy = (pos.height * s) / pos.width;
173
174 n *= 2;
175 n += 2; // adds center point and first point
176 points = (TPoint*)malloc(sizeof(TPoint) * n);
177 if (!points)
178 return;
179
180 // add center point
181 points[0].x = pos.x;
182 points[0].y = pos.y;
183
184 x = 0;
185 y = pos.height * 0.5;
186 for (i = 1; i < n; ++i){
187 points[i].x = x + pos.x;
188 points[i].y = y + pos.y;
189 px = x;
190 py = y;
191 x = c * px + sx * py;
192 y = c * py + sy * px;
193 }
194
195 // add first point
196 points[n-1] = points[1];
197
198 nPoint = n;
199 }
200
201 //////////////////////////////////////////////////////////////////////////////
202
WLEye()203 WLEye::WLEye()
204 : m_nPoint(0)
205 , m_eyeLiner(NULL)
206 , m_nPupilPoint(0)
207 , m_pupil(NULL)
208 , m_nWhiteEyePoint(0)
209 , m_whiteEye(NULL)
210 {
211 }
212
~WLEye()213 WLEye::~WLEye()
214 {
215 if (m_nPoint > 0 && m_eyeLiner){
216 free(m_eyeLiner);
217 }
218 if (m_nPupilPoint > 0 && m_pupil){
219 free(m_pupil);
220 }
221 if (m_nWhiteEyePoint > 0 && m_whiteEye){
222 free(m_whiteEye);
223 }
224 }
225
226 void
CreateEyeLiner(const float & centerX,const float & centerY,const float & diam,const Transform & trans)227 WLEye::CreateEyeLiner(const float& centerX, const float& centerY,
228 const float& diam, const Transform& trans)
229 {
230 if (m_nPoint > 0 && m_eyeLiner){
231 free(m_eyeLiner);
232 m_nPoint = 0;
233 }
234 CreateEllipsePoints(centerX, centerY, diam, trans, m_nPoint, m_eyeLiner);
235
236 CreateWhiteEye(centerX, centerY, diam * 0.8, trans);
237 }
238
239 void
CreateWhiteEye(const float & centerX,const float & centerY,const float & diam,const Transform & trans)240 WLEye::CreateWhiteEye(const float& centerX, const float& centerY,
241 const float& diam, const Transform& trans)
242 {
243 if (m_nWhiteEyePoint > 0 && m_whiteEye){
244 free(m_whiteEye);
245 m_nWhiteEyePoint = 0;
246 }
247 CreateEllipsePoints(centerX, centerY, diam, trans, m_nWhiteEyePoint, m_whiteEye);
248 }
249
250 void
CreatePupil(const float & centerX,const float & centerY,const float & diam,const Transform & trans)251 WLEye::CreatePupil(const float& centerX, const float& centerY,
252 const float& diam, const Transform& trans)
253 {
254 if (m_nPupilPoint > 0 && m_pupil){
255 free(m_pupil);
256 m_nPupilPoint = 0;
257 }
258 CreateEllipsePoints(centerX, centerY, diam, trans, m_nPupilPoint, m_pupil);
259 }
260
261 void
GetEyeLinerGeom(int * nPoint,float ** points)262 WLEye::GetEyeLinerGeom(int* nPoint, float** points)
263 {
264 *nPoint = m_nPoint;
265 *points = (float*)m_eyeLiner;
266 }
267
268 void
GetWhiteEyeGeom(int * nPoint,float ** points)269 WLEye::GetWhiteEyeGeom(int* nPoint, float** points)
270 {
271 *nPoint = m_nWhiteEyePoint;
272 *points = (float*)m_whiteEye;
273 }
274
275 void
GetPupilGeom(int * nPoint,float ** points)276 WLEye::GetPupilGeom(int* nPoint, float** points)
277 {
278 *nPoint = m_nPupilPoint;
279 *points = (float*)m_pupil;
280 }
281
282 //////////////////////////////////////////////////////////////////////////////
283
WLEyes(int screenWidth,int screenHeight)284 WLEyes::WLEyes(int screenWidth, int screenHeight)
285 : m_width(screenWidth)
286 , m_height(screenHeight)
287 {
288 SetTransform(&m_trans, 0, m_width, m_height, 0,
289 W_MIN_X, W_MAX_X, W_MIN_Y, W_MAX_Y);
290 m_eyes[0] = new WLEye;
291 m_eyes[0]->CreateEyeLiner(0.0, 0.0, EYE_DIAM + 2.0 * EYE_THICK, m_trans);
292
293 m_eyes[1] = new WLEye;
294 m_eyes[1]->CreateEyeLiner(2.0, 0.0, EYE_DIAM + 2.0 * EYE_THICK, m_trans);
295 }
296
~WLEyes()297 WLEyes::~WLEyes()
298 {
299 for (int i = 0; i < 2; ++i){
300 if (m_eyes[i]) delete m_eyes[i];
301 }
302 }
303
304 void
SetPointOfView(int mousePosX,int mousePosY)305 WLEyes::SetPointOfView(int mousePosX, int mousePosY)
306 {
307 TPoint mouse;
308 mouse.x = Tx(mousePosX, mousePosY, &m_trans);
309 mouse.y = Ty(mousePosX, mousePosY, &m_trans);
310
311 for (int i = 0; i < 2; ++i){
312 TPoint newPupil = ComputePupil(i, mouse, NULL);
313 m_eyes[i]->CreatePupil(newPupil.x, newPupil.y, BALL_DIAM, m_trans);
314 }
315 }
316
317 void
GetEyeLinerGeom(int n,int * nPoint,float ** points)318 WLEyes::GetEyeLinerGeom(int n, int* nPoint, float** points)
319 {
320 *nPoint = 0;
321 *points = NULL;
322 if (n < 3){
323 m_eyes[n]->GetEyeLinerGeom(nPoint, points);
324 }
325 }
326
327 void
GetWhiteEyeGeom(int n,int * nPoint,float ** points)328 WLEyes::GetWhiteEyeGeom(int n, int* nPoint, float** points)
329 {
330 *nPoint = 0;
331 *points = NULL;
332 if (n < 3){
333 m_eyes[n]->GetWhiteEyeGeom(nPoint, points);
334 }
335 }
336
337 void
GetPupilGeom(int n,int * nPoint,float ** points)338 WLEyes::GetPupilGeom(int n, int* nPoint, float** points)
339 {
340 *nPoint = 0;
341 *points = NULL;
342 if (n < 3){
343 m_eyes[n]->GetPupilGeom(nPoint, points);
344 }
345 }
346