Subversion Repositories public

Rev

Rev 225 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
88 andreas 1
/***************************************************************************
221 andreas 2
 *   Copyright (C) 2007 - 2009 by Andreas Theofilu                         *
119 andreas 3
 *   andreas@theosys.at                                                    *
88 andreas 4
 *                                                                         *
5
 *   This program is free software; you can redistribute it and/or modify  *
6
 *   it under the terms of the GNU General Public License as published by  *
7
 *   the Free Software Foundation version 3 of the License.                *
8
 *                                                                         *
9
 *   This program is distributed in the hope that it will be useful,       *
10
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12
 *   GNU General Public License for more details.                          *
13
 *                                                                         *
14
 *   You should have received a copy of the GNU General Public License     *
15
 *   along with this program; if not, write to the                         *
16
 *   Free Software Foundation, Inc.,                                       *
17
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
18
 ***************************************************************************/
19
 
119 andreas 20
#include "config.h"
88 andreas 21
#include "managefile.h"
22
#include "sportwatcherwidget.h"
23
#include "settingswidget.h"
96 andreas 24
#include "progresswidget.h"
152 andreas 25
#include "wmsbase.h"
158 andreas 26
#include "coordinateswidget.h"
151 andreas 27
#include <string.h>
96 andreas 28
 
137 andreas 29
#include <iostream>
88 andreas 30
#include <kfiledialog.h>
31
#include <kmessagebox.h>
32
#include <ksimpleconfig.h>
33
#include <klocale.h>
34
#include <klistview.h>
100 andreas 35
#include <kaboutdialog.h>
36
#include <kaboutdata.h>
218 andreas 37
#include <kinputdialog.h>
128 andreas 38
#include <kglobalsettings.h>
218 andreas 39
#include <kcombobox.h>
154 andreas 40
#include <qapplication.h>
88 andreas 41
#include <qstring.h>
42
#include <qdatetime.h>
109 andreas 43
#include <qtoolbutton.h>
132 andreas 44
#include <qcursor.h>
151 andreas 45
#include <qcstring.h>
172 andreas 46
#include <qregexp.h>
151 andreas 47
 
157 andreas 48
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
158 andreas 49
   #include <gdal/ogr_spatialref.h>
50
   #include <gdal/ogrsf_frmts.h>
51
   #include <gdal/gdalwarper.h>
165 andreas 52
   #include <gdal/ogrsf_frmts.h>
157 andreas 53
#endif
54
 
218 andreas 55
#include "garmin.h"
137 andreas 56
#include "copy.h"
158 andreas 57
#include "transform.h"
217 andreas 58
#include "import.h"
88 andreas 59
 
216 andreas 60
// #define DEBUG	1
151 andreas 61
 
137 andreas 62
using std::cout;
158 andreas 63
using std::cerr;
64
using std::clog;
137 andreas 65
using std::endl;
66
 
67
 
104 andreas 68
typedef struct
69
{
70
	double lon;
71
	double lat;
72
} posn_type;
73
 
88 andreas 74
sportwatcherWidget::sportwatcherWidget(QWidget* parent, const char* name, WFlags fl)
75
: sportwatcherWidgetBase(parent,name,fl)
76
{
157 andreas 77
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
78
	mFactor = 10;		// Factor to calculate square pixels
79
#endif
88 andreas 80
	mama = parent;
81
	gmn = 0;
82
	min_hr = max_hr = avg_hr = 0;
83
	min_height = max_height = 0.0;
84
	max_time = 0;
85
	index = 0;
104 andreas 86
	zfactor = 0;
132 andreas 87
	mapLap = 0;
88
	mapPan = QRect(0, 0, 0, 0);
89
	stateHand = stateFlag = stateGlas = false;
90
	oldTransX = oldTransY = 0.0;
91
	lmbPressed = 0;
92
 
88 andreas 93
	// Load the config parameters
94
	KSimpleConfig *cfg = new KSimpleConfig(QString("sportwatcher.rc"), true);
95
	cfg->setGroup(QString("SportWatcher"));
143 andreas 96
	lower1 = cfg->readNumEntry("lower1", 0);
97
	lower2 = cfg->readNumEntry("lower2", 0);
98
	lower3 = cfg->readNumEntry("lower3", 0);
99
	upper1 = cfg->readNumEntry("upper1", 0);
100
	upper2 = cfg->readNumEntry("upper2", 0);
101
	upper3 = cfg->readNumEntry("upper3", 0);
102
	MaxHr = cfg->readNumEntry("maxHr", 180);
103
	restHr = cfg->readNumEntry("restHr", 60);
104
	vo2max = cfg->readNumEntry("vo2max", 50);
105
	weight = cfg->readNumEntry("weight", 70);
106
	sampleTime = cfg->readNumEntry("seconds", 15);
149 andreas 107
	Serial = cfg->readBoolEntry("Serial", false);
169 andreas 108
	Contour = cfg->readBoolEntry("Contour", false);
88 andreas 109
	Device = cfg->readEntry("Device", "/dev/ttyUSB0");
143 andreas 110
	Data = cfg->readEntry("Data", QDir::home().absPath() + "/.sportwatcher");
111
	HRM = cfg->readEntry("HRM", QDir::home().absPath() + "/polar");
151 andreas 112
	MAP = cfg->readEntry("MAP", QDir::home().absPath() + "/.sportwatcher/track.wms");
149 andreas 113
	Units = cfg->readNumEntry("Units", 0);
158 andreas 114
	MapType = cfg->readNumEntry("MapType", 7);
88 andreas 115
	delete cfg;
132 andreas 116
	// Set some widget settings
117
	btHand->setToggleButton(true);
118
	btGlas->setToggleButton(true);
88 andreas 119
	// Fill the activities
120
	getActivities();
155 andreas 121
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
151 andreas 122
	// Initialize the GDAL
123
	GDALAllRegister();
124
	poDataset = 0;
125
#endif
88 andreas 126
}
127
 
128
sportwatcherWidget::~sportwatcherWidget()
129
{
104 andreas 130
	destroy();
88 andreas 131
}
132
 
100 andreas 133
void sportwatcherWidget::destroy()
134
{
135
	if (gmn)
136
	   garmin_free_data (gmn);
137
 
138
	if (index)
139
	{
140
	INDEX *n, *akt = index;
141
 
142
	   while (akt)
143
	   {
144
	      n = akt;
145
	      akt = akt->next;
146
	      delete n;
147
	   }
148
	}
149
 
150
	index = 0;
151
	gmn = 0;
132 andreas 152
	oldTransX = oldTransY = 0.0;
100 andreas 153
}
154
 
132 andreas 155
bool sportwatcherWidget::findIndex(const QString &key)
156
{
157
INDEX *akt = index;
158
 
159
	while (akt)
160
	{
161
	   if (akt->path == key || akt->activ == key)
162
	      return true;
163
 
164
	   akt = akt->next;
165
	}
166
 
167
	return false;
168
}
169
 
88 andreas 170
/*
171
 * Search for a directory named .sportwatcher in the home directory of
172
 * the user and search for *.gmn files. Open the files and read the header
173
 * to find the basic data of activities. Then add the information into
174
 * the activities KListView.
175
 */
176
void sportwatcherWidget::getActivities()
177
{
178
QString path, txt;
132 andreas 179
QDir mdir, dir = QDir::homeDirPath();
88 andreas 180
QFileInfo *entries;
181
QStringList years, months;
128 andreas 182
KListViewItem *running, *biking, *other;
183
KListViewItem *el;
88 andreas 184
int anz;
185
RUN_NODE *rn;
186
LAP *lap;
187
 
188
	if (Data.isEmpty())
189
	{
128 andreas 190
	   path = dir.homeDirPath();
88 andreas 191
	   path.append("/.sportwatcher");
192
	}
193
	else
194
	   path = Data;
195
 
196
	dir.setPath(path);
132 andreas 197
	dir.refresh();
88 andreas 198
 
199
	if (!dir.exists())
200
	{
201
	   dir.mkdir(path);
202
	   return;
203
	}
204
 
132 andreas 205
	destroy();
100 andreas 206
	liActivities->clear();
88 andreas 207
	liActivities->setRootIsDecorated(true);
208
	liActivities->setSortColumn(-1);
218 andreas 209
	liActivities->addColumn(QString("Path"), 0);
210
	liActivities->hideColumn(1);
128 andreas 211
	other = new KListViewItem(liActivities, i18n("Others"));
212
	biking = new KListViewItem(liActivities, i18n("Biking"));
213
	running = new KListViewItem(liActivities, i18n("Running"));
214
 
215
	other->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
216
	biking->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
217
	running->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
218
 
88 andreas 219
	liActivities->insertItem(other);
220
	liActivities->insertItem(biking);
221
	liActivities->insertItem(running);
222
 
223
	dir.cd(path);
224
	dir.setFilter(QDir::Dirs | QDir::NoSymLinks);
225
	dir.setSorting(QDir::Name);
132 andreas 226
	dir.refresh();
128 andreas 227
	QFileInfoList *list = (QFileInfoList *)dir.entryInfoList();
88 andreas 228
 
229
	if (!list)
230
	   return;
231
 
232
	QFileInfoListIterator it(*list);
233
 
234
	while ((entries = it.current()) != 0)		// Years
235
	{
236
	   if (entries->fileName() == QString(".") || entries->fileName() == QString(".."))
237
	   {
238
	      ++it;
239
	      continue;
240
	   }
241
 
242
	   years += entries->absFilePath();
243
	   ++it;
244
	}
245
 
246
	for (QStringList::Iterator strit = years.begin(); strit != years.end(); ++strit)
247
	{
248
	   if (months.count() > 0)
249
	      months.clear();
250
 
251
	   dir.setPath(*strit);
132 andreas 252
	   dir.refresh();
128 andreas 253
	   list = (QFileInfoList *)dir.entryInfoList();
88 andreas 254
 
255
	   if (!list)
256
	      continue;
257
 
258
	   it = QFileInfoListIterator (*list);
259
 
260
	   while ((entries = it.current()) != 0)	// Months
261
	   {
262
	      if (entries->fileName() == QString(".") || entries->fileName() == QString(".."))
263
	      {
264
		 ++it;
265
		 continue;
266
	      }
267
 
268
	      months += entries->absFilePath();
269
	      ++it;
270
	   }
271
 
272
	   for (QStringList::Iterator strit1 = months.begin(); strit1 != months.end(); ++strit1)
273
	   {
274
	      mdir.setPath(*strit1);
275
	      mdir.cd(*strit1);
276
	      mdir.setFilter(QDir::Files | QDir::NoSymLinks);
277
	      mdir.setNameFilter(QString("*.gmn"));
132 andreas 278
	      mdir.refresh();
128 andreas 279
	      list = (QFileInfoList *)mdir.entryInfoList();
88 andreas 280
 
281
	      if (!list)
282
		 continue;
283
 
284
	      it = QFileInfoListIterator (*list);
285
	      anz = 0;
286
 
287
	      while ((entries = it.current()) != 0)		// Files
288
	      {
289
		 files += entries->absFilePath();
290
		 ++it;
291
	      }
292
	   }
293
	}
294
 
295
	INDEX *akt, *n;
296
	// Open every file and read its head
297
	for (QStringList::Iterator strfl = files.begin(); strfl != files.end(); ++strfl)
298
	{
132 andreas 299
	   if (findIndex(*strfl))	// avoid duplicate entries
300
	      continue;
301
 
88 andreas 302
	   spw.destroy();
303
 
304
	   if (spw.setFileName(*strfl) == -1)
305
	      return;
306
 
307
	   if (gmn)
308
	      garmin_free_data (gmn);
309
 
310
	   gmn = spw.readFile();
311
	   ds.destroy();
312
	   ds.garmin_print_data(gmn);
313
	   rn = ds.getRunNode();
314
 
315
	   lap = ds.getLap(rn->run->first_lap_index);
316
	   const QDateTime *qt = garmin_dtime (lap->start_time);
317
	   QString idx = qt->toString("dd.MM.yyyy hh:mm.ss");
318
 
217 andreas 319
	   if (strlen (rn->run->workout.name) > 1 && strlen (rn->run->workout.name) < 16 && isalpha (rn->run->workout.name[0]))
320
	      idx.setAscii (rn->run->workout.name);
321
 
88 andreas 322
	   if (!index)
323
	   {
324
	      index = new INDEX;
325
	      index->path = *strfl;
326
	      index->activ = idx;
327
	      index->next = 0;
328
	   }
329
	   else
330
	   {
331
	      n = new INDEX;
332
	      n->path = *strfl;
333
	      n->activ = idx;
334
	      n->next = 0;
335
	      akt = index;
336
 
337
	      while (akt->next)
338
		 akt = akt->next;
339
 
340
	      akt->next = n;
341
	   }
342
 
343
	   switch (rn->run->sport_type)
344
	   {
345
	      case D1000_running:
128 andreas 346
		 el = new KListViewItem(running, idx);
218 andreas 347
		 el->setText(1, *strfl);
128 andreas 348
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("run.png")));
88 andreas 349
		 running->insertItem(el);
350
	      break;
351
 
352
	      case D1000_biking:
128 andreas 353
		 el = new KListViewItem(biking, idx);
218 andreas 354
		 el->setText(1, *strfl);
128 andreas 355
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("bike.png")));
88 andreas 356
		 biking->insertItem(el);
357
	      break;
358
 
359
	      case D1000_other:
128 andreas 360
		 el = new KListViewItem(other, idx);
218 andreas 361
		 el->setText(1, *strfl);
128 andreas 362
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("other.png")));
88 andreas 363
		 other->insertItem(el);
364
	      break;
365
 
366
	      default:
128 andreas 367
		 el = new KListViewItem(other, idx);
218 andreas 368
		 el->setText(1, *strfl);
128 andreas 369
		 el->setPixmap(0, QPixmap::fromMimeSource(QString("other.png")));
88 andreas 370
		 other->insertItem(el);
371
	   }
372
 
373
	   delete qt;
374
	}
375
 
376
	running->setOpen(true);
377
 
378
	if (gmn)
379
	   garmin_free_data (gmn);
380
 
381
	gmn = 0;
382
}
383
 
384
/*$SPECIALIZATION$*/
385
void sportwatcherWidget::btFullscreenSlot()
386
{
132 andreas 387
	oldTransX = oldTransY = 0.0;
388
	mapPan.setCoords(0, 0, 0, 0);
104 andreas 389
	showTrack(0);
88 andreas 390
}
391
 
392
void sportwatcherWidget::btGlasMinusSlot()
393
{
132 andreas 394
bool sh = stateHand;
395
 
396
	stateHand = false;
104 andreas 397
	showTrack(zfactor - 1000);
132 andreas 398
	stateHand = sh;
88 andreas 399
}
400
 
401
void sportwatcherWidget::btGlasPlusSlot()
402
{
132 andreas 403
bool sh = stateHand;
404
 
405
	stateHand = false;
104 andreas 406
	showTrack(zfactor + 1000);
132 andreas 407
	stateHand = sh;
88 andreas 408
}
409
 
410
void sportwatcherWidget::btHandSlot()
411
{
132 andreas 412
QCursor cs;
413
 
414
	if (stateGlas)
415
	{
416
	   stateGlas = false;
417
	   btGlas->toggle();
418
	}
419
 
420
	stateHand = (stateHand) ? false : true;
421
 
422
	if (stateHand)
423
	   cs.setShape(QCursor::PointingHandCursor);
424
	else
425
	   cs.setShape(QCursor::ArrowCursor);
426
 
427
	imgMap->setCursor(cs);
88 andreas 428
}
429
 
430
void sportwatcherWidget::btGlasSlot()
431
{
132 andreas 432
QCursor cs;
433
 
434
	if (stateHand)
435
	{
436
	   stateHand = false;
437
	   btHand->toggle();
438
	}
439
 
440
	stateGlas = (stateGlas) ? false : true;
441
 
442
	if (stateGlas)
443
	   cs.setShape(QCursor::ForbiddenCursor);
444
	else
445
	   cs.setShape(QCursor::ArrowCursor);
446
 
447
	imgMap->setCursor(cs);
88 andreas 448
}
449
 
450
void sportwatcherWidget::btFlagSlot()
451
{
452
}
453
 
132 andreas 454
void sportwatcherWidget::liLapsSlot(QListViewItem *item)
88 andreas 455
{
132 andreas 456
QString sl;
457
int l;
458
int idx;
459
RUN_NODE *rn;
460
LAP *lap;
461
 
462
	if (!item)
463
	   return;
464
 
465
	sl = item->text(0).mid(4, 3);
466
	l = sl.toInt();
467
 
468
	if (l <= 0)
469
	{
470
	   showTrack(zfactor, mapPan, 0);
148 andreas 471
	   showCurves(0);
132 andreas 472
	   return;
473
	}
474
 
475
	rn = ds.getRunNode();
476
	idx = rn->run->first_lap_index;
477
	lap = ds.getLap(idx + l - 1);
478
	showTrack(zfactor, mapPan, lap);
148 andreas 479
	showCurves(lap);
88 andreas 480
}
481
 
482
void sportwatcherWidget::liActivitiesSlot(QListViewItem *item)
483
{
484
INDEX *akt;
485
 
486
	if (!item)
487
	   return;
488
 
218 andreas 489
//	akt = index;
88 andreas 490
 
218 andreas 491
//	while (akt)
492
//	{
493
//	   if (akt->activ == item->text(0))
494
//	   {
88 andreas 495
	      spw.destroy();
496
 
218 andreas 497
//	      if (spw.setFileName(akt->path.ascii()) == -1)
498
	      if (spw.setFileName(item->text(1).ascii()) == -1)
88 andreas 499
		 return;
500
 
501
	      if (gmn)
502
		 garmin_free_data (gmn);
503
 
504
	      gmn = spw.readFile();
104 andreas 505
	      zfactor = 0;
88 andreas 506
	      showLaps();
100 andreas 507
	      showTrack();
88 andreas 508
	      showCurves();
218 andreas 509
//	      return;
510
//	   }
88 andreas 511
 
218 andreas 512
//	   akt = akt->next;
513
//	}
88 andreas 514
}
515
 
516
void sportwatcherWidget::helpAbout()
517
{
119 andreas 518
KAboutData about("SportWatcher", "SportWatcher", VERSION);
100 andreas 519
QString ab = ("About");
520
QString liz = ("License");
521
 
522
	KAboutDialog *info = new KAboutDialog(KAboutDialog::AbtProduct|KAboutDialog::AbtTabbed,
137 andreas 523
		QString("SportWatcher"), KAboutDialog::Close, KAboutDialog::Close, 0,
100 andreas 524
		i18n("About"), false, false, QString::null, QString::null, QString::null);
213 andreas 525
	info->setProduct("SportWatcher", QString("Version %1").arg(VERSION), "Andreas Theofilu", "2007 - 2009");
100 andreas 526
	KAboutContainer *infoAppl = info->addContainerPage(ab, AlignCenter, AlignCenter);
119 andreas 527
	infoAppl->addTitle(QString("SportWatcher"), AlignCenter, false, false);
137 andreas 528
//	infoAppl->addTitle(QString("(C) 2007, 2008, Andreas Theofilu <andreas@theosys.at>"));
529
	infoAppl->addPerson(QString("Andreas Theofilu"), QString("andreas@theosys.at"), QString("http://www.theosys.at"), NULL);
221 andreas 530
	infoAppl->addTitle(i18n("About this Program", "\nRead out the data of a Garmin GPS device over USB, and visualize them on screen"));
137 andreas 531
	about.setLicense(KAboutData::License_Custom);
532
	about.setLicenseText(I18N_NOOP(gpl3));
100 andreas 533
	info->addLicensePage(liz, about.license(), 10);
137 andreas 534
	info->setGeometry(0, 0, 800, 400);
100 andreas 535
	info->centerOnScreen(info, 0);
536
	info->exec();
537
	delete info;
88 andreas 538
}
539
 
540
void sportwatcherWidget::helpContents()
541
{
542
}
543
 
544
void sportwatcherWidget::helpIndex()
545
{
546
}
547
 
548
void sportwatcherWidget::fileExit()
549
{
550
	if (mama)
551
	   mama->close();
552
}
553
 
554
void sportwatcherWidget::filePrint()
555
{
556
}
557
 
104 andreas 558
/*
559
 * This function allows the user to choose a file name, where we save the
560
 * actual lap in Garmins own TCX format. This format is simply a XML-file.
561
 * For details about the schema of this file look at
562
 * http://developer.garmin.com/schemas/tcx/v2/
563
 */
