Subversion Repositories public

Rev

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