Subversion Repositories public

Rev

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