88 andreas 564
void sportwatcherWidget::fileSaveAs()
565
{
104 andreas 566
QString fname;
567
QFile fn;
568
QString buffer;
569
RUN_NODE *rn, *rakt;
570
LAP *lap;
571
POINT *point;
572
int indent, i;
573
QDateTime *qt;
172 andreas 574
QRegExp rx("(.tcx|.gpx|.osm)$");
104 andreas 575
 
576
	if (!gmn)
577
	{
578
	   KMessageBox::error(this, i18n("Currently no activity is selected!"));
579
	   return;
580
	}
581
 
172 andreas 582
	fname = KFileDialog::getSaveFileName(0, QString("*.tcx|Garmin Training Center (*.tcx)\n*.gpx|GPS Excange Format (*.gpx)\n*.osm|OpenStreetMap (*.osm)"), this, QString("SportWatcher"));
104 andreas 583
 
584
	if (fname.isEmpty())
585
	   return;
586
 
172 andreas 587
	if (rx.search(fname) < 0)
588
	{
589
	   KMessageBox::error(this, i18n("The file " + fname + " has no valid file extension!"));
590
	   return;
591
	}
592
 
104 andreas 593
	fn.setName(fname);
594
 
595
	if (fn.exists())
596
	{
597
	   if (KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
598
	      return;
599
	}
600
 
172 andreas 601
	rx.setPattern(".gpx$");
602
 
603
	if (rx.search(fname) >= 0)	// Should we create a *.gpx file?
604
	{
605
	   sportwatcherWidget::saveGPX(fname);
606
	   return;
607
	}
608
 
609
	rx.setPattern(".osm$");
610
 
611
	if (rx.search(fname) >= 0)	// Should we create a *.osm file?
612
	{
613
	   sportwatcherWidget::saveOSM(fname);
614
	   return;
615
	}
616
 
617
	// No, we create a *.tcx file!
171 andreas 618
	indent = 0;
104 andreas 619
	rn = ds.getRunNode();
620
	lap = ds.getLap(rn->run->first_lap_index);
621
 
622
	if ((point = ds.getPoint(lap->start_time)) == 0)
623
	{
624
	   KMessageBox::error(this, i18n("No data to save!"));
625
	   return;
626
	}
627
 
628
	if (!fn.open(IO_ReadWrite | IO_Truncate))
629
	{
172 andreas 630
	   KMessageBox::error(this, i18n("Error creating file " + fname + "!\nPlease check permissions"));
104 andreas 631
	   return;
632
	}
633
 
634
	buffer = QString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
635
	buffer.append("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\" ");
636
	buffer.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
637
	buffer.append("xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 ");
638
	buffer.append("http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd\">\n\n");
639
	writeTag (fn, buffer, indent);
640
	buffer = QString("<folders/>\n\n");
641
	writeTag (fn, buffer, indent);
642
 
643
	// Open a course
644
	QFileInfo finfo(fname);
645
	buffer = QString("<Courses>\n   <Course>\n      <name>%1</name>\n").arg(finfo.baseName(true));
646
	writeTag (fn, buffer, indent);
647
	indent = 2;
648
 
649
	rakt = rn;
650
 
651
	while (rakt)
652
	{
653
	   if (rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
654
	   	rakt->run->type != data_D1010)
655
	   {
656
	      rakt = rakt->next;
657
	      continue;
658
	   }
659
 
660
	   for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
661
	   {
662
	      if ((lap = ds.getLap(i)) == NULL)
663
		 continue;
664
 
665
	      // Write the information of the lap
666
	      writeTag (fn, QString("<Lap>\n"), indent);
667
	      indent++;
668
	      buffer.sprintf("<TotalTimeSeconds>%f</TotalTimeSeconds>\n", (double)lap->total_time / 100.0);
669
	      writeTag (fn, buffer, indent);
172 andreas 670
	      qt = garmin_dtime(lap->start_time);
671
	      buffer = QString("<StartTime>%1</StartTime>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
672
	      writeTag (fn, buffer, indent);
104 andreas 673
	      buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", lap->total_distance);
674
	      writeTag (fn, buffer, indent);
675
 
676
	      writeTag (fn, QString("<BeginPosition>\n"), indent);
677
	      indent++;
678
	      buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->begin.lat));
679
	      writeTag (fn, buffer, indent);
680
	      buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->begin.lon));
681
	      writeTag (fn, buffer, indent);
682
	      indent--;
683
	      writeTag (fn, QString("</BeginPosition>\n"), indent);
684
 
685
	      writeTag (fn, QString("<EndPosition>\n"), indent);
686
	      indent++;
687
	      buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->end.lat));
688
	      writeTag (fn, buffer, indent);
689
	      buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->end.lon));
690
	      writeTag (fn, buffer, indent);
691
	      indent--;
692
	      writeTag (fn, QString("</EndPosition>\n"), indent);
693
 
