Subversion Repositories public

Rev

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