Subversion Repositories public

Rev

Rev 172 | Rev 215 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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