694
	      writeTag (fn, QString("<AverageHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
695
	      indent++;
696
	      buffer.sprintf("<Value>%d</Value>\n", lap->avg_heart_rate);
697
	      writeTag (fn, buffer, indent);
698
	      indent--;
699
	      writeTag (fn, QString("</AverageHeartRateBpm>\n"), indent);
700
 
701
	      writeTag (fn, QString("<MaximumHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
702
	      indent++;
172 andreas 703
	      buffer.sprintf("<Value>%d</Value>\n", lap->max_heart_rate);
104 andreas 704
	      writeTag (fn, buffer, indent);
705
	      indent--;
706
	      writeTag (fn, QString("</MaximumHeartRateBpm>\n"), indent);
707
 
172 andreas 708
	      if (lap->avg_cadence < 255)
709
	      {
710
		 buffer.sprintf("<AverageCadence>%d</AverageCadence>\n", lap->avg_cadence);
711
		 writeTag (fn, buffer, indent);
215 andreas 712
		 buffer.sprintf("<Cadence>%d</Cadence>\n", lap->avg_cadence);
713
		 writeTag (fn, buffer, indent);
172 andreas 714
	      }
715
 
215 andreas 716
	      buffer = QString("<Intensity>%1</Intensity>\n").arg((!lap->intensity) ? "Active" : "Resting");
104 andreas 717
	      writeTag (fn, buffer, indent);
217 andreas 718
 
719
	      buffer.sprintf("<Calories>%d</Calories>\n", lap->calories);
720
	      writeTag (fn, buffer, indent);
721
 
722
	      buffer.sprintf("<MaximumSpeed>%f</MaximumSpeed>\n", lap->max_speed);
723
	      writeTag (fn, buffer, indent);
104 andreas 724
	      indent--;
725
	      writeTag (fn, QString("</Lap>\n"), indent);
726
 
727
	      point = ds.getPoint(lap->start_time);
728
	      writeTag (fn, QString("<Track>\n"), indent);
729
	      indent++;
730
 
731
	      while (point)
732
	      {
733
		 if (point->time > (lap->start_time + (lap->total_time / 100)))
734
		    break;
735
 
736
		 writeTag (fn, QString("<Trackpoint>\n"), indent);
737
		 indent++;
738
		 qt = garmin_dtime(point->time);
739
		 buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
740
		 writeTag (fn, buffer, indent);
741
		 delete qt;
742
		 writeTag (fn, QString("<Position>\n"), indent);
743
		 indent++;
744
		 buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(point->posn.lat));
745
		 writeTag (fn, buffer, indent);
746
		 buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(point->posn.lon));
747
		 writeTag (fn, buffer, indent);
748
		 indent--;
749
		 writeTag (fn, QString("</Position>\n"), indent);
750
 
751
		 if (point->alt < 20000.0)
752
		 {
753
		    buffer.sprintf("<AltitudeMeters>%f</AltitudeMeters>\n", point->alt);
754
		    writeTag (fn, buffer, indent);
755
		 }
756
 
757
		 buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", point->distance);
758
		 writeTag (fn, buffer, indent);
759
 
760
		 if (point->heart_rate > 0 && point->heart_rate < 250)
761
		 {
762
		    writeTag (fn, QString("<HeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
763
		    indent++;
764
		    buffer.sprintf("<Value>%d</Value>\n", point->heart_rate);
765
		    writeTag (fn, buffer, indent);
766
		    indent--;
767
		    writeTag (fn, QString("</HeartRateBpm>\n"), indent);
768
		 }
769
 
215 andreas 770
		 if (point->cadence >= 0 && point->cadence < 250)
771
		 {
772
		    buffer.sprintf("<Cadence>%d</Cadence>\n", point->cadence);
773
		    writeTag (fn, buffer, indent);
774
		 }
775
 
776
		 buffer.sprintf("<SensorState>%s</SensorState>\n", (!point->sensor) ? "Absent" : "Present");
104 andreas 777
		 writeTag (fn, buffer, indent);
778
		 indent--;
779
		 writeTag (fn, QString("</Trackpoint>\n"), indent);
780
		 point = ds.getPoint(point->time + 1);
781
	      }
782
 
783
	      indent--;
784
	      writeTag (fn, QString("</Track>\n"), indent);
785
	   }
786
 
787
	   indent--;
788
	   writeTag (fn, QString("</Course>\n"), indent);
789
	   indent--;
790
	   writeTag (fn, QString("</Courses>\n"), indent);
791
	   rakt = rakt->next;
792
	}
793
 
794
	// Write information about device
795
	// Here my personal signature is written :-)
796
	writeTag (fn, QString("<Author xsi:type=\"Application_t\">\n"), indent);
797
	indent++;
798
	writeTag (fn, QString("<Name>SportWatcher</Name>\n"), indent);
799
	writeTag (fn, QString("<Build>\n"), indent);
800
	indent++;
801
	writeTag (fn, QString("<Version>\n"), indent);
802
	indent++;
803
	writeTag (fn, QString("<VersionMajor>0</VersionMajor>\n"), indent);
804
	writeTag (fn, QString("<VersionMinor>1</VersionMinor>\n"), indent);
805
	writeTag (fn, QString("<BuildMajor>0</BuildMajor>\n"), indent);
806
	writeTag (fn, QString("<BuildMinor>0</BuildMinor>\n"), indent);
807
	indent--;
808
	writeTag (fn, QString("</Version>\n"), indent);
809
	writeTag (fn, QString("<Type>Beta</Type>\n"), indent);
810
	writeTag (fn, QString("<Time>Jan 31 2008, 00:00:00</Time>\n"), indent);
811
	writeTag (fn, QString("<Builder>theosys</Builder>\n"), indent);
812
	indent--;
813
	writeTag (fn, QString("</Build>\n"), indent);
814
	writeTag (fn, QString("<LangID>EN</LangID>\n"), indent);
815
	writeTag (fn, QString("<PartNumber>000-00000-00</PartNumber>\n"), indent);
816
	indent--;
817
	writeTag (fn, QString("</Author>\n"), indent);
818
	writeTag (fn, QString("</TrainingCenterDatabase>\n"), indent);
819
 
820
	fn.close();
821
	KMessageBox::information(this, i18n("File ") + fname + i18n(" was written successfully."));
88 andreas 822
}
823
 
824
void sportwatcherWidget::fileSave()
825
{
172 andreas 826
	KMessageBox::information(this, i18n("This function is currently not implemented!"));
88 andreas 827
}
828
 
172 andreas 829
void sportwatcherWidget::saveGPX(const QString &fn)
830
{
831
QFile qf;
832
QString buffer;
833
RUN_NODE *rn, *rakt;
834
LAP *lap;
835
POINT *point;
836
int indent;
837
unsigned int i;
838
QDateTime *qt;
839
double minLat, minLon, maxLat, maxLon;
840
 
841
	indent = 0;
842
	rn = ds.getRunNode();
843
	lap = ds.getLap(rn->run->first_lap_index);
844
 
845
	if ((point = ds.getPoint(lap->start_time)) == 0)
846
	{
847
	   KMessageBox::error(this, i18n("No data to save!"));
848
	   return;
849
	}
850
 
851
	qf.setName(fn);
852
 
853
	if (!qf.open(IO_ReadWrite | IO_Truncate))
854
	{
855
	   KMessageBox::error(this, i18n("Error creating file " + fn + "!\nPlease check permissions"));
856
	   return;
857
	}
858
 
859
	buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
860
	buffer.append("<gpx version=\"1.1\" creator=\"TheoSys SportWatcher\" xmlns=\"http://www.topografix.com/GPX/1/1\">\n");
861
	buffer.append("   <metadata>\n");
862
	indent = 0;
863
	writeTag (qf, buffer, indent);
864
 
865
	// Find the edges of our coordinates
866
	// We need this information in the header (metadata)
867
	rakt = rn;
868
	minLat = -90.0;
869
	minLon = -180.0;
870
	maxLat = 90.0;
871
	maxLon = 180.0;
872
 
873
	while (rakt)
874
	{
875
	   if (rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
876
	   	rakt->run->type != data_D1010)
877
	   {
878
	      rakt = rakt->next;
879
	      continue;
880
	   }
881
 
882
	   i = rakt->run->first_lap_index;
883
	   // get the first lap
884
	   if ((lap = ds.getLap(i)) == NULL)
885
	      continue;
886
 
887
	   i = 0;
888
	   // iterate the points associated with the laps
889
	   while ((point = ds.getPoint(i)) != 0)
890
	   {
891
	      if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
892
	      {
893
		 i = point->time + 1;
894
		 continue;
895
	      }
896
 
897
	      if (SEMI2DEG(point->posn.lat) > minLat)
898
		 minLat = SEMI2DEG(point->posn.lat);
899
 
900
	      if (SEMI2DEG(point->posn.lat) < maxLat)
901
		 maxLat = SEMI2DEG(point->posn.lat);
902
 
903
	      if (SEMI2DEG(point->posn.lon) > minLon)
904
		 minLon = SEMI2DEG(point->posn.lon);
905
 
906
	      if (SEMI2DEG(point->posn.lon) < maxLon)
907
		 maxLon = SEMI2DEG(point->posn.lon);
908
 
909
	      i = point->time + 1;
910
	   }
911
 
912
	   rakt = rakt->next;
913
	}
914
 
915
	buffer.sprintf("      <bounds minlat=\"%f\" minlon=\"%f\" maxlat=\"%f\" maxlon=\"%f\" />\n",
916
		maxLat, minLon, minLat, maxLon);
917
	buffer.append("   </metadata>\n");
918
	buffer.append("   <trk>\n");
919
	buffer.append("      <trkseg>\n");
920
	writeTag (qf, buffer, indent);
921
	indent = 3;
922
	rn = ds.getRunNode();
923
	lap = ds.getLap(rn->run->first_lap_index);
924
	i = 0;
925
 
926
	while ((point = ds.getPoint(i)) != 0)
927
	{
928
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
929
	   {
930
	      i = point->time + 1;
931
	      continue;
932
	   }
933
 
934
	   buffer.sprintf("<trkpt lat=\"%f\" lon=\"%f\">\n",
935
		SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
936
	   writeTag(qf, buffer, indent);
937
	   indent++;
938
	   buffer.sprintf("<ele>%f</ele>\n", point->alt);
939
	   writeTag(qf, buffer, indent);
940
	   qt = garmin_dtime(point->time);
941
	   buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
942
	   writeTag(qf, buffer, indent);
943
	   indent--;
944
	   writeTag(qf, QString("</trkpt>\n"), indent);
945
	   i = point->time + 1;
946
	}
947
 
948
	indent = 0;
949
	buffer = QString("      </trkseg>\n");
950
	buffer.append("   </trk>\n");
951
	buffer.append("</gpx>\n");
952
	writeTag(qf, buffer, indent);
953
	qf.close();
954
	KMessageBox::information(this, i18n("File ") + fn + i18n(" was written successfully."));
955
}
956
 
957
void sportwatcherWidget::saveOSM(const QString &fn)
958
{
959
QFile qf;
960
QString buffer;
961
RUN_NODE *rn, *rakt;
962
LAP *lap;
963
POINT *point;
964
int indent, id, j;
965
unsigned int i;
966
double minLat, minLon, maxLat, maxLon;
967
QDateTime *qt;
968
 
969
	indent = 0;
970
	rn = ds.getRunNode();
971
	lap = ds.getLap(rn->run->first_lap_index);
972
 
973
	if ((point = ds.getPoint(lap->start_time)) == 0)
974
	{
975
	   KMessageBox::error(this, i18n("No data to save!"));
976
	   return;
977
	}
978
 
979
	qf.setName(fn);
980
 
981
	if (!qf.open(IO_ReadWrite | IO_Truncate))
982
	{
983
	   KMessageBox::error(this, i18n("Error creating file " + fn + "!\nPlease check permissions"));
984
	   return;
985
	}
986
 
987
	buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
988
	buffer.append("<osm version=\"0.5\" generator=\"TheoSys SportWatcher\">\n");
989
	indent = 0;
990
	writeTag (qf, buffer, indent);
991
	// Find the edges of our coordinates
992
	// We need this information in the header (metadata)
993
	rakt = rn;
994
	minLat = -90.0;
995
	minLon = -180.0;
996
	maxLat = 90.0;
997
	maxLon = 180.0;
998
 
999
	while (rakt)
1000
	{
1001
	   if (rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
1002
	   	rakt->run->type != data_D1010)
1003
	   {
1004
	      rakt = rakt->next;
1005
	      continue;
1006
	   }
1007
 
1008
	   i = rakt->run->first_lap_index;
1009
	   // get the first lap
1010
	   if ((lap = ds.getLap(i)) == NULL)
1011
	      continue;
1012
 
1013
	   i = 0;
1014
	   // iterate the points associated with the laps
1015
	   while ((point = ds.getPoint(i)) != 0)
1016
	   {
1017
	      if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1018
	      {
1019
		 i = point->time + 1;
1020
		 continue;
1021
	      }
1022
 
1023
	      if (SEMI2DEG(point->posn.lat) > minLat)
1024
		 minLat = SEMI2DEG(point->posn.lat);
1025
 
1026
	      if (SEMI2DEG(point->posn.lat) < maxLat)
1027
		 maxLat = SEMI2DEG(point->posn.lat);
1028
 
1029
	      if (SEMI2DEG(point->posn.lon) > minLon)
1030
		 minLon = SEMI2DEG(point->posn.lon);
1031
 
1032
	      if (SEMI2DEG(point->posn.lon) < maxLon)
1033
		 maxLon = SEMI2DEG(point->posn.lon);
1034
 
1035
	      i = point->time + 1;
1036
	   }
1037
 
1038
	   rakt = rakt->next;
1039
	}
1040
 
1041
	buffer.sprintf("   <bound box='%f,%f,%f,%f' origin='http://www.openstreetmap.org/api/0.5' />\n",
1042
		maxLat, minLon, minLat, maxLon);
1043
	writeTag (qf, buffer, indent);
1044
	indent = 1;
1045
	rn = ds.getRunNode();
1046
	lap = ds.getLap(rn->run->first_lap_index);
1047
	i = 0;
1048
	id = -1;
1049
 
1050
	while ((point = ds.getPoint(i)) != 0)
1051
	{
1052
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1053
	   {
1054
	      i = point->time + 1;
1055
	      continue;
1056
	   }
1057
 
1058
	   buffer.sprintf("<node id='%d' action='modify' visible='true' lat=\"%f\" lon=\"%f\">\n",
1059
		id, SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
1060
	   writeTag(qf, buffer, indent);
1061
	   indent++;
1062
	   buffer = QString("<tag k='created_by' v='TheoSys Sportwatcher' />\n");
1063
	   writeTag(qf, buffer, indent);
1064
	   buffer = QString("<tag k='highway' v='tertiary' />\n");
1065
	   writeTag(qf, buffer, indent);
1066
	   indent--;
1067
	   writeTag(qf, QString("</node>\n"), indent);
1068
	   id--;
1069
	   i = point->time + 1;
1070
	}
1071
 
1072
	qt = garmin_dtime(lap->start_time);
1073
	buffer.sprintf("<way id='%d' action='modify' visible='true' timestamp='%s'>\n",
1074
		id, QString(qt->toString("yyyy-MM-ddThh:mm:ssZ")).ascii());
1075
	writeTag(qf, buffer, indent);
1076
	indent++;
1077
 
1078
	for (j = -1; j > id; j--)
1079
	{
1080
	   buffer.sprintf("<nd ref='%d' />\n", j);
1081
	   writeTag(qf, buffer, indent);
1082
	}
1083
 
1084
	indent--;
1085
	writeTag(qf, QString("</way>\n"), indent);
1086
	indent = 0;
1087
	writeTag(qf, QString("</osm>\n"), indent);
1088
	qf.close();
1089
	KMessageBox::information(this, i18n("File ") + fn + i18n(" was written successfully."));
1090
}
1091
 
88 andreas 1092
void sportwatcherWidget::fileOpen()
1093
{
1094
QString fname = KFileDialog::getOpenFileName(Data, QString("*.gmn"), this, QString("SportWatcher"));
137 andreas 1095
int m;
88 andreas 1096
 
1097
        if (fname.isEmpty())
1098
           return;
1099
 
1100
	spw.destroy();
1101
 
1102
        if (spw.setFileName(fname.ascii()) == -1)
1103
	   return;
1104
 
1105
	if (gmn)
1106
	   garmin_free_data (gmn);
1107
 
1108
	gmn = spw.readFile();
104 andreas 1109
	zfactor = 0;
137 andreas 1110
 
1111
	if ((m = garmin_count_error()) > 0)
1112
	{
1113
	int i, key = -1;
1114
 
1115
	   for (i = 0; i < m; i++)
1116
	      KMessageBox::error(this, QString(garmin_get_next_error(&key)));
1117
 
1118
	   garmin_clear_errors();
1119
	   return;
1120
	}
1121
 
88 andreas 1122
	showLaps();
100 andreas 1123
	showTrack();
88 andreas 1124
	showCurves();
1125
}
1126
 
217 andreas 1127
void sportwatcherWidget::fileImport()
1128
{
1129
QString fname = KFileDialog::getOpenFileName(QString("~/"), QString("*.tcx"), this, QString("SportWatcher"));
1130
gmn_import import;
1131
int m;
225 andreas 1132
QString tgfile, fld, px;
1133
QFileInfo datei;
1134
QListViewItem *item;
1135
KListViewItem *el, *it;
1136
LAP *lap;
1137
RUN_NODE *rn;
217 andreas 1138
 
1139
        if (fname.isEmpty())
1140
           return;
1141
 
1142
        import.setFile(fname);
1143
 
1144
	if ((m = import.import()) != 0)
1145
	{
1146
	   KMessageBox::error(this, QString(import.getError(m)));
1147
	   return;
1148
	}
1149
 
1150
	if (gmn)
1151
	   garmin_free_data (gmn);
1152
 
1153
	gmn = import.getGarminData ();
1154
 
1155
	showLaps();
1156
	showTrack();
1157
	showCurves();
225 andreas 1158
 
1159
	// Find the filename;
1160
	// It consists of the date and the time.
1161
	// We need this information to set the correct path to store the file.
1162
	tgfile = Data;		// The base path
1163
	rn = ds.getRunNode();
1164
	lap = ds.getLap(rn->run->first_lap_index);
1165
	QDateTime *qt = garmin_dtime (lap->start_time);
1166
	tgfile.append (qt->toString ("/yyyy")); // year is a folder
1167
	tgfile.append (qt->toString ("/MM"));	// month is a folder
1168
	tgfile.append (qt->toString ("/yyyyMMddThhmmss"));	// The file name
1169
	tgfile.append (".gmn");		// Extension of file name
1170
	datei.setFile (tgfile);
1171
	// save the data to a real file, but only if it doesn't exist allready.
1172
	garmin_save_all (gmn, datei.fileName().ascii(), datei.dirPath(true).ascii(), 0);
1173
 
1174
	// in case the item is already in the list on the left side, we
1175
	// only highlight the item.
1176
	if ((item = liActivities->findItem (tgfile, 1, Qt::ExactMatch)) != 0)
1177
	{
1178
	   liActivities->setSelected (item, true);
1179
	   liActivities->setCurrentItem (item);
1180
	   return;
1181
	}
1182
 
1183
	// insert everything into the list on the left side
1184
	switch (rn->run->sport_type)
1185
	{
1186
	   case D1000_running:
1187
	      fld = i18n("Running");
1188
	      px.setAscii("run.png");
1189
	   break;
1190
 
1191
	   case D1000_biking:
1192
	      fld = i18n("Biking");
1193
	      px.setAscii("bike.png");
1194
	   break;
1195
 
1196
	   default:
1197
	      fld = i18n("Others");
1198
	      px.setAscii("other.png");
1199
	}
1200
 
1201
	// Do we have allready so items in the list?
1202
	if ((item = liActivities->findItem (fld, 0, Qt::ExactMatch)) != 0)
1203
	{
1204
	   el = new KListViewItem(item, qt->toString("dd.MM.yyyy hh:mm:ss"));
1205
	   el->setText(1, tgfile);
1206
	   el->setPixmap(0, QPixmap::fromMimeSource(px));
1207
	   item->insertItem(el);
1208
	}
1209
	else	// no, this is the first item. (shouldn't be!)
1210
	{
1211
	   it = new KListViewItem(liActivities, fld);
1212
	   it->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
1213
	   liActivities->insertItem(it);
1214
	   el = new KListViewItem(item, qt->toString("dd.MM.yyyy hh:mm:ss"));
1215
	   el->setText(1, tgfile);
1216
	   el->setPixmap(0, QPixmap::fromMimeSource(px));
1217
	   it->insertItem(el);
1218
	}
217 andreas 1219
}
1220
 
218 andreas 1221
/*
1222
 * Display a small dialog to rename the currently loaded session.
1223
 */
1224
void sportwatcherWidget::editRename()
1225
{
1226
bool ok;
1227
QString name, inhalt;
1228
QPtrList<QListViewItem> item;
1229
QListViewItem *lvItem;
1230
QFileInfo datei;
1231
RUN_NODE *rn;
1232
LAP *lap;
1233
garmin_list *list;
1234
D1009 *n;
1235
 
1236
	if (!gmn)
1237
	{
1238
	   KMessageBox::error(this, i18n("There is no session selected!"));
1239
	   return;
1240
	}
1241
 
1242
	rn = ds.getRunNode();
1243
	item = liActivities->selectedItems (false);
1244
	lvItem = item.first();
1245
 
1246
	if (!isdigit(rn->run->workout.name[0]))
1247
	   inhalt = lvItem->text(0);
1248
	else
1249
	   inhalt = QString::null;
1250
 
1251
	name = KInputDialog::getText(i18n("Rename session"), i18n("Session name"),
1252
		inhalt, &ok, this, "dialogRename", 0,
1253
		QString("Nxxxxxxxxxxxxxx"));
1254
 
1255
	if (!ok)
1256
	   return;
1257
 
1258
	if (name.length() <= 1)
1259
	{
1260
	   lap = ds.getLap(rn->run->first_lap_index);
1261
	   const QDateTime *qt = garmin_dtime (lap->start_time);
1262
	   QString idx = qt->toString("dd.MM.yyyy hh:mm.ss");
1263
	   lvItem->setText (0, idx);
1264
	   datei.setFile (lvItem->text(1));
1265
	   garmin_save_all (gmn, datei.fileName().ascii(), datei.dirPath(true).ascii(), 1);
1266
	   delete qt;
1267
	   return;
1268
	}
1269
 
1270
	strncpy (rn->run->workout.name, name.ascii(), 16);
1271
 
1272
	if (gmn->type != data_Dlist)
1273
	{
1274
	   KMessageBox::error(this, i18n("editRename: Unexpected structure type %1 found!").arg(gmn->type));
1275
	   return;
1276
	}
1277
 
1278
	list = (garmin_list *)gmn->data;
1279
 
1280
	if (list->head->data->type != data_D1009)	// This should be the run node
1281
	{
1282
	   KMessageBox::error(this, i18n("editRename: The run node was not found!"));
1283
	   return;
1284
	}
1285
 
1286
	n = (D1009 *)list->head->data->data;
1287
	strcpy (n->workout.name, rn->run->workout.name);
1288
	lvItem->setText (0, name);
1289
	datei.setFile (lvItem->text(1));
1290
	garmin_save_all (gmn, datei.fileName().ascii(), datei.dirPath(true).ascii(), 1);
1291
}
1292
 
88 andreas 1293
void sportwatcherWidget::fileNew()
1294
{
132 andreas 1295
progressWidget *dlg = new progressWidget(this, "progressWidgetBase");
96 andreas 1296
 
100 andreas 1297
	dlg->show();
137 andreas 1298
 
1299
	if (!dlg->Download())
1300
	{
1301
	int m, key;
1302
 
1303
	   key = -1;
1304
 
1305
	   for (m = 0; m < garmin_count_error(); m++)
1306
	      KMessageBox::error(this, QString(garmin_get_next_error(&key)));
1307
	}
1308
	else
1309
	   getActivities();
1310
 
1311
	garmin_clear_errors();
96 andreas 1312
	delete dlg;
88 andreas 1313
}
1314
 
1315
/*
1316
 * This function is called, when the user clicks at the menu point
1317
 * "Save Heart Rate".
1318
 * First, a file dialog box is displayed, where the user can choose a
1319
 * directory and a file name to save the heart rate.
1320
 * If the file could successfully be created, the heart rate is saved
137 andreas 1321
 * in the "HRM"-format. This is the native format Polar uses to store
88 andreas 1322
 * heart rate data. I've choosen this format, because it's popular and
1323
 * used by many other software too.
1324
 */
1325
void sportwatcherWidget::extrasSaveHR()
1326
{
1327
QString fname, str1, str2;
1328
QFile fdfile;
1329
QDateTime *qt, *oldqt;
1330
QDate dat;
1331
QTime t;
1332
QDir dir = QDir::home();
1333
char hv0[256];
1334
RUN_NODE *rn;
1335
LAP *lap, *alap;
1336
POINT *point;
1337
int samples, smp, seconds, anz, nsec, samsec;
1338
int avgHeart, minHeart, maxHeart, aktHeart;
1339
int secRange1, secRange2, secRange3, secAbove, secBeyond;
1340
 
1341
	if (!gmn)
1342
	{
1343
	   KMessageBox::information(this, i18n("There is no activity open"));
1344
	   return;
1345
	}
1346
 
1347
	if (HRM.isEmpty())
1348
	   str1 = dir.path();
1349
	else
1350
	   str1 = HRM;
1351
 
1352
	str1 +=  "/" + StartTime.toString("yyyyMMddThhmmss.zzz.hrm");
1353
	fname = KFileDialog::getSaveFileName(str1, QString("*.hrm"), this, QString("SportWatcher"));
1354
 
1355
	if (fname.isEmpty())
1356
	   return;
1357
 
1358
	fdfile.setName(fname);
1359
 
1360
	if (fdfile.exists())
1361
	{
1362
	   if (KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
1363
	      return;
1364
	}
1365
 
1366
	if (!fdfile.open(IO_ReadWrite | IO_Truncate))
1367
	{
1368
	   KMessageBox::error(this, i18n("Error creating a file!\nPlease check permissions."));
1369
	   return;
1370
	}
1371
 
1372
	rn = ds.getRunNode();
1373
	lap = ds.getLap(rn->run->first_lap_index);
1374
	t = StartTime.time();
1375
	dat = StartTime.date();
1376
 
1377
	if ((point = ds.getPoint(lap->start_time)) == 0)
1378
	{
1379
	   fdfile.close();
1380
	   return;
1381
	}
1382
 
1383
	strcpy (hv0, "[Params]\n");
1384
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1385
	str1 = dat.toString("yyyyMMdd");
1386
	str2 = t.toString("hh:mm:ss.z");
1387
	sprintf(hv0, "Version=106\nMonitor=11\nSMode=000000000\nDate=%s\nStartTime=%s\n",
1388
		str1.ascii(), str2.ascii());
1389
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1390
	t.setHMS(0, 0, 0);
1391
	t = t.addSecs(max_time);
1392
	str2 = t.toString("hh:mm:ss.z");
1393
 
1394
	switch (sampleTime)
1395
	{
1396
	   case 0: samsec = 5; break;
1397
	   case 1: samsec = 15; break;
1398
	   case 2: samsec = 30; break;
1399
	   case 3: samsec = 60; break;
1400
	   default:
1401
	      samsec = 15;
1402
	}
1403
 
1404
	sprintf(hv0, "Length=%s\nInterval=%d\nUpper1=%d\nLower1=%d\nUpper2=%d\n",
1405
	   str2.ascii(), samsec, upper1, lower1, upper2);
1406
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1407
	sprintf(hv0, "Lower2=%d\nUpper3=%d\nLower3=%d\nTimer1=00:00:00.0\n",
1408
		lower2, upper3, lower3);
1409
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1410
	strcpy(hv0, "Timer2=00:00:00.0\nTimer3=00:00:00.0\nActiveLimit=0\n");
1411
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1412
	sprintf(hv0, "MaxHR=%d\nRestHR=%d\nStartDelay=0\nVO2max=%d\nWeight=%d\n\n",
1413
		MaxHr, restHr, vo2max, weight);
1414
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1415
 
1416
	// Write the intervall times. One block for every lap
1417
	secRange1 = secRange2 = secRange3 = secAbove = secBeyond = 0;
1418
	strcpy(hv0, "[IntTimes]\n");
1419
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1420
	t.setHMS(0, 0, 0);
1421
 
1422
	for (unsigned int i = rn->run->first_lap_index; i < rn->run->last_lap_index; i++)
1423
	{
1424
	   alap = ds.getLap(i);
1425
	   point = ds.getPoint(alap->start_time);
1426
	   oldqt = garmin_dtime(point->time);
1427
	   avgHeart = minHeart = maxHeart = aktHeart = 0;
1428
	   anz = 0;
1429
	   unsigned long lastTime = point->time;
1430
	   int totSec = 0;
1431
 
1432
	   while (point)
1433
	   {
1434
	      if (point->time > (alap->start_time + (alap->total_time / 100)))
1435
		 break;
1436
 
1437
	      if (point->heart_rate > 0)
1438
	      {
1439
		 avgHeart += point->heart_rate;
1440
		 nsec = point->time - lastTime;
1441
		 totSec += nsec;
1442
 
1443
		 if (minHeart == 0 || minHeart > point->heart_rate)
1444
		    minHeart = point->heart_rate;
1445
 
1446
		 if (maxHeart < point->heart_rate)
1447
		    maxHeart = point->heart_rate;
1448
 
1449
		 if (aktHeart == 0 && totSec >= samsec)
1450
		    aktHeart = avgHeart / (anz + 1);
1451
 
1452
		 if (point->heart_rate < lower1)
1453
		    secBeyond += nsec;
1454
		 else if (point->heart_rate < lower2)
1455
		    secRange1 += nsec;
1456
		 else if (point->heart_rate < lower3)
1457
		    secRange2 += nsec;
1458
		 else if (point->heart_rate < upper3)
1459
		    secRange3 += nsec;
1460
		 else
1461
		    secAbove += nsec;
1462
 
1463
		 lastTime = point->time;
1464
		 anz++;
1465
	      }
1466
 
1467
	      point = ds.getPoint(point->time+1);
1468
	   }
1469
 
1470
	   t = t.addSecs(alap->total_time / 100);
1471
	   str1 = t.toString("hh:mm:ss.z");
166 andreas 1472
 
1473
	   if (anz > 0)
1474
	      avgHeart = avgHeart / anz;
1475
	   else
1476
	      avgHeart = 0;
1477
 
88 andreas 1478
	   sprintf(hv0, "%s\t %d\t %d\t %d\t %d\n",
166 andreas 1479
	      str1.ascii(), aktHeart, minHeart, avgHeart, maxHeart);
88 andreas 1480
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
1481
	   strcpy(hv0, "32\t 0\t 0\t 0\t 0\t 0\n");
1482
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
1483
	   strcpy(hv0, "0\t 0\t 0\t 0\t 0\n");
1484
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
1485
	   sprintf(hv0, "0\t %d\t 0\t 0\t 0\t 0\n", (int)alap->total_distance);
1486
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
1487
	   strcpy(hv0, "0\t 0\t 0\t 0\t 0\t 0\n");
1488
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
1489
	}
1490
 
1491
	strcpy(hv0, "\n[IntNotes]\n\n[ExtraData]\n\n");
1492
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1493
 
1494
	strcpy(hv0, "[Summary-123]\n");
1495
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
1496
	smp = max_time - secBeyond - secRange1 - secRange2 - secRange3 - secAbove;
1497
	sprintf(hv0, "%u\t %u\t %u\t %u\t %u\n",
1498
		max_time, secRange1, secRange2 + secRange3,
1499
		secAbove + secBeyond, smp);
1500
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 1
1501
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
1502
		MaxHr, upper1, lower1, restHr);
1503
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
1504
	sprintf(hv0, "%u\t %u\t %u\t %u\t %u\n",
1505
		max_time, secRange2, secRange1 + secRange3,
1506
		secAbove + secBeyond, smp);
1507
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 2
1508
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
1509
		MaxHr, upper2, lower2, restHr);
1510
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 2
1511
	sprintf(hv0, "%u\t %u\t %u\t %u\t %u\n",
1512
		max_time, secRange3, secRange1 + secRange2,
1513
		secAbove + secBeyond, smp);
1514
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 3
1515
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
1516
		MaxHr, upper3, lower3, restHr);
1517
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 3
1518
	samples = max_time / samsec;
1519
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
1520
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1521
 
1522
	strcpy(hv0, "[Summary-TH]\n");
1523
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1524
	sprintf(hv0, "%u\t 0\t %u\t %d\t %d\t 0\n", max_time, max_time - max_hr - restHr, max_hr, restHr);
1525
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1526
	sprintf(hv0, "%d\t %d\t %d\t %d\n", MaxHr, upper3, lower1, restHr);
1527
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1528
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
1529
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1530
 
1531
	sprintf(hv0, "[HRZones]\n%d\n%d\n%d\n%d\n%d\n%d\n0\n0\n0\n0\n0\n\n",
1532
		MaxHr, upper3, upper2, upper1, lower1, restHr);
1533
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1534
 
1535
	strcpy(hv0, "[HRData]\n");
1536
	write(fdfile.handle(), &hv0[0], strlen(hv0));
1537
 
1538
	smp = 0;		// average heart rate of 15 seconds
1539
	seconds = 0;
1540
	anz = 0;
1541
	nsec = samsec;
1542
	oldqt = garmin_dtime(lap->start_time);
1543
	qt = 0;
1544
	point = ds.getPoint(lap->start_time);
1545
 
1546
	while (point)
1547
	{
1548
	   if (seconds >= nsec)
1549
	   {
1550
	      if (anz > 0)
1551
	      {
1552
		 sprintf(hv0, "%d\n", smp / anz);
1553
		 write(fdfile.handle(), &hv0[0], strlen(hv0));
1554
	      }
1555
 
1556
	      if (smp > 0 && seconds >= (nsec + samsec))
1557
	      {
1558
		 if (anz <= 0)
1559
		    anz = 0;
1560
 
1561
		 for (int x = nsec; x < seconds; x += samsec)
1562
		 {
1563
		    sprintf(hv0, "%d\n", smp / anz);
1564
		    write(fdfile.handle(), &hv0[0], strlen(hv0));
1565
		    nsec += samsec;
1566
		 }
1567
	      }
1568
 
1569
	      anz = 0;
1570
	      smp = 0;
1571
	      nsec += samsec;
1572
	   }
1573
 
1574
	   qt = garmin_dtime (point->time);
1575
	   seconds += oldqt->secsTo(*qt);
1576
 
1577
	   if (point->heart_rate > 0)
1578
	   {
1579
	      smp += point->heart_rate;
1580
	      anz++;
1581
	   }
1582
 
1583
	   delete oldqt;
1584
	   oldqt = qt;
1585
	   point = ds.getPoint(point->time + 1);
1586
	}
1587
 
1588
	fdfile.close();
1589
	KMessageBox::information(this, i18n("File successfully written."));
1590
}
1591
 
1592
void sportwatcherWidget::extrasSettings()
1593
{
1594
settingsWidget *dlg = new settingsWidget(this, "settingsWidgetBase", TRUE, 0);
1595
 
1596
	if (dlg->exec() == QDialog::Accepted)
1597
	{
1598
	   KSimpleConfig *cfg = new KSimpleConfig(QString("sportwatcher.rc"), true);
1599
	   cfg->setGroup(QString("SportWatcher"));
1600
	   lower1 = cfg->readNumEntry("lower1");
1601
	   lower2 = cfg->readNumEntry("lower2");
1602
	   lower3 = cfg->readNumEntry("lower3");
1603
	   upper1 = cfg->readNumEntry("upper1");
1604
	   upper2 = cfg->readNumEntry("upper2");
1605
	   upper3 = cfg->readNumEntry("upper3");
1606
	   MaxHr = cfg->readNumEntry("maxHr");
1607
	   restHr = cfg->readNumEntry("restHr");
1608
	   vo2max = cfg->readNumEntry("vo2max");
1609
	   weight = cfg->readNumEntry("weight");
1610
	   sampleTime = cfg->readNumEntry("seconds");
149 andreas 1611
	   Serial = cfg->readBoolEntry("Serial");
168 andreas 1612
	   Contour = cfg->readBoolEntry("Contour");
88 andreas 1613
	   Device = cfg->readEntry("Device");
1614
	   Data = cfg->readEntry("Data");
1615
	   HRM = cfg->readEntry("HRM");
151 andreas 1616
	   MAP = cfg->readEntry("MAP");
149 andreas 1617
	   Units = cfg->readNumEntry("Units");
158 andreas 1618
	   MapType = cfg->readNumEntry("MapType");
88 andreas 1619
	   delete cfg;
1620
	}
1621
 
1622
	delete dlg;
152 andreas 1623
}
151 andreas 1624
 
152 andreas 1625
void sportwatcherWidget::extrasWMSSettings()
1626
{
156 andreas 1627
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
158 andreas 1628
	if (MapType == MPT_BMP || MapType == MPT_GIF || MapType == MPT_PNG ||
1629
	    MapType == MPT_TIF)
1630
	{
1631
	   coordinatesWidget *idlg = new coordinatesWidget(this, "coordinateswidgetbase", true, 0);
1632
	   idlg->exec();
1633
	   delete idlg;
1634
	   return;
1635
	}
1636
 
1637
	if (MapType != MPT_WMS)
1638
	{
1639
	   KMessageBox::detailedSorry(this,
1640
	      i18n("You have not choosen a WMS tag file!"),
1641
	      i18n("This dialog is especialy to set WMS specific parameters. ") +
1642
	      i18n("Therefore this dialog is temporary disabled. It will be ") +
1643
	      i18n("available again, as soon as you choose \"WMS server\" as ") +
1644
	      i18n("your map type."));
1645
	      return;
1646
	}
151 andreas 1647
 
158 andreas 1648
	wmsbase *dlg = new wmsbase(this, "wmswidgetbase", TRUE, 0);
152 andreas 1649
	dlg->exec();
1650
	delete dlg;
156 andreas 1651
#else
1652
	KMessageBox::detailedSorry(this,
1653
	   i18n("This function was disabled at compile time because of missing GDAL v1.5.x!"),
1654
	   i18n("Sportwatcher needs GDAL v1.5.x to enable this function.\n") +
1655
	   i18n("If you like this to be working, install GDAL version 1.5.x and recompile the source!"));
1656
#endif
88 andreas 1657
}
1658
 
1659
/*
1660
 * Functions to fill in the boxes of the main mask.
1661
 */
1662
void sportwatcherWidget::showLaps()
1663
{
1664
QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
1665
QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
1666
QDateTime dt;
1667
QTime t, st;
215 andreas 1668
QDateTime *qt, *ftt, *ltt;
1669
LAP *lap, *flp;
213 andreas 1670
POINT *point, *subPt;
88 andreas 1671
RUN_NODE *rakt, *rn;
149 andreas 1672
int laps, i, anz, men, cad;
1673
double alt_asc, alt_dsc, sum_asc, sum_dsc, old_asc, old_dsc;
216 andreas 1674
bool pause;
215 andreas 1675
long secs;
88 andreas 1676
 
1677
	if (!gmn)
1678
	{
156 andreas 1679
	   KMessageBox::error(this, i18n("No data were loaded!"));
88 andreas 1680
	   return;
1681
	}
1682
 
1683
	if (gmn->type == data_Dnil)
1684
	{
1685
	   KMessageBox::error(0, i18n("No data found!"));
1686
	   return;
1687
	}
1688
 
1689
	if (gmn->type != data_Dlist)     /* List of data */
1690
	{
221 andreas 1691
	   KMessageBox::error(0, i18n("Found unexpected data type %1!").arg(gmn->type));
88 andreas 1692
	   return;
1693
	}
1694
 
1695
	ds.destroy();
221 andreas 1696
	min_hr = max_hr = avg_hr = 0;
88 andreas 1697
	min_height = max_height = 0.0;
218 andreas 1698
	min_speed = max_speed = 0.0;
88 andreas 1699
	liLaps->clear();
100 andreas 1700
	liLaps->setAllColumnsShowFocus(true);
88 andreas 1701
	ds.garmin_print_data(gmn);
1702
	rn = ds.getRunNode();
1703
	rakt = rn;
1704
	liLaps->setRootIsDecorated(true);
128 andreas 1705
	liLaps->setAlternateBackground(KGlobalSettings::alternateBackgroundColor());
88 andreas 1706
	liLaps->setColumnAlignment(1, Qt::AlignRight);
1707
	liLaps->setColumnAlignment(2, Qt::AlignRight);
1708
	liLaps->setColumnAlignment(3, Qt::AlignRight);
1709
	liLaps->setColumnAlignment(4, Qt::AlignRight);
1710
	liLaps->setColumnAlignment(5, Qt::AlignRight);
1711
	liLaps->setColumnAlignment(6, Qt::AlignRight);
1712
	liLaps->setColumnAlignment(7, Qt::AlignRight);
1713
	liLaps->setColumnAlignment(8, Qt::AlignRight);
1714
	liLaps->setColumnAlignment(9, Qt::AlignRight);
1715
	liLaps->setColumnAlignment(10, Qt::AlignRight);
1716
	liLaps->setColumnAlignment(11, Qt::AlignRight);
1717
 
1718
	qs_name = qs_distance = qs_etime = qs_avgpace = qs_avgspeed = qs_maxspeed = QString("");
1719
	qs_calories = qs_avghr = qs_maxhr = qs_avgcadence = qs_ascent = qs_descent = QString("");
1720
	men = 0;
149 andreas 1721
	cad = 0;
88 andreas 1722
 
1723
	while (rakt)
1724
	{
1725
	   if (rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
1726
	   	rakt->run->type == data_D1010)
1727
	   {
1728
	   int lt, cal, ahr, mhr;
1729
	   double distance, speed, mspeed;
1730
	   QDate dat;
1731
 
1732
	      switch (rakt->run->sport_type)
1733
	      {
1734
		 case D1000_running: qs_name = QString("Running: "); break;
1735
		 case D1000_biking:  qs_name = QString("Biking: "); break;
1736
		 case D1000_other:   qs_name = QString("Other: "); break;
1737
		 default:
1738
		    qs_name = QString("Unknown: ");
1739
	      }
1740
 
1741
	      lap = ds.getLap(rakt->run->first_lap_index);
1742
	      qt = garmin_dtime (lap->start_time);
1743
	      StartTime = *qt;
1744
	      st = qt->time();
1745
	      dat = qt->date();
1746
	      delete qt;
213 andreas 1747
	      qt = 0;
1748
	      // Find the last track;
1749
	      //    It is possible to delete laps directly on the watch,
1750
	      //    so we can't be sure the last lap is really the last one.
1751
	      //    Tracks are not deleted and the last track contains the
1752
	      //    summuraries we need.
88 andreas 1753
	      lap = ds.getLap(rakt->run->last_lap_index);
213 andreas 1754
	      point = ds.getPoint(lap->start_time);
1755
 
1756
	      while (point)
1757
	      {
1758
		 subPt = ds.getPoint(point->time + 1);
1759
 
1760
		 if (!subPt || subPt->distance >= 0x7fffffff)
1761
		 {
1762
		    qt = garmin_dtime(point->time);
1763
		    t = qt->time();	// Every point contains the date and time it was recorded
1764
		    break;
1765
		 }
1766
		 else
1767
		    point = subPt;
1768
	      }
1769
 
1770
	      if (!qt)		// only, if we've not found the last track!
1771
	      {
1772
		 qt = garmin_dtime (lap->start_time);
1773
		 t = qt->addSecs(lap->total_time / 100).time();
1774
	      }
1775
 
215 andreas 1776
	      // There can be pauses during a session. Here we find this pauses
1777
	      // and subtract the pause seconds from the total time.
1778
	      subPt = point;	// save this track temporary
1779
	      point = ds.getPoint(0);
1780
	      pause = false;
1781
	      ltt = ftt = 0;
1782
	      secs = 0;
1783
	      lap = ds.getLap(rakt->run->last_lap_index);
1784
	      flp = ds.getLap(rakt->run->first_lap_index);
1785
	      i = rakt->run->first_lap_index;
1786
 
1787
	      while (point)
1788
	      {
216 andreas 1789
		 if (point->distance >= 0x7fffffff && !pause)	// Start of pause?
215 andreas 1790
		 {
1791
		    if (ltt)
1792
		       delete ltt;
1793
 
1794
		    ltt = garmin_dtime (point->time);
1795
		    pause = true;
1796
		 }
216 andreas 1797
		 else if (pause)	// End of pause
215 andreas 1798
		 {
1799
		    QTime t1, t2;
216 andreas 1800
		    POINT *p;
215 andreas 1801
 
216 andreas 1802
		    // Take the track after the stop track to find the real
1803
		    // time of the pause.
1804
		    if (point->distance >= 0x7fffffff)
215 andreas 1805
		    {
216 andreas 1806
		       if ((p = ds.getPoint(point->time + 1)) == 0)
1807
			  p = point;
215 andreas 1808
		       else
216 andreas 1809
			  point = p;
215 andreas 1810
		    }
1811
 
216 andreas 1812
		    // In case there's no stop track, we take the one
1813
		    // immediateley after the stop track as our start track.
1814
		    ftt = garmin_dtime (point->time);
215 andreas 1815
		    t1 = ltt->time();
1816
		    t2 = ftt->time();
1817
 
1818
		    if (t1 < t2)
1819
		       secs += t1.secsTo(t2);
1820
 
1821
		    delete ltt;
1822
		    delete ftt;
1823
		    ltt = ftt = 0;
1824
		    pause = false;
1825
		 }
1826
 
1827
		 if (point->time >= flp->start_time)
1828
		 {
216 andreas 1829
		    if ((unsigned int)i < rakt->run->last_lap_index)
215 andreas 1830
		    {
1831
		       i++;
1832
		       flp = ds.getLap(i);
1833
		    }
1834
		 }
1835
 
1836
		 point = ds.getPoint(point->time + 1);
1837
	      }
1838
 
1839
	      if (ltt)
1840
		 delete ltt;
1841
 
1842
	      if (ftt)
1843
		 delete ftt;
1844
 
1845
	      point = subPt;
88 andreas 1846
	      lt = st.secsTo(t);
1847
	      t.setHMS(0, 0, 0);
215 andreas 1848
	      t = t.addSecs(lt - secs);
88 andreas 1849
	      qt->setDate(dat);
1850
	      qt->setTime(t);
1851
	      qs_name.append(dat.toString("dd.MM.yyyy"));
1852
	      qs_name.append(" ");
1853
	      qs_name.append(st.toString("hh:mm:ss"));
1854
	      max_time = lt;
1855
	      qs_etime = QString(qt->toString("hh:mm:ss.zzz"));
1856
 
1857
	      distance = 0.0;
1858
	      cal = 0;
1859
	      mspeed = 0;
1860
	      ahr = mhr = 0;
1861
	      anz = 0;
149 andreas 1862
	      cad = 0;
1863
	      sum_asc = sum_dsc = old_asc = old_dsc = 0;
88 andreas 1864
 
1865
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
1866
	      {
1867
		 if ((lap = ds.getLap(i)) == NULL)
1868
		    continue;
1869
 
1870
		 distance += lap->total_distance;
1871
		 cal += lap->calories;
149 andreas 1872
 
1873
		 if (lap->avg_cadence != 0xff)
1874
		    cad += lap->avg_cadence;
1875
 
88 andreas 1876
		 ahr += lap->avg_heart_rate;
1877
		 anz++;
1878
 
1879
		 if (lap->max_speed > mspeed)
1880
		    mspeed = lap->max_speed;
1881
 
1882
		 if (lap->max_heart_rate > mhr)
1883
		    mhr = lap->max_heart_rate;
1884
	      }
1885
 
225 andreas 1886
	      if (point && point->distance > 0 && point->distance < 1.0e20)
213 andreas 1887
	      {
1888
		 total_distance = point->distance;
1889
		 distance = point->distance;
1890
	      }
1891
	      else
1892
		 total_distance = distance;
1893
 
149 andreas 1894
	      if (Units == 1)		// Statute?
1895
		 qs_distance.sprintf("%.2f ft", distance / 0.304);
1896
	      else
1897
	         qs_distance.sprintf("%.2f m", distance);
1898
 
88 andreas 1899
	      if (distance > 0)
1900
	      {
1901
		 QTime tt = qt->time();
156 andreas 1902
		 long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0;
1903
 
1904
		 if (Units == 0)
1905
		    secs = secs * (1000.0 / distance * 100.0);
1906
		 else
1907
		    secs = secs * (1609.344 / distance * 100.0);
1908
 
88 andreas 1909
		 int h = secs / 3600;
1910
		 int m = (secs - (h * 3600)) / 60;
1911
		 int s = secs - ((h * 3600) + (m * 60));
1912
		 t = QTime(h, m, s, 0);
1913
		 qs_avgpace = t.toString("  hh:mm:ss");
156 andreas 1914
 
1915
		 if (Units == 0)
1916
		    qs_avgpace.append(QString(" /km"));
1917
		 else
1918
		    qs_avgpace.append(QString(" /mi"));
88 andreas 1919
	      }
1920
 
149 andreas 1921
	      if (Units == 1)		// Statute?
156 andreas 1922
		 speed = distance / lt * 3.6 / 1.609344;
149 andreas 1923
	      else
1924
		 speed = distance / lt * 3.6;
1925
 
156 andreas 1926
	      qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mph" : "km/h");
1927
	      qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed * 3.6 / 1.609344 : mspeed * 3.6, (Units == 1) ? "mph" : "km/h");
88 andreas 1928
	      qs_calories.sprintf("%d", cal);
1929
	      qs_avghr.sprintf("%d bpm", ahr / anz);
1930
	      qs_maxhr.sprintf("%d bpm", mhr);
1931
 
149 andreas 1932
	      if (cad > 0)
1933
		 qs_avgcadence.sprintf("%d", cad / anz);
1934
 
128 andreas 1935
	      KListViewItem *element = new KListViewItem(liLaps, qs_name, qs_distance,
88 andreas 1936
		qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed, qs_calories, qs_avghr);
1937
	      element->setText(8, qs_maxhr);
1938
	      element->setText(9, qs_avgcadence);
1939
	      element->setText(10, qs_ascent);
1940
	      element->setText(11, qs_descent);
1941
	      element->sortChildItems(0, false);
1942
	      element->setOpen(true);
128 andreas 1943
	      element->setPixmap(0, QPixmap::fromMimeSource(QString("activity.png")));
88 andreas 1944
	      liLaps->insertItem(element);
1945
	      delete qt;
1946
	      /* Get the laps. */
1947
	      laps = 1;
1948
 
1949
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
1950
	      {
149 andreas 1951
		 double spd;
1952
		 char *un;
1953
 
88 andreas 1954
		 if ((lap = ds.getLap(i)) == NULL)
1955
		    continue;
1956
 
1957
		 qt = garmin_dtime (lap->start_time);
1958
		 qs_name.sprintf("Lap %03d - ", laps);
1959
		 qs_name.append(qt->toString("hh:mm:ss"));
149 andreas 1960
		 qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
88 andreas 1961
		 t = QTime(0, 0, 0, 0);
1962
		 t = t.addMSecs(lap->total_time * 10);
1963
		 qs_etime = t.toString("hh:mm:ss.zzz");
149 andreas 1964
		 spd = lap->total_distance / (lap->total_time / 100.0);
1965
 
1966
		 if (Units == 0)
1967
		 {
1968
		    un = (char *)"km/h";
1969
		    spd *= 3.6;
1970
		 }
1971
		 else
156 andreas 1972
		 {
1973
		    spd *= 3.6 / 1.609344;
1974
		    un = (char *)"mph";
1975
		 }
149 andreas 1976
 
1977
		 qs_avgspeed.sprintf("%.2f %s", spd, un);
156 andreas 1978
		 qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? lap->max_speed * 3.6 / 1.609344 : lap->max_speed * 3.6, un);
88 andreas 1979
		 qs_calories.sprintf("%d", lap->calories);
1980
 
1981
		 if (lap->total_distance > 0 && lap->total_time != 0)
1982
		 {
156 andreas 1983
		    double fact;
1984
 
1985
		    if (Units == 0)
1986
		       fact = 1000.0;		// 1 km
1987
		    else
1988
		       fact = 1609.344;		// 1 mile in meters
1989
 
1990
		    long secs = (double)lap->total_time / 10000.0 * (fact / lap->total_distance * 100.0);
88 andreas 1991
		    int h = secs / 3600;
1992
		    int m = (secs - (h * 3600)) / 60;
1993
		    int s = secs - ((h * 3600) + (m * 60));
1994
		    t = QTime(h, m, s, 0);
1995
		    qs_avgpace = t.toString("hh:mm:ss");
156 andreas 1996
 
1997
		    if (Units == 0)
1998
		       qs_avgpace.append(QString(" /km"));
1999
		    else
2000
		       qs_avgpace.append(QString(" /mi"));
88 andreas 2001
		 }
2002
 
2003
		 qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);
2004
		 qs_maxhr.sprintf("%d bpm", lap->max_heart_rate);
2005
 
2006
		 anz = 0;
2007
		 alt_asc = alt_dsc = 0;
2008
 
2009
		 if ((point = ds.getPoint(lap->start_time)) != 0)
2010
		 {
2011
		    if (point->alt < 20000)
149 andreas 2012
		    {
88 andreas 2013
		       alt_dsc = alt_asc = point->alt;
149 andreas 2014
 
2015
		       if (old_asc == 0)
2016
			  old_asc = alt_asc;
2017
 
2018
		       if (old_dsc == 0)
2019
			  old_dsc = alt_dsc;
2020
		    }
88 andreas 2021
		    else
2022
		       alt_dsc = alt_asc = 0;
2023
 
218 andreas 2024
		    POINT *oldPoint = 0;
2025
		    double sc, dist, speed;
222 andreas 2026
		    unsigned long t1, t2;
2027
		    t1 = t2 = 0;
2028
		    pause = false;
2029
		    bool ignore = false;
218 andreas 2030
 
88 andreas 2031
		    while (point)
2032
		    {
2033
		       if (point->time > (lap->start_time + (lap->total_time / 100)))
2034
			 break;
2035
 
218 andreas 2036
		       if (!oldPoint)
2037
			  oldPoint = point;
2038
 
88 andreas 2039
		       if (point->alt > alt_asc && point->alt < 20000)
2040
		       {
2041
			  alt_asc = point->alt;
2042
 
2043
			  if (alt_dsc == 0)
2044
			     alt_dsc = point->alt;
2045
		       }
2046
 
2047
		       if (point->alt < alt_dsc)
2048
			  alt_dsc = point->alt;
2049
 
2050
		       // save the min and max values. We need this information to
2051
		       // build the graphics.
221 andreas 2052
		       if (point->heart_rate > max_hr && point->heart_rate < 250)
88 andreas 2053
			  max_hr = point->heart_rate;
2054
 
221 andreas 2055
		       if ((min_hr == 0 && point->heart_rate > 0 && point->heart_rate < 250)
2056
			   || (point->heart_rate > 0 && point->heart_rate < min_hr))
88 andreas 2057
			  min_hr = point->heart_rate;
2058
 
2059
		       if (point->alt < 20000 && max_height < point->alt)
2060
			  max_height = point->alt;
2061
 
2062
		       if (point->alt < 20000 && (min_height == 0.0 || min_height > point->alt))
2063
			  min_height = point->alt;
2064
 
218 andreas 2065
		       // Calculate speed of current track
222 andreas 2066
		       if (!pause && point->distance > 1.0e10)
2067
		       {
2068
			  t1 = point->time;
2069
			  pause = true;
2070
			  ignore = true;
2071
		       }
2072
		       else if (pause)
2073
		       {
2074
			  t2 = point->time;
2075
			  pause = false;
2076
			  point = ds.getPoint(point->time + 1);
2077
			  continue;
2078
		       }
218 andreas 2079
 
222 andreas 2080
		       if (!ignore && !pause)
2081
		       {
2082
			  sc = point->time - oldPoint->time;
2083
			  dist = point->distance - oldPoint->distance;
218 andreas 2084
 
222 andreas 2085
			  if (t2 > t1)
2086
			     sc -= t2 - t1;
218 andreas 2087
 
222 andreas 2088
			  if (sc > 0.0)
223 andreas 2089
			  {
222 andreas 2090
			     speed = (dist / sc) * 3.6;
223 andreas 2091
 
2092
			     if (speed > lap->max_speed * 3.6)
2093
			        speed = lap->max_speed * 3.6;
2094
			  }
222 andreas 2095
			  else
2096
			     speed = 0.0;
218 andreas 2097
 
222 andreas 2098
			  if (Units == 1)
2099
			     speed /= 1.609344;
218 andreas 2100
 
222 andreas 2101
			  if (speed > 0.0 && speed < 400.0 && max_speed < speed)
2102
			     max_speed = speed;
2103
 
2104
			  if (speed > 0.0 && (min_speed == 0.0 || min_speed > speed))
2105
			     min_speed = speed;
2106
 
2107
			  oldPoint = point;
2108
		       }
2109
 
2110
		       if (!pause && ignore)
2111
			  ignore = false;
2112
 
221 andreas 2113
		       if (point->heart_rate > 0 && point->heart_rate < 250)
88 andreas 2114
		       {
2115
			  avg_hr += point->heart_rate;
2116
			  men++;
2117
		       }
2118
 
2119
		       point = ds.getPoint(point->time + 1);
2120
		    }
2121
 
149 andreas 2122
		    if (old_asc < alt_asc)
2123
		       sum_asc += (alt_asc - old_asc);
2124
 
2125
		    if (old_dsc > alt_dsc)
2126
		       sum_dsc += (old_dsc - alt_dsc);
2127
 
2128
		    old_asc = alt_asc;
2129
		    old_dsc = alt_dsc;
2130
		    qs_ascent.sprintf("%.2f %s", (Units == 1) ? (alt_asc / 0.304) : alt_asc, (Units == 1) ? "ft" : "m");
2131
		    qs_descent.sprintf("%.2f %s", (Units == 1) ? (alt_dsc / 0.304) : alt_dsc, (Units == 1) ? "ft" : "m");
88 andreas 2132
		 }
2133
 
2134
		 if (lap->avg_cadence != 0xff)
2135
		    qs_avgcadence.sprintf("%d", lap->avg_cadence);
2136
 
128 andreas 2137
		 KListViewItem *edetail = new KListViewItem(element, qs_name, qs_distance,
88 andreas 2138
			qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed, qs_calories, qs_avghr);
2139
		 edetail->setText(8, qs_maxhr);
2140
		 edetail->setText(9, qs_avgcadence);
2141
		 edetail->setText(10, qs_ascent);
2142
		 edetail->setText(11, qs_descent);
128 andreas 2143
		 edetail->setPixmap(0, QPixmap::fromMimeSource(QString("history.png")));
2144
 
2145
		 switch (rakt->run->sport_type)
2146
		 {
2147
		    case D1000_running: edetail->setPixmap(0, QPixmap::fromMimeSource(QString("run.png"))); break;
2148
		    case D1000_biking:  edetail->setPixmap(0, QPixmap::fromMimeSource(QString("bike.png"))); break;
2149
		    case D1000_other:   edetail->setPixmap(0, QPixmap::fromMimeSource(QString("other.png"))); break;
2150
		    default:
2151
		       edetail->setPixmap(0, QPixmap::fromMimeSource(QString("other.png")));
2152
		 }
2153
 
88 andreas 2154
		 liLaps->clearSelection();
2155
		 element->insertItem(edetail);
2156
		 delete qt;
2157
		 laps++;
2158
	      }
149 andreas 2159
 
2160
	      qs_ascent.sprintf("%.2f %s", (Units == 1) ? sum_asc / 0.304 : sum_asc, (Units == 1) ? "ft" : "m");
2161
	      qs_descent.sprintf("%.2f %s", (Units == 1) ? sum_dsc / 0.304 : sum_dsc, (Units == 1) ? "ft" : "m");
2162
      	      element->setText(10, qs_ascent);
2163
	      element->setText(11, qs_descent);
88 andreas 2164
	   }
