Subversion Repositories public

Rev

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

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