• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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