2165
 
2166
	   rakt = rakt->next;
2167
	}
2168
 
2169
	if (men > 0)
2170
	   avg_hr /= men;
221 andreas 2171
	else
2172
	   min_hr = max_hr = avg_hr = 0;
88 andreas 2173
}
2174
 
100 andreas 2175
void sportwatcherWidget::showTrack()
2176
{
132 andreas 2177
	showTrack(0, QRect(0, 0, 0, 0), 0);
104 andreas 2178
}
2179
 
2180
void sportwatcherWidget::showTrack(int zoom)
2181
{
132 andreas 2182
	showTrack(zoom, mapPan, mapLap);
2183
}
2184
 
2185
void sportwatcherWidget::showTrack(int zoom, const QRect &pan, LAP *lap)
2186
{
100 andreas 2187
int width, height;
2188
double x1, y1, x2, y2;
132 andreas 2189
int a, top, left, panX, panY;
2190
uint32 i;
109 andreas 2191
double coordW, coordH, tick;
156 andreas 2192
double meterW, dist, fact;
100 andreas 2193
QPainter paint;
152 andreas 2194
posn_type posNW, posSE, posLXY, posRXY;
100 andreas 2195
POINT *point;
152 andreas 2196
bool Fgeo = false;
157 andreas 2197
bool Data = false;
155 andreas 2198
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
158 andreas 2199
QString fName = MAP;
2200
//double adfGeoTransform[6];
2201
GDALDataset *poDataset = 0;
151 andreas 2202
GDALRasterBand *poBand;
2203
unsigned char *pafScanline;
2204
unsigned char *pafScanlineRed;
2205
unsigned char *pafScanlineGreen;
2206
unsigned char *pafScanlineBlue;
154 andreas 2207
unsigned char *pafScanlineAlpha;
151 andreas 2208
int nXSize, nYSize;
159 andreas 2209
int xOff, yOff;
158 andreas 2210
double oriLeftLon, oriLeftLat, oriRightLon, oriRightLat;
151 andreas 2211
#endif
100 andreas 2212
 
109 andreas 2213
	if (!gmn)
2214
	   return;
2215
 
154 andreas 2216
	QApplication::setOverrideCursor (QCursor(Qt::WaitCursor));
2217
 
104 andreas 2218
	if (zoom != zfactor)
2219
	   zfactor = zoom;
2220
 
132 andreas 2221
	if (mapLap != lap)
2222
	   mapLap = lap;
2223
 
157 andreas 2224
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
2225
	KSimpleConfig *cfg = new KSimpleConfig(QString("sportwatcher.rc"));
2226
	cfg->setGroup(QString("WMS"));
2227
	bool square = cfg->readBoolEntry("Square", false);
2228
	int CorrX = cfg->readNumEntry("CorrX", 0);
2229
	int CorrY = cfg->readNumEntry("CorrY", 0);
158 andreas 2230
	cfg->setGroup(QString("ImageCoords"));
2231
	oriLeftLon = cfg->readDoubleNumEntry("LeftLon", 0.0);
2232
	oriLeftLat = cfg->readDoubleNumEntry("LeftLat", 0.0);
2233
	oriRightLon = cfg->readDoubleNumEntry("RightLon", 0.0);
2234
	oriRightLat = cfg->readDoubleNumEntry("RightLat", 0.0);
2235
//	int isrs = cfg->readNumEntry("SRS", 0);
157 andreas 2236
#endif
148 andreas 2237
	width = imgMap->width() - 2;
2238
	height = imgMap->height();
157 andreas 2239
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
158 andreas 2240
	if (MapType == MPT_WMS && square)
157 andreas 2241
	   pmMap.resize(width / (int)mFactor * (int)mFactor, height / (int)mFactor * (int)mFactor);
2242
	else
2243
	   pmMap.resize(width, height);
2244
#else
100 andreas 2245
	pmMap.resize(width, height);
157 andreas 2246
#endif
100 andreas 2247
	paint.begin(&pmMap);
2248
 
132 andreas 2249
	panX = panY = 0;
2250
 
2251
	if (stateHand && mapPan != pan)
2252
	{
2253
	   mapPan = pan;
2254
	   panX = mapPan.right() - mapPan.left();
2255
	   panY = mapPan.bottom() - mapPan.top();
2256
	   oldTransX += (double)panX;
2257
	   oldTransY += (double)panY;
2258
	}
2259
 
104 andreas 2260
	memset(&posNW, 0, sizeof(posn_type));
2261
	memset(&posSE, 0, sizeof(posn_type));
100 andreas 2262
 
156 andreas 2263
	posSE.lat = 90.0;
2264
	posSE.lon = 180.0;
2265
	posNW.lat = -90.0;
2266
	posNW.lon = -180.0;
100 andreas 2267
 
2268
	/*
2269
	 * Find out the corners of our track (NW, NE, SE, SW)
2270
	 */
132 andreas 2271
	if (mapLap)
2272
	   i = mapLap->start_time;
2273
	else
2274
	   i = 0;
100 andreas 2275
 
2276
	while ((point = ds.getPoint(i)) != 0)
2277
	{
132 andreas 2278
	   if (mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
2279
	      break;
2280
 
100 andreas 2281
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
2282
	   {
132 andreas 2283
	      i = point->time + 1;
100 andreas 2284
	      continue;
2285
	   }
2286
 
2287
	   if (SEMI2DEG(point->posn.lat) > posNW.lat)
2288
	      posNW.lat = SEMI2DEG(point->posn.lat);
2289
 
2290
	   if (SEMI2DEG(point->posn.lat) < posSE.lat)
2291
	      posSE.lat = SEMI2DEG(point->posn.lat);
2292
 
156 andreas 2293
	   if (SEMI2DEG(point->posn.lon) > posNW.lon)
100 andreas 2294
	      posNW.lon = SEMI2DEG(point->posn.lon);
2295
 
156 andreas 2296
	   if (SEMI2DEG(point->posn.lon) < posSE.lon)
100 andreas 2297
	      posSE.lon = SEMI2DEG(point->posn.lon);
2298
 
132 andreas 2299
	   i = point->time + 1;
157 andreas 2300
	   Data = true;
100 andreas 2301
	}
104 andreas 2302
 
2303
	coordW = (posNW.lon > posSE.lon) ? posNW.lon - posSE.lon : posSE.lon - posNW.lon;
2304
	coordH = (posNW.lat > posSE.lat) ? posNW.lat - posSE.lat : posSE.lat - posNW.lat;
109 andreas 2305
	meterW = ds.earth_distance(posNW.lat, posNW.lon, posNW.lat, posSE.lon);
104 andreas 2306
 
2307
	// define the ticks to translate the GPS coordinates into pixels.
2308
	// The track should be centered and we have to calculate the
2309
	// rectangular within we draw the track.
152 andreas 2310
	if (coordW < coordH)
100 andreas 2311
	{
152 andreas 2312
	   tick = (double)width / coordW + (double)zoom;
2313
 
2314
	   if ((tick * coordH) > height)
109 andreas 2315
	      tick = (double)height / coordH + (double)zoom;
100 andreas 2316
	}
2317
	else
2318
	{
152 andreas 2319
	   tick = (double)height / coordH + (double)zoom;
2320
 
2321
	   if ((tick * coordW) > width)
109 andreas 2322
	      tick = (double)width / coordW + (double)zoom;
100 andreas 2323
	}
104 andreas 2324
 
156 andreas 2325
	left = width - (width - tick * coordW) / 2;
152 andreas 2326
	top = (height - tick * coordH) / 2;
2327
 
132 andreas 2328
	a = tick * coordW;
156 andreas 2329
 
2330
	if (Units == 0)
2331
	   dist = meterW / a;			// Meters
2332
	else
2333
	   dist = meterW * 1.609344 / a;	// 1/1000 mile (5.28 feet)
2334
 
155 andreas 2335
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
159 andreas 2336
	geoRect.llat = 0.0;
2337
	geoRect.llon = 0.0;
2338
	geoRect.rlat = 0.0;
2339
	geoRect.rlon = 0.0;
158 andreas 2340
	geoRect.width = width;
2341
	geoRect.height = height;
146 andreas 2342
	/*
2343
	 * If we have a map file, we try to read it and if successfull,
2344
	 * we should get a map painted.
154 andreas 2345
	 *
2346
	 * Currently only WMS-Server is supported, allthough GDAL allows
2347
	 * several other formats too.
146 andreas 2348
	 */
157 andreas 2349
	if (!MAP.isEmpty() && Data)
146 andreas 2350
	{
158 andreas 2351
	bool writeTag = true;
2352
	double mtx, mty;
2353
	double vx, vy;
152 andreas 2354
 
158 andreas 2355
	   xOff = yOff = 0;
2356
	   posRXY.lon = posNW.lon + (width - left + oldTransX) / tick;
2357
	   posLXY.lat = posNW.lat + (top + oldTransY) / tick;
2358
	   posLXY.lon = posSE.lon - (left - a - oldTransX) / tick;
2359
	   posRXY.lat = posSE.lat - (height - top - (tick * coordH) - oldTransY) / tick;
159 andreas 2360
	   geoRect.llat = posLXY.lat;
2361
	   geoRect.llon = posLXY.lon;
2362
	   geoRect.rlat = posRXY.lat;
2363
	   geoRect.rlon = posRXY.lon;
158 andreas 2364
	   // width and height of map in meters
2365
	   mtx = ds.earth_distance(posRXY.lat, posRXY.lon, posRXY.lat, posLXY.lon);
2366
	   mty = ds.earth_distance(posRXY.lat, posRXY.lon, posLXY.lat, posRXY.lon);
157 andreas 2367
 
158 andreas 2368
	   // factor to correct the map, in case we use a WMS server
2369
	   if (MapType == MPT_WMS)
2370
	   {
2371
	      vx = (posRXY.lon - posLXY.lon) / mtx * CorrX;
2372
	      vy = (posRXY.lat - posLXY.lat) / mty * CorrY;
2373
	      posRXY.lon += vx;
2374
	      posRXY.lat += vy;
2375
	      posLXY.lon += vx;
2376
	      posLXY.lat += vy;
2377
	   }
2378
 
154 andreas 2379
	   /*
158 andreas 2380
	    * Write a control file for GDAL, if we use a WMS server.
2381
	    * Warp an image if we use PNG or BMP or GIF.
2382
	    * Warp a region if we use TIFF
154 andreas 2383
	    */
158 andreas 2384
	   if (MapType == MPT_WMS)
2385
	      writeTag = writeWMSTag(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat, width, height);
2386
 
159 andreas 2387
	   if (MapType == MPT_GIF || MapType == MPT_BMP || MapType == MPT_PNG ||
2388
	       MapType == MPT_SGI || MapType == MPT_TIF)
158 andreas 2389
	      writeTag = warpImage(MAP, &fName);
2390
 
2391
	   if (writeTag)
151 andreas 2392
	   {
158 andreas 2393
	      if (MapType != MPT_SHP && (poDataset = (GDALDataset *)GDALOpen (fName.ascii(), GA_ReadOnly)) != NULL)
151 andreas 2394
	      {
2395
		 QPixmap bild;
2396
		 int nRasterCount = poDataset->GetRasterCount();
2397
		 int nXBlock, nYBlock;
154 andreas 2398
		 GDALColorTable *pCT, *pCTb, *pCTr, *pCTg, *pCTa;
146 andreas 2399
 
151 andreas 2400
		 int             bGotMin, bGotMax;
2401
		 int		 tTypeLen, tColor, tColorEntrys;
2402
		 GDALDataType    tRasterType;
2403
		 double          adfMinMax[2];
2404
 
154 andreas 2405
		 pafScanlineRed = pafScanlineGreen = pafScanlineBlue = pafScanlineAlpha = 0;
152 andreas 2406
 
154 andreas 2407
		 /*
2408
		  * Read every raster band.
2409
		  *
2410
		  * If we get 3 raster bands, the image is a 24 bit image.
2411
		  * If we get 4 raster bands, the image is probably a 24 bit
2412
		  * image with an alpha channel. Currently the alpha channel
2413
		  * is ignored!
2414
		  * If we have 1 raster band, the image is 8 bit monochrom.
2415
		  * Otherwise the image is undefined and the results are also.
2416
		  */
151 andreas 2417
		 for (a = 1; a <= nRasterCount; a++)
2418
		 {
2419
		    poBand = poDataset->GetRasterBand (a);
2420
		    poBand->GetBlockSize (&nXBlock, &nYBlock);
2421
		    nXSize = poBand->GetXSize();
2422
		    nYSize = poBand->GetYSize();
2423
		    tRasterType = poBand->GetRasterDataType ();
2424
		    tTypeLen = GDALGetDataTypeSize (tRasterType) / 8;	// We need Bytes not Bits!
2425
		    tColor = poBand->GetColorInterpretation ();
2426
 
2427
		    adfMinMax[0] = poBand->GetMinimum (&bGotMin);
2428
		    adfMinMax[1] = poBand->GetMaximum (&bGotMax);
2429
 
2430
		    if (!(bGotMin && bGotMax))
2431
		       GDALComputeRasterMinMax ((GDALRasterBandH)poBand, TRUE, adfMinMax);
2432
 
152 andreas 2433
		    if ((pCT = poBand->GetColorTable()) != NULL)
151 andreas 2434
		       tColorEntrys = poBand->GetColorTable()->GetColorEntryCount();
2435
 
2436
		    switch (a)
2437
		    {
152 andreas 2438
		       case 1: pafScanlineRed   = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineRed; pCTr = pCT; break;
2439
		       case 2: pafScanlineGreen = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineGreen; pCTg = pCT; break;
2440
		       case 3: pafScanlineBlue  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineBlue; pCTb = pCT; break;
154 andreas 2441
		       case 4: pafScanlineAlpha  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineAlpha; pCTa = pCT; break;
151 andreas 2442
		    }
2443
 
152 andreas 2444
		    memset (pafScanline, 0, tTypeLen * nXSize * nYSize);
151 andreas 2445
 
154 andreas 2446
		    /*
158 andreas 2447
		     * Get the image (from the server) and put the tiles together.
154 andreas 2448
		     *
2449
		     * The function reads only one raster band. This is,
2450
		     * because the function is called for every raster band and
2451
		     * every raster band is stored into a separate array.
2452
		     */
152 andreas 2453
		    if (poBand->RasterIO (GF_Read, 0, 0, nXSize, nYSize, pafScanline, nXSize, nYSize, tRasterType, 0, 0) == CE_Failure)
2454
		    {
151 andreas 2455
		       KMessageBox::error(this, i18n("Error reading a raster band!"));
152 andreas 2456
		       Fgeo = false;
2457
		       break;
2458
		    }
2459
		    else
2460
		       Fgeo = true;
151 andreas 2461
		 }
2462
 
154 andreas 2463
		 /*
2464
		  * Only if Fgeo is TRUE, we've read successfully all raster
2465
		  * bands. Now we have to put the bands together to get
2466
		  * an image.
2467
		  */
152 andreas 2468
		 if (Fgeo)
2469
		 {
2470
		 unsigned char *pCombinedBytes = new unsigned char[(tTypeLen * nXSize * nYSize * nRasterCount)];
2471
		 unsigned char *ptr_dest, *ptr_src;
2472
		 int j;
151 andreas 2473
 
154 andreas 2474
		    /*
2475
		     * We need two nested loops to set the pixels in the wanted
2476
		     * order.
2477
		     */
152 andreas 2478
		    for (a = 0, j = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount, j++)
151 andreas 2479
		    {
152 andreas 2480
		       int k = a;
2481
 
2482
		       for (int m = nRasterCount - 1; m >= 0; m--, k++)
2483
		       {
2484
		       unsigned char *pBytes;
2485
 
2486
			  switch (m)
2487
			  {
154 andreas 2488
			     case 3: pBytes = pafScanlineAlpha; pCT = pCTa; break;
152 andreas 2489
			     case 2: pBytes = pafScanlineBlue; pCT = pCTb; break;
2490
			     case 1: pBytes = pafScanlineGreen; pCT = pCTg; break;
2491
			     default: pBytes = pafScanlineRed; pCT = pCTr;
2492
			  }
2493
 
2494
			  ptr_dest = pCombinedBytes + k;
2495
			  unsigned char b = pBytes[j];
2496
 
154 andreas 2497
			  /*
2498
			   * If we have a color table, the pixels are pointers
2499
			   * to the color table. We need to convert them into
2500
			   * 24 bit pixels plus an optional alpha channel.
2501
			   */
152 andreas 2502
			  if (pCT != NULL)
2503
			  {
2504
			     GDALColorEntry ce;
2505
			     unsigned int c = (unsigned int)b;
2506
			     c = pCT->GetColorEntryAsRGB (c, &ce);
2507
 
2508
			     if  (m == 0) c = ce.c1;
2509
			     if  (m == 1) c = ce.c2;
2510
			     if  (m == 2) c = ce.c3;
154 andreas 2511
			     if  (m == 3) c = ce.c4;
152 andreas 2512
 
2513
			     b = (unsigned char)c;
2514
			  }
2515
 
2516
			  ptr_src = &b;
2517
			  memcpy (ptr_dest, ptr_src, 1);
2518
		       }
151 andreas 2519
		    }
152 andreas 2520
 
2521
		    x1 = y1 = 0;
2522
 
154 andreas 2523
		    /*
2524
		     * The following loop is QT specific! It sets the pixels
2525
		     * of the raw image, pixel by pixel. This may be slow, but
2526
		     * everything else didn't work :-(
2527
		     *
2528
		     * FIXME: We need a more effective routine to put the
158 andreas 2529
		     *        raw image into QT's "painter" class.
154 andreas 2530
		     */
2531
		    for (a = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount)
152 andreas 2532
		    {
158 andreas 2533
		       if (x1 < width && y1 < height)
2534
		       {
2535
			  if (nRasterCount == 3)
2536
			     paint.setPen (QPen(QColor((int)pCombinedBytes[a+2], (int)pCombinedBytes[a+1], (int)pCombinedBytes[a]), QPen::SolidLine));
2537
			  else if (nRasterCount > 3)
159 andreas 2538
			     paint.setPen (QPen(QColor(qRgba((int)pCombinedBytes[a+3], (int)pCombinedBytes[a+2], (int)pCombinedBytes[a+1], (int)pCombinedBytes[a])), QPen::SolidLine));
158 andreas 2539
			  else if (nRasterCount == 2)
2540
			     paint.setPen (QPen(QColor((int)pCombinedBytes[a+1], (int)pCombinedBytes[a], (int)pCombinedBytes[a+1]), QPen::SolidLine));
2541
			  else if (nRasterCount == 1)
2542
			     paint.setPen (QPen(QColor((int)pCombinedBytes[a], (int)pCombinedBytes[a], (int)pCombinedBytes[a]), QPen::SolidLine));
154 andreas 2543
 
158 andreas 2544
			  paint.drawPoint(x1, y1);
2545
		       }
2546
 
152 andreas 2547
		       x1++;
2548
 
2549
		       if (x1 >= nXSize)
2550
		       {
2551
			  x1 = 0;
2552
			  y1++;
2553
		       }
2554
		    }
2555
 
2556
		    delete pCombinedBytes;
151 andreas 2557
		 }
2558
 
152 andreas 2559
		 if (pafScanlineRed)
2560
		    delete pafScanlineRed;
151 andreas 2561
 
152 andreas 2562
		 if (pafScanlineGreen)
2563
		    delete pafScanlineGreen;
2564
 
2565
		 if (pafScanlineBlue)
2566
		    delete pafScanlineBlue;
2567
 
154 andreas 2568
		 if (pafScanlineAlpha)
2569
		    delete pafScanlineAlpha;
2570
 
152 andreas 2571
		 GDALClose (poDataset);
2572
		 poDataset = 0;
158 andreas 2573
 
2574
		 if (MAP != fName)
2575
		    unlink (fName.ascii());
151 andreas 2576
	      }
158 andreas 2577
	      else if (MapType == MPT_SHP)
2578
	      {
2579
		 QDir shpd(MAP, QString("*.shp"));
2580
 
2581
		 if (shpd.count() < 1)
2582
		 {
2583
		    KMessageBox::error(this, i18n("There is no shape file in directory ") + MAP);
2584
		    Fgeo = false;
2585
		 }
2586
		 else
2587
		 {
2588
		 OGRDataSource *poDS = 0;
165 andreas 2589
		 OGRLayer *poLy;
2590
		 OGRFeature *poFeat;
2591
		 OGRFeatureDefn *poFDefn;
2592
		 OGRFieldDefn *poFieldDefn;
2593
		 OGRGeometry *poGeometry;
2594
		 OGRPoint *poPoint;
2595
		 int nLayers, iField;
2596
		 QString sfn;
158 andreas 2597
 
165 andreas 2598
		    OGRRegisterAll ();
158 andreas 2599
		    // read all shape files and put them together
2600
		    for (a = 0; a < shpd.count(); a++)
2601
		    {
165 andreas 2602
		       sfn = MAP + shpd[a];
2603
		       poDS = OGRSFDriverRegistrar::Open(sfn.ascii(), false);
158 andreas 2604
 
2605
		       if (!poDS)
165 andreas 2606
		       {
2607
			  cerr << "Error opening the file " << sfn.ascii() << "!" << endl;
158 andreas 2608
			  break;
165 andreas 2609
		       }
158 andreas 2610
 
165 andreas 2611
		       nLayers = poDS->GetLayerCount ();
2612
 
2613
		       // Read all layers of a shape file
2614
		       for (int j = 0; j< nLayers; j++)
2615
		       {
2616
			  if ((poLy = poDS->GetLayer (j)) == NULL)
2617
			  {
2618
			     cerr << "Error getting layer " << j << "!" << endl;
2619
			     continue;
2620
			  }
2621
 
2622
			  poLy->SetSpatialFilterRect (geoRect.llon, geoRect.llat, geoRect.rlon, geoRect.rlat);
2623
 
2624
			  // Read all features of a layer and get the fields
2625
			  // of the features
2626
			  poLy->ResetReading();
2627
 
2628
			  while ((poFeat = poLy->GetNextFeature()) != NULL)
2629
			  {
2630
			     if ((poFDefn = poLy->GetLayerDefn()) == NULL)
2631
			     {
2632
			        cerr << "Error getting a layer defination!" << endl;
2633
			        continue;
2634
			     }
2635
 
2636
			     poGeometry = poFeat->GetGeometryRef();
2637
 
2638
			     if (poGeometry != NULL && wkbFlatten (poGeometry->getGeometryType()) == wkbPoint)
2639
			     {
2640
			        poPoint = (OGRPoint *) poGeometry;
2641
			        cout << "pointX: " << poPoint->getX() << ", pointY: " << poPoint->getY() << endl;
2642
			     }
2643
 
2644
			     for (iField = 0; iField < poFDefn->GetFieldCount(); iField++)
2645
			     {
2646
			        poFieldDefn = poFDefn->GetFieldDefn (iField);
2647
 
2648
				if (poFieldDefn->GetType() == OFTInteger)
2649
				   cout << "Layer: " << j << " int: " << poFeat->GetFieldAsInteger (iField) << endl;
2650
				else if (poFieldDefn->GetType() == OFTReal)
2651
				   cout << "Layer: " << j << " float: " << poFeat->GetFieldAsDouble (iField) << endl;
2652
				else if (poFieldDefn->GetType() == OFTString)
2653
				   cout << "Layer: " << j << " string: " << poFeat->GetFieldAsString (iField) << endl;
2654
				else
2655
				   cout << "Layer: " << j << " Unkn.: " << poFeat->GetFieldAsString (iField) << endl;
2656
			     }
2657
 
2658
			     cout << "----------------------------" << endl;
2659
        		  }
2660
 
2661
        		  OGRFeature::DestroyFeature (poFeat);
2662
		       }
2663
 
158 andreas 2664
		       OGRDataSource::DestroyDataSource(poDS);
2665
		    }
2666
		 }
2667
	      }
151 andreas 2668
	      else
157 andreas 2669
	      {
158 andreas 2670
		 KMessageBox::error(this, i18n("Error opening map file!"));
157 andreas 2671
		 Fgeo = false;
2672
	      }
151 andreas 2673
	   }
146 andreas 2674
	}
151 andreas 2675
#endif
154 andreas 2676
	/*
2677
	 * Here we come to draw the track. It will be drawn over the previous
2678
	 * created map image.
2679
	 */
100 andreas 2680
	// Colors and fonts
154 andreas 2681
	QColor background(220, 220, 220);		// background color
2682
	QColor red(255, 0, 0);				// mile marker
2683
	QColor black(0, 0, 0);				// Text, center of track
2684
//	QColor yellow(255, 255, 0);
2685
	QColor yellow(0x00cf, 0x00ff, 0x0000);		// color of track
100 andreas 2686
	QFont fntNormal("Helvetica");
2687
	fntNormal.setPixelSize(10);
2688
	fntNormal.setStyleHint(QFont::Helvetica);
104 andreas 2689
	QPen dot(red, 4, QPen::SolidLine);
154 andreas 2690
	QPen line(black, 2, QPen::SolidLine);
2691
	QPen yline(yellow, 5, QPen::SolidLine);
2692
	// Fill background with background colors, if there is no map.
152 andreas 2693
	if (!Fgeo)
2694
	   paint.fillRect(0, 0, width+2, height+2, background);
2695
 
156 andreas 2696
	if (Units == 0)
2697
	   fact = 1000.0;
2698
	else
2699
	   fact = 1609.344;
2700
 
109 andreas 2701
	paint.setPen(line);
2702
	paint.drawLine(10, height - 9, 10, height - 4);
156 andreas 2703
	paint.drawLine(10, height - 4, 10 + (fact / dist), height - 4);
2704
	paint.drawLine(10 + (fact / dist), height - 9, 10 + (fact / dist), height - 4);
109 andreas 2705
	paint.setFont(fntNormal);
2706
 
156 andreas 2707
	if (Units == 0)
2708
	   paint.drawText(10, height - 10, QString("1000 m"));
2709
	else
2710
	   paint.drawText(10, height - 10, QString("5280 ft"));
2711
 
100 andreas 2712
	// Draw track
132 andreas 2713
	if (mapLap)
2714
	   i = mapLap->start_time;
2715
	else
2716
	   i = 0;
2717
 
100 andreas 2718
	x1 = y1 = 0.0;
157 andreas 2719
	bool wStart = false;
104 andreas 2720
 
100 andreas 2721
	while ((point = ds.getPoint(i)) != 0)
2722
	{
132 andreas 2723
	   if (mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
2724
	      break;
2725
 
100 andreas 2726
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
2727
	   {
132 andreas 2728
	      i = point->time + 1;
100 andreas 2729
	      continue;
2730
	   }
2731
 
157 andreas 2732
	   x2 = (left + ((posNW.lon - SEMI2DEG(point->posn.lon)) * tick * -1)) + oldTransX;
2733
	   y2 = (top + ((posNW.lat - SEMI2DEG(point->posn.lat)) * tick)) + oldTransY;
100 andreas 2734
 
157 andreas 2735
	   if (!wStart && x1 != 0.0 && y1 != 0.0)
2736
	   {
2737
	      // Load the start symbol
2738
	      QPixmap qpx = QPixmap::fromMimeSource(QString("wstart.png"));
2739
	      // Find the angle of the track and turn the symbol accordingly
2740
	      // we use Pythagoras to calculate the triangle
2741
	      double xl = (x1 < x2) ? x2 - x1 : x1 - x2;
2742
	      double yl = (y1 < y2) ? y2 - y1 : y1 - y2;
2743
	      double da = fmin (xl, yl);
2744
	      double db = fmax (xl, yl);
2745
	      double zl = sqrt (pow (da, 2) + pow (db, 2));
2746
	      double angle = (asin(da / zl) / M_PIl) * 180.0;
2747
 
2748
	      angle = (angle > 45.0) ? 90.0 - angle : angle;
2749
// cout << "Winkel: " << angle << " ---- X: " << xl << ", Y: " << yl << ", Z: " << zl << ", Point (x1,y1,x2,y2): " << x1 << ", " << y1 << ", " << x2 << ", " << y2 << endl;
2750
	      if (x1 < x2 && y1 < y2)		// right, down
2751
		 angle = 90.0 + angle;
2752
	      else if (x1 > x2 && y1 < y2)	// left, down
2753
		 angle = 270.0 - angle;
2754
	      else if (x1 > x2 && y1 > y2)	// left, up
2755
		 angle = 270.0 + angle;
2756
	      else				// right, up
2757
		 angle = 90.0 - angle;
2758
// cout << "Realer Winkel: " << angle << endl;
2759
	      // Set the center of the symbol
2760
	      paint.save ();
2761
	      paint.translate (x1, y1);
2762
	      // rotate the symbol
2763
	      paint.rotate (angle);
2764
	      paint.drawPixmap (-8, -8, qpx);
2765
	      paint.restore ();
2766
	      wStart = true;
2767
	   }
2768
 
100 andreas 2769
	   if (x1 == 0.0 && y1 == 0.0)
2770
	   {
2771
	      x1 = x2;
2772
	      y1 = y2;
2773
	   }
104 andreas 2774
 
100 andreas 2775
	   paint.setPen(yline);
104 andreas 2776
	   paint.drawLine(x1, y1, x2, y2);
2777
 
156 andreas 2778
	   if ((point->distance - dist) >= fact)	// a dot at every 1000 meters or at 1 mile
104 andreas 2779
	   {
2780
	      paint.setPen(dot);
154 andreas 2781
	      paint.drawEllipse(x2-2, y2-2, 3, 3);
156 andreas 2782
	      dist = (int)(point->distance / fact) * fact;
104 andreas 2783
	   }
2784
 
100 andreas 2785
	   paint.setPen(line);
2786
	   paint.drawLine(x1, y1, x2, y2);
2787
	   x1 = x2;
2788
	   y1 = y2;
132 andreas 2789
	   i = point->time + 1;
100 andreas 2790
	}
2791
 
157 andreas 2792
	bool lastLap = false;
2793
 
2794
	if (mapLap)
2795
	   if (ds.getRunNode()->run->last_lap_index == mapLap->index)
2796
	      lastLap = true;
2797
 
2798
	if ((!mapLap || lastLap) && wStart)
2799
	{
2800
	   // load the end symbol
2801
	   QPixmap qpx = QPixmap::fromMimeSource(QString("wtarget.png"));
2802
	   paint.drawPixmap (x2, y2 - 16, qpx);
2803
	}
2804
 
100 andreas 2805
	paint.end();
2806
	imgMap->setPixmap(pmMap);
154 andreas 2807
	QApplication::restoreOverrideCursor();
100 andreas 2808
}
2809
 
88 andreas 2810
void sportwatcherWidget::showCurves()
2811
{
148 andreas 2812
	showCurves (mapLap);
2813
}
2814
 
2815
void sportwatcherWidget::showCurves(LAP *lap)
2816
{
88 andreas 2817
QPainter paint;
2818
int width, height;
218 andreas 2819
int i, secs, cuType;
88 andreas 2820
int lineHeight, margin_left, margin_right, margin_bottom;
2821
int x1, y1, x2, y2;		// Coordinates
2822
bool meter;
218 andreas 2823
double maxHeight, minHeight, maxSpeed, minSpeed;
88 andreas 2824
int maxHr, minHr, rh;
2825
POINT *point;
148 andreas 2826
RUN_NODE *rn;
2827
LAP *lp;
88 andreas 2828
double w_tick, h_tick;		// Number of pixels one "tick" has;
2829
				// This depends on the width and height
2830
				// of the image.
2831
	// First we draw a grid based on the min and max
2832
	// values detected in the function showLap(). In case
2833
	// all values are 0, we exit here.
2834
	if (min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
2835
	   return;
2836
 
218 andreas 2837
	// Look up, what curves we should draw
2838
	cuType = kcbCurveTypes->currentItem();
2839
	// Get the dimensions of the available draw area
148 andreas 2840
	width = imgProfile->width() - 2;
2841
	height = imgProfile->height();
2842
	pmProfile.resize(width, height);
88 andreas 2843
	paint.begin(&pmProfile);
2844
 
2845
	// we need a somewhat bigger area to draw our curves than
2846
	// we have with the real min and max values.
2847
	if (max_height > 0.0)
2848
	{
148 andreas 2849
	double add = (max_height - min_height) / 100.0 * 5.0;	// Percent
88 andreas 2850
 
2851
	   maxHeight = max_height + add;
2852
	   minHeight = min_height - add;
2853
 
2854
	   if (minHeight < 0.0)		// make sure, we are not too deep
2855
	      minHeight = 0.0;
2856
	}
221 andreas 2857
	else
2858
	   maxHeight = minHeight = 0.0;
88 andreas 2859
 
218 andreas 2860
	if (max_speed > 0.0)
2861
	{
2862
	double add = (max_speed - min_speed) / 100.0 * 5.0;	// Percent
2863
 
2864
	   maxSpeed = max_speed + add;
2865
	   minSpeed = min_speed - add;
2866
 
2867
	   if (minSpeed < 0.0)		// make sure, we are not too deep
2868
	      minSpeed = 0.0;
2869
	}
221 andreas 2870
	else
2871
	   maxSpeed = minSpeed = 0.0;
218 andreas 2872
 
88 andreas 2873
	if (max_hr > 0)
2874
	{
2875
	   maxHr = max_hr + 10;
2876
	   minHr = min_hr - 10;
2877
 
2878
	   if (minHr < 0)
2879
	      minHr = 0;
2880
	}
221 andreas 2881
	else
2882
	   maxHr = minHr = 0;
88 andreas 2883
 
2884
	// Define colors
148 andreas 2885
	QColor background(220, 220, 220);	// Background of graphic
2886
	QColor mark(255, 255, 255);		// Lines inside curve area
2887
	QColor hlight(180, 180, 180);		// area of current lap
2888
//	hlight.setAlpha(128);			// 50% transparent
2889
	QColor frame(0, 0, 0);			// Text and borders
2890
	QColor barcol(151, 190, 13);		// heart rate
2891
	QColor barcol2(190, 151, 13);		// height over NN
222 andreas 2892
	QColor red(220, 128, 128);		// speed
88 andreas 2893
	QColor blue(0, 0, 240);
2894
	QFont fntNormal("Helvetica");
2895
//	QFont fntBold("Helvetica", 10, QFont::Bold);
2896
	fntNormal.setPixelSize(10);
2897
	fntNormal.setStyleHint(QFont::Helvetica);
2898
//	fntBold.setPixelSize(10);
2899
//	fntBold.setStyleHint(QFont::Helvetica);
2900
	// Calculate ticks
2901
	margin_left = 52;
2902
	margin_right = 40;
2903
	margin_bottom = 12;
2904
	lineHeight = 10;
2905
	rh = height - margin_bottom - 1;
2906
 
2907
	w_tick = (double)(width - (margin_left + margin_right)) / max_time;	// 1 tick = 1 second
2908
 
222 andreas 2909
	if (cuType == 1)	// Speed and heart rate?
88 andreas 2910
	{
218 andreas 2911
	   if ((maxSpeed - minSpeed) > (double)(maxHr - minHr))
2912
	   {
222 andreas 2913
	      h_tick = (double)rh / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
218 andreas 2914
	      meter = true;
2915
	   }
2916
	   else
2917
	   {
2918
	      h_tick = (double)rh / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
2919
	      meter = false;
2920
	   }
88 andreas 2921
	}
222 andreas 2922
	else if (cuType == 2)	// Elevation and speed?
88 andreas 2923
	{
218 andreas 2924
	   if ((maxHeight - minHeight) > (double)(maxHr - minHr))
2925
	   {
2926
	      h_tick = (double)rh / (maxHeight - minHeight);		// 1 tick = 1 meter
2927
	      meter = true;
2928
	   }
2929
	   else
2930
	   {
222 andreas 2931
	      h_tick = (double)rh / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
2932
	      meter = false;
2933
	   }
2934
	}
2935
	else			// Elevation and heart rate
2936
	{
2937
	   if ((maxHeight - minHeight) > (double)(maxHr - minHr))
2938
	   {
2939
	      h_tick = (double)rh / (maxHeight - minHeight);		// 1 tick = 1 meter
2940
	      meter = true;
2941
	   }
2942
	   else
2943
	   {
218 andreas 2944
	      h_tick = (double)rh / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
2945
	      meter = false;
2946
	   }
88 andreas 2947
	}
218 andreas 2948
 
88 andreas 2949
	// Fill background with background colors
2950
	paint.fillRect(0, 0, width + 4, height + 4, background);
2951
	// Draw a grid with markers at every 10 minutes
2952
	paint.setPen(QPen(frame, 1, QPen::SolidLine));
2953
	// Bottom border line
2954
	x1 = margin_left;
2955
	y1 = height - margin_bottom;
2956
	x2 = width - margin_right;
2957
	y2 = y1;
2958
	paint.drawLine(x1, y1, x2, y2);
2959
	// Left border line
2960
	x1 = x2 = margin_left;
2961
	y1 = 2;
2962
	y2 = height - margin_bottom;
2963
	paint.drawLine(x1, y1, x2, y2);
2964
	// right border line
2965
	x1 = x2 = width - margin_right;
2966
	paint.drawLine(x1, y1, x2, y2);
148 andreas 2967
 
2968
	// Draw some darker lines to show the laps, if we have one
2969
	// and, in case we have a given lap, we fill the area.
2970
	QDateTime *qt;
2971
	QTime zeit = StartTime.time();
2972
	rn = ds.getRunNode();
2973
	paint.setPen(QPen(hlight, 1, QPen::SolidLine));
2974
 
2975
	for (i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
2976
	{
2977
	   if ((lp = ds.getLap(i)) == NULL)
2978
	      continue;
2979
 
2980
	   qt = garmin_dtime(lp->start_time);
2981
	   secs = zeit.secsTo(qt->time());
2982
	   delete qt;
2983
	   x1 = secs * w_tick + margin_left + 1;
2984
 
2985
	   if (lap && lp->start_time == lap->start_time)
2986
	      paint.fillRect(x1, 2, (int)((double)lap->total_time / 100.0 * w_tick), height - margin_bottom - 2, hlight);
2987
	   else
2988
	      paint.drawLine(x1, 2, x1, height - margin_bottom);
2989
	}
2990
 
88 andreas 2991
	// Grid vertical
2992
	paint.setPen(QPen(frame, 1, QPen::SolidLine));
2993
	paint.setFont(fntNormal);
2994
	paint.drawText(margin_left - 20, height - lineHeight, 40, lineHeight, Qt::AlignCenter, QString("00:00"));
2995
	paint.save();
2996
	paint.rotate(270);
218 andreas 2997
 
222 andreas 2998
	if (cuType == 1)
2999
	   paint.setPen(QPen(red, 1, QPen::SolidLine));
3000
	else
3001
	   paint.setPen(QPen(barcol, 1, QPen::SolidLine));
3002
 
3003
	// Information on left side
218 andreas 3004
	if (cuType == 0)
3005
	   paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Elevation (ft)" : "Elevation (m)"));
3006
	else if (cuType == 1)
3007
	   paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Speed (mph)" : "Speed (km/h)"));
3008
	else
3009
	   paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Elevation (ft)" : "Elevation (m)"));
3010
 
222 andreas 3011
	if (cuType == 2)
3012
	   paint.setPen(QPen(red, 1, QPen::SolidLine));
3013
	else
3014
	   paint.setPen(QPen(blue, 1, QPen::SolidLine));
218 andreas 3015
 
222 andreas 3016
	// Information on right side
218 andreas 3017
	if (cuType < 2)
3018
	   paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
3019
	else
3020
	   paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Speed (mph)" : "Speed (km/h)"));
3021
 
88 andreas 3022
	paint.restore();
3023
	paint.setPen(QPen(mark, 1, QPen::SolidLine));
222 andreas 3024
	// Draw the time scale on the bottom of the graphic
88 andreas 3025
	for (i = 0; (unsigned int)i < max_time; i++)
3026
	{
3027
	   if (i > 0 && !(i % 600))	// every 10 minutes
3028
	   {
3029
	      x1 = x2 = margin_left + w_tick * i;
3030
 
3031
	      if (x1 == (width - margin_right))
3032
		 continue;
3033
 
3034
	      y1 = 2;
3035
	      y2 = height - margin_bottom;
3036
	      paint.drawLine(x1, y1, x2, y2);
3037
	      QTime tm(0, 0, 0);
3038
	      tm = tm.addSecs(i);
3039
	      paint.setPen(QPen(frame, 1, QPen::SolidLine));
3040
	      paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((i >= 3600) ? "hh:mm:ss" : "mm:ss"));
3041
	      paint.setPen(QPen(mark, 1, QPen::SolidLine));
3042
	   }
3043
	}
222 andreas 3044
 
3045
	// This is the total time, with pauses included, at the lower right
3046
	// corner of the graphic.
88 andreas 3047
	QTime tm(0, 0, 0);
3048
	QString qs;
3049
	tm = tm.addSecs(max_time);
3050
	paint.setPen(QPen(frame, 1, QPen::SolidLine));
3051
	paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((max_time >= 3600) ? "hh:mm:ss" : "mm:ss"));
3052
 
222 andreas 3053
	// Draw the minimal elevation, speed and/or heart rate
218 andreas 3054
	if (max_height > 0.0 || max_speed > 0.0)
88 andreas 3055
	{
222 andreas 3056
	   // left side
218 andreas 3057
	   if (cuType == 1)
222 andreas 3058
	   {
3059
	      paint.setPen(QPen(red, 1, QPen::SolidLine));
218 andreas 3060
	      paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minSpeed));
222 andreas 3061
	   }
218 andreas 3062
	   else
222 andreas 3063
	   {
3064
	      paint.setPen(QPen(barcol, 1, QPen::SolidLine));
218 andreas 3065
	      paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? minHeight / 0.304 : minHeight));
222 andreas 3066
	   }
