Subversion Repositories public

Rev

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