Added support for 3d route in routedialog
[speedfreak] / Client / routedialog.cpp
1 /*
2  * RouteDialog class
3  *
4  * @author     Olavi Pulkkinen <olavi.pulkkinen@fudeco.com>
5  * @copyright  (c) 2010 Speed Freak team
6  * @license    http://opensource.org/licenses/gpl-license.php GNU Public License
7  */
8
9 #include "routedialog.h"
10 #include "ui_routedialog.h"
11 #include <cmath>
12 #include <QPainter>
13 #include <QList>
14 //#include <QMessageBox>
15
16 /*
17   * Vector class
18   */
19 class Vector
20 {
21     qreal x, y, z;
22 public:
23     Vector() { x=0.; y=0. ; z=0.; };
24     Vector( qreal initX, qreal initY, qreal initZ) { x = initX, y = initY; z = initZ; };
25     void setX( qreal newX) { x = newX; };
26     void setY( qreal newY) { y = newY; };
27     void setZ( qreal newZ) { z = newZ; };
28     qreal getX() { return x; };
29     qreal getY() { return y; };
30     qreal getZ() { return z; };
31     qreal length() { return sqrt(x*x+y*y+z*z); };
32     Vector operator+(Vector v)
33     {
34         x = x + v.x; y = y + v.y; z = z + v.z;
35         return *this;
36     };
37     Vector operator-(Vector v)
38     {
39         x = x - v.x; y = y - v.y; z = z - v.z;
40         return *this;
41     };
42     Vector operator/(qreal c)
43     {
44         x = x/c; y = y/c; z = z/c;
45         return *this;
46     };
47     Vector crossProduct( Vector a, Vector b)
48     {
49         x = a.y*b.z - a.z*b.y;
50         y = a.z*b.x - a.x*b.z;
51         z = a.x*b.y - a.y*b.x;
52         return *this;
53     };
54 };
55
56 int left, top, right, bottom;       // Limits in screen coordinates
57 qreal xmax, xmin, ymin, ymax;       // Limits in world coordinates
58
59 QList<Vector> vertexList;           // Vertecies of route
60
61 Vector atPoint, fromPoint, up, a1, a2, a3;
62 qreal offsx, offsy, offsz;
63
64 qreal objxmin, objxmax, objymin, objymax, objzmin, objzmax;
65 qreal angle;
66 qreal a, b,c,d, dval;
67
68 #define maxof(val1,val2)  ((val1>val2)?val1:val2)
69 #define toradians( degrees) (degrees*0.017453293)
70
71 #define WIDTH 1.8
72
73 int length = 24;
74 int connection[30];
75
76 void setAtPoint();
77 void setFromPoint();
78 void setEye();
79
80 RouteDialog::RouteDialog(QWidget *parent) :
81     QDialog(parent),
82     ui(new Ui::RouteDialog)
83 {
84     ui->setupUi(this);
85     //left = 50; top = 50; right = 350; bottom = 200;
86     left = 5; top = 5; right = 395; bottom = 295;
87     xmin =0.0; xmax=100.0; ymin = 0.0; ymax = 20.0;
88     // Ruudun koko 400 x 300
89
90     /*vertexList.append(QVector3D(40.02, 10.02, 10.02));
91    vertexList.append(QVector3D(50.01,  5.01, 10));
92    vertexList.append(QVector3D(69.98,  4.98, 10));
93    vertexList.append(QVector3D(80.02,  9.98, 10));
94    vertexList.append(QVector3D(70.01, 15.01, 10));
95    vertexList.append(QVector3D(49.99, 14.97, 10));
96    vertexList.append(QVector3D(40.01, 10.01, 10.02));
97 */
98        vertexList.append(Vector(0.0, 0.0, 0.0));
99        vertexList.append(Vector(1.0, 1.0, 1.0));
100        vertexList.append(Vector(1.0, 1.0, 0.0));
101
102        vertexList.append(Vector(1.0, 0.0, 0.0));
103        vertexList.append(Vector(1.0, 0.0, 1.0));
104        vertexList.append(Vector(0.0, 1.0, 1.0));
105
106        vertexList.append(Vector(0.0, 1.0, 0.0));
107        vertexList.append(Vector(0.0, 0.0, 0.0));
108        vertexList.append(Vector(0.0, 0.0, 1.0));
109
110    connection[0] = 0;
111    connection[1] = 1; connection[2] = 5; connection[3] = 8; connection[4] = -4;
112    connection[5] =  5; connection[6] = 6; connection[7] = 7; connection[8] = -8;
113    connection[9] =  6; connection[10] = 2; connection[11] = 3; connection[12] = -7;
114    connection[13] = 1; connection[14] = 4; connection[15] = 3; connection[16] = -2;
115    connection[17] = 8; connection[18] = 7; connection[19] = 3; connection[20] = -4;
116    connection[21] = 6;  connection[22] = 5; connection[23] = 1;  connection[24] = -2;
117
118    fromPoint.setX( 1.0); fromPoint.setY( 0.0); fromPoint.setZ( 0.0);
119    atPoint.setX( 0.0); atPoint.setY( 0.0); atPoint.setZ( 0.0);
120    up.setX( 0.0); up.setY( 0.0); up.setZ(1.0);
121
122    a = 400/2.;
123    b = 1 - a*(-1);
124    c = -300/2.;
125    d = 300 - c*(-1);
126    angle = toradians(60);
127
128    setAtPoint();
129    setFromPoint();
130    setEye();
131 }
132
133 RouteDialog::~RouteDialog()
134 {
135     delete ui;
136 }
137
138 void RouteDialog::changeEvent(QEvent *e)
139 {
140     QDialog::changeEvent(e);
141     switch (e->type()) {
142     case QEvent::LanguageChange:
143         ui->retranslateUi(this);
144         break;
145     default:
146         break;
147     }
148 }
149
150
151 /**
152   * Draws route to the route dialog
153   * @param QPaintEvent
154  *
155 void RouteDialog::paintEvent(QPaintEvent *)
156 {
157     // 2d draw
158     int i, maxi;
159     qreal x1, y1, x2, y2;
160     int scx1, scy1, scx2, scy2;
161
162         QPainter painter(this);
163
164         painter.setRenderHint(QPainter::Antialiasing, true);
165         painter.setPen(QPen((Qt::black),2));
166         painter.setBrush(QBrush((Qt::yellow), Qt::SolidPattern));
167
168         // Draw route window frsme
169         painter.drawLine(left,top,right,top);
170         painter.drawLine(right,top,right,bottom);
171         painter.drawLine(left,top,left,bottom);
172         painter.drawLine(left,bottom,right,bottom);
173
174         //maxi = vertexList.size();
175         for (i=0; i<maxi-1; i++)
176         {
177             x1 = vertexList.at(i).x();
178             y1 = vertexList.at(i).y();
179             x2 = vertexList.at(i+1).x();
180             y2 = vertexList.at(i+1).y();
181
182             scx1 = left + (x1-xmin)/(xmax-xmin)*(right-left);
183             scy1 = top + (ymax-y1)/(ymax-ymin)*(bottom-top);
184             scx2 = left + (x2-xmin)/(xmax-xmin)*(right-left);
185             scy2 = top + (ymax-y2)/(ymax-ymin)*(bottom-top);
186
187             painter.drawLine( scx1, scy1, scx2, scy2);
188         }
189 }
190 */
191
192 void RouteDialog::on_closePushButton_clicked()
193 {
194     close();
195 }
196
197 // Next functions below for 3D
198 void dataMinMax( void)
199 {
200     int i, maxi;
201     qreal x,y,z;
202     Vector temp;
203
204     temp = vertexList.at(0);
205     objxmax = objxmin = temp.getX();
206     objymax = objymin = temp.getY();
207     objzmax = objzmin = temp.getZ();
208
209     maxi = vertexList.size();
210     //maxi = 9;
211     for (i=1; i<maxi; i++)
212     {
213         temp = vertexList.at(i);
214         x = temp.getX();
215         y = temp.getY();
216         z = temp.getZ();
217
218         if (x < objxmin)
219         {
220                 objxmin = x;
221         }
222         else if (x > objxmax)
223         {
224                objxmax = x;
225         }
226
227         if (y < objymin)
228         {
229                 objymin = y;
230         }
231         else if (y > objymax)
232         {
233                objymax = y;
234         }
235
236         if (z < objzmin)
237         {
238                 objzmin = z;
239         }
240         else if (z > objzmax)
241         {
242                objzmax = z;
243         }
244     }
245     //QString jono = QString("ojxmin %1 objxmax %2").arg(objxmin).arg(objxmax);
246     //QString jono = QString("ojymin %1 objymax %2").arg(objymin).arg(objymax);
247     //QString jono = QString("ojzmin %1 objzmax %2").arg(objzmin).arg(objzmax);
248     //QMessageBox::about(0,"Tark", jono);
249 }
250
251 void setAtPoint()
252 {
253     dataMinMax();
254     atPoint.setX((objxmax+objxmin)/2.0);
255     atPoint.setY((objymax+objymin)/2.0);
256     atPoint.setZ((objzmax+objzmin)/2.0);
257     //QString jono = QString("AtX %1 Aty %2 AtZ %3").arg(atPoint.x()).arg(atPoint.y()).arg(atPoint.z());
258     //QString jono = QString("AtX %1 Aty %2 AtZ %3").arg(atPoint.x).arg(atPoint.y).arg(atPoint.z);
259     //QMessageBox::about(0,"At point", jono);
260 }
261
262 void setFromPoint()
263 {
264     //fromPoint.setX( atPoint.getX() + (objxmax-objxmin)/2.0 + WIDTH*maxof((objzmax-objzmin)/2.0,(objymax-objymin)/2.0));
265     fromPoint.setX(3.0);
266     fromPoint.setY( atPoint.getY());
267     fromPoint.setZ( atPoint.getZ());
268     //QString jono = QString("FromX %1 FromY %2 FromZ %3").arg(fromPoint.x()).arg(fromPoint.y()).arg(fromPoint.z());
269     //QString jono = QString("FromX %1 FromY %2 FromZ %3").arg(fromPoint.x).arg(fromPoint.y).arg(fromPoint.z);
270     //QMessageBox::about(0,"From point", jono); // (1.9, 0.5, 0.5)
271 }
272
273 void setEye()
274 {
275     double amarkmag, tempmag;
276     Vector temp, dist;
277
278     dval = cos(angle/2.0)/sin(angle/2.0);
279     dist = atPoint-fromPoint;
280     amarkmag = dist.length();
281     a3 = dist/amarkmag;
282
283     temp.crossProduct( dist, up);
284     tempmag = temp.length();
285     a1 = temp/tempmag;
286
287     temp.crossProduct( a1, a3);
288     tempmag = temp.length();
289     a2 = temp/tempmag;
290
291     offsx = -a1.getX()*fromPoint.getX() - a1.getY()*fromPoint.getY() - a1.getZ()*fromPoint.getZ();
292     offsy = -a2.getX()*fromPoint.getX() - a2.getY()*fromPoint.getY() - a2.getZ()*fromPoint.getZ();
293     offsz = -a3.getX()*fromPoint.getX() - a3.getY()*fromPoint.getY() - a3.getZ()*fromPoint.getZ();
294     //QString jono2 = QString("offsx %1 offsy %2 offsz %3").arg(offsx).arg(offsy).arg(offsz);
295     //QMessageBox::about(0,"offs x y z", jono2);
296 }
297
298 #define NOEDGE     0x00
299 #define LEFTEDGE   0x01
300 #define RIGHTEDGE  0x02
301 #define BOTTOMEDGE 0x04
302 #define TOPEDGE    0x08
303 /*
304   * Returns a code specifying which edge in the viewing pyramid was crossed.
305   * There may be more than one.
306   */
307 int code( qreal x, qreal y, qreal z)
308 {
309     int c;
310
311     c = NOEDGE;
312     if (x<-z) c |= LEFTEDGE;
313     if (x>z) c |= RIGHTEDGE;
314     if (y<-z) c |= BOTTOMEDGE;
315     if (y>z) c |= TOPEDGE;
316
317     return c;
318 }
319 /*
320   * Converts clipped world coordinates to screen coordinates.
321   */
322 void WORLDtoSCREEN( qreal xWorld, qreal yWorld, int *xScreen, int *yScreen)
323 {
324    *xScreen = (int) (a*xWorld+b);
325    *yScreen = (int) (c*yWorld+d);
326 }
327
328 /*
329   * Clips the line segment in three-dimensional coordinates to the
330   * viewing pyramid.
331   */
332 void clip3d( qreal x1, qreal y1, qreal z1, qreal x2, qreal y2, qreal z2, int *xscreen1, int *yscreen1, int *xscreen2, int *yscreen2)
333 {
334     int c,c1,c2;
335     qreal x,y,z,t;
336
337     c1 = code(x1,y1,z1);
338     c2 = code(x2,y2,z2);
339
340     while (c1!= NOEDGE || c2 != NOEDGE)
341     {
342         if ((c1 & c2 ) != NOEDGE) return;
343         c = c1;
344         if (c == NOEDGE) c = c2;
345         if ((c&LEFTEDGE) == LEFTEDGE)
346         {
347                 // Crosses left edge
348                 t = (z1+x1)/((x1-x2)-(z2-z1));
349                 z = t*(z2-z1)+z1;
350                 x = -z;
351                 y = t*(y2-y1)+y1;
352         }
353         else if ((c&RIGHTEDGE) == RIGHTEDGE)
354         {
355                 // Crosses right edge
356                 t = (z1-x1)/((x2-x1)-(z2-z1));
357                 z = t*(z2-z1)+z1;
358                 x = z;
359                 y = t*(y2-y1)+y1;
360         }
361         else if ((c&BOTTOMEDGE) == BOTTOMEDGE)
362         {
363                 // Crosses bottom edge
364                 t = (z1+y1)/((y1-y2)-(z2-z1));
365                 z = t*(z2-z1)+z1;
366                 x = t*(x2-x1)+x1;
367                 y = -z;
368         }
369         else if ((c&TOPEDGE) == TOPEDGE)
370         {
371                 // Crosses top edge
372                 t = (z1-y1)/((y2-y1)-(z2-z1));
373                 z = t*(z2-z1)+z1;
374                 x = t*(x2-x1)+x1;
375                 y = z;
376         }
377
378         if (c == c1)
379         {
380             x1=x; y1=y; z1=z;
381             c1 = code(x,y,z);
382         }
383         else
384         {
385             x2=x; y2=y; z2=z;
386             c2 = code(x,y,z);
387         }
388     }
389
390     if (z1 != 0)
391     {
392         WORLDtoSCREEN(x1/z1,y1/z1,xscreen1, yscreen1);
393         WORLDtoSCREEN(x2/z2,y2/z2,xscreen2, yscreen2);
394     }
395     else
396     {
397         WORLDtoSCREEN(x1,y1,xscreen1, yscreen1);
398         WORLDtoSCREEN(x2,y2,xscreen2, yscreen2);
399     }
400     //line( xscreen1, yscreen1, xscreen2, yscreen2);
401 }
402
403 /*
404   * Transform the segment connecting the two vectors into the viewing plane.
405   * clip3d() clips the line if needed.
406   */
407 void transformseg( Vector *v1, Vector *v2, int *xscreen1, int *yscreen1, int *xscreen2, int *yscreen2 )
408
409 {
410     qreal x1, y1, z1, x2, y2, z2;
411
412     x1 = (a1.getX()*v1->getX() + a1.getY()*v1->getY() + a1.getZ()*v1->getZ() + offsx)*dval;
413     y1 = (a2.getX()*v1->getX() + a2.getY()*v1->getY() + a2.getZ()*v1->getZ() + offsy)*dval;
414     z1 = a3.getX()*v1->getX() + a3.getY()*v1->getY() + a3.getZ()*v1->getZ() + offsz;
415
416     x2 = (a1.getX()*v2->getX() + a1.getY()*v2->getY() + a1.getZ()*v2->getZ() + offsx)*dval;
417     y2 = (a2.getX()*v2->getX() + a2.getY()*v2->getY() + a2.getZ()*v2->getZ() + offsy)*dval;
418     z2 = a3.getX()*v2->getX() + a3.getY()*v2->getY() + a3.getZ()*v2->getZ() + offsz;
419
420     clip3d(x1,y1,z1,x2,y2,z2, xscreen1, yscreen1, xscreen2, yscreen2 );
421 }
422
423 void RouteDialog::paintEvent(QPaintEvent *)
424 {
425     int i, startofside;
426     qreal x1, y1, x2, y2;
427     int scx1, scy1, scx2, scy2;
428     int xpc1, ypc1, xpc2, ypc2;
429     Vector temp1, temp2;
430
431     QPainter painter(this);
432
433     painter.setRenderHint(QPainter::Antialiasing, true);
434     painter.setPen(QPen((Qt::black),2));
435     painter.setBrush(QBrush((Qt::yellow), Qt::SolidPattern));
436
437     // Draw route window frsme
438     //painter.drawLine(left,top,right,top);
439     //painter.drawLine(right,top,right,bottom);
440     //painter.drawLine(left,top,left,bottom);
441     //painter.drawLine(left,bottom,right,bottom);
442
443     i=1;
444     while(i<length)
445     {
446         startofside = i;
447         i++;
448         while (connection[i] > 0)
449         {
450             //transformseg( &pa[connection[i-1]],&pa[connection[i]], &xpc1, &ypc1, &xpc2, &ypc2);
451             temp1 = vertexList.at(connection[i-1]);
452             temp2 = vertexList.at(connection[i]);
453             transformseg( &temp1,&temp2, &xpc1, &ypc1, &xpc2, &ypc2);
454
455             painter.drawLine(xpc1, ypc1, xpc2, ypc2);
456             i++;
457         }
458         // to last segment
459         //transformseg( &pa[connection[i-1]],&pa[-connection[i]],&xpc1, &ypc1, &xpc2, &ypc2);
460         temp1 = vertexList.at(connection[i-1]);
461         temp2 = vertexList.at(-connection[i]);
462         transformseg( &temp1,&temp2, &xpc1, &ypc1, &xpc2, &ypc2);
463         painter.drawLine(xpc1, ypc1, xpc2, ypc2);
464         // from last segemt to start
465         //transformseg( &pa[-connection[i]],&pa[connection[startofside]],&xpc1, &ypc1, &xpc2, &ypc2);
466         temp1 = vertexList.at(-connection[i]);
467         temp2 = vertexList.at(connection[startofside]);
468         transformseg( &temp1,&temp2, &xpc1, &ypc1, &xpc2, &ypc2);
469         painter.drawLine(xpc1, ypc1, xpc2, ypc2);
470         i++;
471     }
472 }