88 andreas 3067
	}
3068
 
222 andreas 3069
	if (max_hr > 0 || max_speed > 0.0)
88 andreas 3070
	{
222 andreas 3071
	   // right side
3072
	   if (cuType == 2)
3073
	   {
3074
	      paint.setPen(QPen(red, 1, QPen::SolidLine));
3075
	      paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", minSpeed));
3076
	   }
3077
	   else
3078
	   {
3079
	      paint.setPen(QPen(blue, 1, QPen::SolidLine));
3080
	      paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
3081
	   }
88 andreas 3082
	}
3083
 
3084
	paint.setPen(QPen(mark, 1, QPen::SolidLine));
3085
 
3086
	// Grid horizontal
218 andreas 3087
	int factor = 0;
3088
	int target = 0;
3089
 
222 andreas 3090
	if (cuType == 0)	// Elevation and heart rate
218 andreas 3091
	{
222 andreas 3092
	   factor = (meter) ? (maxHeight - minHeight) / (rh / 12) : (maxHr - minHr) / (rh / 12);
3093
	   target = (meter) ? (int)(maxHeight - minHeight) : (maxHr - minHr);
3094
	}
3095
	else if (cuType == 1)	// Speed and heart rate
3096
	{
218 andreas 3097
	   factor = (meter) ? (maxSpeed - minSpeed) / (rh / 12) : (maxHr - minHr) / (rh / 12);
3098
	   target = (meter) ? (int)(maxSpeed - minSpeed) : (maxHr - minHr);
3099
	}
222 andreas 3100
	else			// Elevation and speed
218 andreas 3101
	{
222 andreas 3102
	   factor = (meter) ? (maxHeight - minHeight) / (rh /12) : (maxSpeed - minSpeed) / (rh / 12);
3103
	   target = (meter) ? (int)(maxHeight - minHeight) : (int)(maxSpeed - minSpeed);
218 andreas 3104
	}
3105
 
222 andreas 3106
	// To prevent a division by zero error, we check the <factor>
3107
	if (factor == 0)
3108
	   factor = 1;
3109
 
3110
	// Beside the horizontal part of the grid, we draw the scale on the
3111
	// left and the right side.
88 andreas 3112
	int oldy = height;
3113
 
3114
	for (i = 0; i < target; i++)
3115
	{
3116
	   if (i > 0 && !(i % factor))
3117
	   {
3118
	      x1 = margin_left + 1;
3119
	      x2 = width - margin_right - 1;
3120
	      y1 = y2 = rh - h_tick * i;
3121
 
3122
	      if (y1 < 12)
3123
		 break;
3124
 
3125
	      paint.drawLine(x1, y1, x2, y2);
3126
 
3127
	      if (y1 < (oldy - lineHeight))
3128
	      {
3129
		 if (meter)
3130
		 {
3131
		    paint.setPen(QPen(barcol, 1, QPen::SolidLine));
222 andreas 3132
		    // left side
218 andreas 3133
		    if (cuType == 1)
222 andreas 3134
		    {
3135
		       paint.setPen(QPen(red, 1, QPen::SolidLine));
3136
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + i));
3137
		    }
218 andreas 3138
		    else
3139
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? (minHeight + i) / 0.304 : minHeight + i));
3140
 
222 andreas 3141
		    // right side
3142
		    if (maxHr > 0 && cuType != 2)
88 andreas 3143
		    {
3144
		       double hrscale = (double)(maxHr - minHr) / (double)target;
3145
		       paint.setPen(QPen(blue, 1, QPen::SolidLine));
3146
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", (int)((double)minHr + hrscale * (double)i)));
3147
		    }
222 andreas 3148
		    else
3149
		    {
3150
		       double spscale = (maxSpeed - minSpeed) / (double)target;
3151
 
3152
		       if (cuType == 2)
3153
			  paint.setPen(QPen(red, 1, QPen::SolidLine));
3154
		       else
3155
			  paint.setPen(QPen(blue, 1, QPen::SolidLine));
3156
 
3157
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", (minSpeed + spscale * (double)i)));
3158
		    }
88 andreas 3159
		 }
3160
		 else
3161
		 {
222 andreas 3162
		    // right side
3163
		    if (cuType == 2)
3164
		    {
3165
		       paint.setPen(QPen(red, 1, QPen::SolidLine));
3166
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", minSpeed + i));
3167
		    }
3168
		    else
3169
		    {
3170
		       paint.setPen(QPen(blue, 1, QPen::SolidLine));
3171
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
3172
		    }
88 andreas 3173
 
222 andreas 3174
		    // left side
3175
		    if ((cuType == 0 || cuType == 2) && max_height > 0)
88 andreas 3176
		    {
3177
		       double hrscale = (maxHeight - minHeight) / (double)target;
3178
		       paint.setPen(QPen(barcol, 1, QPen::SolidLine));
3179
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minHeight + hrscale * (double)i));
3180
		    }
222 andreas 3181
		    else if (max_speed > 0 && cuType == 1)
218 andreas 3182
		    {
3183
		       double hrscale = (maxSpeed - minSpeed) / (double)target;
222 andreas 3184
		       paint.setPen(QPen(red, 1, QPen::SolidLine));
3185
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + hrscale * (double)i));
218 andreas 3186
		    }
88 andreas 3187
		}
3188
 
3189
		 paint.setPen(QPen(mark, 1, QPen::SolidLine));
3190
		 oldy = y1;
3191
	      }
3192
	   }
3193
	}
3194
 
168 andreas 3195
	// To make our graphics more beautiful, we draw lines for the
88 andreas 3196
	// heart rate limits and the average heart rate.
222 andreas 3197
	if (max_hr > 0 && cuType != 2)
88 andreas 3198
	{
3199
	int ay1, ay2, ay3, ay4, ay5;
3200
 
3201
	   x1 = margin_left + 1;
3202
	   x2 = width - margin_right - 1;
3203
 
3204
	   if (meter)
3205
	   {
3206
	      double hrscale = rh / (double)(maxHr - minHr);
3207
	      ay1 = (double)rh - (double)(lower1 - minHr) * hrscale;
3208
	      ay2 = (double)rh - (double)(lower2 - minHr) * hrscale;
3209
	      ay3 = (double)rh - (double)(lower3 - minHr) * hrscale;
3210
	      ay4 = (double)rh - (double)(upper3 - minHr) * hrscale;
3211
	      ay5 = (double)rh - (double)(avg_hr - minHr) * hrscale;
3212
	   }
3213
	   else
3214
	   {
3215
	      ay1 = (double)rh - (double)(lower1 - minHr) * h_tick;
3216
	      ay2 = (double)rh - (double)(lower2 - minHr) * h_tick;
3217
	      ay3 = (double)rh - (double)(lower3 - minHr) * h_tick;
3218
	      ay4 = (double)rh - (double)(upper3 - minHr) * h_tick;
3219
	      ay5 = (double)rh - (double)(avg_hr - minHr) * h_tick;
3220
	   }
3221
 
3222
	   paint.setPen(QPen(barcol2, 1, QPen::DashLine));	// color for limits
3223
 
3224
	   if (lower1 > minHr && lower1 < maxHr)
3225
	      paint.drawLine(x1, ay1, x2, ay1);
3226
 
3227
	   if (lower2 > minHr && lower2 < maxHr)
3228
	      paint.drawLine(x1, ay2, x2, ay2);
3229
 
3230
	   if (lower3 > minHr && lower3 < maxHr)
3231
	      paint.drawLine(x1, ay3, x2, ay3);
3232
 
3233
	   if (upper3 > minHr && upper3 < maxHr)
3234
	      paint.drawLine(x1, ay4, x2, ay4);
3235
 
3236
	   paint.setPen(QPen(red, 1, QPen::DashDotLine));	// color for average heart rate
3237
 
3238
	   if (avg_hr > minHr && avg_hr < maxHr)
3239
	      paint.drawLine(x1, ay5, x2, ay5);
3240
	}
3241
 
3242
	// Now we have a grid and we've done the scaling.
3243
	// This is the point where we draw the curves itself.
223 andreas 3244
	// We use different colors to draw the lines:
3245
	//
3246
	// Green: Elevation
3247
	// Red:   Speed
3248
	// Blue   Heart Rate
3249
	//
88 andreas 3250
	x1 = x2 = y1 = y2 = 0;
148 andreas 3251
	int hy1, hy2, hx1, hx2;
222 andreas 3252
	int sy1, sy2, sx1, sx2;
88 andreas 3253
	hy1 = hy2 = hx1 = hx2 = 0;
222 andreas 3254
	sy1 = sy2 = sx1 = sx2 = 0;
169 andreas 3255
	int hEc = 0;
3256
	i = 0;
3257
	AVGHEIGHT *avgHakt, *avgHfirst, *avgHlast, *avgHeight = 0;
170 andreas 3258
	avgHfirst = avgHlast = 0;
169 andreas 3259
	// To even the surface lines, we store every altitude in the
3260
	// memory, by building a chain. Then, if the user has set in the
3261
	// settings (Contour == true), we will even the line by calculating
3262
	// the average of 10 messure points and setting every value to the
3263
	// average, who is up or down more than 2 meters from the average.
3264
	while ((point = ds.getPoint(i)) != 0)
3265
	{
3266
	   if (point->alt > 20000.0 || point->alt < -1000.0)
3267
	   {
3268
	      i++;
3269
	      continue;
3270
	   }
168 andreas 3271
 
169 andreas 3272
	   if (!avgHeight)
3273
	   {
3274
	      avgHeight = new AVGHEIGHT;
3275
	      avgHeight->alt = point->alt;
3276
	      avgHeight->pos = hEc;
3277
	      avgHeight->prev = 0;
3278
	      avgHeight->next = 0;
3279
	      avgHakt = avgHeight;
3280
	      avgHfirst = avgHeight;
3281
	   }
3282
	   else
3283
	   {
3284
	      avgHakt = new AVGHEIGHT;
3285
	      avgHakt->alt = point->alt;
3286
	      avgHakt->pos = hEc;
3287
	      avgHakt->next = 0;
3288
	      avgHakt->prev = avgHeight;
3289
	      avgHeight->next = avgHakt;
3290
	      avgHeight = avgHakt;
3291
	   }
3292
 
3293
	   // FIXME: Currently we can not draw below 0 meters, because the
3294
	   // base line is always 0!
222 andreas 3295
	   if (avgHakt->alt < minHeight)
3296
	      avgHakt->alt = minHeight;
169 andreas 3297
 
3298
	   hEc++;
3299
	   i++;
3300
	}
3301
 
3302
	avgHlast = avgHeight;
3303
	// If wanted, even the lines
218 andreas 3304
	if (Contour && hEc > 0 && cuType != 0)
169 andreas 3305
	{
213 andreas 3306
	double alt[100], avg, avg1, avg2, avg3, avg4;
3307
	int a, pos;
169 andreas 3308
 
213 andreas 3309
	   for (i = 0; i < (hEc + 100); i += 100)
169 andreas 3310
	   {
213 andreas 3311
	      avg = avg1 = avg2 = avg3 = avg4 = 0.0;
3312
	      pos = 0;
169 andreas 3313
 
213 andreas 3314
	      for (a = 0; a < 100; a++)
169 andreas 3315
	      {
3316
		 alt[a] = getAvgAlt(avgHfirst, i + a);
3317
		 avg += alt[a];
213 andreas 3318
 
3319
		 if (a < 25)
3320
		    avg1 += alt[a];
3321
		 else if (a < 50)
3322
		    avg2 += alt[a];
3323
		 else if (a < 75)
3324
		    avg3 += alt[a];
3325
		 else
3326
		    avg4 += alt[a];
169 andreas 3327
	      }
3328
 
213 andreas 3329
	      if ((i + 100) >= hEc)
169 andreas 3330
		 avg /= (double)(hEc - i) + 1.0;
3331
	      else
213 andreas 3332
		 avg /= 100.0;
169 andreas 3333
 
213 andreas 3334
	      for (a = 0; a < 100; a++)
169 andreas 3335
	      {
3336
		 if ((avgHakt = getAvgPtr(avgHfirst, i + a)) != 0)
3337
		 {
3338
		    if ((avgHakt->alt - avg) > 2 || (avgHakt->alt - avg) < -2)
3339
		       avgHakt->alt = avg;
3340
		 }
3341
	      }
3342
	   }
3343
	}
3344
 
222 andreas 3345
	// plot the elevation, speed and/or heart rate. Depends on <cuType>)
168 andreas 3346
	i = 0;
169 andreas 3347
	int j = 0;
218 andreas 3348
	POINT *oldPoint = 0;
222 andreas 3349
	double speed = 0.0;	// calculated speed
3350
	bool pause = false;	// filter pause out of speed
3351
	unsigned long t1, t2;
3352
	t1 = t2 = 0;
218 andreas 3353
 
88 andreas 3354
	while ((point = ds.getPoint(i)) != 0)
3355
	{
218 andreas 3356
	   if (!oldPoint)
3357
	      oldPoint = point;
3358
 
88 andreas 3359
	   // calculate the y position based on the time
3360
	   qt = garmin_dtime(point->time);
3361
	   secs = zeit.secsTo(qt->time());
3362
	   delete qt;
3363
	   x2 = secs * w_tick + margin_left + 1;
3364
	   hx2 = x2;
222 andreas 3365
	   sx2 = x2;
88 andreas 3366
 
3367
	   if (x1 == 0)
3368
	      x1 = x2;
3369
 
3370
	   if (hx1 == 0)
3371
	      hx1 = hx2;
3372
 
222 andreas 3373
	   if (sx1 == 0)
3374
	      sx1 = sx2;
3375
 
3376
	   // The speed is not very exact, because smallest time is
3377
	   // one second. This allows a maximum error of 99 hundredths
3378
	   // of a second, what is very close to one second. Because of
3379
	   // this, speed seems to hop for every messure point. This
3380
	   // looks ugly, but currently I don't know how to make it
3381
	   // better.
3382
	   if (cuType == 1 || cuType == 2)	// Draw speed?
88 andreas 3383
	   {
218 andreas 3384
	      double dist;
3385
	      double sc;
168 andreas 3386
 
222 andreas 3387
	      if (!pause && point->distance > 1.0e10)
218 andreas 3388
	      {
222 andreas 3389
		 pause = true;
3390
		 t1 = point->time;
3391
	      }
3392
	      else if (pause)
3393
	      {
3394
		 pause = false;
3395
		 t2 = point->time;
3396
		 i += 2;
3397
		 continue;
3398
	      }
3399
 
3400
	      if (point->distance >= 0.1 && point->distance < 1.0e10)
3401
	      {
218 andreas 3402
		 dist = point->distance - oldPoint->distance;
3403
		 sc = point->time - oldPoint->time;
223 andreas 3404
		 LAP *runde = ds.getLapT (point->time);
222 andreas 3405
 
3406
		 if (t2 > t1)
3407
		 {
3408
		    sc -= t2 - t1;
3409
 
3410
		    if (sc <= 0.0)
3411
		       sc = 1.0;		// at least 1 second!
3412
		 }
3413
 
218 andreas 3414
		 speed = (dist / sc) * 3.6;
168 andreas 3415
 
223 andreas 3416
		 if (runde && runde->max_speed > 0.0 && speed > (runde->max_speed * 3.6))
3417
		    speed = runde->max_speed * 3.6;
3418
 
218 andreas 3419
		 if (Units == 1)
3420
		    speed /= 1.609344;
3421
 
222 andreas 3422
		 if (speed < minSpeed || speed > 400.0)
3423
		    speed = minSpeed;
218 andreas 3424
 
222 andreas 3425
		 if ((meter && cuType == 1) || (!meter && cuType == 2))
218 andreas 3426
		    y2 = (double)rh - (speed - minSpeed) * h_tick;
3427
		 else
3428
		 {
3429
		    double hrscale = rh / (maxSpeed - minSpeed);
3430
		    y2 = (double)rh - (speed - minSpeed) * hrscale;
3431
		 }
3432
 
3433
		 if (y1 == 0)
3434
		    y1 = y2;
3435
 
222 andreas 3436
		 paint.setPen(QPen(red, 1, QPen::SolidLine));
218 andreas 3437
		 paint.drawLine(x1, y1, x2, y2);
3438
		 y1 = y2;
3439
		 x1 = x2;
222 andreas 3440
		 t1 = t2 = 0;
3441
		 oldPoint = point;
218 andreas 3442
	      }
3443
	   }
222 andreas 3444
 
3445
	   if (cuType == 0 || cuType == 2)		// Draw elevation?
218 andreas 3446
	   {
3447
	      if (point->alt < 20000.0 && point->alt > -1000.0)
88 andreas 3448
	      {
218 andreas 3449
	      double alt = getAvgAlt(avgHfirst, j);
88 andreas 3450
 
218 andreas 3451
		 j++;
3452
 
3453
		 if (meter)
222 andreas 3454
		    sy2 = (double)rh - (alt - minHeight) * h_tick;
218 andreas 3455
		 else
3456
		 {
3457
		    double hrscale = rh / (maxHeight - minHeight);
222 andreas 3458
		    sy2 = (double)rh - (alt - minHeight) * hrscale;
218 andreas 3459
		 }
3460
 
222 andreas 3461
		 if (sy1 == 0)
3462
		    sy1 = sy2;
218 andreas 3463
 
3464
		 paint.setPen(QPen(barcol, 1, QPen::SolidLine));
222 andreas 3465
		 paint.drawLine(sx1, sy1, sx2, sy2);
3466
		 sy1 = sy2;
3467
		 sx1 = sx2;
218 andreas 3468
	      }
88 andreas 3469
	   }
3470
 
222 andreas 3471
	   if (point->heart_rate > 0 && cuType < 2)	// Draw heart rate?
88 andreas 3472
	   {
3473
	      if (meter)
3474
	      {
3475
		 double hrscale = rh / (double)(maxHr - minHr);
3476
		 hy2 = (double)rh - (double)(point->heart_rate - minHr) * hrscale;
3477
	      }
3478
	      else
3479
		 hy2 = (double)rh - (double)(point->heart_rate - minHr) * h_tick;
3480
 
3481
	      if (hy1 == 0)
3482
		 hy1 = hy2;
3483
 
3484
	      paint.setPen(QPen(blue, 1, QPen::SolidLine));
3485
	      paint.drawLine(hx1, hy1, hx2, hy2);
3486
	      hy1 = hy2;
3487
	      hx1 = hx2;
3488
	   }
3489
 
3490
	   i++;
3491
	}
3492
 
3493
	paint.end();
3494
	imgProfile->setPixmap(pmProfile);
3495
 
169 andreas 3496
	// free the chain of altitudes
3497
	avgHakt = avgHfirst;
3498
 
3499
	while (avgHakt)
3500
	{
3501
	   avgHeight = avgHakt->next;
3502
	   delete avgHakt;
3503
	   avgHakt = avgHeight;
3504
	}
3505
 
88 andreas 3506
//	if (bProfile)
3507
//	   bitBlt(imgProfile, 0, 0, &pmProfile);
3508
}
3509
 
169 andreas 3510
double sportwatcherWidget::getAvgAlt(AVGHEIGHT *avgHeight, int pos)
3511
{
3512
AVGHEIGHT *akt;
3513
 
170 andreas 3514
	if (!avgHeight)
3515
	   return 0.0;
3516
 
169 andreas 3517
	akt = avgHeight;
3518
 
3519
	while (akt)
3520
	{
3521
	   if (akt->pos == pos)
3522
	      return akt->alt;
3523
 
3524
	   akt = akt->next;
3525
	}
3526
 
3527
	return 0.0;
3528
}
3529
 
3530
AVGHEIGHT *sportwatcherWidget::getAvgPtr(AVGHEIGHT *avgHeight, int pos)
3531
{
3532
AVGHEIGHT *akt;
3533
 
3534
	akt = avgHeight;
3535
 
3536
	while (akt)
3537
	{
3538
	   if (akt->pos == pos)
3539
	      return akt;
3540
 
3541
	   akt = akt->next;
3542
	}
3543
 
3544
	return 0;
3545
}
3546
 
88 andreas 3547
void sportwatcherWidget::resizeEvent(QResizeEvent */* *e */)
3548
{
132 andreas 3549
	showTrack(zfactor);
88 andreas 3550
	showCurves();
3551
}
3552
 
3553
void sportwatcherWidget::paintEvent(QPaintEvent */* *e */)
3554
{
132 andreas 3555
	showTrack(zfactor);
88 andreas 3556
	showCurves();
3557
}
3558
 
132 andreas 3559
void sportwatcherWidget::mouseMoveEvent(QMouseEvent *e)
3560
{
3561
QPoint pos(0, 0);
3562
QPoint ev = imgMap->mapFrom(this, e->pos());
3563
static QRect coord;
88 andreas 3564
 
132 andreas 3565
	if (!stateHand)
3566
	   return;
3567
 
3568
	if (ev.x() >= pos.x() &&
3569
	    ev.y() >= pos.y() &&
3570
	    ev.x() <= (pos.x() + imgMap->geometry().width()) &&
3571
	    ev.y() <= (pos.y() + imgMap->geometry().height()))
3572
	{
3573
	   if (lmbPressed == 1)
3574
	   {
3575
	      coord.setCoords(ev.x(), ev.y(), 0, 0);
3576
	      lmbPressed = 0;
3577
	   }
3578
	   else
3579
	   {
3580
	      coord.setRight(ev.x());
3581
	      coord.setBottom(ev.y());
3582
	   }
3583
 
3584
	   if (lmbPressed == 2)
3585
	   {
3586
	      showTrack(zfactor, coord, mapLap);
3587
	      lmbPressed = 0;
3588
	   }
3589
	}
3590
}
3591
 
3592
void sportwatcherWidget::mousePressEvent(QMouseEvent *e)
3593
{
3594
	if (stateHand && e->button() == QMouseEvent::LeftButton)
3595
	   lmbPressed = 1;	// Left Mouse Button is pressed
3596
	else if (stateHand)
3597
	   lmbPressed = 0;	// Wrong button is pressed
3598
 
3599
	if (stateGlas)
3600
	{
3601
	   if (e->button() == QMouseEvent::LeftButton)
3602
	      btGlasPlusSlot();
3603
	   else if (e->button() == QMouseEvent::RightButton)
3604
	      btGlasMinusSlot();
3605
	}
3606
}
3607
 
3608
void sportwatcherWidget::mouseReleaseEvent(QMouseEvent *e)
3609
{
3610
	if (stateHand && e->button() == QMouseEvent::LeftButton)
3611
	{
3612
	   lmbPressed = 2;	// Left Mouse Button was released
3613
	   mouseMoveEvent(e);
3614
	}
3615
}
3616
 
88 andreas 3617
/*
3618
 * Private functions to help decode the data
3619
 */
3620
QDateTime *sportwatcherWidget::garmin_dtime (uint32 t)
3621
{
3622
time_t     tval;
3623
struct tm  tmval;
3624
QTime ti;
3625
QDate dt;
3626
QDateTime *qt;
3627
 
3628
	if (t == 0)
3629
	   return new QDateTime(QDate(1900, 1, 1), QTime(0, 0, 0, 0));
3630
 
3631
	tval = t + TIME_OFFSET;
3632
	localtime_r (&tval, &tmval);
3633
	qt = new QDateTime();
3634
	qt->setDate(QDate(tmval.tm_year+1900, tmval.tm_mon+1, tmval.tm_mday));
3635
	qt->setTime(QTime(tmval.tm_hour, tmval.tm_min, tmval.tm_sec, 0));
3636
	/* OK.  Done. */
3637
	return qt;
3638
}
3639
 
104 andreas 3640
bool sportwatcherWidget::writeTag(const QFile &fn, const QString &str, int indent)
3641
{
3642
QString qs;
3643
char *p = new char[str.length()+100];
3644
QCString qcs;
3645
int i;
88 andreas 3646
 
171 andreas 3647
	if (indent > 0)
3648
	   qs.fill(' ', indent * 3);
3649
 
104 andreas 3650
	qs.append(str);
3651
	qcs = qs.utf8();
3652
	qstrcpy(p, qcs);
3653
	i = strlen(p);
3654
 
3655
	if (write(fn.handle(), p, i) != i)
3656
	{
3657
	   delete p;
3658
	   return false;
3659
	}
3660
 
3661
	delete p;
3662
	return true;
3663
}
3664
 
155 andreas 3665
#if defined HAVE_GDAL && HAVE_LIBGDAL1_5_0
151 andreas 3666
bool sportwatcherWidget::writeWMSTag(double llat, double llon, double rlat, double rlon, int width, int height)
3667
{
3668
QFile fl(MAP);
152 andreas 3669
QString xml, s, srs, crs, styles, bSize, ext;
3670
QDir dir = QDir::home();
3671
QString path = dir.absPath();
157 andreas 3672
int item, isrs;
3673
double _llat, _llon, _rlat, _rlon;
3674
bool offline, square;
151 andreas 3675
 
3676
	if (!fl.open(IO_ReadWrite | IO_Truncate))
3677
	{
3678
	   KMessageBox::error (this, i18n("Error opening or creating the WMS tag file!\nPlease check file name and/or permissions."));
3679
	   return false;
3680
	}
3681
 
152 andreas 3682
	KSimpleConfig *cfg = new KSimpleConfig(QString("sportwatcher.rc"));
3683
	cfg->setGroup(QString("WMS"));
157 andreas 3684
	square = cfg->readBoolEntry("Square", false);
152 andreas 3685
	styles = cfg->readEntry("Styles");
3686
 
151 andreas 3687
	xml = "<GDAL_WMS>\n";
3688
	xml += "   <Service name=\"WMS\">\n";
3689
	xml += "      <Version>1.1.1</Version>\n";
152 andreas 3690
	xml += "      <ServerURL>" + cfg->readEntry("ServerURL", "http://onearth.jpl.nasa.gov/wms.cgi") + "?</serverURL>\n";
157 andreas 3691
	isrs = cfg->readNumEntry("SRS", 0);
3692
	_llon = llon;
3693
	_llat = llat;
3694
	_rlon = rlon;
3695
	_rlat = rlat;
3696
	offline = false;
152 andreas 3697
 
157 andreas 3698
	switch (isrs)
152 andreas 3699
	{
3700
	   case 0: srs = QString("EPSG:4326"); break;
157 andreas 3701
 
3702
	   case 1:
3703
	      srs = QString("EPSG:31257");
3704
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31257, width, height, square);
3705
	   break;
3706
 
3707
	   case 2:
3708
	      srs = QString("EPSG:31258");
3709
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31258, width, height, square);
3710
	   break;
3711
 
3712
	   case 3:
3713
	      srs = QString("EPSG:31259");
3714
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31259, width, height, square);
3715
	   break;
3716
 
3717
	   case 4:
3718
	      srs = QString("EPSG:31286");
3719
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31286, width, height, square);
3720
	   break;
3721
 
3722
	   case 5:
3723
	      srs = QString("EPSG:31287");
3724
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31287, width, height, square);
3725
	   break;
3726
 
3727
	   case 6:
3728
	      srs = QString("EPSG:31288");
3729
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31288, width, height, square);
3730
	   break;
3731
 
152 andreas 3732
	   default: srs = QString("EPSG:4326");
3733
	}
3734
 
3735
	xml += "      <SRS>" + srs + "</SRS>\n";
3736
	item = cfg->readNumEntry("CRS", 0);
3737
 
3738
	switch (item)
3739
	{
3740
	   case 0: crs = QString("CRS:83"); break;
157 andreas 3741
	   case 1: crs = QString("CRS:84"); break;
3742
	   case 2: crs = QString("EPSG:4326"); break;
3743
	   case 3: crs = QString("EPSG:31259"); break;
3744
	   case 4: crs = QString("EPSG:31287"); break;
152 andreas 3745
	   default: crs = QString("CRS:83"); break;
3746
	}
3747
 
3748
	xml += "      <CRS>" + crs + "</CRS>\n";
3749
	item = cfg->readNumEntry("Image", 2);
3750
	xml += "      <ImageFormat>image/";
3751
 
3752
	switch (item)
3753
	{
3754
	   case 0: xml += "gif"; ext = QString(".gif"); break;
3755
	   case 1: xml += "jpeg"; ext = QString(".jpg"); break;
3756
	   case 2: xml += "png"; ext = QString(".png"); break;
3757
	   case 3: xml += "tiff"; ext = QString(".tif"); break;
3758
	   default: xml += "png"; ext = QString(".png");
3759
	}
3760
 
3761
	xml += "</ImageFormat>\n";
3762
 
3763
	xml += "      <Layers>" + cfg->readEntry("Layer") + "</Layers>\n";
3764
 
3765
	if (!styles.isEmpty())
3766
	   xml += "      <Styles>" + styles + "</Styles>\n";
3767
 
151 andreas 3768
	xml += "      <BBoxOrder>xyXY</BBoxOrder>\n";
3769
	xml += "   </Service>\n";
3770
	xml += "   <DataWindow>\n";
157 andreas 3771
	s.sprintf ("%f", _llat);
151 andreas 3772
	xml += "      <UpperLeftX>" + s + "</UpperLeftX>\n";
157 andreas 3773
	s.sprintf ("%f", _llon);
151 andreas 3774
	xml += "      <UpperLeftY>" + s + "</UpperLeftY>\n";
157 andreas 3775
	s.sprintf ("%f", _rlat);
151 andreas 3776
	xml += "      <LowerRightX>" + s + "</LowerRightX>\n";
157 andreas 3777
	s.sprintf ("%f", _rlon);
151 andreas 3778
	xml += "      <LowerRightY>" + s + "</LowerRightY>\n";
3779
	s.sprintf ("%d", width);
3780
	xml += "      <SizeX>" + s + "</SizeX>\n";
3781
	s.sprintf ("%d", height);
3782
	xml += "      <SizeY>" + s + "</SizeY>\n";
3783
	xml += "   </DataWindow>\n";
157 andreas 3784
 
3785
/*	switch (isrs)
3786
	{
3787
	   case 0: srs = QString("EPSG:4326"); break;
3788
	   case 1: srs = QString("EPSG:31259"); break;
3789
	   case 2: srs = QString("EPSG:31286"); break;
3790
	   case 3: srs = QString("EPSG:31287"); break;
3791
	   case 4: srs = QString("EPSG:31288"); break;
3792
	   default: srs = QString("EPSG:4326");
3793
	}
3794
*/
3795
//	srs = QString("EPSG:4326");
3796
	xml += "   <Projection>" + srs + "</Projection>\n";
152 andreas 3797
	xml += "   <BandsCount>" + cfg->readEntry("Bands", "3") + "</BandsCount>\n";
3798
	item = cfg->readNumEntry("Tile", 2);
3799
 
3800
	switch (item)
3801
	{
3802
	   case 0: bSize = QString("64"); break;
3803
	   case 1: bSize = QString("128"); break;
3804
	   case 2: bSize = QString("256"); break;
3805
	   case 3: bSize = QString("512"); break;
3806
	   case 4: bSize = QString("1024"); break;
3807
	   default: bSize = QString("256");
3808
	}
3809
 
3810
	xml += "   <BlockSizeX>" + bSize + "</BlockSizeX>\n";
3811
	xml += "   <BlockSizeY>" + bSize + "</BlockSizeY>\n";
3812
	xml += "   <OverviewCount>" + cfg->readEntry("Overview", "10") + "</OverviewCount>\n";
151 andreas 3813
	xml += "   <Cache>\n";
152 andreas 3814
	xml += "      <Path>" + path + "/.gdalwmscache" + "</Path>\n";
3815
	xml += "      <Depth>" + cfg->readEntry("Depth", "2") + "</Depth>\n";
3816
	xml += "      <Extension>" + ext + "</Extension>\n";
151 andreas 3817
	xml += "   </Cache>\n";
152 andreas 3818
	QString off((cfg->readBoolEntry("Offline", false)) ? "true" : "false");
3819
	QString adv((cfg->readBoolEntry("Advice", false)) ? "true" : "false");
3820
	QString ver((cfg->readBoolEntry("Verify", true)) ? "true" : "false");
157 andreas 3821
 
3822
	if (offline)
3823
	   xml += "   <OfflineMode>true</OfflineMode>\n";
3824
	else
3825
	   xml += "   <OfflineMode>" + off + "</OfflineMode>\n";
3826
 
152 andreas 3827
	xml += "   <AdviseRead>" + adv + "</AdviseRead>\n";
3828
	xml += "   <VerifyAdviseRead>" + ver + "</VerifyAdviseRead>\n";
151 andreas 3829
	xml += "</GDAL_WMS>\n";
3830
 
3831
	write (fl.handle(), xml.ascii(), strlen (xml.ascii()));
3832
	fl.close();
152 andreas 3833
	delete cfg;
151 andreas 3834
	return true;
3835
}
3836
 
157 andreas 3837
bool sportwatcherWidget::transCoords (double *x1, double *y1, double *x2, double *y2, int code, int width, int height, bool square)
151 andreas 3838
{
157 andreas 3839
OGRSpatialReference oSourceSRS, oTargetSRS;
3840
OGRCoordinateTransformation *poCT;
3841
 
3842
	oSourceSRS.SetWellKnownGeogCS ("WGS84");
3843
	oTargetSRS.importFromEPSG(code);
3844
	poCT = OGRCreateCoordinateTransformation (&oSourceSRS, &oTargetSRS);
3845
 
3846
	if (poCT == NULL || !poCT->Transform( 1, x1, y1))
3847
	{
3848
	   KMessageBox::error(this, i18n("Translation between coordinate systems failed!"));
3849
 
3850
	   if (poCT != NULL)
3851
	      delete poCT;
3852
 
3853
	   return true;
3854
	}
3855
 
3856
	if (poCT != NULL)
3857
	{
3858
	   poCT->Transform (1, x2, y2);
3859
	   delete poCT;
3860
	}
3861
 
3862
	if (square)
3863
	{
3864
	double wdiff = (double)((long)(*x1 - *x2) / (width / 2 * 2) * (width / 2 * 2));
3865
	double hdiff = (double)((long)(*y2 - *y1) / (height / 2 * 2) * (height / 2 * 2));
3866
 
3867
	   *x2 = *x1 - wdiff; // * (double)mFactor;
3868
	   *y2 = *y1 + hdiff; // * (double)mFactor;
3869
//	   *x2 = *x1 - (double)((long)(wdiff / mFactor * mFactor));
3870
//	   *y2 = *y1 - (double)((long)(hdiff / mFactor * mFactor));
3871
/*	   wdiff = wdiff - (*x1 - *x2);
3872
	   hdiff = hdiff - (*y2 - *y1);
3873
	   *x1 -= wdiff / 2.0;
3874
	   *x2 -= wdiff / 2.0;
3875
	   *y1 += hdiff / 2.0;
3876
	   *y2 += hdiff / 2.0; */
3877
	}
3878
 
3879
	return false;
151 andreas 3880
}
3881
 
158 andreas 3882
QString *sportwatcherWidget::getProjection (int isrs, QString *srs)
3883
{
3884
	switch (isrs)
3885
	{
3886
	   case 0: *srs = QString("EPSG:4326"); break;
3887
	   case 1: *srs = QString("EPSG:31257"); break;
3888
	   case 2: *srs = QString("EPSG:31258"); break;
3889
	   case 3: *srs = QString("EPSG:31259"); break;
3890
	   case 4: *srs = QString("EPSG:31286"); break;
3891
	   case 5: *srs = QString("EPSG:31287"); break;
3892
	   case 6: *srs = QString("EPSG:31288"); break;
3893
	   default: *srs = QString("EPSG:4326");
3894
	}
3895
 
3896
	return srs;
3897
}
3898
 
3899
bool sportwatcherWidget::warpImage(QString fn, QString *fName)
3900
{
3901
GDALDatasetH  hSrcDS, hDstDS;
3902
GDALDataset *inSet, *outSet;
3903
GDALDataType eDT;
3904
GDALRasterBand *poBand;
3905
GDALDriverH hDriver;
3906
char hv0[256];
3907
int nXSize, nYSize;
3908
double adfGeoTransform[6];
3909
double oriLeftLon, oriRightLon, oriLeftLat, oriRightLat;
3910
 
159 andreas 3911
 
3912
	// Loading the user set geo coords of our source image and
3913
	// load the projection used for that image
3914
	KSimpleConfig *cfg = new KSimpleConfig(QString("sportwatcher.rc"));
3915
	cfg->setGroup(QString("ImageCoords"));
3916
	oriLeftLon = cfg->readDoubleNumEntry("LeftLon", 0.0);
3917
	oriLeftLat = cfg->readDoubleNumEntry("LeftLat", 0.0);
3918
	oriRightLon = cfg->readDoubleNumEntry("RightLon", 0.0);
3919
	oriRightLat = cfg->readDoubleNumEntry("RightLat", 0.0);
3920
	int isrs = cfg->readNumEntry("SRS", 0);
3921
 
158 andreas 3922
	// Create a temporary file name for our output file
3923
	strcpy (hv0, "/tmp/SportWatcherTIFFXXXXXX");
216 andreas 3924
	mkdtemp (&hv0[0]);
158 andreas 3925
	*fName = QString(hv0) + ".tif";
3926
 
3927
	// Open input and output files.
3928
	if ((hSrcDS = GDALOpen(fn.ascii(), GA_ReadOnly)) == NULL)
3929
	{
3930
	   KMessageBox::error(this, i18n("Error opening an image file!"));
3931
	   return false;
3932
	}
3933
 
3934
	inSet = (GDALDataset *)hSrcDS;
3935
	// Create output with same datatype as first input band.
3936
	poBand = inSet->GetRasterBand (1);
3937
	eDT = poBand->GetRasterDataType ();
3938
 
3939
	if ((hDriver = GDALGetDriverByName ("GTiff")) == NULL)
3940
	{
3941
	   KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
3942
	   GDALClose (hSrcDS);
3943
	   return false;
3944
	}
3945
 
3946
	// Get dimensions of image and set transform data
3947
	int nRasterCount = inSet->GetRasterCount();
3948
	nXSize = inSet->GetRasterXSize();
3949
	nYSize = inSet->GetRasterYSize();
3950
 
159 andreas 3951
	// cut the wanted region out of image
3952
	transform *tf = new transform (oriLeftLat, oriLeftLon, oriRightLat, oriRightLon);
3953
	tf->setDimensions(nXSize, nYSize);
158 andreas 3954
 
159 andreas 3955
	if (!tf->cutImage (geoRect.llat, geoRect.llon, geoRect.rlat, geoRect.rlon, fn))
3956
	{
3957
	   GDALClose (hSrcDS);
3958
	   return false;
3959
	}
158 andreas 3960
 
159 andreas 3961
	GDALClose (hSrcDS);
3962
	QString nfn = fn + "_tmp.png";
158 andreas 3963
 
159 andreas 3964
	// repeat the part above and open the now cutted part of the image.
3965
	// Open input and output files.
3966
	if ((hSrcDS = GDALOpen(nfn.ascii(), GA_ReadOnly)) == NULL)
3967
	{
3968
	   KMessageBox::error(this, i18n("Error opening an image file!"));
3969
	   return false;
3970
	}
158 andreas 3971
 
159 andreas 3972
	inSet = (GDALDataset *)hSrcDS;
3973
	// Create output with same datatype as first input band.
3974
	poBand = inSet->GetRasterBand (1);
3975
	eDT = poBand->GetRasterDataType ();
158 andreas 3976
 
159 andreas 3977
	if ((hDriver = GDALGetDriverByName ("GTiff")) == NULL)
158 andreas 3978
	{
159 andreas 3979
	   KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
3980
	   GDALClose (hSrcDS);
3981
	   return false;
158 andreas 3982
	}
3983
 
159 andreas 3984
	// Get dimensions of image and set transform data
3985
	nRasterCount = inSet->GetRasterCount();
3986
	nXSize = inSet->GetRasterXSize();
3987
	nYSize = inSet->GetRasterYSize();
3988
 
158 andreas 3989
	// Set the values needed to transform the image
3990
	OGRSpatialReference iSRS;
3991
	const char *iWKT;
3992
 
3993
	switch (isrs)
3994
	{
3995
	   case 0: iSRS.importFromEPSG(4326); break;
3996
	   case 1: iSRS.importFromEPSG(31257); break;
3997
	   case 2: iSRS.importFromEPSG(31258); break;
3998
	   case 3: iSRS.importFromEPSG(31259); break;
3999
	   case 4: iSRS.importFromEPSG(31286); break;
4000
	   case 5: iSRS.importFromEPSG(31287); break;
4001
	   case 6: iSRS.importFromEPSG(31288); break;
4002
	   default: iSRS.importFromEPSG(4326);
4003
	}
4004
 
4005
	iSRS.exportToWkt ((char **)&iWKT);
4006
 
4007
	if (inSet->SetProjection (iWKT) != CE_None)
4008
	{
4009
	   KMessageBox::error(this, i18n("Error setting projection on source!"));
4010
	   GDALClose (hSrcDS);
4011
	   return false;
4012
	}
4013
 
159 andreas 4014
	adfGeoTransform[0] = geoRect.llon;
4015
	adfGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)nXSize;
158 andreas 4016
	adfGeoTransform[2] = 0.0;
159 andreas 4017
	adfGeoTransform[3] = geoRect.llat;
158 andreas 4018
	adfGeoTransform[4] = 0.0;
159 andreas 4019
	adfGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)nYSize);
158 andreas 4020
 
4021
	if (inSet->SetGeoTransform (&adfGeoTransform[0]) != CE_None)
4022
	{
4023
	   KMessageBox::error(this, i18n("Error setting geo transform data to source!"));
4024
	   GDALClose (hSrcDS);
4025
	   return false;
4026
	}
4027
 
159 andreas 4028
	// Get Source coordinate system.
158 andreas 4029
	const char *pszSrcWKT, *pszDstWKT = NULL;
4030
 
4031
	if ((pszSrcWKT = GDALGetProjectionRef (hSrcDS)) == NULL)
4032
	{
4033
	   KMessageBox::error(this, i18n("Error getting the projection reference"));
4034
	   GDALClose (hSrcDS);
4035
	   return false;
4036
	}
4037
 
4038
	// Setup output coordinate system that is UTM ? WGS84.
4039
	OGRSpatialReference oSRS;
4040
 
159 andreas 4041
//	oSRS.SetUTM( 0, TRUE );
158 andreas 4042
	oSRS.SetWellKnownGeogCS("WGS84");
4043
	oSRS.exportToWkt ((char **)&pszDstWKT);
4044
 
159 andreas 4045
	// Create the output file.
158 andreas 4046
	double adfDstGeoTransform[6];
159 andreas 4047
	adfDstGeoTransform[0] = geoRect.llon;
4048
	adfDstGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)geoRect.width;
158 andreas 4049
	adfDstGeoTransform[2] = 0.0;
4050
	adfDstGeoTransform[3] = geoRect.llat;
4051
	adfDstGeoTransform[4] = 0.0;
159 andreas 4052
	adfDstGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)geoRect.height);
158 andreas 4053
 
159 andreas 4054
	if ((hDstDS = GDALCreate(hDriver, fName->ascii(), geoRect.width, geoRect.height,
158 andreas 4055
			nRasterCount, eDT, NULL )) == NULL)
4056
	{
4057
	   KMessageBox::error(this, i18n("Error creating a temporary image file! (" + *fName + ")"));
4058
	   GDALClose (hSrcDS);
4059
	   return false;
4060
	}
4061
 
4062
	outSet = (GDALDataset *)hDstDS;
4063
 
159 andreas 4064
	for (int i = 0; i < nRasterCount; i++)
4065
	{
4066
	   poBand = outSet->GetRasterBand (i+1);
4067
	   poBand->Fill (0.0);
4068
	}
4069
 
158 andreas 4070
	if (outSet->SetProjection (pszDstWKT) != CE_None)
4071
	{
4072
	   KMessageBox::error(this, i18n("Error setting projection on destination!"));
4073
	   GDALClose (hDstDS);
4074
	   GDALClose (hSrcDS);
4075
	   unlink (fName->ascii());
4076
	   return false;
4077
	}
4078
 
4079
	if (outSet->SetGeoTransform (&adfDstGeoTransform[0]) != CE_None)
4080
	{
159 andreas 4081
	   KMessageBox::error(this, i18n("Error setting geo transform data to destination!"));
158 andreas 4082
	   GDALClose (hDstDS);
4083
	   GDALClose (hSrcDS);
4084
	   unlink (fName->ascii());
4085
	   return false;
4086
	}
159 andreas 4087
 
158 andreas 4088
	// Copy the color table, if required.
4089
	GDALColorTableH hCT;
4090
 
4091
	for (int i = 0; i < nRasterCount; i++)
4092
	{
4093
	   hCT = GDALGetRasterColorTable (inSet->GetRasterBand (i+1));
4094
 
4095
	   if (hCT != NULL)
4096
              GDALSetRasterColorTable (outSet->GetRasterBand (i+1), hCT);
4097
	}
4098
 
4099
	// Setup warp options.
4100
	GDALWarpOptions *psWarpOptions = GDALCreateWarpOptions();
4101
 
4102
	psWarpOptions->hSrcDS = hSrcDS;
4103
	psWarpOptions->hDstDS = hDstDS;
4104
 
4105
	psWarpOptions->nBandCount = nRasterCount;
4106
	psWarpOptions->panSrcBands =
4107
        	(int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount );
4108
	psWarpOptions->panDstBands =
4109
		(int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount );
4110
 
4111
	for (int i = 0; i < nRasterCount; i++)
4112
	{
4113
	   psWarpOptions->panSrcBands[i] = i+1;
4114
	   psWarpOptions->panDstBands[i] = i+1;
4115
	}
4116
 
159 andreas 4117
//	psWarpOptions->pfnProgress = GDALTermProgress;
158 andreas 4118
 
4119
	// Establish reprojection transformer.
4120
	psWarpOptions->pTransformerArg =
4121
        	GDALCreateGenImgProjTransformer(hSrcDS,
4122
					 GDALGetProjectionRef(hSrcDS), 
4123
					 hDstDS,
4124
					 GDALGetProjectionRef(hDstDS),
159 andreas 4125
					 FALSE, 0.0, 1);
158 andreas 4126
 
4127
	psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
4128
 
4129
	// Initialize and execute the warp operation.
4130
	GDALWarpOperation oOperation;
4131
 
4132
	if (oOperation.Initialize (psWarpOptions) != CE_None)
4133
	{
4134
	   KMessageBox::error(this, i18n("Error initializing warp operation!"));
4135
	   GDALClose (hDstDS);
4136
	   GDALClose (hSrcDS);
4137
	   unlink (fName->ascii());
4138
	   return false;
4139
	}
4140
 
159 andreas 4141
	oOperation.ChunkAndWarpMulti (0, 0, geoRect.width, geoRect.height);
158 andreas 4142
	GDALDestroyGenImgProjTransformer (psWarpOptions->pTransformerArg);
4143
	GDALDestroyWarpOptions(psWarpOptions);
4144
 
4145
	GDALClose (hDstDS);
4146
	GDALClose (hSrcDS);
159 andreas 4147
	unlink (nfn.ascii());
158 andreas 4148
	return true;
4149
}
4150
 
151 andreas 4151
#endif
4152
 
88 andreas 4153
#include "sportwatcherwidget.moc"
4154