Subversion Repositories public

Rev

Rev 276 | Rev 283 | 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"
274 andreas 27
#include "shapewidget.h"
151 andreas 28
#include <string.h>
96 andreas 29
 
137 andreas 30
#include <iostream>
88 andreas 31
#include <kfiledialog.h>
32
#include <kmessagebox.h>
232 andreas 33
#include <KConfig>
88 andreas 34
#include <klocale.h>
232 andreas 35
#include <k3listview.h>
100 andreas 36
#include <kaboutdata.h>
232 andreas 37
#include <kaboutapplicationdialog.h>
218 andreas 38
#include <kinputdialog.h>
128 andreas 39
#include <kglobalsettings.h>
218 andreas 40
#include <kcombobox.h>
154 andreas 41
#include <qapplication.h>
88 andreas 42
#include <qstring.h>
43
#include <qdatetime.h>
109 andreas 44
#include <qtoolbutton.h>
132 andreas 45
#include <qcursor.h>
172 andreas 46
#include <qregexp.h>
232 andreas 47
#include <QMouseEvent>
246 andreas 48
#include <QRect>
49
#include <QRegion>
245 andreas 50
#include <KIcon>
280 andreas 51
#include <QPrintDialog>
52
#include <QPrinter>
151 andreas 53
 
232 andreas 54
#if defined HAVE_GDAL
158 andreas 55
   #include <gdal/ogr_spatialref.h>
56
   #include <gdal/ogrsf_frmts.h>
57
   #include <gdal/gdalwarper.h>
165 andreas 58
   #include <gdal/ogrsf_frmts.h>
157 andreas 59
#endif
60
 
218 andreas 61
#include "garmin.h"
158 andreas 62
#include "transform.h"
217 andreas 63
#include "import.h"
88 andreas 64
 
280 andreas 65
#if defined HAVE_MAPNIK
66
   #include "render.h"
67
#endif
151 andreas 68
 
137 andreas 69
using std::cout;
158 andreas 70
using std::cerr;
71
using std::clog;
137 andreas 72
using std::endl;
73
 
74
 
104 andreas 75
typedef struct
76
{
77
	double lon;
78
	double lat;
79
} posn_type;
80
 
245 andreas 81
sportwatcherWidget::sportwatcherWidget(QWidget *parent)
88 andreas 82
{
245 andreas 83
	ui_sportwatcherWidgetBase.setupUi(this);
232 andreas 84
 
85
#if defined HAVE_GDAL
157 andreas 86
	mFactor = 10;		// Factor to calculate square pixels
87
#endif
88 andreas 88
	mama = parent;
89
	gmn = 0;
90
	min_hr = max_hr = avg_hr = 0;
91
	min_height = max_height = 0.0;
92
	max_time = 0;
104 andreas 93
	zfactor = 0;
132 andreas 94
	mapLap = 0;
95
	mapPan = QRect(0, 0, 0, 0);
96
	stateHand = stateFlag = stateGlas = false;
97
	oldTransX = oldTransY = 0.0;
98
	lmbPressed = 0;
246 andreas 99
	DIRTY = true;
248 andreas 100
	curTab = ui_sportwatcherWidgetBase.tabView->currentIndex();
101
	tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
280 andreas 102
	ActivePrint = false;	// true if we are printing on paper
230 andreas 103
	kl = new KLocale(QString("kdesktop"), 0);
132 andreas 104
 
88 andreas 105
	// Load the config parameters
232 andreas 106
	KConfig cfg (QString("sportwatcher.rc"), KConfig::SimpleConfig);
107
	KConfigGroup ic (&cfg, "SportWatcher");
108
	lower1 = ic.readEntry("lower1", 0);
109
	lower2 = ic.readEntry("lower2", 0);
110
	lower3 = ic.readEntry("lower3", 0);
111
	upper1 = ic.readEntry("upper1", 0);
112
	upper2 = ic.readEntry("upper2", 0);
113
	upper3 = ic.readEntry("upper3", 0);
114
	MaxHr = ic.readEntry("maxHr", 180);
115
	restHr = ic.readEntry("restHr", 60);
116
	vo2max = ic.readEntry("vo2max", 50);
117
	weight = ic.readEntry("weight", 70);
118
	sampleTime = ic.readEntry("seconds", 15);
119
	Serial = ic.readEntry("Serial", false);
120
	Forerunner = ic.readEntry("Forerunner", false);
121
	Contour = ic.readEntry("Contour", false);
122
	Device = ic.readEntry("Device", "/dev/ttyUSB0");
123
	Data = ic.readEntry("Data", QDir::home().absolutePath() + "/.sportwatcher");
124
	HRM = ic.readEntry("HRM", QDir::home().absolutePath() + "/polar");
125
	MAP = ic.readEntry("MAP", QDir::home().absolutePath() + "/.sportwatcher/track.wms");
126
	Units = ic.readEntry("Units", 0);
127
	MapType = ic.readEntry("MapType", 7);
88 andreas 128
}
129
 
130
sportwatcherWidget::~sportwatcherWidget()
131
{
104 andreas 132
	destroy();
230 andreas 133
	delete kl;
88 andreas 134
}
135
 
100 andreas 136
void sportwatcherWidget::destroy()
137
{
138
	if (gmn)
139
	   garmin_free_data (gmn);
140
 
141
	gmn = 0;
132 andreas 142
	oldTransX = oldTransY = 0.0;
100 andreas 143
}
144
 
245 andreas 145
void sportwatcherWidget::Initialize()
146
{
147
	// Set some widget settings
148
	ui_sportwatcherWidgetBase.btHand->setIcon(KIcon("hand"));
149
	ui_sportwatcherWidgetBase.btGlas->setIcon(KIcon("glas"));
150
	ui_sportwatcherWidgetBase.btGlasMinus->setIcon(KIcon("glas_minus"));
151
	ui_sportwatcherWidgetBase.btGlasPlus->setIcon(KIcon("glas_plus"));
152
	ui_sportwatcherWidgetBase.btFlag->setIcon(KIcon("flag"));
153
	ui_sportwatcherWidgetBase.btFullscreen->setIcon(KIcon("fullscreen"));
248 andreas 154
 
155
	if (curTab != 0)
156
	{
157
	   ui_sportwatcherWidgetBase.tabView->setCurrentIndex(0);
158
	   curTab = ui_sportwatcherWidgetBase.tabView->currentIndex();
159
	}
160
 
245 andreas 161
//	btHand->setToggleButton(true);
162
//	btGlas->setToggleButton(true);
163
	// Fill the activities
164
	getActivities();
165
#if defined HAVE_GDAL
166
	// Initialize the GDAL
167
	GDALAllRegister();
168
	poDataset = 0;
169
#endif
170
}
171
 
247 andreas 172
QTreeWidgetItem *sportwatcherWidget::findElement(QTreeWidget *wdg, const QString &val)
132 andreas 173
{
247 andreas 174
QTreeWidgetItem *item, *child, *subchild;
132 andreas 175
 
246 andreas 176
	if (!wdg)
247 andreas 177
	   return 0;
246 andreas 178
 
179
	for (int a = 0; a < wdg->topLevelItemCount(); a++)
132 andreas 180
	{
246 andreas 181
	   if (!(item = wdg->topLevelItem(a)))
182
	      continue;
132 andreas 183
 
246 andreas 184
	   for (int j = 0; j < item->childCount(); j++)
185
	   {
186
	      if (!(child = item->child(j)))
187
		 continue;
188
 
189
	      if (child->data(0, Qt::UserRole).toString() == val)
247 andreas 190
		 return child;
191
 
192
	      for (int i = 0; i < child->childCount(); i++)
193
	      {
194
		 if (!(subchild = child->child(i)))
195
		    continue;
196
 
197
		 if (subchild->data(0, Qt::UserRole).toString() == val)
198
		    return subchild;
199
	      }
246 andreas 200
	   }
132 andreas 201
	}
202
 
247 andreas 203
	return 0;
132 andreas 204
}
205
 
88 andreas 206
/*
207
 * Search for a directory named .sportwatcher in the home directory of
208
 * the user and search for *.gmn files. Open the files and read the header
209
 * to find the basic data of activities. Then add the information into
210
 * the activities KListView.
211
 */
212
void sportwatcherWidget::getActivities()
213
{
214
QString path, txt;
232 andreas 215
QDir mdir, dir = QDir::home();
88 andreas 216
QStringList years, months;
247 andreas 217
QTreeWidgetItem *running, *biking, *other, *year_run, *year_bike, *year_other;
246 andreas 218
QTreeWidgetItem *el;
219
QList<QTreeWidgetItem *> item;
232 andreas 220
int i, j;
247 andreas 221
int y_run, y_bike, y_other;
88 andreas 222
RUN_NODE *rn;
223
LAP *lap;
224
 
225
	if (Data.isEmpty())
226
	{
232 andreas 227
	   path = dir.homePath();
88 andreas 228
	   path.append("/.sportwatcher");
229
	}
230
	else
231
	   path = Data;
232
 
233
	dir.setPath(path);
132 andreas 234
	dir.refresh();
88 andreas 235
 
236
	if (!dir.exists())
237
	{
238
	   dir.mkdir(path);
239
	   return;
240
	}
241
 
132 andreas 242
	destroy();
128 andreas 243
 
245 andreas 244
	if (!ui_sportwatcherWidgetBase.liActivities)
245
	{
246
	   KMessageBox::error(this, i18n("Error initializing some widgets of main window!"));
247
	   return;
248
	}
249
 
250
	ui_sportwatcherWidgetBase.liActivities->clear();
246 andreas 251
	ui_sportwatcherWidgetBase.liActivities->setSortingEnabled(false);
252
	ui_sportwatcherWidgetBase.liActivities->setColumnCount(1);
245 andreas 253
 
246 andreas 254
	running = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
255
	biking = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
256
	other = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
257
 
245 andreas 258
	if (!other || !biking || !running)
259
	{
260
	   KMessageBox::error(this, i18n("Not enough memory to initilize application!"));
261
	   return;
262
	}
263
 
246 andreas 264
	running->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
265
	biking->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
266
	other->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
128 andreas 267
 
246 andreas 268
	running->setText(0, i18n("Running"));
269
	biking->setText(0, i18n("Biking"));
270
	other->setText(0, i18n("Others"));
88 andreas 271
 
246 andreas 272
	KIcon fld(QString("history"));
273
	running->setIcon(0, fld);
274
	biking->setIcon(0, fld);
275
	other->setIcon(0, fld);
276
 
277
	running->setStatusTip(0, i18n("\"Running\" activities."));
278
	biking->setStatusTip(0, i18n("\"Biking\" activities."));
279
	other->setStatusTip(0, i18n("\"Other\" and \"Multisport\" activities."));
280
 
88 andreas 281
	dir.cd(path);
282
	dir.setFilter(QDir::Dirs | QDir::NoSymLinks);
283
	dir.setSorting(QDir::Name);
132 andreas 284
	dir.refresh();
232 andreas 285
	QFileInfoList list = dir.entryInfoList();
88 andreas 286
 
232 andreas 287
	if (!list.size())
88 andreas 288
	   return;
289
 
232 andreas 290
	for (i = 0; i < list.size(); i++)		// Years
291
	{
292
	QFileInfo fileInfo = list.at(i);
88 andreas 293
 
232 andreas 294
	   if (fileInfo.fileName() == QString(".") || fileInfo.fileName() == QString(".."))
88 andreas 295
	      continue;
296
 
232 andreas 297
	   years += fileInfo.absoluteFilePath();
88 andreas 298
	}
299
 
232 andreas 300
	for (i = 0; i < years.size(); ++i)
88 andreas 301
	{
232 andreas 302
	   if (months.size() > 0)
88 andreas 303
	      months.clear();
304
 
232 andreas 305
	   dir.setPath(years.at(i));
132 andreas 306
	   dir.refresh();
232 andreas 307
	   list = dir.entryInfoList();
88 andreas 308
 
232 andreas 309
	   if (!list.size())
88 andreas 310
	      continue;
311
 
232 andreas 312
	   for (j = 0; j < list.size(); j++)		// Months
313
	   {
314
	   QFileInfo fileInfo = list.at(j);
88 andreas 315
 
232 andreas 316
	      if (fileInfo.fileName() == QString(".") || fileInfo.fileName() == QString(".."))
88 andreas 317
		 continue;
318
 
232 andreas 319
	      months += fileInfo.absoluteFilePath();
88 andreas 320
	   }
321
 
232 andreas 322
	   for (j = 0; j < months.size(); ++j)
88 andreas 323
	   {
232 andreas 324
	      mdir.setPath(months.at(j));
325
	      mdir.cd(months.at(j));
88 andreas 326
	      mdir.setFilter(QDir::Files | QDir::NoSymLinks);
246 andreas 327
	      mdir.setSorting(QDir::Name);
232 andreas 328
	      mdir.setNameFilters(QStringList("*.gmn"));
132 andreas 329
	      mdir.refresh();
232 andreas 330
	      list = mdir.entryInfoList();
88 andreas 331
 
232 andreas 332
	      if (!list.size())
88 andreas 333
		 continue;
334
 
232 andreas 335
	      for (int a = 0; a < list.size(); a++)		// Files
336
	      {
337
	      QFileInfo fileInfo = list.at(a);
88 andreas 338
 
232 andreas 339
		 files += fileInfo.absoluteFilePath();
88 andreas 340
	      }
341
	   }
342
	}
343
 
247 andreas 344
	y_run = y_bike = y_other = 0;
345
	year_run = year_bike = year_other = 0;
88 andreas 346
	// Open every file and read its head
232 andreas 347
	for (i = 0; i < files.size(); ++i)
88 andreas 348
	{
247 andreas 349
	QTreeWidgetItem *yr, *yb, *yo;
132 andreas 350
 
246 andreas 351
	   if (findElement(ui_sportwatcherWidgetBase.liActivities, files.at(i)))
352
	      continue;
353
 
88 andreas 354
	   spw.destroy();
355
 
232 andreas 356
	   if (spw.setFileName(files.at(i).toAscii().constData()) == -1)
88 andreas 357
	      return;
358
 
359
	   if (gmn)
246 andreas 360
	   {
88 andreas 361
	      garmin_free_data (gmn);
246 andreas 362
	      gmn = 0;
363
	   }
88 andreas 364
 
246 andreas 365
	   if (!(gmn = spw.readFile()))
366
	      continue;
367
 
88 andreas 368
	   ds.destroy();
369
	   ds.garmin_print_data(gmn);
370
	   rn = ds.getRunNode();
371
 
245 andreas 372
	   if (!rn)
373
	      return;
374
 
88 andreas 375
	   lap = ds.getLap(rn->run->first_lap_index);
245 andreas 376
 
377
	   if (!lap)
378
	      return;
379
 
88 andreas 380
	   const QDateTime *qt = garmin_dtime (lap->start_time);
232 andreas 381
	   // By default set the name of the session to the date and time
382
	   // it was recorded.
383
	   QString idx = kl->formatDateTime (*qt, KLocale::ShortDate, true);
248 andreas 384
	   QString stTip = kl->formatDateTime (*qt, KLocale::LongDate, true);
88 andreas 385
 
232 andreas 386
	   // If we have a custom name for this session, set it.
217 andreas 387
	   if (strlen (rn->run->workout.name) > 1 && strlen (rn->run->workout.name) < 16 && isalpha (rn->run->workout.name[0]))
232 andreas 388
	      idx = QString (rn->run->workout.name);
217 andreas 389
 
88 andreas 390
	   switch (rn->run->sport_type)
391
	   {
392
	      case D1000_running:
247 andreas 393
		 yr = findElement(ui_sportwatcherWidgetBase.liActivities, QString("run_%1").arg(qt->date().year()));
394
 
395
		 if (!yr && qt->date().year() != y_run)
396
		 {
397
		    year_run = new QTreeWidgetItem(running, running);
398
		    y_run = qt->date().year();
399
		    year_run->setText(0, QString("%1").arg(y_run));
400
		    year_run->setData(0, Qt::UserRole, QString("run_%1").arg(y_run));
401
		    year_run->setIcon(0, KIcon(QString("today")));
402
		    year_run->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
403
		 }
404
		 else
405
		    year_run = yr;
406
 
407
		 el = new QTreeWidgetItem(year_run, year_run);
246 andreas 408
		 el->setText(0, idx);
409
		 el->setData(0, Qt::UserRole, files.at(i));
247 andreas 410
		 el->setIcon(0, KIcon(QString("spw-running")));
246 andreas 411
		 el->setStatusTip(0, stTip);
412
		 el->setToolTip(0, stTip);
413
		 el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
88 andreas 414
	      break;
415
 
416
	      case D1000_biking:
247 andreas 417
		 yb = findElement(ui_sportwatcherWidgetBase.liActivities, QString("bike_%1").arg(qt->date().year()));
418
 
419
		 if (!yb && qt->date().year() != y_bike)
420
		 {
421
		    year_bike = new QTreeWidgetItem(biking, biking);
422
		    y_bike = qt->date().year();
423
		    year_bike->setText(0, QString("%1").arg(y_bike));
424
		    year_bike->setData(0, Qt::UserRole, QString("bike_%1").arg(y_run));
425
		    year_bike->setIcon(0, KIcon(QString("today")));
426
		    year_bike->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
427
		 }
428
		 else
429
		    year_bike = yb;
430
 
431
		 el = new QTreeWidgetItem(year_bike, year_bike);
246 andreas 432
		 el->setText(0, idx);
433
		 el->setData(0, Qt::UserRole, files.at(i));
434
		 el->setStatusTip(0, stTip);
435
		 el->setToolTip(0, stTip);
436
		 el->setIcon(0, KIcon(QString("bike")));
437
		 el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
88 andreas 438
	      break;
439
 
440
	      case D1000_other:
247 andreas 441
	      default:
442
		 yo = findElement(ui_sportwatcherWidgetBase.liActivities, QString("other_%1").arg(qt->date().year()));
88 andreas 443
 
247 andreas 444
		 if (!yo && qt->date().year() != y_other)
445
		 {
446
		    year_other = new QTreeWidgetItem(other, other);
447
		    y_other = qt->date().year();
448
		    year_other->setText(0, QString("%1").arg(y_other));
449
		    year_other->setData(0, Qt::UserRole, QString("other_%1").arg(y_run));
450
		    year_other->setIcon(0, KIcon(QString("today")));
451
		    year_other->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
452
		 }
453
		 else
454
		    year_other = yo;
455
 
456
		 el = new QTreeWidgetItem(year_other, year_other);
246 andreas 457
		 el->setText(0, idx);
458
		 el->setData(0, Qt::UserRole, files.at(i));
459
		 el->setStatusTip(0, stTip);
460
		 el->setToolTip(0, stTip);
461
		 el->setIcon(0, KIcon(QString("other")));
462
		 el->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
88 andreas 463
	   }
464
 
465
	   delete qt;
466
	}
467
 
246 andreas 468
	ui_sportwatcherWidgetBase.liActivities->setItemExpanded(running, true);
88 andreas 469
 
247 andreas 470
	if (year_run)
471
	   ui_sportwatcherWidgetBase.liActivities->setItemExpanded(year_run, true);
472
 
88 andreas 473
	if (gmn)
474
	   garmin_free_data (gmn);
475
 
476
	gmn = 0;
477
}
478
 
479
/*$SPECIALIZATION$*/
480
void sportwatcherWidget::btFullscreenSlot()
481
{
132 andreas 482
	oldTransX = oldTransY = 0.0;
483
	mapPan.setCoords(0, 0, 0, 0);
246 andreas 484
	DIRTY = true;
104 andreas 485
	showTrack(0);
246 andreas 486
	DIRTY = false;
88 andreas 487
}
488
 
489
void sportwatcherWidget::btGlasMinusSlot()
490
{
132 andreas 491
bool sh = stateHand;
492
 
493
	stateHand = false;
246 andreas 494
	DIRTY = true;
104 andreas 495
	showTrack(zfactor - 1000);
246 andreas 496
	DIRTY = false;
132 andreas 497
	stateHand = sh;
88 andreas 498
}
499
 
500
void sportwatcherWidget::btGlasPlusSlot()
501
{
132 andreas 502
bool sh = stateHand;
503
 
504
	stateHand = false;
246 andreas 505
	DIRTY = true;
104 andreas 506
	showTrack(zfactor + 1000);
246 andreas 507
	DIRTY = false;
132 andreas 508
	stateHand = sh;
88 andreas 509
}
510
 
511
void sportwatcherWidget::btHandSlot()
512
{
132 andreas 513
QCursor cs;
514
 
515
	if (stateGlas)
516
	{
517
	   stateGlas = false;
245 andreas 518
	   ui_sportwatcherWidgetBase.btGlas->toggle();
132 andreas 519
	}
520
 
521
	stateHand = (stateHand) ? false : true;
522
 
523
	if (stateHand)
232 andreas 524
	   cs.setShape(Qt::PointingHandCursor);
132 andreas 525
	else
232 andreas 526
	   cs.setShape(Qt::ArrowCursor);
132 andreas 527
 
245 andreas 528
	ui_sportwatcherWidgetBase.imgMap->setCursor(cs);
88 andreas 529
}
530
 
531
void sportwatcherWidget::btGlasSlot()
532
{
132 andreas 533
QCursor cs;
534
 
535
	if (stateHand)
536
	{
537
	   stateHand = false;
245 andreas 538
	   ui_sportwatcherWidgetBase.btHand->toggle();
132 andreas 539
	}
540
 
541
	stateGlas = (stateGlas) ? false : true;
542
 
543
	if (stateGlas)
232 andreas 544
	   cs.setShape(Qt::ForbiddenCursor);
132 andreas 545
	else
232 andreas 546
	   cs.setShape(Qt::ArrowCursor);
132 andreas 547
 
245 andreas 548
	ui_sportwatcherWidgetBase.imgMap->setCursor(cs);
88 andreas 549
}
550
 
551
void sportwatcherWidget::btFlagSlot()
552
{
553
}
554
 
232 andreas 555
void sportwatcherWidget::liLapsSlot(Q3ListViewItem *item)
88 andreas 556
{
132 andreas 557
QString sl;
558
int l;
559
int idx;
560
RUN_NODE *rn;
561
LAP *lap;
562
 
563
	if (!item)
564
	   return;
565
 
246 andreas 566
	DIRTY = true;
132 andreas 567
	sl = item->text(0).mid(4, 3);
568
	l = sl.toInt();
569
 
570
	if (l <= 0)
571
	{
245 andreas 572
	   // Show the whole map and track
132 andreas 573
	   showTrack(zfactor, mapPan, 0);
245 andreas 574
	   // Don't mark any lap. Just display normal.
148 andreas 575
	   showCurves(0);
132 andreas 576
	   return;
577
	}
578
 
579
	rn = ds.getRunNode();
580
	idx = rn->run->first_lap_index;
581
	lap = ds.getLap(idx + l - 1);
245 andreas 582
	// Show the part of the track, corresponding to the selected lap
132 andreas 583
	showTrack(zfactor, mapPan, lap);
245 andreas 584
	// Mark the selected lap
148 andreas 585
	showCurves(lap);
246 andreas 586
	DIRTY = false;
88 andreas 587
}
588
 
246 andreas 589
void sportwatcherWidget::liActivitiesSlot(QTreeWidgetItem *item, int)
88 andreas 590
{
591
	if (!item)
592
	   return;
593
 
245 andreas 594
	spw.destroy();
88 andreas 595
 
246 andreas 596
	if (spw.setFileName(item->data(0, Qt::UserRole).toString().toAscii().constData()) == -1)
245 andreas 597
	   return;
88 andreas 598
 
245 andreas 599
	if (gmn)
600
	   garmin_free_data (gmn);
88 andreas 601
 
245 andreas 602
	gmn = spw.readFile();
603
	zfactor = 0;
248 andreas 604
 
605
	// Make sure, the currently not visible tabs will be redrawn as soon
606
	// as they are visible.
607
	switch (curTab)
608
	{
609
	   case 0: tabDirt1 = tabDirt2 = tabDirt3 = true; break;
610
	   case 1: tabDirt0 = tabDirt2 = tabDirt3 = true; break;
611
	   case 2: tabDirt0 = tabDirt1 = tabDirt3 = true; break;
612
	   case 3: tabDirt0 = tabDirt1 = tabDirt2 = true; break;
613
	}
614
 
245 andreas 615
	// Display the just loaded sport session
246 andreas 616
	DIRTY = true;
245 andreas 617
	showLaps();
618
	showTrack();
619
	showCurves();
250 andreas 620
 
621
	if (curTab == 2)
622
	{
623
	   showThreeCurve();
624
	   tabDirt2 = false;
625
	}
626
 
246 andreas 627
	DIRTY = false;
88 andreas 628
}
629
 
280 andreas 630
/*
631
 * The following function is called, when the user clicks the print button.
632
 * It then prints the currently loaded activity. First the laps and on a
633
 * seperate page the map, heart rate, elevation and speed.
634
 *
635
 * The function uses the already existing function showTrack() to draw an
636
 * optional map and the track on it. It uses the function showThreeCurve()
637
 * to draw the heart rate, elevation and speed. Only the laps are drawn
638
 * directly in this function.
639
 */
88 andreas 640
void sportwatcherWidget::filePrint()
641
{
280 andreas 642
QPrinter printer(QPrinter::HighResolution);
643
QDateTime dt;
644
QTime t, st;
645
QDateTime *qt;
646
QRectF rect;
647
QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
648
QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
649
QString qs_totdist, hv0;
650
LAP *lap;
651
POINT *point;
652
RUN_NODE *rakt, *rn;
653
int laps, i, anz, cad, page, firstPage, lastPage;
654
qreal extMil[4];
655
double sum_asc, sum_dsc, old_asc, old_dsc;
656
double totdist, lineH, aktLine;
657
bool printed = false;
658
 
659
	if (!gmn)
660
	{
661
	   KMessageBox::error(this, i18n("You must select an activity first!"));
662
	   return;
663
	}
664
 
665
	printer.setCreator(QString("SportWatcher"));
666
	printer.setDocName(QString("SportWatcher_%1").arg(QString(VERSION)));
667
	QPrintDialog printDialog(&printer, this);
668
 
669
	if (!printDialog.exec() == QDialog::Accepted)
670
	   return;
671
 
672
	if (!(rn = ds.getRunNode()))
673
	   return;
674
 
675
	// We dont care about page margins of a printer. Instead we assume
676
	// a frame from about 20mm arround the page. European paper size is
677
	// A4 (210x297mm) and the output is optimized for this.
678
	extMil[0] = 20.0;
679
	extMil[1] = 20.0;
680
	extMil[2] = 210.0 - 20.0;
681
	extMil[3] = 279.0 - 20.0;
682
	lineH = 4.5;	// The height of a line with 10pt letters
683
	page = 1;	// The page number
684
	firstPage = printer.fromPage();
685
	lastPage = printer.toPage();
686
 
687
	if (!printArea.begin(&printer))
688
	{
689
	   KMessageBox::error(this, i18n("Error initializing printer! Printing is currently not available!"));
690
	   return;
691
	}
692
 
693
	ActivePrint = true;
694
	rakt = rn;
695
	QApplication::setOverrideCursor (QCursor(Qt::WaitCursor));
696
 
697
	while (rakt)
698
	{
699
	   // Check for a supported run type
700
	   if (rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
701
	   	rakt->run->type == data_D1010)
702
	   {
703
	   int ahr;
704
	   double distance, speed, mspeed;
705
	   QDate dat;
706
 
707
	      printArea.setFont(QFont(QString("Helvetica"), 12, QFont::Bold, false));
708
	      rect.setCoords(milToPixel(extMil[0], printer),
709
			milToPixel(extMil[1], printer, true),
710
			milToPixel(extMil[0]+170, printer),
711
			milToPixel(extMil[1] + 7.0, printer, true));
712
	      printArea.setPen(QPen(QBrush(QColor("black")), (qreal)milToPixel(0.5, printer, false)));
713
 
714
	      if ((lastPage > 0 && page >= firstPage && page <= lastPage) ||
715
		  (lastPage == 0 && firstPage == 0))
716
	      {
717
		 printArea.drawRect(rect);
718
		 printed = true;
719
	      }
720
 
721
	      if (!(lap = ds.getLap(rakt->run->first_lap_index)))
722
	      {
723
		 ActivePrint = false;
724
		 QApplication::restoreOverrideCursor();
725
		 return;
726
	      }
727
 
728
	      if (strlen (rn->run->workout.name) > 1 && strlen (rn->run->workout.name) < 16 && isalpha (rn->run->workout.name[0]))
729
		 hv0 = QString(rakt->run->workout.name);
730
	      else
731
	      {
732
		 qt = garmin_dtime(lap->start_time);
733
		 hv0 = kl->formatDate(qt->date(), KLocale::ShortDate) + " ";
734
		 hv0.append(qt->toString("hh:mm:ss"));
735
		 delete qt;
736
	      }
737
 
738
	      // Set the name depending on the sport type
739
	      // This is used on the tab "Summary"
740
	      switch (rakt->run->sport_type)
741
	      {
742
		 case D1000_running: qs_name = i18n("Running: "); break;
743
		 case D1000_biking:  qs_name = i18n("Biking: "); break;
744
		 case D1000_other:   qs_name = i18n("Other: "); break;
745
		 default:
746
		    qs_name = i18n("Unknown: ");
747
	      }
748
 
749
	      // Print the headline inside the frame
750
	      if ((lastPage > 0 && page >= firstPage && page <= lastPage) ||
751
		  (lastPage == 0 && firstPage == 0))
752
	      {
753
		 printArea.drawText(rect, Qt::AlignHCenter, QString("%1%2").arg(qs_name).arg(hv0));
754
		 // Print the headline of the table
755
		 printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Bold, false));
756
		 rect.setCoords(milToPixel(extMil[0], printer), milToPixel(extMil[1]+10, printer, true), milToPixel(extMil[0]+35, printer), milToPixel(extMil[0]+10+lineH, printer, true));
757
		 printArea.drawText(rect, Qt::AlignHCenter, i18n("Lap"));
758
		 rect.setCoords(milToPixel(extMil[0]+35, printer), milToPixel(extMil[1]+10, printer, true), milToPixel(extMil[0]+60, printer), milToPixel(extMil[0]+10+lineH, printer, true));
759
		 printArea.drawText(rect, Qt::AlignHCenter, i18n("Distance"));
760
		 rect.setCoords(milToPixel(extMil[0]+60, printer), milToPixel(extMil[1]+10, printer, true), milToPixel(extMil[0]+85, printer), milToPixel(extMil[0]+10+lineH, printer, true));
761
		 printArea.drawText(rect, Qt::AlignHCenter, i18n("Time"));
762
		 rect.setCoords(milToPixel(extMil[0]+85, printer), milToPixel(extMil[1]+10, printer, true), milToPixel(extMil[0]+122, printer), milToPixel(extMil[0]+10+lineH, printer, true));
763
		 printArea.drawText(rect, Qt::AlignHCenter, i18n("Speed"));
764
		 rect.setCoords(milToPixel(extMil[0]+122, printer), milToPixel(extMil[1]+10, printer, true), milToPixel(extMil[0]+147, printer), milToPixel(extMil[0]+10+lineH, printer, true));
765
		 printArea.drawText(rect, Qt::AlignHCenter, i18n("Heart rate"));
766
		 rect.setCoords(milToPixel(extMil[0]+147, printer), milToPixel(extMil[1]+10, printer, true), milToPixel(extMil[0]+170, printer), milToPixel(extMil[0]+10+lineH, printer, true));
767
		 printArea.drawText(rect, Qt::AlignHCenter, i18n("Cadence"));
768
		 aktLine = extMil[1] + 10.0 + lineH;
769
		 printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
770
		 aktLine += 1.0;
771
		 printed = true;
772
	      }
773
	      else
774
	      {
775
		 aktLine = extMil[1] + 10.0 + lineH;
776
		 aktLine += 1.0;
777
	      }
778
 
779
	      // Prepare to print the first line
780
	      qt = garmin_dtime (lap->start_time);
781
	      StartTime = *qt;
782
	      st = qt->time();
783
	      dat = qt->date();
784
	      delete qt;
785
	      qt = 0;
786
	      // Find the last track
787
	      if (!(point = ds.getLastPoint()))
788
	      {
789
		 QApplication::restoreOverrideCursor();
790
		 KMessageBox::error(this, i18n("Error getting the last messure point!"));
791
		 ActivePrint = false;
792
		 return;
793
	      }
794
 
795
	      qt = garmin_dtime(point->time);
796
	      t = qt->time();
797
	      t.setHMS(0, 0, 0);
798
	      t = t.addSecs(ds.getTotalTime());
799
	      qt->setDate(dat);
800
	      qt->setTime(t);
801
	      qs_name = kl->formatDate(dat, KLocale::ShortDate);
802
	      qs_name.append(" ");
803
	      qs_name.append(kl->formatTime(st, true));
804
	      max_time = ds.getTotalTime();
805
	      qs_etime = QString(qt->toString("hh:mm:ss.zzz"));
806
 
807
	      distance = 0.0;
808
	      mspeed = 0;
809
	      ahr = 0;
810
	      anz = 0;
811
	      cad = 0;
812
	      sum_asc = sum_dsc = old_asc = old_dsc = 0;
813
 
814
	      // Find out the total distance, calories, maximum speed,
815
	      // maximum heart rate and the average heart rate. Get this
816
	      // values from the lap summary the watch made.
817
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
818
	      {
819
		 if ((lap = ds.getLap(i)) == NULL)
820
		    continue;
821
 
822
		 distance += lap->total_distance;
823
 
824
		 if (lap->avg_cadence != 0xff)
825
		    cad += lap->avg_cadence;
826
 
827
		 ahr += lap->avg_heart_rate;
828
		 anz++;
829
 
830
		 if (lap->max_speed > mspeed)
831
		    mspeed = lap->max_speed;
832
	      }
833
 
834
	      total_distance = distance = ds.getTotalDistance();
835
 
836
	      if (Units == 1)		// Statute?
837
		 qs_distance.sprintf("%.2f ft", distance / 0.304);
838
	      else
839
	         qs_distance.sprintf("%.2f m", distance);
840
 
841
	      if (distance > 0)
842
	      {
843
		 QTime tt = qt->time();
844
		 long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0;
845
 
846
		 if (Units == 0)
847
		    secs = secs * (1000.0 / distance * 100.0);
848
		 else
849
		    secs = secs * (1609.344 / distance * 100.0);
850
 
851
		 int h = secs / 3600;
852
		 int m = (secs - (h * 3600)) / 60;
853
		 int s = secs - ((h * 3600) + (m * 60));
854
		 t = QTime(h, m, s, 0);
855
		 qs_avgpace = QString("  ") + kl->formatTime(t, true);
856
 
857
		 if (Units == 0)
858
		    qs_avgpace.append(QString(" /km"));
859
		 else
860
		    qs_avgpace.append(QString(" /mi"));
861
	      }
862
 
863
	      if (Units == 1)		// Statute?
864
		 speed = distance / ds.getTotalTime() * 3.6 / 1.609344;
865
	      else
866
		 speed = distance / ds.getTotalTime() * 3.6;
867
 
868
	      qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mph" : "km/h");
869
	      qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed * 3.6 / 1.609344 : mspeed * 3.6, (Units == 1) ? "mph" : "km/h");
870
	      qs_avghr.sprintf("%d bpm", ahr / anz);
871
 
872
	      if (cad > 0)
873
		 qs_avgcadence.sprintf("%d", cad / anz);
874
 
875
	      // Print out the summary line and draw twi thin lines underneath
876
	      if ((lastPage > 0 && page >= firstPage && page <= lastPage) ||
877
		  (lastPage == 0 && firstPage == 0))
878
	      {
879
		 printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Normal, false));
880
		 rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+35, printer), milToPixel(aktLine+lineH, printer, true));
881
		 printArea.drawText(rect, Qt::AlignLeft, qs_name);
882
		 rect.setCoords(milToPixel(extMil[0]+35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+60, printer), milToPixel(aktLine+lineH, printer, true));
883
		 printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_distance, false));
884
		 rect.setCoords(milToPixel(extMil[0]+60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+85, printer), milToPixel(aktLine+lineH, printer, true));
885
		 printArea.drawText(rect, Qt::AlignRight, qs_etime);
886
		 rect.setCoords(milToPixel(extMil[0]+85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+122, printer), milToPixel(aktLine+lineH, printer, true));
887
		 printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_avgspeed, false));
888
		 rect.setCoords(milToPixel(extMil[0]+122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+147, printer), milToPixel(aktLine+lineH, printer, true));
889
		 printArea.drawText(rect, Qt::AlignRight, qs_avghr);
890
		 rect.setCoords(milToPixel(extMil[0]+147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+170, printer), milToPixel(aktLine+lineH, printer, true));
891
		 printArea.drawText(rect, Qt::AlignRight, qs_avgcadence);
892
		 aktLine += (lineH + (lineH / 3.0));
893
		 printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.1, printer, false)));
894
		 printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
895
		 printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine+0.5, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine+0.5, printer, true));
896
		 aktLine += (lineH / 3.0);
897
		 printed = true;
898
	      }
899
	      else
900
	      {
901
		 aktLine += (lineH + (lineH / 3.0));
902
		 aktLine += (lineH / 3.0);
903
	      }
904
 
905
	      delete qt;
906
	      /* Get the laps. */
907
	      laps = 1;
908
 
909
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
910
	      {
911
		 double spd;
912
		 char *un;
913
 
914
		 if ((lap = ds.getLap(i)) == NULL)
915
		    continue;
916
 
917
		 qt = garmin_dtime (lap->start_time);
918
		 qs_name.sprintf("Lap %03d - ", laps);
919
		 qs_name.append(kl->formatTime(qt->time(), true));
920
		 qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
921
		 totdist += (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance;
922
		 qs_totdist.sprintf("%2.f %s", totdist, (Units == 1) ? "ft" : "m");
923
		 t = QTime(0, 0, 0, 0);
924
		 t = t.addMSecs(lap->total_time * 10);
925
		 qs_etime = t.toString("hh:mm:ss.zzz");
926
		 spd = lap->total_distance / (lap->total_time / 100.0);
927
		 delete qt;
928
		 qt = 0;
929
 
930
		 if (Units == 0)
931
		 {
932
		    un = (char *)"km/h";
933
		    spd *= 3.6;
934
		 }
935
		 else
936
		 {
937
		    spd *= 3.6 / 1.609344;
938
		    un = (char *)"mph";
939
		 }
940
 
941
		 qs_avgspeed.sprintf("%.2f %s", spd, un);
942
 
943
		 if (lap->total_distance > 0 && lap->total_time != 0)
944
		 {
945
		    double fact;
946
 
947
		    if (Units == 0)
948
		       fact = 1000.0;		// 1 km
949
		    else
950
		       fact = 1609.344;		// 1 mile in meters
951
 
952
		    long secs = (double)lap->total_time / 10000.0 * (fact / lap->total_distance * 100.0);
953
		    int h = secs / 3600;
954
		    int m = (secs - (h * 3600)) / 60;
955
		    int s = secs - ((h * 3600) + (m * 60));
956
		    t = QTime(h, m, s, 0);
957
		    qs_avgpace = kl->formatTime(t, true);
958
 
959
		    if (Units == 0)
960
		       qs_avgpace.append(QString(" /km"));
961
		    else
962
		       qs_avgpace.append(QString(" /mi"));
963
		 }
964
 
965
		 qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);
966
 
967
		 if (lap->avg_cadence != 0xff)
968
		    qs_avgcadence.sprintf("%d", lap->avg_cadence);
969
		 // Draw a new detail line
970
		 if ((lastPage > 0 && page >= firstPage && page <= lastPage) ||
971
		     (lastPage == 0 && firstPage == 0))
972
		 {
973
		    rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+35, printer), milToPixel(aktLine+lineH, printer, true));
974
		    printArea.drawText(rect, Qt::AlignLeft, qs_name);
975
		    rect.setCoords(milToPixel(extMil[0]+35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+60, printer), milToPixel(aktLine+lineH, printer, true));
976
		    printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_distance, false));
977
		    rect.setCoords(milToPixel(extMil[0]+60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+85, printer), milToPixel(aktLine+lineH, printer, true));
978
		    printArea.drawText(rect, Qt::AlignRight, qs_etime);
979
		    rect.setCoords(milToPixel(extMil[0]+85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+122, printer), milToPixel(aktLine+lineH, printer, true));
980
		    printArea.drawText(rect, Qt::AlignRight, kl->formatNumber(qs_avgspeed, false));
981
		    rect.setCoords(milToPixel(extMil[0]+122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+147, printer), milToPixel(aktLine+lineH, printer, true));
982
		    printArea.drawText(rect, Qt::AlignRight, qs_avghr);
983
		    rect.setCoords(milToPixel(extMil[0]+147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+170, printer), milToPixel(aktLine+lineH, printer, true));
984
		    printArea.drawText(rect, Qt::AlignRight, qs_avgcadence);
985
		    printed = true;
986
		 }
987
 
988
		 aktLine += lineH;
989
 
990
		 if (aktLine >= extMil[3])	// Print on the next page
991
		 {
992
		    aktLine = extMil[3] + 10.0;
993
 
994
		    if ((lastPage > 0 && page >= firstPage && page <= lastPage) ||
995
		        (lastPage == 0 && firstPage == 0))
996
		    {
997
		       printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
998
		       rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+170, printer), milToPixel(aktLine+lineH, printer, true));
999
		       printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
1000
		       aktLine = extMil[1];
1001
		       printed = true;
1002
		    }
1003
		    else
1004
		       aktLine = extMil[1];
1005
 
1006
		    if (printed)
1007
		       printer.newPage();
1008
 
1009
		    page++;
1010
		    // Print the headline of the table
1011
		    if ((lastPage > 0 && page >= firstPage && page <= lastPage) ||
1012
		        (lastPage == 0 && firstPage == 0))
1013
		    {
1014
		       printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Bold, false));
1015
		       rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+35, printer), milToPixel(aktLine+lineH, printer, true));
1016
		       printArea.drawText(rect, Qt::AlignHCenter, i18n("Lap"));
1017
		       rect.setCoords(milToPixel(extMil[0]+35, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+60, printer), milToPixel(aktLine+lineH, printer, true));
1018
		       printArea.drawText(rect, Qt::AlignHCenter, i18n("Distance"));
1019
		       rect.setCoords(milToPixel(extMil[0]+60, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+85, printer), milToPixel(aktLine+lineH, printer, true));
1020
		       printArea.drawText(rect, Qt::AlignHCenter, i18n("Time"));
1021
		       rect.setCoords(milToPixel(extMil[0]+85, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+122, printer), milToPixel(aktLine+lineH, printer, true));
1022
		       printArea.drawText(rect, Qt::AlignHCenter, i18n("Speed"));
1023
		       rect.setCoords(milToPixel(extMil[0]+122, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+147, printer), milToPixel(aktLine+lineH, printer, true));
1024
		       printArea.drawText(rect, Qt::AlignHCenter, i18n("Heart rate"));
1025
		       rect.setCoords(milToPixel(extMil[0]+147, printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0]+170, printer), milToPixel(aktLine+lineH, printer, true));
1026
		       printArea.drawText(rect, Qt::AlignHCenter, i18n("Cadence"));
1027
		       aktLine += lineH;
1028
		       printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.5, printer, false)));
1029
		       printArea.drawLine(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true), milToPixel(extMil[0] + 170, printer), milToPixel(aktLine, printer, true));
1030
		       aktLine += 1.0;
1031
		       printed = true;
1032
		    }
1033
		    else
1034
		    {
1035
		       aktLine += lineH;
1036
		       aktLine += 1.0;
1037
		    }
1038
 
1039
		    printArea.setFont(QFont(QString("Helvetica"), 10, QFont::Normal, false));
1040
		 }
1041
 
1042
		 delete qt;
1043
		 laps++;
1044
	      }
1045
 
1046
	      aktLine = extMil[3] + 10.0;
1047
	      if ((lastPage > 0 && page >= firstPage && page <= lastPage) ||
1048
		  (lastPage == 0 && firstPage == 0))
1049
	      {
1050
		 printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
1051
		 rect.setCoords(milToPixel(extMil[0], printer),
1052
				milToPixel(aktLine, printer, true),
1053
				milToPixel(extMil[0]+170, printer),
1054
				milToPixel(aktLine+lineH, printer, true));
1055
		 printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
1056
		 printed = true;
1057
	      }
1058
 
1059
	      aktLine = extMil[1];
1060
	      page++;
1061
 
1062
	      if (printed && (page <= lastPage || lastPage == 0))
1063
		 printer.newPage();
1064
 
1065
	      if ((lastPage > 0 && (page < firstPage || page > lastPage)))
1066
		 break;
1067
 
1068
	      // Draw the map on top of a new page
1069
	      // Use 1/3 of the available height for the map
1070
	      qreal resFact = 8;	// The factor to calculate the resolution for pixmaps
1071
	      int width = (int)(milToPixel(170, printer) / resFact);
1072
	      int height = (int)(milToPixel(extMil[3] - extMil[1], printer, true) / resFact);
1073
	      pmPrMap = QPixmap(width, height / 3);	// 1/3 of page height
1074
	      DIRTY = true;
1075
	      int ct = curTab;
1076
	      curTab = 1;
1077
	      QApplication::restoreOverrideCursor();
1078
	      showTrack();
1079
	      QApplication::setOverrideCursor (QCursor(Qt::WaitCursor));
1080
	      DIRTY = false;
1081
	      curTab = ct;
1082
	      printArea.drawPixmap(milToPixel(extMil[0], printer),
1083
				milToPixel(extMil[1], printer),
1084
				pmPrMap.scaled((int)milToPixel(170, printer),
1085
				(int)milToPixel(extMil[3] - extMil[1], printer, true) / 3,
1086
				Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1087
	      // Put a frame around the map
1088
	      rect.setCoords(milToPixel(extMil[0], printer), milToPixel(extMil[1], printer, true),
1089
				milToPixel(extMil[0] + 170, printer),
1090
				milToPixel(extMil[1], printer, true) + (milToPixel(extMil[3] - extMil[1], printer, true) / 3));
1091
	      printArea.setPen(QPen(QBrush(QColor("black")), milToPixel(0.2, printer)));
1092
	      printArea.drawRect(rect);
1093
	      aktLine = (extMil[3] - extMil[1]) / 3.0 + extMil[1] + lineH;
1094
 
1095
	      // Draw the heart rate diagram
1096
	      rect.setCoords(milToPixel(extMil[0], printer),
1097
				milToPixel(aktLine, printer, true),
1098
				milToPixel(extMil[2], printer),
1099
				milToPixel(aktLine + lineH, printer, true));
1100
	      printArea.drawText(rect, Qt::AlignLeft, i18n("Heart rate:"));
1101
	      aktLine += lineH;
1102
	      qreal pixHeight = (extMil[3] - aktLine) / 3.0 - lineH * 2.0;
1103
	      int realH = (int)milToPixel(pixHeight, printer, true);
1104
	      height = realH / (int)resFact;
1105
	      showThreeCurve(width, height);	// Calculate the curves
1106
	      printArea.drawPixmap(milToPixel(extMil[0], printer),
1107
				milToPixel(aktLine, printer, true),
1108
				prHR.scaled((int)milToPixel(170, printer),
1109
				realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1110
	      rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
1111
				milToPixel(extMil[0] + 170, printer),
1112
				milToPixel(aktLine + pixHeight, printer, true));
1113
	      printArea.drawRect(rect);
1114
	      aktLine += pixHeight + lineH;
1115
 
1116
	      // Draw the elevation diagram
1117
	      rect.setCoords(milToPixel(extMil[0], printer),
1118
				milToPixel(aktLine, printer, true),
1119
				milToPixel(extMil[2], printer),
1120
				milToPixel(aktLine + lineH, printer, true));
1121
	      printArea.drawText(rect, Qt::AlignLeft, i18n("Elevation:"));
1122
	      aktLine += lineH;
1123
	      printArea.drawPixmap(milToPixel(extMil[0], printer),
1124
				milToPixel(aktLine, printer, true),
1125
				prElevation.scaled((int)milToPixel(170, printer),
1126
				realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1127
	      rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
1128
				milToPixel(extMil[0] + 170, printer),
1129
				milToPixel(aktLine + pixHeight, printer, true));
1130
	      printArea.drawRect(rect);
1131
	      aktLine += pixHeight + lineH;
1132
 
1133
	      // Draw the speed diagram
1134
	      rect.setCoords(milToPixel(extMil[0], printer),
1135
				milToPixel(aktLine, printer, true),
1136
				milToPixel(extMil[2], printer),
1137
				milToPixel(aktLine + lineH, printer, true));
1138
	      printArea.drawText(rect, Qt::AlignLeft, i18n("Speed:"));
1139
	      aktLine += lineH;
1140
	      printArea.drawPixmap(milToPixel(extMil[0], printer),
1141
				milToPixel(aktLine, printer, true),
1142
				prSpeed.scaled((int)milToPixel(170, printer),
1143
				realH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
1144
	      rect.setCoords(milToPixel(extMil[0], printer), milToPixel(aktLine, printer, true),
1145
				milToPixel(extMil[0] + 170, printer),
1146
				milToPixel(aktLine + pixHeight, printer, true));
1147
	      printArea.drawRect(rect);
1148
 
1149
	      // Print the page number at the right bottom of the page
1150
	      aktLine = extMil[3] + 10.0;
1151
	      printArea.setFont(QFont(QString("Helvetica"), 8, QFont::Normal, false));
1152
	      rect.setCoords(milToPixel(extMil[0], printer),
1153
				milToPixel(aktLine, printer, true),
1154
				milToPixel(extMil[0]+170, printer),
1155
				milToPixel(aktLine+lineH, printer, true));
1156
	      printArea.drawText(rect, Qt::AlignRight, i18n("Page %1").arg(page));
1157
	   }
1158
 
1159
	   rakt = rakt->next;
1160
	}
1161
 
1162
	printArea.end();
1163
	// Mark printing as done
1164
	ActivePrint = false;
1165
	QApplication::restoreOverrideCursor();
88 andreas 1166
}
1167
 
280 andreas 1168
qreal sportwatcherWidget::milToPixel(qreal dist, QPrinter &pr, bool dir)
1169
{
1170
	QSizeF r = pr.paperSize(QPrinter::DevicePixel);
1171
	QSizeF m = pr.paperSize(QPrinter::Millimeter);
1172
 
1173
	if (!dir)	// width
1174
	   return r.width() / m.width() * dist;
1175
	else
1176
	   return r.height() / m.height() * dist;
1177
}
1178
 
104 andreas 1179
/*
1180
 * This function allows the user to choose a file name, where we save the
1181
 * actual lap in Garmins own TCX format. This format is simply a XML-file.
1182
 * For details about the schema of this file look at
1183
 * http://developer.garmin.com/schemas/tcx/v2/
1184
 */
88 andreas 1185
void sportwatcherWidget::fileSaveAs()
1186
{
104 andreas 1187
QString fname;
1188
QFile fn;
1189
QString buffer;
1190
RUN_NODE *rn, *rakt;
1191
LAP *lap;
1192
POINT *point;
1193
int indent, i;
1194
QDateTime *qt;
232 andreas 1195
KUrl sDir("~/");
246 andreas 1196
QRegExp rx("(\\.tcx|\\.gpx|\\.osm)$");
104 andreas 1197
 
1198
	if (!gmn)
1199
	{
1200
	   KMessageBox::error(this, i18n("Currently no activity is selected!"));
1201
	   return;
1202
	}
1203
 
246 andreas 1204
	rx.setPatternSyntax(QRegExp::RegExp);
232 andreas 1205
	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 1206
 
1207
	if (fname.isEmpty())
1208
	   return;
1209
 
246 andreas 1210
	if (rx.indexIn(fname) < 0)
172 andreas 1211
	{
232 andreas 1212
	   KMessageBox::error(this, i18n("The file %1 has no valid file extension!").arg(fname));
172 andreas 1213
	   return;
1214
	}
1215
 
232 andreas 1216
	fn.setFileName(fname);
104 andreas 1217
 
1218
	if (fn.exists())
1219
	{
1220
	   if (KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
1221
	      return;
1222
	}
1223
 
246 andreas 1224
	rx.setPattern("*.gpx");
1225
	rx.setPatternSyntax(QRegExp::Wildcard);
172 andreas 1226
 
246 andreas 1227
	if (rx.exactMatch(fname))	// Should we create a *.gpx file?
172 andreas 1228
	{
1229
	   sportwatcherWidget::saveGPX(fname);
1230
	   return;
1231
	}
1232
 
246 andreas 1233
	rx.setPattern("*.osm");
1234
	rx.setPatternSyntax(QRegExp::Wildcard);
172 andreas 1235
 
246 andreas 1236
	if (rx.exactMatch(fname))	// Should we create a *.osm file?
172 andreas 1237
	{
1238
	   sportwatcherWidget::saveOSM(fname);
1239
	   return;
1240
	}
1241
 
1242
	// No, we create a *.tcx file!
171 andreas 1243
	indent = 0;
104 andreas 1244
	rn = ds.getRunNode();
1245
	lap = ds.getLap(rn->run->first_lap_index);
1246
 
1247
	if ((point = ds.getPoint(lap->start_time)) == 0)
1248
	{
1249
	   KMessageBox::error(this, i18n("No data to save!"));
1250
	   return;
1251
	}
1252
 
232 andreas 1253
	if (!fn.open(QIODevice::ReadWrite | QIODevice::Truncate))
104 andreas 1254
	{
232 andreas 1255
	   KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fname));
104 andreas 1256
	   return;
1257
	}
1258
 
1259
	buffer = QString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
1260
	buffer.append("<TrainingCenterDatabase xmlns=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2\" ");
1261
	buffer.append("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
1262
	buffer.append("xsi:schemaLocation=\"http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 ");
1263
	buffer.append("http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd\">\n\n");
1264
	writeTag (fn, buffer, indent);
1265
	buffer = QString("<folders/>\n\n");
1266
	writeTag (fn, buffer, indent);
1267
 
1268
	// Open a course
1269
	QFileInfo finfo(fname);
232 andreas 1270
	buffer = QString("<Courses>\n   <Course>\n      <name>%1</name>\n").arg(QFileInfo(finfo).baseName());
104 andreas 1271
	writeTag (fn, buffer, indent);
1272
	indent = 2;
1273
 
1274
	rakt = rn;
1275
 
1276
	while (rakt)
1277
	{
1278
	   if (rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
1279
	   	rakt->run->type != data_D1010)
1280
	   {
1281
	      rakt = rakt->next;
1282
	      continue;
1283
	   }
1284
 
1285
	   for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
1286
	   {
1287
	      if ((lap = ds.getLap(i)) == NULL)
1288
		 continue;
1289
 
1290
	      // Write the information of the lap
1291
	      writeTag (fn, QString("<Lap>\n"), indent);
1292
	      indent++;
1293
	      buffer.sprintf("<TotalTimeSeconds>%f</TotalTimeSeconds>\n", (double)lap->total_time / 100.0);
1294
	      writeTag (fn, buffer, indent);
172 andreas 1295
	      qt = garmin_dtime(lap->start_time);
1296
	      buffer = QString("<StartTime>%1</StartTime>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
1297
	      writeTag (fn, buffer, indent);
104 andreas 1298
	      buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", lap->total_distance);
1299
	      writeTag (fn, buffer, indent);
1300
 
1301
	      writeTag (fn, QString("<BeginPosition>\n"), indent);
1302
	      indent++;
1303
	      buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->begin.lat));
1304
	      writeTag (fn, buffer, indent);
1305
	      buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->begin.lon));
1306
	      writeTag (fn, buffer, indent);
1307
	      indent--;
1308
	      writeTag (fn, QString("</BeginPosition>\n"), indent);
1309
 
1310
	      writeTag (fn, QString("<EndPosition>\n"), indent);
1311
	      indent++;
1312
	      buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(lap->end.lat));
1313
	      writeTag (fn, buffer, indent);
1314
	      buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(lap->end.lon));
1315
	      writeTag (fn, buffer, indent);
1316
	      indent--;
1317
	      writeTag (fn, QString("</EndPosition>\n"), indent);
1318
 
1319
	      writeTag (fn, QString("<AverageHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
1320
	      indent++;
1321
	      buffer.sprintf("<Value>%d</Value>\n", lap->avg_heart_rate);
1322
	      writeTag (fn, buffer, indent);
1323
	      indent--;
1324
	      writeTag (fn, QString("</AverageHeartRateBpm>\n"), indent);
1325
 
1326
	      writeTag (fn, QString("<MaximumHeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
1327
	      indent++;
172 andreas 1328
	      buffer.sprintf("<Value>%d</Value>\n", lap->max_heart_rate);
104 andreas 1329
	      writeTag (fn, buffer, indent);
1330
	      indent--;
1331
	      writeTag (fn, QString("</MaximumHeartRateBpm>\n"), indent);
1332
 
172 andreas 1333
	      if (lap->avg_cadence < 255)
1334
	      {
1335
		 buffer.sprintf("<AverageCadence>%d</AverageCadence>\n", lap->avg_cadence);
1336
		 writeTag (fn, buffer, indent);
215 andreas 1337
		 buffer.sprintf("<Cadence>%d</Cadence>\n", lap->avg_cadence);
1338
		 writeTag (fn, buffer, indent);
172 andreas 1339
	      }
1340
 
215 andreas 1341
	      buffer = QString("<Intensity>%1</Intensity>\n").arg((!lap->intensity) ? "Active" : "Resting");
104 andreas 1342
	      writeTag (fn, buffer, indent);
217 andreas 1343
 
1344
	      buffer.sprintf("<Calories>%d</Calories>\n", lap->calories);
1345
	      writeTag (fn, buffer, indent);
1346
 
1347
	      buffer.sprintf("<MaximumSpeed>%f</MaximumSpeed>\n", lap->max_speed);
1348
	      writeTag (fn, buffer, indent);
104 andreas 1349
	      indent--;
1350
	      writeTag (fn, QString("</Lap>\n"), indent);
1351
 
1352
	      point = ds.getPoint(lap->start_time);
1353
	      writeTag (fn, QString("<Track>\n"), indent);
1354
	      indent++;
1355
 
1356
	      while (point)
1357
	      {
1358
		 if (point->time > (lap->start_time + (lap->total_time / 100)))
1359
		    break;
1360
 
1361
		 writeTag (fn, QString("<Trackpoint>\n"), indent);
1362
		 indent++;
1363
		 qt = garmin_dtime(point->time);
1364
		 buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
1365
		 writeTag (fn, buffer, indent);
1366
		 delete qt;
1367
		 writeTag (fn, QString("<Position>\n"), indent);
1368
		 indent++;
1369
		 buffer.sprintf("<LatitudeDegrees>%f</LatitudeDegrees>\n", SEMI2DEG(point->posn.lat));
1370
		 writeTag (fn, buffer, indent);
1371
		 buffer.sprintf("<LongitudeDegrees>%f</LongitudeDegrees>\n", SEMI2DEG(point->posn.lon));
1372
		 writeTag (fn, buffer, indent);
1373
		 indent--;
1374
		 writeTag (fn, QString("</Position>\n"), indent);
1375
 
1376
		 if (point->alt < 20000.0)
1377
		 {
1378
		    buffer.sprintf("<AltitudeMeters>%f</AltitudeMeters>\n", point->alt);
1379
		    writeTag (fn, buffer, indent);
1380
		 }
1381
 
1382
		 buffer.sprintf("<DistanceMeters>%f</DistanceMeters>\n", point->distance);
1383
		 writeTag (fn, buffer, indent);
1384
 
1385
		 if (point->heart_rate > 0 && point->heart_rate < 250)
1386
		 {
1387
		    writeTag (fn, QString("<HeartRateBpm xsi:type=\"HeartRateInBeatsPerMinute_t\">\n"), indent);
1388
		    indent++;
1389
		    buffer.sprintf("<Value>%d</Value>\n", point->heart_rate);
1390
		    writeTag (fn, buffer, indent);
1391
		    indent--;
1392
		    writeTag (fn, QString("</HeartRateBpm>\n"), indent);
1393
		 }
1394
 
249 andreas 1395
		 if (point->cadence < 0xff)
215 andreas 1396
		 {
1397
		    buffer.sprintf("<Cadence>%d</Cadence>\n", point->cadence);
1398
		    writeTag (fn, buffer, indent);
1399
		 }
1400
 
1401
		 buffer.sprintf("<SensorState>%s</SensorState>\n", (!point->sensor) ? "Absent" : "Present");
104 andreas 1402
		 writeTag (fn, buffer, indent);
1403
		 indent--;
1404
		 writeTag (fn, QString("</Trackpoint>\n"), indent);
1405
		 point = ds.getPoint(point->time + 1);
1406
	      }
1407
 
1408
	      indent--;
1409
	      writeTag (fn, QString("</Track>\n"), indent);
1410
	   }
1411
 
1412
	   indent--;
1413
	   writeTag (fn, QString("</Course>\n"), indent);
1414
	   indent--;
1415
	   writeTag (fn, QString("</Courses>\n"), indent);
1416
	   rakt = rakt->next;
1417
	}
1418
 
1419
	// Write information about device
1420
	// Here my personal signature is written :-)
1421
	writeTag (fn, QString("<Author xsi:type=\"Application_t\">\n"), indent);
1422
	indent++;
1423
	writeTag (fn, QString("<Name>SportWatcher</Name>\n"), indent);
1424
	writeTag (fn, QString("<Build>\n"), indent);
1425
	indent++;
1426
	writeTag (fn, QString("<Version>\n"), indent);
1427
	indent++;
1428
	writeTag (fn, QString("<VersionMajor>0</VersionMajor>\n"), indent);
1429
	writeTag (fn, QString("<VersionMinor>1</VersionMinor>\n"), indent);
1430
	writeTag (fn, QString("<BuildMajor>0</BuildMajor>\n"), indent);
1431
	writeTag (fn, QString("<BuildMinor>0</BuildMinor>\n"), indent);
1432
	indent--;
1433
	writeTag (fn, QString("</Version>\n"), indent);
1434
	writeTag (fn, QString("<Type>Beta</Type>\n"), indent);
1435
	writeTag (fn, QString("<Time>Jan 31 2008, 00:00:00</Time>\n"), indent);
1436
	writeTag (fn, QString("<Builder>theosys</Builder>\n"), indent);
1437
	indent--;
1438
	writeTag (fn, QString("</Build>\n"), indent);
1439
	writeTag (fn, QString("<LangID>EN</LangID>\n"), indent);
1440
	writeTag (fn, QString("<PartNumber>000-00000-00</PartNumber>\n"), indent);
1441
	indent--;
1442
	writeTag (fn, QString("</Author>\n"), indent);
1443
	writeTag (fn, QString("</TrainingCenterDatabase>\n"), indent);
1444
 
1445
	fn.close();
1446
	KMessageBox::information(this, i18n("File ") + fname + i18n(" was written successfully."));
88 andreas 1447
}
1448
 
1449
void sportwatcherWidget::fileSave()
1450
{
172 andreas 1451
	KMessageBox::information(this, i18n("This function is currently not implemented!"));
88 andreas 1452
}
1453
 
172 andreas 1454
void sportwatcherWidget::saveGPX(const QString &fn)
1455
{
1456
QFile qf;
1457
QString buffer;
1458
RUN_NODE *rn, *rakt;
1459
LAP *lap;
1460
POINT *point;
1461
int indent;
1462
unsigned int i;
1463
QDateTime *qt;
1464
double minLat, minLon, maxLat, maxLon;
1465
 
1466
	indent = 0;
1467
	rn = ds.getRunNode();
1468
	lap = ds.getLap(rn->run->first_lap_index);
1469
 
1470
	if ((point = ds.getPoint(lap->start_time)) == 0)
1471
	{
1472
	   KMessageBox::error(this, i18n("No data to save!"));
1473
	   return;
1474
	}
1475
 
232 andreas 1476
	qf.setFileName(fn);
172 andreas 1477
 
232 andreas 1478
	if (!qf.open(QIODevice::ReadWrite | QIODevice::Truncate))
172 andreas 1479
	{
232 andreas 1480
	   KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fn));
172 andreas 1481
	   return;
1482
	}
1483
 
1484
	buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
1485
	buffer.append("<gpx version=\"1.1\" creator=\"TheoSys SportWatcher\" xmlns=\"http://www.topografix.com/GPX/1/1\">\n");
1486
	buffer.append("   <metadata>\n");
1487
	indent = 0;
1488
	writeTag (qf, buffer, indent);
1489
 
1490
	// Find the edges of our coordinates
1491
	// We need this information in the header (metadata)
1492
	rakt = rn;
1493
	minLat = -90.0;
1494
	minLon = -180.0;
1495
	maxLat = 90.0;
1496
	maxLon = 180.0;
1497
 
1498
	while (rakt)
1499
	{
1500
	   if (rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
1501
	   	rakt->run->type != data_D1010)
1502
	   {
1503
	      rakt = rakt->next;
1504
	      continue;
1505
	   }
1506
 
1507
	   i = rakt->run->first_lap_index;
1508
	   // get the first lap
1509
	   if ((lap = ds.getLap(i)) == NULL)
1510
	      continue;
1511
 
1512
	   i = 0;
1513
	   // iterate the points associated with the laps
1514
	   while ((point = ds.getPoint(i)) != 0)
1515
	   {
1516
	      if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1517
	      {
1518
		 i = point->time + 1;
1519
		 continue;
1520
	      }
1521
 
1522
	      if (SEMI2DEG(point->posn.lat) > minLat)
1523
		 minLat = SEMI2DEG(point->posn.lat);
1524
 
1525
	      if (SEMI2DEG(point->posn.lat) < maxLat)
1526
		 maxLat = SEMI2DEG(point->posn.lat);
1527
 
1528
	      if (SEMI2DEG(point->posn.lon) > minLon)
1529
		 minLon = SEMI2DEG(point->posn.lon);
1530
 
1531
	      if (SEMI2DEG(point->posn.lon) < maxLon)
1532
		 maxLon = SEMI2DEG(point->posn.lon);
1533
 
1534
	      i = point->time + 1;
1535
	   }
1536
 
1537
	   rakt = rakt->next;
1538
	}
1539
 
1540
	buffer.sprintf("      <bounds minlat=\"%f\" minlon=\"%f\" maxlat=\"%f\" maxlon=\"%f\" />\n",
1541
		maxLat, minLon, minLat, maxLon);
1542
	buffer.append("   </metadata>\n");
1543
	buffer.append("   <trk>\n");
1544
	buffer.append("      <trkseg>\n");
1545
	writeTag (qf, buffer, indent);
1546
	indent = 3;
1547
	rn = ds.getRunNode();
1548
	lap = ds.getLap(rn->run->first_lap_index);
1549
	i = 0;
1550
 
1551
	while ((point = ds.getPoint(i)) != 0)
1552
	{
1553
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1554
	   {
1555
	      i = point->time + 1;
1556
	      continue;
1557
	   }
1558
 
1559
	   buffer.sprintf("<trkpt lat=\"%f\" lon=\"%f\">\n",
1560
		SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
1561
	   writeTag(qf, buffer, indent);
1562
	   indent++;
1563
	   buffer.sprintf("<ele>%f</ele>\n", point->alt);
1564
	   writeTag(qf, buffer, indent);
1565
	   qt = garmin_dtime(point->time);
1566
	   buffer = QString("<Time>%1</Time>\n").arg(qt->toString("yyyy-MM-ddThh:mm:ssZ"));
1567
	   writeTag(qf, buffer, indent);
1568
	   indent--;
1569
	   writeTag(qf, QString("</trkpt>\n"), indent);
1570
	   i = point->time + 1;
1571
	}
1572
 
1573
	indent = 0;
1574
	buffer = QString("      </trkseg>\n");
1575
	buffer.append("   </trk>\n");
1576
	buffer.append("</gpx>\n");
1577
	writeTag(qf, buffer, indent);
1578
	qf.close();
1579
	KMessageBox::information(this, i18n("File ") + fn + i18n(" was written successfully."));
1580
}
1581
 
1582
void sportwatcherWidget::saveOSM(const QString &fn)
1583
{
1584
QFile qf;
1585
QString buffer;
1586
RUN_NODE *rn, *rakt;
1587
LAP *lap;
1588
POINT *point;
1589
int indent, id, j;
1590
unsigned int i;
1591
double minLat, minLon, maxLat, maxLon;
1592
QDateTime *qt;
1593
 
1594
	indent = 0;
1595
	rn = ds.getRunNode();
1596
	lap = ds.getLap(rn->run->first_lap_index);
1597
 
1598
	if ((point = ds.getPoint(lap->start_time)) == 0)
1599
	{
1600
	   KMessageBox::error(this, i18n("No data to save!"));
1601
	   return;
1602
	}
1603
 
232 andreas 1604
	qf.setFileName(fn);
172 andreas 1605
 
232 andreas 1606
	if (!qf.open(QIODevice::ReadWrite | QIODevice::Truncate))
172 andreas 1607
	{
232 andreas 1608
	   KMessageBox::error(this, i18n("Error creating file %1!\nPlease check permissions").arg(fn));
172 andreas 1609
	   return;
1610
	}
1611
 
1612
	buffer = QString("<?xml version='1.0' encoding='UTF-8'?>\n");
1613
	buffer.append("<osm version=\"0.5\" generator=\"TheoSys SportWatcher\">\n");
1614
	indent = 0;
1615
	writeTag (qf, buffer, indent);
1616
	// Find the edges of our coordinates
1617
	// We need this information in the header (metadata)
1618
	rakt = rn;
1619
	minLat = -90.0;
1620
	minLon = -180.0;
1621
	maxLat = 90.0;
1622
	maxLon = 180.0;
1623
 
1624
	while (rakt)
1625
	{
1626
	   if (rakt->run->type != data_D1000 && rakt->run->type != data_D1009 &&
1627
	   	rakt->run->type != data_D1010)
1628
	   {
1629
	      rakt = rakt->next;
1630
	      continue;
1631
	   }
1632
 
1633
	   i = rakt->run->first_lap_index;
1634
	   // get the first lap
1635
	   if ((lap = ds.getLap(i)) == NULL)
1636
	      continue;
1637
 
1638
	   i = 0;
1639
	   // iterate the points associated with the laps
1640
	   while ((point = ds.getPoint(i)) != 0)
1641
	   {
1642
	      if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1643
	      {
1644
		 i = point->time + 1;
1645
		 continue;
1646
	      }
1647
 
1648
	      if (SEMI2DEG(point->posn.lat) > minLat)
1649
		 minLat = SEMI2DEG(point->posn.lat);
1650
 
1651
	      if (SEMI2DEG(point->posn.lat) < maxLat)
1652
		 maxLat = SEMI2DEG(point->posn.lat);
1653
 
1654
	      if (SEMI2DEG(point->posn.lon) > minLon)
1655
		 minLon = SEMI2DEG(point->posn.lon);
1656
 
1657
	      if (SEMI2DEG(point->posn.lon) < maxLon)
1658
		 maxLon = SEMI2DEG(point->posn.lon);
1659
 
1660
	      i = point->time + 1;
1661
	   }
1662
 
1663
	   rakt = rakt->next;
1664
	}
1665
 
1666
	buffer.sprintf("   <bound box='%f,%f,%f,%f' origin='http://www.openstreetmap.org/api/0.5' />\n",
1667
		maxLat, minLon, minLat, maxLon);
1668
	writeTag (qf, buffer, indent);
1669
	indent = 1;
1670
	rn = ds.getRunNode();
1671
	lap = ds.getLap(rn->run->first_lap_index);
1672
	i = 0;
1673
	id = -1;
1674
 
1675
	while ((point = ds.getPoint(i)) != 0)
1676
	{
1677
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
1678
	   {
1679
	      i = point->time + 1;
1680
	      continue;
1681
	   }
1682
 
1683
	   buffer.sprintf("<node id='%d' action='modify' visible='true' lat=\"%f\" lon=\"%f\">\n",
1684
		id, SEMI2DEG(point->posn.lat), SEMI2DEG(point->posn.lon));
1685
	   writeTag(qf, buffer, indent);
1686
	   indent++;
1687
	   buffer = QString("<tag k='created_by' v='TheoSys Sportwatcher' />\n");
1688
	   writeTag(qf, buffer, indent);
1689
	   buffer = QString("<tag k='highway' v='tertiary' />\n");
1690
	   writeTag(qf, buffer, indent);
1691
	   indent--;
1692
	   writeTag(qf, QString("</node>\n"), indent);
1693
	   id--;
1694
	   i = point->time + 1;
1695
	}
1696
 
1697
	qt = garmin_dtime(lap->start_time);
1698
	buffer.sprintf("<way id='%d' action='modify' visible='true' timestamp='%s'>\n",
232 andreas 1699
		id, QString(qt->toString("yyyy-MM-ddThh:mm:ssZ")).toAscii().data());
172 andreas 1700
	writeTag(qf, buffer, indent);
1701
	indent++;
1702
 
1703
	for (j = -1; j > id; j--)
1704
	{
1705
	   buffer.sprintf("<nd ref='%d' />\n", j);
1706
	   writeTag(qf, buffer, indent);
1707
	}
1708
 
1709
	indent--;
1710
	writeTag(qf, QString("</way>\n"), indent);
1711
	indent = 0;
1712
	writeTag(qf, QString("</osm>\n"), indent);
1713
	qf.close();
232 andreas 1714
	KMessageBox::information(this, i18n("File %1 was written successfully.").arg(fn));
172 andreas 1715
}
1716
 
88 andreas 1717
void sportwatcherWidget::fileOpen()
1718
{
1719
QString fname = KFileDialog::getOpenFileName(Data, QString("*.gmn"), this, QString("SportWatcher"));
137 andreas 1720
int m;
88 andreas 1721
 
1722
        if (fname.isEmpty())
1723
           return;
1724
 
1725
	spw.destroy();
1726
 
232 andreas 1727
        if (spw.setFileName(fname.toAscii().data()) == -1)
88 andreas 1728
	   return;
1729
 
1730
	if (gmn)
1731
	   garmin_free_data (gmn);
1732
 
1733
	gmn = spw.readFile();
104 andreas 1734
	zfactor = 0;
137 andreas 1735
 
1736
	if ((m = garmin_count_error()) > 0)
1737
	{
1738
	int i, key = -1;
1739
 
1740
	   for (i = 0; i < m; i++)
1741
	      KMessageBox::error(this, QString(garmin_get_next_error(&key)));
1742
 
1743
	   garmin_clear_errors();
1744
	   return;
1745
	}
1746
 
246 andreas 1747
	DIRTY = true;
250 andreas 1748
	tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
88 andreas 1749
	showLaps();
100 andreas 1750
	showTrack();
88 andreas 1751
	showCurves();
250 andreas 1752
 
1753
	if (curTab == 2)
1754
	{
1755
	   showThreeCurve();
1756
	   tabDirt2 = false;
1757
	}
1758
 
1759
	tabDirt0 = tabDirt3 = false;
246 andreas 1760
	DIRTY = false;
88 andreas 1761
}
1762
 
217 andreas 1763
void sportwatcherWidget::fileImport()
1764
{
1765
QString fname = KFileDialog::getOpenFileName(QString("~/"), QString("*.tcx"), this, QString("SportWatcher"));
1766
gmn_import import;
1767
int m;
225 andreas 1768
QString tgfile, fld, px;
232 andreas 1769
QPixmap qpx;
225 andreas 1770
QFileInfo datei;
246 andreas 1771
QList<QTreeWidgetItem *>item;
1772
QTreeWidgetItem *el, *it;
225 andreas 1773
LAP *lap;
1774
RUN_NODE *rn;
217 andreas 1775
 
1776
        if (fname.isEmpty())
1777
           return;
1778
 
1779
        import.setFile(fname);
1780
 
1781
	if ((m = import.import()) != 0)
1782
	{
1783
	   KMessageBox::error(this, QString(import.getError(m)));
1784
	   return;
1785
	}
1786
 
1787
	if (gmn)
246 andreas 1788
	{
217 andreas 1789
	   garmin_free_data (gmn);
246 andreas 1790
	   gmn = 0;
1791
	}
217 andreas 1792
 
246 andreas 1793
	if (!(gmn = import.getGarminData ()))
1794
	   return;
217 andreas 1795
 
246 andreas 1796
	DIRTY = true;
250 andreas 1797
	tabDirt0 = tabDirt1 = tabDirt2 = tabDirt3 = true;
217 andreas 1798
	showLaps();
1799
	showTrack();
1800
	showCurves();
250 andreas 1801
 
1802
	if (curTab == 2)
1803
	{
1804
	   showThreeCurve();
1805
	   tabDirt2 = false;
1806
	}
1807
 
1808
	tabDirt0 = tabDirt3 = false;
246 andreas 1809
	DIRTY = false;
225 andreas 1810
 
1811
	// Find the filename;
1812
	// It consists of the date and the time.
1813
	// We need this information to set the correct path to store the file.
1814
	tgfile = Data;		// The base path
1815
	rn = ds.getRunNode();
1816
	lap = ds.getLap(rn->run->first_lap_index);
1817
	QDateTime *qt = garmin_dtime (lap->start_time);
1818
	tgfile.append (qt->toString ("/yyyy")); // year is a folder
1819
	tgfile.append (qt->toString ("/MM"));	// month is a folder
1820
	tgfile.append (qt->toString ("/yyyyMMddThhmmss"));	// The file name
1821
	tgfile.append (".gmn");		// Extension of file name
1822
	datei.setFile (tgfile);
1823
	// save the data to a real file, but only if it doesn't exist allready.
232 andreas 1824
	garmin_save_all (gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 0);
225 andreas 1825
 
1826
	// in case the item is already in the list on the left side, we
1827
	// only highlight the item.
246 andreas 1828
	item = ui_sportwatcherWidgetBase.liActivities->findItems (tgfile, Qt::MatchExactly);
1829
 
1830
	if (item.size() > 0)
225 andreas 1831
	{
246 andreas 1832
	   ui_sportwatcherWidgetBase.liActivities->setItemSelected (item.at(0), true);
1833
	   ui_sportwatcherWidgetBase.liActivities->setCurrentItem (item.at(0));
225 andreas 1834
	   return;
1835
	}
1836
 
1837
	// insert everything into the list on the left side
1838
	switch (rn->run->sport_type)
1839
	{
1840
	   case D1000_running:
1841
	      fld = i18n("Running");
247 andreas 1842
	      px = QString("spw-running");
225 andreas 1843
	   break;
1844
 
1845
	   case D1000_biking:
1846
	      fld = i18n("Biking");
245 andreas 1847
	      px = QString("bike");
225 andreas 1848
	   break;
1849
 
1850
	   default:
1851
	      fld = i18n("Others");
245 andreas 1852
	      px = QString("other");
225 andreas 1853
	}
1854
 
1855
	// Do we have allready so items in the list?
246 andreas 1856
	item = ui_sportwatcherWidgetBase.liActivities->findItems (fld, Qt::MatchExactly);
1857
 
1858
	if (item.size() > 0)
225 andreas 1859
	{
246 andreas 1860
	   el = new QTreeWidgetItem(item.at(0));
1861
	   el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
1862
	   el->setData(0, Qt::UserRole, tgfile);
1863
	   el->setIcon(0, KIcon(px));
225 andreas 1864
	}
1865
	else	// no, this is the first item. (shouldn't be!)
1866
	{
246 andreas 1867
	   it = new QTreeWidgetItem(ui_sportwatcherWidgetBase.liActivities);
1868
	   it->setText(0, fld);
1869
	   it->setIcon(0, KIcon(QString("history")));
1870
 
1871
	   el = new QTreeWidgetItem(item.at(0));
1872
	   el->setText(0, kl->formatDateTime(*qt, KLocale::ShortDate, true));
1873
	   el->setData(0, Qt::UserRole, tgfile);
1874
	   el->setIcon(0, KIcon(px));
225 andreas 1875
	}
217 andreas 1876
}
1877
 
218 andreas 1878
/*
1879
 * Display a small dialog to rename the currently loaded session.
1880
 */
1881
void sportwatcherWidget::editRename()
1882
{
1883
bool ok;
1884
QString name, inhalt;
246 andreas 1885
QList<QTreeWidgetItem *> item;
1886
QTreeWidgetItem *lvItem;
218 andreas 1887
QFileInfo datei;
1888
RUN_NODE *rn;
1889
LAP *lap;
1890
garmin_list *list;
1891
D1009 *n;
1892
 
1893
	if (!gmn)
1894
	{
1895
	   KMessageBox::error(this, i18n("There is no session selected!"));
1896
	   return;
1897
	}
1898
 
1899
	rn = ds.getRunNode();
246 andreas 1900
	item = ui_sportwatcherWidgetBase.liActivities->selectedItems ();
218 andreas 1901
	lvItem = item.first();
1902
 
1903
	if (!isdigit(rn->run->workout.name[0]))
1904
	   inhalt = lvItem->text(0);
1905
	else
246 andreas 1906
	   inhalt.clear();
218 andreas 1907
 
1908
	name = KInputDialog::getText(i18n("Rename session"), i18n("Session name"),
246 andreas 1909
		inhalt, &ok, this, (QValidator *)0, QString("Nxxxxxxxxxxxxxx"),
1910
		i18n("Enter a new name for the currently selected activity."));
218 andreas 1911
 
1912
	if (!ok)
1913
	   return;
1914
 
1915
	if (name.length() <= 1)
1916
	{
1917
	   lap = ds.getLap(rn->run->first_lap_index);
1918
	   const QDateTime *qt = garmin_dtime (lap->start_time);
232 andreas 1919
	   QString idx = kl->formatDateTime(*qt, KLocale::ShortDate, true);
218 andreas 1920
	   lvItem->setText (0, idx);
246 andreas 1921
	   datei.setFile (lvItem->data(0, Qt::UserRole).toString());
232 andreas 1922
	   garmin_save_all (gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 1);
218 andreas 1923
	   delete qt;
1924
	   return;
1925
	}
1926
 
232 andreas 1927
	strncpy (rn->run->workout.name, name.toAscii().data(), 16);
218 andreas 1928
 
1929
	if (gmn->type != data_Dlist)
1930
	{
1931
	   KMessageBox::error(this, i18n("editRename: Unexpected structure type %1 found!").arg(gmn->type));
1932
	   return;
1933
	}
1934
 
1935
	list = (garmin_list *)gmn->data;
1936
 
1937
	if (list->head->data->type != data_D1009)	// This should be the run node
1938
	{
1939
	   KMessageBox::error(this, i18n("editRename: The run node was not found!"));
1940
	   return;
1941
	}
1942
 
1943
	n = (D1009 *)list->head->data->data;
246 andreas 1944
	strncpy (n->workout.name, rn->run->workout.name, 15);
218 andreas 1945
	lvItem->setText (0, name);
246 andreas 1946
	datei.setFile (lvItem->data(0, Qt::UserRole).toString());
232 andreas 1947
	garmin_save_all (gmn, datei.fileName().toAscii().data(), datei.absolutePath().toAscii().data(), 1);
218 andreas 1948
}
1949
 
88 andreas 1950
void sportwatcherWidget::fileNew()
1951
{
232 andreas 1952
progressWidget *dlg = new progressWidget(this);
96 andreas 1953
 
100 andreas 1954
	dlg->show();
137 andreas 1955
 
1956
	if (!dlg->Download())
1957
	{
1958
	int m, key;
1959
 
1960
	   key = -1;
1961
 
1962
	   for (m = 0; m < garmin_count_error(); m++)
1963
	      KMessageBox::error(this, QString(garmin_get_next_error(&key)));
1964
	}
1965
	else
1966
	   getActivities();
1967
 
1968
	garmin_clear_errors();
96 andreas 1969
	delete dlg;
88 andreas 1970
}
1971
 
1972
/*
1973
 * This function is called, when the user clicks at the menu point
1974
 * "Save Heart Rate".
1975
 * First, a file dialog box is displayed, where the user can choose a
1976
 * directory and a file name to save the heart rate.
1977
 * If the file could successfully be created, the heart rate is saved
137 andreas 1978
 * in the "HRM"-format. This is the native format Polar uses to store
88 andreas 1979
 * heart rate data. I've choosen this format, because it's popular and
1980
 * used by many other software too.
1981
 */
1982
void sportwatcherWidget::extrasSaveHR()
1983
{
1984
QString fname, str1, str2;
1985
QFile fdfile;
1986
QDateTime *qt, *oldqt;
1987
QDate dat;
1988
QTime t;
1989
QDir dir = QDir::home();
1990
char hv0[256];
1991
RUN_NODE *rn;
1992
LAP *lap, *alap;
1993
POINT *point;
1994
int samples, smp, seconds, anz, nsec, samsec;
1995
int avgHeart, minHeart, maxHeart, aktHeart;
1996
int secRange1, secRange2, secRange3, secAbove, secBeyond;
1997
 
1998
	if (!gmn)
1999
	{
2000
	   KMessageBox::information(this, i18n("There is no activity open"));
2001
	   return;
2002
	}
2003
 
2004
	if (HRM.isEmpty())
2005
	   str1 = dir.path();
2006
	else
2007
	   str1 = HRM;
2008
 
2009
	str1 +=  "/" + StartTime.toString("yyyyMMddThhmmss.zzz.hrm");
2010
	fname = KFileDialog::getSaveFileName(str1, QString("*.hrm"), this, QString("SportWatcher"));
2011
 
2012
	if (fname.isEmpty())
2013
	   return;
2014
 
232 andreas 2015
	fdfile.setFileName(fname);
88 andreas 2016
 
2017
	if (fdfile.exists())
2018
	{
2019
	   if (KMessageBox::questionYesNo(this, i18n("Do you really want to overwrite this file?")) == KMessageBox::No)
2020
	      return;
2021
	}
2022
 
232 andreas 2023
	if (!fdfile.open(QIODevice::ReadWrite | QIODevice::Truncate))
88 andreas 2024
	{
2025
	   KMessageBox::error(this, i18n("Error creating a file!\nPlease check permissions."));
2026
	   return;
2027
	}
2028
 
2029
	rn = ds.getRunNode();
2030
	lap = ds.getLap(rn->run->first_lap_index);
2031
	t = StartTime.time();
2032
	dat = StartTime.date();
2033
 
2034
	if ((point = ds.getPoint(lap->start_time)) == 0)
2035
	{
2036
	   fdfile.close();
2037
	   return;
2038
	}
2039
 
2040
	strcpy (hv0, "[Params]\n");
2041
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2042
	str1 = dat.toString("yyyyMMdd");
2043
	str2 = t.toString("hh:mm:ss.z");
2044
	sprintf(hv0, "Version=106\nMonitor=11\nSMode=000000000\nDate=%s\nStartTime=%s\n",
232 andreas 2045
		str1.toAscii().data(), str2.toAscii().data());
88 andreas 2046
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2047
	t.setHMS(0, 0, 0);
2048
	t = t.addSecs(max_time);
2049
	str2 = t.toString("hh:mm:ss.z");
2050
 
2051
	switch (sampleTime)
2052
	{
2053
	   case 0: samsec = 5; break;
2054
	   case 1: samsec = 15; break;
2055
	   case 2: samsec = 30; break;
2056
	   case 3: samsec = 60; break;
2057
	   default:
2058
	      samsec = 15;
2059
	}
2060
 
2061
	sprintf(hv0, "Length=%s\nInterval=%d\nUpper1=%d\nLower1=%d\nUpper2=%d\n",
232 andreas 2062
	   str2.toAscii().data(), samsec, upper1, lower1, upper2);
88 andreas 2063
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2064
	sprintf(hv0, "Lower2=%d\nUpper3=%d\nLower3=%d\nTimer1=00:00:00.0\n",
2065
		lower2, upper3, lower3);
2066
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2067
	strcpy(hv0, "Timer2=00:00:00.0\nTimer3=00:00:00.0\nActiveLimit=0\n");
2068
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2069
	sprintf(hv0, "MaxHR=%d\nRestHR=%d\nStartDelay=0\nVO2max=%d\nWeight=%d\n\n",
2070
		MaxHr, restHr, vo2max, weight);
2071
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2072
 
2073
	// Write the intervall times. One block for every lap
2074
	secRange1 = secRange2 = secRange3 = secAbove = secBeyond = 0;
2075
	strcpy(hv0, "[IntTimes]\n");
2076
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2077
	t.setHMS(0, 0, 0);
2078
 
2079
	for (unsigned int i = rn->run->first_lap_index; i < rn->run->last_lap_index; i++)
2080
	{
2081
	   alap = ds.getLap(i);
2082
	   point = ds.getPoint(alap->start_time);
2083
	   oldqt = garmin_dtime(point->time);
2084
	   avgHeart = minHeart = maxHeart = aktHeart = 0;
2085
	   anz = 0;
2086
	   unsigned long lastTime = point->time;
2087
	   int totSec = 0;
2088
 
2089
	   while (point)
2090
	   {
2091
	      if (point->time > (alap->start_time + (alap->total_time / 100)))
2092
		 break;
2093
 
2094
	      if (point->heart_rate > 0)
2095
	      {
2096
		 avgHeart += point->heart_rate;
2097
		 nsec = point->time - lastTime;
2098
		 totSec += nsec;
2099
 
2100
		 if (minHeart == 0 || minHeart > point->heart_rate)
2101
		    minHeart = point->heart_rate;
2102
 
2103
		 if (maxHeart < point->heart_rate)
2104
		    maxHeart = point->heart_rate;
2105
 
2106
		 if (aktHeart == 0 && totSec >= samsec)
2107
		    aktHeart = avgHeart / (anz + 1);
2108
 
2109
		 if (point->heart_rate < lower1)
2110
		    secBeyond += nsec;
2111
		 else if (point->heart_rate < lower2)
2112
		    secRange1 += nsec;
2113
		 else if (point->heart_rate < lower3)
2114
		    secRange2 += nsec;
2115
		 else if (point->heart_rate < upper3)
2116
		    secRange3 += nsec;
2117
		 else
2118
		    secAbove += nsec;
2119
 
2120
		 lastTime = point->time;
2121
		 anz++;
2122
	      }
2123
 
2124
	      point = ds.getPoint(point->time+1);
2125
	   }
2126
 
2127
	   t = t.addSecs(alap->total_time / 100);
2128
	   str1 = t.toString("hh:mm:ss.z");
166 andreas 2129
 
2130
	   if (anz > 0)
2131
	      avgHeart = avgHeart / anz;
2132
	   else
2133
	      avgHeart = 0;
2134
 
88 andreas 2135
	   sprintf(hv0, "%s\t %d\t %d\t %d\t %d\n",
232 andreas 2136
	      str1.toAscii().data(), aktHeart, minHeart, avgHeart, maxHeart);
88 andreas 2137
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
2138
	   strcpy(hv0, "32\t 0\t 0\t 0\t 0\t 0\n");
2139
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
2140
	   strcpy(hv0, "0\t 0\t 0\t 0\t 0\n");
2141
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
2142
	   sprintf(hv0, "0\t %d\t 0\t 0\t 0\t 0\n", (int)alap->total_distance);
2143
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
2144
	   strcpy(hv0, "0\t 0\t 0\t 0\t 0\t 0\n");
2145
	   write(fdfile.handle(), &hv0[0], strlen(hv0));
2146
	}
2147
 
2148
	strcpy(hv0, "\n[IntNotes]\n\n[ExtraData]\n\n");
2149
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2150
 
2151
	strcpy(hv0, "[Summary-123]\n");
2152
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
2153
	smp = max_time - secBeyond - secRange1 - secRange2 - secRange3 - secAbove;
245 andreas 2154
	sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
88 andreas 2155
		max_time, secRange1, secRange2 + secRange3,
2156
		secAbove + secBeyond, smp);
2157
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 1
2158
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
2159
		MaxHr, upper1, lower1, restHr);
2160
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 1
245 andreas 2161
	sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
88 andreas 2162
		max_time, secRange2, secRange1 + secRange3,
2163
		secAbove + secBeyond, smp);
2164
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 2
2165
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
2166
		MaxHr, upper2, lower2, restHr);
2167
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 2
245 andreas 2168
	sprintf(hv0, "%lu\t %u\t %u\t %u\t %u\n",
88 andreas 2169
		max_time, secRange3, secRange1 + secRange2,
2170
		secAbove + secBeyond, smp);
2171
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// limits 3
2172
	sprintf(hv0, "%d\t %d\t %d\t %d\n",
2173
		MaxHr, upper3, lower3, restHr);
2174
	write(fdfile.handle(), &hv0[0], strlen(hv0));	// Time limits 3
2175
	samples = max_time / samsec;
2176
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
2177
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2178
 
2179
	strcpy(hv0, "[Summary-TH]\n");
2180
	write(fdfile.handle(), &hv0[0], strlen(hv0));
245 andreas 2181
	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 2182
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2183
	sprintf(hv0, "%d\t %d\t %d\t %d\n", MaxHr, upper3, lower1, restHr);
2184
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2185
	sprintf(hv0, "0\t %u\n\n", samples);	// samples
2186
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2187
 
2188
	sprintf(hv0, "[HRZones]\n%d\n%d\n%d\n%d\n%d\n%d\n0\n0\n0\n0\n0\n\n",
2189
		MaxHr, upper3, upper2, upper1, lower1, restHr);
2190
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2191
 
2192
	strcpy(hv0, "[HRData]\n");
2193
	write(fdfile.handle(), &hv0[0], strlen(hv0));
2194
 
2195
	smp = 0;		// average heart rate of 15 seconds
2196
	seconds = 0;
2197
	anz = 0;
2198
	nsec = samsec;
2199
	oldqt = garmin_dtime(lap->start_time);
2200
	qt = 0;
2201
	point = ds.getPoint(lap->start_time);
2202
 
2203
	while (point)
2204
	{
2205
	   if (seconds >= nsec)
2206
	   {
2207
	      if (anz > 0)
2208
	      {
2209
		 sprintf(hv0, "%d\n", smp / anz);
2210
		 write(fdfile.handle(), &hv0[0], strlen(hv0));
2211
	      }
2212
 
2213
	      if (smp > 0 && seconds >= (nsec + samsec))
2214
	      {
2215
		 if (anz <= 0)
2216
		    anz = 0;
2217
 
2218
		 for (int x = nsec; x < seconds; x += samsec)
2219
		 {
2220
		    sprintf(hv0, "%d\n", smp / anz);
2221
		    write(fdfile.handle(), &hv0[0], strlen(hv0));
2222
		    nsec += samsec;
2223
		 }
2224
	      }
2225
 
2226
	      anz = 0;
2227
	      smp = 0;
2228
	      nsec += samsec;
2229
	   }
2230
 
2231
	   qt = garmin_dtime (point->time);
2232
	   seconds += oldqt->secsTo(*qt);
2233
 
2234
	   if (point->heart_rate > 0)
2235
	   {
2236
	      smp += point->heart_rate;
2237
	      anz++;
2238
	   }
2239
 
2240
	   delete oldqt;
2241
	   oldqt = qt;
2242
	   point = ds.getPoint(point->time + 1);
2243
	}
2244
 
2245
	fdfile.close();
2246
	KMessageBox::information(this, i18n("File successfully written."));
2247
}
2248
 
2249
void sportwatcherWidget::extrasSettings()
2250
{
232 andreas 2251
settingsWidget *dlg = new settingsWidget(this);
88 andreas 2252
 
2253
	if (dlg->exec() == QDialog::Accepted)
2254
	{
232 andreas 2255
	   KConfig cfg(QString("sportwatcher.rc"), KConfig::SimpleConfig);
2256
	   KConfigGroup ic (&cfg, "SportWatcher");
2257
	   lower1 = ic.readEntry("lower1", 0);
2258
	   lower2 = ic.readEntry("lower2", 0);
2259
	   lower3 = ic.readEntry("lower3", 0);
2260
	   upper1 = ic.readEntry("upper1", 0);
2261
	   upper2 = ic.readEntry("upper2", 0);
2262
	   upper3 = ic.readEntry("upper3", 0);
2263
	   MaxHr = ic.readEntry("maxHr", 0);
2264
	   restHr = ic.readEntry("restHr", 0);
2265
	   vo2max = ic.readEntry("vo2max", 0);
2266
	   weight = ic.readEntry("weight", 0);
2267
	   sampleTime = ic.readEntry("seconds", 1);
2268
	   Serial = ic.readEntry("Serial", false);
2269
	   Contour = ic.readEntry("Contour", false);
2270
	   Device = ic.readEntry("Device", QString("/dev/ttyUSB0"));
2271
	   Forerunner = ic.readEntry("Forerunner", false);
2272
	   Data = ic.readEntry("Data", QString("/"));
2273
	   HRM = ic.readEntry("HRM", QString("/"));
2274
	   MAP = ic.readEntry("MAP", QString("/"));
2275
	   Units = ic.readEntry("Units", 0);
2276
	   MapType = ic.readEntry("MapType", 0);
88 andreas 2277
	}
2278
 
2279
	delete dlg;
152 andreas 2280
}
151 andreas 2281
 
152 andreas 2282
void sportwatcherWidget::extrasWMSSettings()
2283
{
232 andreas 2284
#if defined HAVE_GDAL
158 andreas 2285
	if (MapType == MPT_BMP || MapType == MPT_GIF || MapType == MPT_PNG ||
2286
	    MapType == MPT_TIF)
2287
	{
232 andreas 2288
	   coordinatesWidget *idlg = new coordinatesWidget(this);
158 andreas 2289
	   idlg->exec();
2290
	   delete idlg;
2291
	   return;
2292
	}
274 andreas 2293
 
2294
	if (MapType == MPT_WMS)
158 andreas 2295
	{
274 andreas 2296
	   wmsbase *dlg = new wmsbase(this);
2297
	   dlg->exec();
2298
	   delete dlg;
2299
	}
280 andreas 2300
#if defined HAVE_MAPNIK
276 andreas 2301
	if (MapType == MPT_SHP || MapType == MPT_OSM)
274 andreas 2302
	{
2303
	   shapeWidget *dlg = new shapeWidget(this);
276 andreas 2304
 
2305
	   if (MapType == MPT_SHP)
2306
	      dlg->setMapType(shapeWidget::MAP_SHAPE);
2307
	   else
2308
	      dlg->setMapType(shapeWidget::MAP_OSM);
2309
 
274 andreas 2310
	   dlg->exec();
2311
	   delete dlg;
2312
	}
280 andreas 2313
#else
2314
	KMessageBox::detailedSorry(this,
2315
	   i18n("This function was disabled at compile time because of missing Mapnik!"),
2316
	   i18n("SportWatcher needs Mapnik 0.6 or newer, to enable this function.\n") +
2317
	   i18n("If you like this to be working, install Mapnik and recompile the source."));
2318
#endif
276 andreas 2319
	if (MapType != MPT_WMS && MapType != MPT_SHP && MapType != MPT_OSM)
274 andreas 2320
	{
158 andreas 2321
	   KMessageBox::detailedSorry(this,
274 andreas 2322
	      i18n("You have not choosen a WMS tag file or shape file directory!"),
2323
	      i18n("This dialog is especialy to set map specific parameters. ") +
158 andreas 2324
	      i18n("Therefore this dialog is temporary disabled. It will be ") +
274 andreas 2325
	      i18n("available again, as soon as you choose \"WMS server\" or ") +
2326
	      i18n("Shape file as your map type."));
158 andreas 2327
	      return;
2328
	}
156 andreas 2329
#else
2330
	KMessageBox::detailedSorry(this,
280 andreas 2331
	   i18n("This function was disabled at compile time because of missing GDAL v1.x.x!"),
2332
	   i18n("Sportwatcher needs GDAL v1.5.x or newer, to enable this function.\n") +
2333
	   i18n("If you like this to be working, install GDAL and recompile the source!"));
156 andreas 2334
#endif
88 andreas 2335
}
2336
 
2337
/*
2338
 * Functions to fill in the boxes of the main mask.
2339
 */
2340
void sportwatcherWidget::showLaps()
2341
{
2342
QString qs_name, qs_distance, qs_etime, qs_avgpace, qs_avgspeed, qs_maxspeed;
2343
QString qs_calories, qs_avghr, qs_maxhr, qs_avgcadence, qs_ascent, qs_descent;
248 andreas 2344
QString qs_totdist;
88 andreas 2345
QDateTime dt;
2346
QTime t, st;
249 andreas 2347
QDateTime *qt;
2348
LAP *lap;
2349
POINT *point;
88 andreas 2350
RUN_NODE *rakt, *rn;
149 andreas 2351
int laps, i, anz, men, cad;
249 andreas 2352
double alt_asc, alt_dsc, sum_asc, sum_dsc, old_asc, old_dsc;
248 andreas 2353
double totdist;
216 andreas 2354
bool pause;
88 andreas 2355
 
246 andreas 2356
	if (!DIRTY)
2357
	   return;
2358
 
88 andreas 2359
	if (!gmn)
2360
	   return;
2361
 
2362
	if (gmn->type == data_Dnil)
2363
	{
280 andreas 2364
	   KMessageBox::error(this, i18n("No data found!"));
88 andreas 2365
	   return;
2366
	}
2367
 
2368
	if (gmn->type != data_Dlist)     /* List of data */
2369
	{
280 andreas 2370
	   KMessageBox::error(this, i18n("Found unexpected data type %1!").arg(gmn->type));
88 andreas 2371
	   return;
2372
	}
2373
 
2374
	ds.destroy();
221 andreas 2375
	min_hr = max_hr = avg_hr = 0;
88 andreas 2376
	min_height = max_height = 0.0;
218 andreas 2377
	min_speed = max_speed = 0.0;
248 andreas 2378
	totdist = 0.0;
2379
	// Tab Summary
245 andreas 2380
	ui_sportwatcherWidgetBase.liLaps->clear();
2381
	ui_sportwatcherWidgetBase.liLaps->setAllColumnsShowFocus(true);
248 andreas 2382
	// Tab Laps
2383
	ui_sportwatcherWidgetBase.twLaps->clear();
88 andreas 2384
	ds.garmin_print_data(gmn);
245 andreas 2385
 
2386
	if (!(rn = ds.getRunNode()))
2387
	   return;
2388
 
88 andreas 2389
	rakt = rn;
248 andreas 2390
	// Tab Summary
245 andreas 2391
	ui_sportwatcherWidgetBase.liLaps->setRootIsDecorated(true);
88 andreas 2392
 
248 andreas 2393
	for (i = 1; i < 12; i++)
2394
	   ui_sportwatcherWidgetBase.liLaps->setColumnAlignment(i, Qt::AlignRight);
2395
	// Tab Laps
2396
	ui_sportwatcherWidgetBase.edTotalDistance->clear();
2397
	ui_sportwatcherWidgetBase.edTotalTime->clear();
2398
	ui_sportwatcherWidgetBase.edAvgSpeed->clear();
2399
	ui_sportwatcherWidgetBase.edTotalHeight->clear();
2400
	ui_sportwatcherWidgetBase.edAvgHR->clear();
2401
	ui_sportwatcherWidgetBase.edLapNumber->clear();
2402
 
88 andreas 2403
	qs_name = qs_distance = qs_etime = qs_avgpace = qs_avgspeed = qs_maxspeed = QString("");
2404
	qs_calories = qs_avghr = qs_maxhr = qs_avgcadence = qs_ascent = qs_descent = QString("");
2405
	men = 0;
149 andreas 2406
	cad = 0;
88 andreas 2407
 
249 andreas 2408
	// The main loop.
2409
	// If a supported run type is detected, it will be processed.
88 andreas 2410
	while (rakt)
2411
	{
249 andreas 2412
	   // Check for a supported run type
88 andreas 2413
	   if (rakt->run->type == data_D1000 || rakt->run->type == data_D1009 ||
2414
	   	rakt->run->type == data_D1010)
2415
	   {
249 andreas 2416
	   int cal, ahr, mhr;
88 andreas 2417
	   double distance, speed, mspeed;
2418
	   QDate dat;
2419
 
249 andreas 2420
	      // Set the name depending on the sport type
2421
	      // This is used on the tab "Summary"
88 andreas 2422
	      switch (rakt->run->sport_type)
2423
	      {
280 andreas 2424
		 case D1000_running: qs_name = i18n("Running: "); break;
2425
		 case D1000_biking:  qs_name = i18n("Biking: "); break;
2426
		 case D1000_other:   qs_name = i18n("Other: "); break;
88 andreas 2427
		 default:
280 andreas 2428
		    qs_name = i18n("Unknown: ");
88 andreas 2429
	      }
2430
 
245 andreas 2431
	      if (!(lap = ds.getLap(rakt->run->first_lap_index)))
2432
		 return;
2433
 
88 andreas 2434
	      qt = garmin_dtime (lap->start_time);
2435
	      StartTime = *qt;
2436
	      st = qt->time();
2437
	      dat = qt->date();
2438
	      delete qt;
213 andreas 2439
	      qt = 0;
2440
	      // Find the last track;
2441
	      //    It is possible to delete laps directly on the watch,
2442
	      //    so we can't be sure the last lap is really the last one.
2443
	      //    Tracks are not deleted and the last track contains the
2444
	      //    summuraries we need.
249 andreas 2445
	      if (!(point = ds.getLastPoint()))
213 andreas 2446
	      {
249 andreas 2447
		 KMessageBox::error(this, i18n("Error getting the last messure point!"));
245 andreas 2448
		 return;
215 andreas 2449
	      }
2450
 
249 andreas 2451
	      qt = garmin_dtime(point->time);
2452
	      t = qt->time();
88 andreas 2453
	      t.setHMS(0, 0, 0);
249 andreas 2454
	      t = t.addSecs(ds.getTotalTime());
88 andreas 2455
	      qt->setDate(dat);
2456
	      qt->setTime(t);
232 andreas 2457
	      qs_name.append(kl->formatDate(dat, KLocale::ShortDate));
88 andreas 2458
	      qs_name.append(" ");
230 andreas 2459
	      qs_name.append(kl->formatTime(st, true));
249 andreas 2460
	      max_time = ds.getTotalTime();
88 andreas 2461
	      qs_etime = QString(qt->toString("hh:mm:ss.zzz"));
2462
 
2463
	      distance = 0.0;
2464
	      cal = 0;
2465
	      mspeed = 0;
2466
	      ahr = mhr = 0;
2467
	      anz = 0;
149 andreas 2468
	      cad = 0;
2469
	      sum_asc = sum_dsc = old_asc = old_dsc = 0;
88 andreas 2470
 
249 andreas 2471
	      // Find out the total distance, calories, maximum speed,
2472
	      // maximum heart rate and the average heart rate. Get this
2473
	      // values from the lap summary the watch made.
88 andreas 2474
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
2475
	      {
2476
		 if ((lap = ds.getLap(i)) == NULL)
2477
		    continue;
2478
 
2479
		 distance += lap->total_distance;
2480
		 cal += lap->calories;
149 andreas 2481
 
2482
		 if (lap->avg_cadence != 0xff)
2483
		    cad += lap->avg_cadence;
2484
 
88 andreas 2485
		 ahr += lap->avg_heart_rate;
2486
		 anz++;
2487
 
2488
		 if (lap->max_speed > mspeed)
2489
		    mspeed = lap->max_speed;
2490
 
2491
		 if (lap->max_heart_rate > mhr)
2492
		    mhr = lap->max_heart_rate;
2493
	      }
2494
 
249 andreas 2495
	      total_distance = distance = ds.getTotalDistance();
213 andreas 2496
 
149 andreas 2497
	      if (Units == 1)		// Statute?
2498
		 qs_distance.sprintf("%.2f ft", distance / 0.304);
2499
	      else
2500
	         qs_distance.sprintf("%.2f m", distance);
2501
 
88 andreas 2502
	      if (distance > 0)
2503
	      {
2504
		 QTime tt = qt->time();
156 andreas 2505
		 long secs = (double)(tt.hour() * 3600 + tt.minute() * 60 + tt.second()) / 100.0;
2506
 
2507
		 if (Units == 0)
2508
		    secs = secs * (1000.0 / distance * 100.0);
2509
		 else
2510
		    secs = secs * (1609.344 / distance * 100.0);
2511
 
88 andreas 2512
		 int h = secs / 3600;
2513
		 int m = (secs - (h * 3600)) / 60;
2514
		 int s = secs - ((h * 3600) + (m * 60));
2515
		 t = QTime(h, m, s, 0);
230 andreas 2516
		 qs_avgpace = QString("  ") + kl->formatTime(t, true);
156 andreas 2517
 
2518
		 if (Units == 0)
2519
		    qs_avgpace.append(QString(" /km"));
2520
		 else
2521
		    qs_avgpace.append(QString(" /mi"));
88 andreas 2522
	      }
2523
 
149 andreas 2524
	      if (Units == 1)		// Statute?
249 andreas 2525
		 speed = distance / ds.getTotalTime() * 3.6 / 1.609344;
149 andreas 2526
	      else
249 andreas 2527
		 speed = distance / ds.getTotalTime() * 3.6;
149 andreas 2528
 
156 andreas 2529
	      qs_avgspeed.sprintf("%.2f %s", speed, (Units == 1) ? "mph" : "km/h");
2530
	      qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? mspeed * 3.6 / 1.609344 : mspeed * 3.6, (Units == 1) ? "mph" : "km/h");
88 andreas 2531
	      qs_calories.sprintf("%d", cal);
2532
	      qs_avghr.sprintf("%d bpm", ahr / anz);
2533
	      qs_maxhr.sprintf("%d bpm", mhr);
2534
 
149 andreas 2535
	      if (cad > 0)
2536
		 qs_avgcadence.sprintf("%d", cad / anz);
2537
 
248 andreas 2538
	      // Add the summary line columns to the tab "Summary"
2539
	      K3ListViewItem *element = new K3ListViewItem(ui_sportwatcherWidgetBase.liLaps,
2540
	        qs_name, kl->formatNumber(qs_distance, false),
2541
		qs_etime, qs_avgpace, kl->formatNumber(qs_avgspeed, false),
2542
		kl->formatNumber(qs_maxspeed, false), qs_calories, qs_avghr);
88 andreas 2543
	      element->setText(8, qs_maxhr);
2544
	      element->setText(9, qs_avgcadence);
248 andreas 2545
	      element->setText(10, kl->formatNumber(qs_ascent, false));
2546
	      element->setText(11, kl->formatNumber(qs_descent, false));
88 andreas 2547
	      element->sortChildItems(0, false);
2548
	      element->setOpen(true);
245 andreas 2549
	      element->setPixmap(0, KIcon(QString("activity")).pixmap(16));
2550
	      ui_sportwatcherWidgetBase.liLaps->insertItem(element);
248 andreas 2551
	      // Add some of the summaries to the fields on the tab "Lap details"
2552
	      ui_sportwatcherWidgetBase.edTotalDistance->setAlignment(Qt::AlignRight);
2553
	      ui_sportwatcherWidgetBase.edTotalDistance->insert(kl->formatNumber(qs_distance, false));
2554
	      ui_sportwatcherWidgetBase.edTotalTime->setAlignment(Qt::AlignRight);
2555
	      ui_sportwatcherWidgetBase.edTotalTime->insert(qs_etime);
2556
	      ui_sportwatcherWidgetBase.edAvgSpeed->setAlignment(Qt::AlignRight);
2557
	      ui_sportwatcherWidgetBase.edAvgSpeed->insert(kl->formatNumber(qs_avgspeed, false));
2558
	      ui_sportwatcherWidgetBase.edTotalHeight->setAlignment(Qt::AlignRight);
2559
	      ui_sportwatcherWidgetBase.edTotalHeight->insert(kl->formatNumber(qs_ascent, false));
2560
	      ui_sportwatcherWidgetBase.edAvgHR->setAlignment(Qt::AlignRight);
2561
	      ui_sportwatcherWidgetBase.edAvgHR->insert(qs_avghr);
88 andreas 2562
	      delete qt;
2563
	      /* Get the laps. */
2564
	      laps = 1;
2565
 
2566
	      for (i = rakt->run->first_lap_index; (unsigned int)i <= rakt->run->last_lap_index; i++)
2567
	      {
149 andreas 2568
		 double spd;
2569
		 char *un;
2570
 
88 andreas 2571
		 if ((lap = ds.getLap(i)) == NULL)
2572
		    continue;
2573
 
2574
		 qt = garmin_dtime (lap->start_time);
2575
		 qs_name.sprintf("Lap %03d - ", laps);
230 andreas 2576
		 qs_name.append(kl->formatTime(qt->time(), true));
149 andreas 2577
		 qs_distance.sprintf("%.2f %s", (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance, (Units == 1) ? "ft" : "m");
248 andreas 2578
		 totdist += (Units == 1) ? lap->total_distance / 0.304 : lap->total_distance;
2579
		 qs_totdist.sprintf("%2.f %s", totdist, (Units == 1) ? "ft" : "m");
88 andreas 2580
		 t = QTime(0, 0, 0, 0);
2581
		 t = t.addMSecs(lap->total_time * 10);
2582
		 qs_etime = t.toString("hh:mm:ss.zzz");
149 andreas 2583
		 spd = lap->total_distance / (lap->total_time / 100.0);
249 andreas 2584
		 delete qt;
2585
		 qt = 0;
149 andreas 2586
 
2587
		 if (Units == 0)
2588
		 {
2589
		    un = (char *)"km/h";
2590
		    spd *= 3.6;
2591
		 }
2592
		 else
156 andreas 2593
		 {
2594
		    spd *= 3.6 / 1.609344;
2595
		    un = (char *)"mph";
2596
		 }
149 andreas 2597
 
2598
		 qs_avgspeed.sprintf("%.2f %s", spd, un);
156 andreas 2599
		 qs_maxspeed.sprintf("%.2f %s", (Units == 1) ? lap->max_speed * 3.6 / 1.609344 : lap->max_speed * 3.6, un);
88 andreas 2600
		 qs_calories.sprintf("%d", lap->calories);
2601
 
2602
		 if (lap->total_distance > 0 && lap->total_time != 0)
2603
		 {
156 andreas 2604
		    double fact;
2605
 
2606
		    if (Units == 0)
2607
		       fact = 1000.0;		// 1 km
2608
		    else
2609
		       fact = 1609.344;		// 1 mile in meters
2610
 
2611
		    long secs = (double)lap->total_time / 10000.0 * (fact / lap->total_distance * 100.0);
88 andreas 2612
		    int h = secs / 3600;
2613
		    int m = (secs - (h * 3600)) / 60;
2614
		    int s = secs - ((h * 3600) + (m * 60));
2615
		    t = QTime(h, m, s, 0);
230 andreas 2616
		    qs_avgpace = kl->formatTime(t, true);
156 andreas 2617
 
2618
		    if (Units == 0)
2619
		       qs_avgpace.append(QString(" /km"));
2620
		    else
2621
		       qs_avgpace.append(QString(" /mi"));
88 andreas 2622
		 }
2623
 
2624
		 qs_avghr.sprintf("%d bpm", lap->avg_heart_rate);
2625
		 qs_maxhr.sprintf("%d bpm", lap->max_heart_rate);
2626
 
2627
		 anz = 0;
2628
		 alt_asc = alt_dsc = 0;
249 andreas 2629
		 // Add a new detail line to the tab "Lap details"
2630
		 QTreeWidgetItem * trdetail = new QTreeWidgetItem(ui_sportwatcherWidgetBase.twLaps);
88 andreas 2631
 
2632
		 if ((point = ds.getPoint(lap->start_time)) != 0)
2633
		 {
2634
		    if (point->alt < 20000)
149 andreas 2635
		    {
88 andreas 2636
		       alt_dsc = alt_asc = point->alt;
149 andreas 2637
 
2638
		       if (old_asc == 0)
2639
			  old_asc = alt_asc;
2640
 
2641
		       if (old_dsc == 0)
2642
			  old_dsc = alt_dsc;
2643
		    }
88 andreas 2644
		    else
2645
		       alt_dsc = alt_asc = 0;
2646
 
218 andreas 2647
		    POINT *oldPoint = 0;
2648
		    double sc, dist, speed;
222 andreas 2649
		    unsigned long t1, t2;
2650
		    t1 = t2 = 0;
2651
		    pause = false;
2652
		    bool ignore = false;
218 andreas 2653
 
88 andreas 2654
		    while (point)
2655
		    {
2656
		       if (point->time > (lap->start_time + (lap->total_time / 100)))
2657
			 break;
2658
 
249 andreas 2659
		       QTreeWidgetItem *child = new QTreeWidgetItem(trdetail);
2660
		       qt = garmin_dtime (point->time);
2661
		       child->setText(0, kl->formatTime(qt->time(), true));
2662
		       child->setTextAlignment(0, Qt::AlignRight);
2663
		       child->setText(8, QString("%1 %2").arg(kl->formatNumber((double)point->heart_rate, 0)).arg(" bpm"));
2664
		       child->setTextAlignment(8, Qt::AlignRight);
2665
 
2666
		       if (point->cadence < 0xff)
2667
		       {
2668
			  child->setText(10, kl->formatNumber((double)point->cadence, 0));
2669
			  child->setTextAlignment(10, Qt::AlignRight);
2670
		       }
2671
 
2672
		       if (point->alt < 20000)
2673
		       {
2674
		       double alt = (Units == 0) ? (double)point->alt : (double)point->alt / 0.304;
2675
 
2676
			  child->setText(11, QString("%1 %2").arg(kl->formatNumber(alt, 2)).arg((Units == 0) ? QString(" m") : QString(" ft")));
2677
			  child->setTextAlignment(11, Qt::AlignRight);
2678
		       }
2679
 
218 andreas 2680
		       if (!oldPoint)
2681
			  oldPoint = point;
2682
 
88 andreas 2683
		       if (point->alt > alt_asc && point->alt < 20000)
2684
		       {
2685
			  alt_asc = point->alt;
2686
 
2687
			  if (alt_dsc == 0)
2688
			     alt_dsc = point->alt;
2689
		       }
2690
 
2691
		       if (point->alt < alt_dsc)
2692
			  alt_dsc = point->alt;
2693
 
2694
		       // save the min and max values. We need this information to
2695
		       // build the graphics.
221 andreas 2696
		       if (point->heart_rate > max_hr && point->heart_rate < 250)
88 andreas 2697
			  max_hr = point->heart_rate;
2698
 
221 andreas 2699
		       if ((min_hr == 0 && point->heart_rate > 0 && point->heart_rate < 250)
2700
			   || (point->heart_rate > 0 && point->heart_rate < min_hr))
88 andreas 2701
			  min_hr = point->heart_rate;
2702
 
2703
		       if (point->alt < 20000 && max_height < point->alt)
2704
			  max_height = point->alt;
2705
 
2706
		       if (point->alt < 20000 && (min_height == 0.0 || min_height > point->alt))
2707
			  min_height = point->alt;
2708
 
218 andreas 2709
		       // Calculate speed of current track
222 andreas 2710
		       if (!pause && point->distance > 1.0e10)
2711
		       {
2712
			  t1 = point->time;
2713
			  pause = true;
2714
			  ignore = true;
2715
		       }
2716
		       else if (pause)
2717
		       {
2718
			  t2 = point->time;
2719
			  pause = false;
2720
			  point = ds.getPoint(point->time + 1);
2721
			  continue;
2722
		       }
218 andreas 2723
 
222 andreas 2724
		       if (!ignore && !pause)
2725
		       {
2726
			  sc = point->time - oldPoint->time;
2727
			  dist = point->distance - oldPoint->distance;
218 andreas 2728
 
249 andreas 2729
			  child->setText(1, QString("%1 %2").arg(kl->formatNumber((Units == 0) ? (double)dist : (double)dist / 0.304, 2)).arg((Units == 0) ? QString(" m") : QString(" ft")));
2730
			  child->setTextAlignment(1, Qt::AlignRight);
2731
 
222 andreas 2732
			  if (t2 > t1)
2733
			     sc -= t2 - t1;
218 andreas 2734
 
222 andreas 2735
			  if (sc > 0.0)
223 andreas 2736
			  {
222 andreas 2737
			     speed = (dist / sc) * 3.6;
223 andreas 2738
 
2739
			     if (speed > lap->max_speed * 3.6)
2740
			        speed = lap->max_speed * 3.6;
2741
			  }
222 andreas 2742
			  else
2743
			     speed = 0.0;
218 andreas 2744
 
222 andreas 2745
			  if (Units == 1)
2746
			     speed /= 1.609344;
218 andreas 2747
 
249 andreas 2748
			  child->setText(5, QString("%1 %2").arg(kl->formatNumber(speed, 2)).arg((Units == 0) ? QString(" Km/h") : QString(" mi/h")));
2749
			  child->setTextAlignment(5, Qt::AlignRight);
2750
 
222 andreas 2751
			  if (speed > 0.0 && speed < 400.0 && max_speed < speed)
2752
			     max_speed = speed;
2753
 
2754
			  if (speed > 0.0 && (min_speed == 0.0 || min_speed > speed))
2755
			     min_speed = speed;
2756
 
2757
			  oldPoint = point;
2758
		       }
2759
 
2760
		       if (!pause && ignore)
2761
			  ignore = false;
2762
 
221 andreas 2763
		       if (point->heart_rate > 0 && point->heart_rate < 250)
88 andreas 2764
		       {
2765
			  avg_hr += point->heart_rate;
2766
			  men++;
2767
		       }
2768
 
2769
		       point = ds.getPoint(point->time + 1);
2770
		    }
2771
 
149 andreas 2772
		    if (old_asc < alt_asc)
2773
		       sum_asc += (alt_asc - old_asc);
2774
 
2775
		    if (old_dsc > alt_dsc)
2776
		       sum_dsc += (old_dsc - alt_dsc);
2777
 
2778
		    old_asc = alt_asc;
2779
		    old_dsc = alt_dsc;
2780
		    qs_ascent.sprintf("%.2f %s", (Units == 1) ? (alt_asc / 0.304) : alt_asc, (Units == 1) ? "ft" : "m");
2781
		    qs_descent.sprintf("%.2f %s", (Units == 1) ? (alt_dsc / 0.304) : alt_dsc, (Units == 1) ? "ft" : "m");
88 andreas 2782
		 }
2783
 
2784
		 if (lap->avg_cadence != 0xff)
2785
		    qs_avgcadence.sprintf("%d", lap->avg_cadence);
248 andreas 2786
		 // Add a new detail line to the tab "Summary"
2787
		 K3ListViewItem *edetail = new K3ListViewItem(element, qs_name,
2788
			kl->formatNumber(qs_distance, false),
2789
			qs_etime, qs_avgpace, kl->formatNumber(qs_avgspeed, false),
2790
			kl->formatNumber(qs_maxspeed, false), qs_calories, qs_avghr);
88 andreas 2791
		 edetail->setText(8, qs_maxhr);
2792
		 edetail->setText(9, qs_avgcadence);
248 andreas 2793
		 edetail->setText(10, kl->formatNumber(qs_ascent, false));
2794
		 edetail->setText(11, kl->formatNumber(qs_descent, false));
245 andreas 2795
		 edetail->setPixmap(0, KIcon(QString("history")).pixmap(16));
2796
		 QPixmap qpx = KIcon(QString("other")).pixmap(16);
249 andreas 2797
 
248 andreas 2798
		 trdetail->setText(0, qs_etime);
2799
		 trdetail->setTextAlignment(0, Qt::AlignRight);
2800
		 trdetail->setText(1, kl->formatNumber(qs_distance));
2801
		 trdetail->setTextAlignment(1, Qt::AlignRight);
2802
		 trdetail->setText(2, kl->formatNumber(qs_totdist));
2803
		 trdetail->setTextAlignment(2, Qt::AlignRight);
2804
		 trdetail->setText(4, qs_avgpace);
2805
		 trdetail->setTextAlignment(4, Qt::AlignRight);
2806
		 trdetail->setText(5, kl->formatNumber(qs_avgspeed, false));
2807
		 trdetail->setTextAlignment(5, Qt::AlignRight);
2808
		 trdetail->setText(6, kl->formatNumber(qs_maxspeed, false));
2809
		 trdetail->setTextAlignment(6, Qt::AlignRight);
2810
		 trdetail->setText(7, qs_calories);
2811
		 trdetail->setTextAlignment(7, Qt::AlignRight);
2812
		 trdetail->setText(8, qs_avghr);
2813
		 trdetail->setTextAlignment(8, Qt::AlignRight);
2814
		 trdetail->setText(9, qs_maxhr);
2815
		 trdetail->setTextAlignment(9, Qt::AlignRight);
2816
		 trdetail->setText(10, qs_avgcadence);
2817
		 trdetail->setTextAlignment(10, Qt::AlignRight);
2818
		 trdetail->setText(11, kl->formatNumber(qs_ascent, false));
2819
		 trdetail->setTextAlignment(11, Qt::AlignRight);
2820
 
128 andreas 2821
		 switch (rakt->run->sport_type)
2822
		 {
232 andreas 2823
		    case D1000_running:
247 andreas 2824
		       edetail->setPixmap(0, KIcon(QString("spw-running")).pixmap(16));
232 andreas 2825
		    break;
2826
 
2827
		    case D1000_biking:
245 andreas 2828
		       edetail->setPixmap(0, KIcon(QString("bike")).pixmap(16));
232 andreas 2829
		    break;
2830
 
2831
		    case D1000_other:
2832
		       edetail->setPixmap(0, qpx);
2833
		    break;
2834
 
128 andreas 2835
		    default:
232 andreas 2836
		       edetail->setPixmap(0, qpx);
128 andreas 2837
		 }
2838
 
245 andreas 2839
		 ui_sportwatcherWidgetBase.liLaps->clearSelection();
88 andreas 2840
		 element->insertItem(edetail);
2841
		 delete qt;
2842
		 laps++;
2843
	      }
149 andreas 2844
 
2845
	      qs_ascent.sprintf("%.2f %s", (Units == 1) ? sum_asc / 0.304 : sum_asc, (Units == 1) ? "ft" : "m");
2846
	      qs_descent.sprintf("%.2f %s", (Units == 1) ? sum_dsc / 0.304 : sum_dsc, (Units == 1) ? "ft" : "m");
2847
      	      element->setText(10, qs_ascent);
2848
	      element->setText(11, qs_descent);
248 andreas 2849
	      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");
2850
	      ui_sportwatcherWidgetBase.edTotalHeight->clear();
2851
	      ui_sportwatcherWidgetBase.edTotalHeight->insert(qs_ascent);
2852
	      ui_sportwatcherWidgetBase.edLapNumber->setAlignment(Qt::AlignRight);
2853
	      ui_sportwatcherWidgetBase.edLapNumber->insert(kl->formatNumber((double)laps, 0));
88 andreas 2854
	   }
2855
 
2856
	   rakt = rakt->next;
2857
	}
2858
 
2859
	if (men > 0)
2860
	   avg_hr /= men;
221 andreas 2861
	else
2862
	   min_hr = max_hr = avg_hr = 0;
88 andreas 2863
}
2864
 
100 andreas 2865
void sportwatcherWidget::showTrack()
2866
{
132 andreas 2867
	showTrack(0, QRect(0, 0, 0, 0), 0);
104 andreas 2868
}
2869
 
2870
void sportwatcherWidget::showTrack(int zoom)
2871
{
132 andreas 2872
	showTrack(zoom, mapPan, mapLap);
2873
}
2874
 
2875
void sportwatcherWidget::showTrack(int zoom, const QRect &pan, LAP *lap)
2876
{
100 andreas 2877
int width, height;
2878
double x1, y1, x2, y2;
132 andreas 2879
int a, top, left, panX, panY;
2880
uint32 i;
109 andreas 2881
double coordW, coordH, tick;
156 andreas 2882
double meterW, dist, fact;
100 andreas 2883
QPainter paint;
152 andreas 2884
posn_type posNW, posSE, posLXY, posRXY;
100 andreas 2885
POINT *point;
152 andreas 2886
bool Fgeo = false;
157 andreas 2887
bool Data = false;
232 andreas 2888
#if defined HAVE_GDAL
158 andreas 2889
QString fName = MAP;
2890
//double adfGeoTransform[6];
2891
GDALDataset *poDataset = 0;
246 andreas 2892
GDALRasterBand *poBand = 0;
2893
unsigned char *pafScanline = 0;
2894
unsigned char *pafScanlineRed = 0;
2895
unsigned char *pafScanlineGreen = 0;
2896
unsigned char *pafScanlineBlue = 0;
2897
unsigned char *pafScanlineAlpha = 0;
151 andreas 2898
int nXSize, nYSize;
159 andreas 2899
int xOff, yOff;
158 andreas 2900
double oriLeftLon, oriLeftLat, oriRightLon, oriRightLat;
151 andreas 2901
#endif
100 andreas 2902
 
248 andreas 2903
	if (!DIRTY || curTab == 2 || curTab == 3)
246 andreas 2904
	   return;
2905
 
109 andreas 2906
	if (!gmn)
2907
	   return;
2908
 
154 andreas 2909
	QApplication::setOverrideCursor (QCursor(Qt::WaitCursor));
2910
 
104 andreas 2911
	if (zoom != zfactor)
2912
	   zfactor = zoom;
2913
 
132 andreas 2914
	if (mapLap != lap)
2915
	   mapLap = lap;
2916
 
232 andreas 2917
#if defined HAVE_GDAL
2918
	KConfig cfg (QString("sportwatcher.rc"), KConfig::SimpleConfig);
2919
	KConfigGroup wms (&cfg, "WMS");
2920
	bool square = wms.readEntry("Square", false);
2921
	int CorrX = wms.readEntry("CorrX", 0);
2922
	int CorrY = wms.readEntry("CorrY", 0);
2923
	KConfigGroup ic (&cfg, "ImageCoords");
2924
	oriLeftLon = ic.readEntry("LeftLon", 0.0);
2925
	oriLeftLat = ic.readEntry("LeftLat", 0.0);
2926
	oriRightLon = ic.readEntry("RightLon", 0.0);
2927
	oriRightLat = ic.readEntry("RightLat", 0.0);
2928
//	int isrs = ic.readEntry("SRS", 0);
157 andreas 2929
#endif
280 andreas 2930
	if (curTab == 0 && !ActivePrint)
248 andreas 2931
	{
2932
	   width = ui_sportwatcherWidgetBase.imgMap->width() - 2;
2933
	   height = ui_sportwatcherWidgetBase.imgMap->height();
2934
	}
280 andreas 2935
	else if (ActivePrint)
2936
	{
2937
	   width = pmPrMap.width();
2938
	   height = pmPrMap.height();
2939
	}
248 andreas 2940
	else
2941
	{
2942
	   width = ui_sportwatcherWidgetBase.grMap->width() - 2;
2943
	   height = ui_sportwatcherWidgetBase.grMap->height();
2944
	}
232 andreas 2945
#if defined HAVE_GDAL
158 andreas 2946
	if (MapType == MPT_WMS && square)
232 andreas 2947
	   pmMap = QPixmap(width / (int)mFactor * (int)mFactor, height / (int)mFactor * (int)mFactor);
157 andreas 2948
	else
232 andreas 2949
	   pmMap = QPixmap(width, height);
157 andreas 2950
#else
232 andreas 2951
	pmMap = QPixmap(width, height);
157 andreas 2952
#endif
245 andreas 2953
	if (pmMap.isNull())
2954
	   return;
2955
 
2956
	// Here we begin do draw something
100 andreas 2957
	paint.begin(&pmMap);
2958
 
132 andreas 2959
	panX = panY = 0;
2960
 
2961
	if (stateHand && mapPan != pan)
2962
	{
2963
	   mapPan = pan;
2964
	   panX = mapPan.right() - mapPan.left();
2965
	   panY = mapPan.bottom() - mapPan.top();
2966
	   oldTransX += (double)panX;
2967
	   oldTransY += (double)panY;
2968
	}
2969
 
104 andreas 2970
	memset(&posNW, 0, sizeof(posn_type));
2971
	memset(&posSE, 0, sizeof(posn_type));
100 andreas 2972
 
156 andreas 2973
	posSE.lat = 90.0;
2974
	posSE.lon = 180.0;
2975
	posNW.lat = -90.0;
2976
	posNW.lon = -180.0;
100 andreas 2977
 
2978
	/*
2979
	 * Find out the corners of our track (NW, NE, SE, SW)
2980
	 */
132 andreas 2981
	if (mapLap)
2982
	   i = mapLap->start_time;
2983
	else
2984
	   i = 0;
100 andreas 2985
 
2986
	while ((point = ds.getPoint(i)) != 0)
2987
	{
132 andreas 2988
	   if (mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
2989
	      break;
2990
 
100 andreas 2991
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
2992
	   {
132 andreas 2993
	      i = point->time + 1;
100 andreas 2994
	      continue;
2995
	   }
2996
 
2997
	   if (SEMI2DEG(point->posn.lat) > posNW.lat)
2998
	      posNW.lat = SEMI2DEG(point->posn.lat);
2999
 
3000
	   if (SEMI2DEG(point->posn.lat) < posSE.lat)
3001
	      posSE.lat = SEMI2DEG(point->posn.lat);
3002
 
156 andreas 3003
	   if (SEMI2DEG(point->posn.lon) > posNW.lon)
100 andreas 3004
	      posNW.lon = SEMI2DEG(point->posn.lon);
3005
 
156 andreas 3006
	   if (SEMI2DEG(point->posn.lon) < posSE.lon)
100 andreas 3007
	      posSE.lon = SEMI2DEG(point->posn.lon);
3008
 
132 andreas 3009
	   i = point->time + 1;
157 andreas 3010
	   Data = true;
100 andreas 3011
	}
104 andreas 3012
 
3013
	coordW = (posNW.lon > posSE.lon) ? posNW.lon - posSE.lon : posSE.lon - posNW.lon;
3014
	coordH = (posNW.lat > posSE.lat) ? posNW.lat - posSE.lat : posSE.lat - posNW.lat;
109 andreas 3015
	meterW = ds.earth_distance(posNW.lat, posNW.lon, posNW.lat, posSE.lon);
104 andreas 3016
 
3017
	// define the ticks to translate the GPS coordinates into pixels.
3018
	// The track should be centered and we have to calculate the
3019
	// rectangular within we draw the track.
152 andreas 3020
	if (coordW < coordH)
100 andreas 3021
	{
152 andreas 3022
	   tick = (double)width / coordW + (double)zoom;
3023
 
3024
	   if ((tick * coordH) > height)
109 andreas 3025
	      tick = (double)height / coordH + (double)zoom;
100 andreas 3026
	}
3027
	else
3028
	{
152 andreas 3029
	   tick = (double)height / coordH + (double)zoom;
3030
 
3031
	   if ((tick * coordW) > width)
109 andreas 3032
	      tick = (double)width / coordW + (double)zoom;
100 andreas 3033
	}
104 andreas 3034
 
156 andreas 3035
	left = width - (width - tick * coordW) / 2;
152 andreas 3036
	top = (height - tick * coordH) / 2;
3037
 
132 andreas 3038
	a = tick * coordW;
156 andreas 3039
 
3040
	if (Units == 0)
3041
	   dist = meterW / a;			// Meters
3042
	else
3043
	   dist = meterW * 1.609344 / a;	// 1/1000 mile (5.28 feet)
3044
 
232 andreas 3045
#if defined HAVE_GDAL
159 andreas 3046
	geoRect.llat = 0.0;
3047
	geoRect.llon = 0.0;
3048
	geoRect.rlat = 0.0;
3049
	geoRect.rlon = 0.0;
158 andreas 3050
	geoRect.width = width;
3051
	geoRect.height = height;
146 andreas 3052
	/*
3053
	 * If we have a map file, we try to read it and if successfull,
3054
	 * we should get a map painted.
154 andreas 3055
	 *
3056
	 * Currently only WMS-Server is supported, allthough GDAL allows
3057
	 * several other formats too.
146 andreas 3058
	 */
157 andreas 3059
	if (!MAP.isEmpty() && Data)
146 andreas 3060
	{
158 andreas 3061
	bool writeTag = true;
3062
	double mtx, mty;
3063
	double vx, vy;
152 andreas 3064
 
158 andreas 3065
	   xOff = yOff = 0;
3066
	   posRXY.lon = posNW.lon + (width - left + oldTransX) / tick;
3067
	   posLXY.lat = posNW.lat + (top + oldTransY) / tick;
3068
	   posLXY.lon = posSE.lon - (left - a - oldTransX) / tick;
3069
	   posRXY.lat = posSE.lat - (height - top - (tick * coordH) - oldTransY) / tick;
159 andreas 3070
	   geoRect.llat = posLXY.lat;
3071
	   geoRect.llon = posLXY.lon;
3072
	   geoRect.rlat = posRXY.lat;
3073
	   geoRect.rlon = posRXY.lon;
158 andreas 3074
	   // width and height of map in meters
3075
	   mtx = ds.earth_distance(posRXY.lat, posRXY.lon, posRXY.lat, posLXY.lon);
3076
	   mty = ds.earth_distance(posRXY.lat, posRXY.lon, posLXY.lat, posRXY.lon);
157 andreas 3077
 
158 andreas 3078
	   // factor to correct the map, in case we use a WMS server
3079
	   if (MapType == MPT_WMS)
3080
	   {
3081
	      vx = (posRXY.lon - posLXY.lon) / mtx * CorrX;
3082
	      vy = (posRXY.lat - posLXY.lat) / mty * CorrY;
3083
	      posRXY.lon += vx;
3084
	      posRXY.lat += vy;
3085
	      posLXY.lon += vx;
3086
	      posLXY.lat += vy;
3087
	   }
3088
 
154 andreas 3089
	   /*
158 andreas 3090
	    * Write a control file for GDAL, if we use a WMS server.
3091
	    * Warp an image if we use PNG or BMP or GIF.
3092
	    * Warp a region if we use TIFF
154 andreas 3093
	    */
158 andreas 3094
	   if (MapType == MPT_WMS)
3095
	      writeTag = writeWMSTag(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat, width, height);
3096
 
159 andreas 3097
	   if (MapType == MPT_GIF || MapType == MPT_BMP || MapType == MPT_PNG ||
3098
	       MapType == MPT_SGI || MapType == MPT_TIF)
158 andreas 3099
	      writeTag = warpImage(MAP, &fName);
3100
 
3101
	   if (writeTag)
151 andreas 3102
	   {
246 andreas 3103
	      if (MapType != MPT_SHP && (poDataset = (GDALDataset *)GDALOpen (fName.toAscii().constData(), GA_ReadOnly)) != NULL)
151 andreas 3104
	      {
3105
		 QPixmap bild;
3106
		 int nRasterCount = poDataset->GetRasterCount();
3107
		 int nXBlock, nYBlock;
154 andreas 3108
		 GDALColorTable *pCT, *pCTb, *pCTr, *pCTg, *pCTa;
146 andreas 3109
 
151 andreas 3110
		 int             bGotMin, bGotMax;
3111
		 int		 tTypeLen, tColor, tColorEntrys;
3112
		 GDALDataType    tRasterType;
3113
		 double          adfMinMax[2];
3114
 
154 andreas 3115
		 pafScanlineRed = pafScanlineGreen = pafScanlineBlue = pafScanlineAlpha = 0;
246 andreas 3116
		 Fgeo = true;
154 andreas 3117
		 /*
3118
		  * Read every raster band.
3119
		  *
3120
		  * If we get 3 raster bands, the image is a 24 bit image.
3121
		  * If we get 4 raster bands, the image is probably a 24 bit
3122
		  * image with an alpha channel. Currently the alpha channel
3123
		  * is ignored!
3124
		  * If we have 1 raster band, the image is 8 bit monochrom.
3125
		  * Otherwise the image is undefined and the results are also.
3126
		  */
151 andreas 3127
		 for (a = 1; a <= nRasterCount; a++)
3128
		 {
246 andreas 3129
		    if (!Fgeo)
3130
		       break;
3131
 
245 andreas 3132
		    if (!(poBand = poDataset->GetRasterBand (a)))
3133
		    {
3134
		       paint.end();
3135
		       return;
3136
		    }
3137
 
151 andreas 3138
		    poBand->GetBlockSize (&nXBlock, &nYBlock);
3139
		    nXSize = poBand->GetXSize();
3140
		    nYSize = poBand->GetYSize();
3141
		    tRasterType = poBand->GetRasterDataType ();
3142
		    tTypeLen = GDALGetDataTypeSize (tRasterType) / 8;	// We need Bytes not Bits!
3143
		    tColor = poBand->GetColorInterpretation ();
3144
 
3145
		    adfMinMax[0] = poBand->GetMinimum (&bGotMin);
3146
		    adfMinMax[1] = poBand->GetMaximum (&bGotMax);
3147
 
3148
		    if (!(bGotMin && bGotMax))
3149
		       GDALComputeRasterMinMax ((GDALRasterBandH)poBand, TRUE, adfMinMax);
3150
 
152 andreas 3151
		    if ((pCT = poBand->GetColorTable()) != NULL)
151 andreas 3152
		       tColorEntrys = poBand->GetColorTable()->GetColorEntryCount();
3153
 
3154
		    switch (a)
3155
		    {
152 andreas 3156
		       case 1: pafScanlineRed   = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineRed; pCTr = pCT; break;
3157
		       case 2: pafScanlineGreen = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineGreen; pCTg = pCT; break;
3158
		       case 3: pafScanlineBlue  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineBlue; pCTb = pCT; break;
154 andreas 3159
		       case 4: pafScanlineAlpha  = new unsigned char[tTypeLen * nXSize * nYSize]; pafScanline = pafScanlineAlpha; pCTa = pCT; break;
151 andreas 3160
		    }
3161
 
246 andreas 3162
		    if (!pafScanline)
3163
		    {
3164
		       paint.end();
3165
		       KMessageBox::error(this, i18n("Not enough memory for a raster operation!"));
3166
		       return;
3167
		    }
3168
 
152 andreas 3169
		    memset (pafScanline, 0, tTypeLen * nXSize * nYSize);
151 andreas 3170
 
154 andreas 3171
		    /*
158 andreas 3172
		     * Get the image (from the server) and put the tiles together.
154 andreas 3173
		     *
3174
		     * The function reads only one raster band. This is,
3175
		     * because the function is called for every raster band and
3176
		     * every raster band is stored into a separate array.
3177
		     */
152 andreas 3178
		    if (poBand->RasterIO (GF_Read, 0, 0, nXSize, nYSize, pafScanline, nXSize, nYSize, tRasterType, 0, 0) == CE_Failure)
3179
		    {
248 andreas 3180
		       paint.end();
151 andreas 3181
		       KMessageBox::error(this, i18n("Error reading a raster band!"));
248 andreas 3182
		       paint.begin(&pmMap);
152 andreas 3183
		       Fgeo = false;
3184
		       break;
3185
		    }
3186
		    else
3187
		       Fgeo = true;
151 andreas 3188
		 }
3189
 
154 andreas 3190
		 /*
3191
		  * Only if Fgeo is TRUE, we've read successfully all raster
3192
		  * bands. Now we have to put the bands together to get
3193
		  * an image.
3194
		  */
152 andreas 3195
		 if (Fgeo)
3196
		 {
3197
		 unsigned char *pCombinedBytes = new unsigned char[(tTypeLen * nXSize * nYSize * nRasterCount)];
3198
		 unsigned char *ptr_dest, *ptr_src;
3199
		 int j;
151 andreas 3200
 
245 andreas 3201
		    ptr_dest = ptr_src = 0;
3202
 
154 andreas 3203
		    /*
3204
		     * We need two nested loops to set the pixels in the wanted
3205
		     * order.
3206
		     */
152 andreas 3207
		    for (a = 0, j = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount, j++)
151 andreas 3208
		    {
152 andreas 3209
		       int k = a;
3210
 
3211
		       for (int m = nRasterCount - 1; m >= 0; m--, k++)
3212
		       {
245 andreas 3213
		       unsigned char *pBytes = 0;
152 andreas 3214
 
3215
			  switch (m)
3216
			  {
154 andreas 3217
			     case 3: pBytes = pafScanlineAlpha; pCT = pCTa; break;
152 andreas 3218
			     case 2: pBytes = pafScanlineBlue; pCT = pCTb; break;
3219
			     case 1: pBytes = pafScanlineGreen; pCT = pCTg; break;
3220
			     default: pBytes = pafScanlineRed; pCT = pCTr;
3221
			  }
3222
 
3223
			  ptr_dest = pCombinedBytes + k;
3224
			  unsigned char b = pBytes[j];
3225
 
154 andreas 3226
			  /*
3227
			   * If we have a color table, the pixels are pointers
3228
			   * to the color table. We need to convert them into
3229
			   * 24 bit pixels plus an optional alpha channel.
3230
			   */
152 andreas 3231
			  if (pCT != NULL)
3232
			  {
3233
			     GDALColorEntry ce;
3234
			     unsigned int c = (unsigned int)b;
3235
			     c = pCT->GetColorEntryAsRGB (c, &ce);
3236
 
3237
			     if  (m == 0) c = ce.c1;
3238
			     if  (m == 1) c = ce.c2;
3239
			     if  (m == 2) c = ce.c3;
154 andreas 3240
			     if  (m == 3) c = ce.c4;
152 andreas 3241
 
3242
			     b = (unsigned char)c;
3243
			  }
3244
 
3245
			  ptr_src = &b;
3246
			  memcpy (ptr_dest, ptr_src, 1);
3247
		       }
151 andreas 3248
		    }
152 andreas 3249
 
3250
		    x1 = y1 = 0;
3251
 
154 andreas 3252
		    /*
3253
		     * The following loop is QT specific! It sets the pixels
3254
		     * of the raw image, pixel by pixel. This may be slow, but
3255
		     * everything else didn't work :-(
3256
		     *
3257
		     * FIXME: We need a more effective routine to put the
158 andreas 3258
		     *        raw image into QT's "painter" class.
154 andreas 3259
		     */
3260
		    for (a = 0; a < (nXSize * nYSize * nRasterCount); a += nRasterCount)
152 andreas 3261
		    {
158 andreas 3262
		       if (x1 < width && y1 < height)
3263
		       {
3264
			  if (nRasterCount == 3)
232 andreas 3265
			     paint.setPen (QPen(QColor((int)pCombinedBytes[a+2], (int)pCombinedBytes[a+1], (int)pCombinedBytes[a]), Qt::SolidLine));
158 andreas 3266
			  else if (nRasterCount > 3)
232 andreas 3267
			     paint.setPen (QPen(QColor(qRgba((int)pCombinedBytes[a+3], (int)pCombinedBytes[a+2], (int)pCombinedBytes[a+1], (int)pCombinedBytes[a])), Qt::SolidLine));
158 andreas 3268
			  else if (nRasterCount == 2)
232 andreas 3269
			     paint.setPen (QPen(QColor((int)pCombinedBytes[a+1], (int)pCombinedBytes[a], (int)pCombinedBytes[a+1]), Qt::SolidLine));
158 andreas 3270
			  else if (nRasterCount == 1)
232 andreas 3271
			     paint.setPen (QPen(QColor((int)pCombinedBytes[a], (int)pCombinedBytes[a], (int)pCombinedBytes[a]), Qt::SolidLine));
154 andreas 3272
 
158 andreas 3273
			  paint.drawPoint(x1, y1);
3274
		       }
3275
 
152 andreas 3276
		       x1++;
3277
 
3278
		       if (x1 >= nXSize)
3279
		       {
3280
			  x1 = 0;
3281
			  y1++;
3282
		       }
3283
		    }
3284
 
3285
		    delete pCombinedBytes;
245 andreas 3286
		    pCombinedBytes = 0;
151 andreas 3287
		 }
3288
 
152 andreas 3289
		 if (pafScanlineRed)
3290
		    delete pafScanlineRed;
151 andreas 3291
 
152 andreas 3292
		 if (pafScanlineGreen)
3293
		    delete pafScanlineGreen;
3294
 
3295
		 if (pafScanlineBlue)
3296
		    delete pafScanlineBlue;
3297
 
154 andreas 3298
		 if (pafScanlineAlpha)
3299
		    delete pafScanlineAlpha;
3300
 
152 andreas 3301
		 GDALClose (poDataset);
3302
		 poDataset = 0;
158 andreas 3303
 
3304
		 if (MAP != fName)
232 andreas 3305
		    unlink (fName.toAscii().data());
151 andreas 3306
	      }
280 andreas 3307
#if defined HAVE_MAPNIK
158 andreas 3308
	      else if (MapType == MPT_SHP)
3309
	      {
3310
		 QDir shpd(MAP, QString("*.shp"));
3311
 
3312
		 if (shpd.count() < 1)
3313
		 {
275 andreas 3314
		    KMessageBox::error(this, i18n("There is no shape file in directory %1").arg(MAP));
158 andreas 3315
		    Fgeo = false;
3316
		 }
3317
		 else
3318
		 {
274 andreas 3319
		 SRender rd;
275 andreas 3320
		 QColor bg(220, 220, 220);		// background color
158 andreas 3321
 
280 andreas 3322
		    if (curTab == 0 && !ActivePrint)
3323
		       rd.setDrawArea(ui_sportwatcherWidgetBase.imgMap->width(), ui_sportwatcherWidgetBase.imgMap->height());
3324
		    else if (!ActivePrint)
3325
		       rd.setDrawArea(ui_sportwatcherWidgetBase.grMap->width(), ui_sportwatcherWidgetBase.grMap->height());
3326
		    else if (ActivePrint)
3327
		       rd.setDrawArea(pmPrMap.width(), pmPrMap.height());
275 andreas 3328
 
276 andreas 3329
		    rd.setMapType(SRender::MAP_SHAPE);
3330
 
275 andreas 3331
		    if (rd.getMap(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat))
3332
		    {
3333
		       paint.fillRect(0, 0, width+2, height+2, bg);
280 andreas 3334
		       paint.drawPixmap(0, 0, rd.pixmap());
275 andreas 3335
		       Fgeo = true;
3336
		    }
3337
		    else
3338
		       Fgeo = false;
158 andreas 3339
		 }
3340
	      }
276 andreas 3341
	      else if (MapType == MPT_OSM)
3342
	      {
3343
		 QFileInfo osmf(MAP);
3344
 
3345
		 if (!osmf.exists())
3346
		 {
3347
		    KMessageBox::error(this, i18n("The OSM file %1 does not exist!").arg(MAP));
3348
		    Fgeo = false;
3349
		 }
3350
		 else
3351
		 {
3352
		 SRender rd;
3353
		 QColor bg(220, 220, 220);		// background color
3354
 
280 andreas 3355
		    if (curTab == 0 && !ActivePrint)
3356
		       rd.setDrawArea(ui_sportwatcherWidgetBase.imgMap->width(), ui_sportwatcherWidgetBase.imgMap->height());
3357
		    else if (!ActivePrint)
3358
		       rd.setDrawArea(ui_sportwatcherWidgetBase.grMap->width(), ui_sportwatcherWidgetBase.grMap->height());
3359
		    else if (ActivePrint)
3360
		       rd.setDrawArea(pmPrMap.width(), pmPrMap.height());
276 andreas 3361
 
3362
		    rd.setMapType(SRender::MAP_OSM);
3363
 
3364
		    if (rd.getMap(posLXY.lon, posLXY.lat, posRXY.lon, posRXY.lat))
3365
		    {
3366
		       paint.fillRect(0, 0, width+2, height+2, bg);
280 andreas 3367
		       paint.drawPixmap(0, 0, rd.pixmap());
276 andreas 3368
		       Fgeo = true;
3369
		    }
3370
		    else
3371
		       Fgeo = false;
3372
		 }
3373
	      }
280 andreas 3374
#endif	// HAVE_MAPNIK
151 andreas 3375
	      else
157 andreas 3376
	      {
158 andreas 3377
		 KMessageBox::error(this, i18n("Error opening map file!"));
157 andreas 3378
		 Fgeo = false;
3379
	      }
151 andreas 3380
	   }
146 andreas 3381
	}
280 andreas 3382
#endif	// HAVE_GDAL
154 andreas 3383
	/*
3384
	 * Here we come to draw the track. It will be drawn over the previous
3385
	 * created map image.
3386
	 */
100 andreas 3387
	// Colors and fonts
154 andreas 3388
	QColor background(220, 220, 220);		// background color
3389
	QColor red(255, 0, 0);				// mile marker
3390
	QColor black(0, 0, 0);				// Text, center of track
3391
//	QColor yellow(255, 255, 0);
3392
	QColor yellow(0x00cf, 0x00ff, 0x0000);		// color of track
100 andreas 3393
	QFont fntNormal("Helvetica");
3394
	fntNormal.setPixelSize(10);
3395
	fntNormal.setStyleHint(QFont::Helvetica);
232 andreas 3396
	QPen dot(red, 4, Qt::SolidLine);
3397
	QPen line(black, 2, Qt::SolidLine);
247 andreas 3398
	QPen yline(yellow, 4, Qt::SolidLine);
154 andreas 3399
	// Fill background with background colors, if there is no map.
152 andreas 3400
	if (!Fgeo)
3401
	   paint.fillRect(0, 0, width+2, height+2, background);
3402
 
156 andreas 3403
	if (Units == 0)
3404
	   fact = 1000.0;
3405
	else
3406
	   fact = 1609.344;
3407
 
109 andreas 3408
	paint.setPen(line);
3409
	paint.drawLine(10, height - 9, 10, height - 4);
156 andreas 3410
	paint.drawLine(10, height - 4, 10 + (fact / dist), height - 4);
3411
	paint.drawLine(10 + (fact / dist), height - 9, 10 + (fact / dist), height - 4);
109 andreas 3412
	paint.setFont(fntNormal);
3413
 
156 andreas 3414
	if (Units == 0)
3415
	   paint.drawText(10, height - 10, QString("1000 m"));
3416
	else
3417
	   paint.drawText(10, height - 10, QString("5280 ft"));
3418
 
100 andreas 3419
	// Draw track
132 andreas 3420
	if (mapLap)
3421
	   i = mapLap->start_time;
3422
	else
3423
	   i = 0;
3424
 
100 andreas 3425
	x1 = y1 = 0.0;
157 andreas 3426
	bool wStart = false;
104 andreas 3427
 
100 andreas 3428
	while ((point = ds.getPoint(i)) != 0)
3429
	{
132 andreas 3430
	   if (mapLap && point->time > (mapLap->start_time + (mapLap->total_time / 100)))
3431
	      break;
3432
 
100 andreas 3433
	   if (point->posn.lat == 0x7fffffff || point->posn.lon == 0x7fffffff)
3434
	   {
132 andreas 3435
	      i = point->time + 1;
100 andreas 3436
	      continue;
3437
	   }
3438
 
157 andreas 3439
	   x2 = (left + ((posNW.lon - SEMI2DEG(point->posn.lon)) * tick * -1)) + oldTransX;
3440
	   y2 = (top + ((posNW.lat - SEMI2DEG(point->posn.lat)) * tick)) + oldTransY;
100 andreas 3441
 
157 andreas 3442
	   if (!wStart && x1 != 0.0 && y1 != 0.0)
3443
	   {
3444
	      // Load the start symbol
245 andreas 3445
	      QPixmap qpx (KIcon(QString("wstart")).pixmap(16));
157 andreas 3446
	      // Find the angle of the track and turn the symbol accordingly
3447
	      // we use Pythagoras to calculate the triangle
3448
	      double xl = (x1 < x2) ? x2 - x1 : x1 - x2;
3449
	      double yl = (y1 < y2) ? y2 - y1 : y1 - y2;
3450
	      double da = fmin (xl, yl);
3451
	      double db = fmax (xl, yl);
3452
	      double zl = sqrt (pow (da, 2) + pow (db, 2));
3453
	      double angle = (asin(da / zl) / M_PIl) * 180.0;
3454
 
3455
	      angle = (angle > 45.0) ? 90.0 - angle : angle;
3456
// cout << "Winkel: " << angle << " ---- X: " << xl << ", Y: " << yl << ", Z: " << zl << ", Point (x1,y1,x2,y2): " << x1 << ", " << y1 << ", " << x2 << ", " << y2 << endl;
3457
	      if (x1 < x2 && y1 < y2)		// right, down
3458
		 angle = 90.0 + angle;
3459
	      else if (x1 > x2 && y1 < y2)	// left, down
3460
		 angle = 270.0 - angle;
3461
	      else if (x1 > x2 && y1 > y2)	// left, up
3462
		 angle = 270.0 + angle;
3463
	      else				// right, up
3464
		 angle = 90.0 - angle;
3465
// cout << "Realer Winkel: " << angle << endl;
3466
	      // Set the center of the symbol
3467
	      paint.save ();
3468
	      paint.translate (x1, y1);
3469
	      // rotate the symbol
3470
	      paint.rotate (angle);
3471
	      paint.drawPixmap (-8, -8, qpx);
3472
	      paint.restore ();
3473
	      wStart = true;
3474
	   }
3475
 
100 andreas 3476
	   if (x1 == 0.0 && y1 == 0.0)
3477
	   {
3478
	      x1 = x2;
3479
	      y1 = y2;
3480
	   }
104 andreas 3481
 
100 andreas 3482
	   paint.setPen(yline);
104 andreas 3483
	   paint.drawLine(x1, y1, x2, y2);
3484
 
156 andreas 3485
	   if ((point->distance - dist) >= fact)	// a dot at every 1000 meters or at 1 mile
104 andreas 3486
	   {
3487
	      paint.setPen(dot);
154 andreas 3488
	      paint.drawEllipse(x2-2, y2-2, 3, 3);
156 andreas 3489
	      dist = (int)(point->distance / fact) * fact;
104 andreas 3490
	   }
3491
 
100 andreas 3492
	   paint.setPen(line);
3493
	   paint.drawLine(x1, y1, x2, y2);
3494
	   x1 = x2;
3495
	   y1 = y2;
132 andreas 3496
	   i = point->time + 1;
100 andreas 3497
	}
3498
 
157 andreas 3499
	bool lastLap = false;
3500
 
3501
	if (mapLap)
3502
	   if (ds.getRunNode()->run->last_lap_index == mapLap->index)
3503
	      lastLap = true;
3504
 
3505
	if ((!mapLap || lastLap) && wStart)
3506
	{
3507
	   // load the end symbol
245 andreas 3508
	   QPixmap qpx (KIcon(QString("wtarget")).pixmap(16));
157 andreas 3509
	   paint.drawPixmap (x2, y2 - 16, qpx);
3510
	}
3511
 
100 andreas 3512
	paint.end();
248 andreas 3513
 
280 andreas 3514
	if (curTab == 0 && !ActivePrint)
248 andreas 3515
	   ui_sportwatcherWidgetBase.imgMap->setPixmap(pmMap);
280 andreas 3516
	else if (ActivePrint)
3517
	   pmPrMap = pmMap;
248 andreas 3518
	else
3519
	   ui_sportwatcherWidgetBase.grMap->setPixmap(pmMap);
3520
 
154 andreas 3521
	QApplication::restoreOverrideCursor();
100 andreas 3522
}
3523
 
245 andreas 3524
void sportwatcherWidget::kcbCurveSlot(int)
3525
{
246 andreas 3526
	DIRTY = true;
245 andreas 3527
	showCurves();
246 andreas 3528
	DIRTY = false;
245 andreas 3529
}
3530
 
248 andreas 3531
void sportwatcherWidget::tabViewSlot(int tab)
3532
{
3533
	curTab = tab;
3534
 
3535
	if (tab == 0 && tabDirt0)
3536
	{
3537
	   DIRTY = true;
3538
	   showLaps();
3539
	   showTrack();
3540
	   showCurves();
3541
	   DIRTY = false;
3542
	   tabDirt0 = false;
3543
	}
3544
	else if (tab == 1 && tabDirt1)
3545
	{
3546
	   DIRTY = true;
3547
 
3548
	   if (tabDirt0)
3549
	      showLaps();
3550
 
3551
	   showTrack();
3552
	   DIRTY = false;
3553
	   tabDirt1 = false;
3554
	}
250 andreas 3555
	else if (tab == 2 && tabDirt2)
3556
	{
3557
	   DIRTY = true;
3558
 
3559
	   if (tabDirt0)
3560
	      showLaps();
3561
 
3562
	   setMouseTracking (true);
3563
	   ui_sportwatcherWidgetBase.tabView->setMouseTracking (true);
3564
	   ui_sportwatcherWidgetBase.grHR->setMouseTracking (true);
3565
	   ui_sportwatcherWidgetBase.grElevation->setMouseTracking (true);
3566
	   ui_sportwatcherWidgetBase.grSpeed->setMouseTracking (true);
3567
	   showThreeCurve();
3568
	   tabDirt2 = false;
3569
	   DIRTY = false;
3570
	}
248 andreas 3571
}
3572
 
88 andreas 3573
void sportwatcherWidget::showCurves()
3574
{
148 andreas 3575
	showCurves (mapLap);
3576
}
3577
 
3578
void sportwatcherWidget::showCurves(LAP *lap)
3579
{
88 andreas 3580
QPainter paint;
3581
int width, height;
218 andreas 3582
int i, secs, cuType;
88 andreas 3583
int lineHeight, margin_left, margin_right, margin_bottom;
3584
int x1, y1, x2, y2;		// Coordinates
3585
bool meter;
218 andreas 3586
double maxHeight, minHeight, maxSpeed, minSpeed;
88 andreas 3587
int maxHr, minHr, rh;
3588
POINT *point;
148 andreas 3589
RUN_NODE *rn;
3590
LAP *lp;
88 andreas 3591
double w_tick, h_tick;		// Number of pixels one "tick" has;
3592
				// This depends on the width and height
3593
				// of the image.
3594
	// First we draw a grid based on the min and max
3595
	// values detected in the function showLap(). In case
3596
	// all values are 0, we exit here.
3597
	if (min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
3598
	   return;
3599
 
248 andreas 3600
	if (!DIRTY || curTab != 0)
246 andreas 3601
	   return;
3602
 
218 andreas 3603
	// Look up, what curves we should draw
245 andreas 3604
	cuType = ui_sportwatcherWidgetBase.kcbCurveTypes->currentIndex();
218 andreas 3605
	// Get the dimensions of the available draw area
245 andreas 3606
	width = ui_sportwatcherWidgetBase.imgProfile->width() - 2;
3607
	height = ui_sportwatcherWidgetBase.imgProfile->height();
232 andreas 3608
	pmProfile = QPixmap(width, height);
88 andreas 3609
	paint.begin(&pmProfile);
3610
 
3611
	// we need a somewhat bigger area to draw our curves than
3612
	// we have with the real min and max values.
3613
	if (max_height > 0.0)
3614
	{
148 andreas 3615
	double add = (max_height - min_height) / 100.0 * 5.0;	// Percent
88 andreas 3616
 
3617
	   maxHeight = max_height + add;
3618
	   minHeight = min_height - add;
3619
 
3620
	   if (minHeight < 0.0)		// make sure, we are not too deep
3621
	      minHeight = 0.0;
3622
	}
221 andreas 3623
	else
3624
	   maxHeight = minHeight = 0.0;
88 andreas 3625
 
218 andreas 3626
	if (max_speed > 0.0)
3627
	{
3628
	double add = (max_speed - min_speed) / 100.0 * 5.0;	// Percent
3629
 
3630
	   maxSpeed = max_speed + add;
3631
	   minSpeed = min_speed - add;
3632
 
3633
	   if (minSpeed < 0.0)		// make sure, we are not too deep
3634
	      minSpeed = 0.0;
3635
	}
221 andreas 3636
	else
3637
	   maxSpeed = minSpeed = 0.0;
218 andreas 3638
 
88 andreas 3639
	if (max_hr > 0)
3640
	{
3641
	   maxHr = max_hr + 10;
3642
	   minHr = min_hr - 10;
3643
 
3644
	   if (minHr < 0)
3645
	      minHr = 0;
3646
	}
221 andreas 3647
	else
3648
	   maxHr = minHr = 0;
88 andreas 3649
 
3650
	// Define colors
148 andreas 3651
	QColor background(220, 220, 220);	// Background of graphic
3652
	QColor mark(255, 255, 255);		// Lines inside curve area
3653
	QColor hlight(180, 180, 180);		// area of current lap
3654
//	hlight.setAlpha(128);			// 50% transparent
3655
	QColor frame(0, 0, 0);			// Text and borders
3656
	QColor barcol(151, 190, 13);		// heart rate
3657
	QColor barcol2(190, 151, 13);		// height over NN
222 andreas 3658
	QColor red(220, 128, 128);		// speed
88 andreas 3659
	QColor blue(0, 0, 240);
3660
	QFont fntNormal("Helvetica");
3661
//	QFont fntBold("Helvetica", 10, QFont::Bold);
3662
	fntNormal.setPixelSize(10);
3663
	fntNormal.setStyleHint(QFont::Helvetica);
3664
//	fntBold.setPixelSize(10);
3665
//	fntBold.setStyleHint(QFont::Helvetica);
3666
	// Calculate ticks
3667
	margin_left = 52;
3668
	margin_right = 40;
3669
	margin_bottom = 12;
3670
	lineHeight = 10;
3671
	rh = height - margin_bottom - 1;
3672
 
249 andreas 3673
	w_tick = (double)(width - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
88 andreas 3674
 
222 andreas 3675
	if (cuType == 1)	// Speed and heart rate?
88 andreas 3676
	{
218 andreas 3677
	   if ((maxSpeed - minSpeed) > (double)(maxHr - minHr))
3678
	   {
222 andreas 3679
	      h_tick = (double)rh / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
218 andreas 3680
	      meter = true;
3681
	   }
3682
	   else
3683
	   {
3684
	      h_tick = (double)rh / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
3685
	      meter = false;
3686
	   }
88 andreas 3687
	}
222 andreas 3688
	else if (cuType == 2)	// Elevation and speed?
88 andreas 3689
	{
218 andreas 3690
	   if ((maxHeight - minHeight) > (double)(maxHr - minHr))
3691
	   {
3692
	      h_tick = (double)rh / (maxHeight - minHeight);		// 1 tick = 1 meter
3693
	      meter = true;
3694
	   }
3695
	   else
3696
	   {
222 andreas 3697
	      h_tick = (double)rh / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
3698
	      meter = false;
3699
	   }
3700
	}
3701
	else			// Elevation and heart rate
3702
	{
3703
	   if ((maxHeight - minHeight) > (double)(maxHr - minHr))
3704
	   {
3705
	      h_tick = (double)rh / (maxHeight - minHeight);		// 1 tick = 1 meter
3706
	      meter = true;
3707
	   }
3708
	   else
3709
	   {
218 andreas 3710
	      h_tick = (double)rh / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
3711
	      meter = false;
3712
	   }
88 andreas 3713
	}
218 andreas 3714
 
88 andreas 3715
	// Fill background with background colors
3716
	paint.fillRect(0, 0, width + 4, height + 4, background);
3717
	// Draw a grid with markers at every 10 minutes
232 andreas 3718
	paint.setPen(QPen(frame, 1, Qt::SolidLine));
88 andreas 3719
	// Bottom border line
3720
	x1 = margin_left;
3721
	y1 = height - margin_bottom;
3722
	x2 = width - margin_right;
3723
	y2 = y1;
3724
	paint.drawLine(x1, y1, x2, y2);
3725
	// Left border line
3726
	x1 = x2 = margin_left;
3727
	y1 = 2;
3728
	y2 = height - margin_bottom;
3729
	paint.drawLine(x1, y1, x2, y2);
3730
	// right border line
3731
	x1 = x2 = width - margin_right;
3732
	paint.drawLine(x1, y1, x2, y2);
148 andreas 3733
 
3734
	// Draw some darker lines to show the laps, if we have one
3735
	// and, in case we have a given lap, we fill the area.
3736
	QDateTime *qt;
3737
	QTime zeit = StartTime.time();
3738
	rn = ds.getRunNode();
232 andreas 3739
	paint.setPen(QPen(hlight, 1, Qt::SolidLine));
148 andreas 3740
 
3741
	for (i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
3742
	{
3743
	   if ((lp = ds.getLap(i)) == NULL)
3744
	      continue;
3745
 
3746
	   qt = garmin_dtime(lp->start_time);
3747
	   secs = zeit.secsTo(qt->time());
3748
	   delete qt;
3749
	   x1 = secs * w_tick + margin_left + 1;
3750
 
3751
	   if (lap && lp->start_time == lap->start_time)
3752
	      paint.fillRect(x1, 2, (int)((double)lap->total_time / 100.0 * w_tick), height - margin_bottom - 2, hlight);
3753
	   else
3754
	      paint.drawLine(x1, 2, x1, height - margin_bottom);
3755
	}
3756
 
88 andreas 3757
	// Grid vertical
232 andreas 3758
	paint.setPen(QPen(frame, 1, Qt::SolidLine));
88 andreas 3759
	paint.setFont(fntNormal);
3760
	paint.drawText(margin_left - 20, height - lineHeight, 40, lineHeight, Qt::AlignCenter, QString("00:00"));
3761
	paint.save();
3762
	paint.rotate(270);
218 andreas 3763
 
222 andreas 3764
	if (cuType == 1)
232 andreas 3765
	   paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3766
	else
232 andreas 3767
	   paint.setPen(QPen(barcol, 1, Qt::SolidLine));
222 andreas 3768
 
3769
	// Information on left side
218 andreas 3770
	if (cuType == 0)
3771
	   paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Elevation (ft)" : "Elevation (m)"));
3772
	else if (cuType == 1)
3773
	   paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Speed (mph)" : "Speed (km/h)"));
3774
	else
3775
	   paint.drawText((height + 4) * -1, 3, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Elevation (ft)" : "Elevation (m)"));
3776
 
222 andreas 3777
	if (cuType == 2)
232 andreas 3778
	   paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3779
	else
232 andreas 3780
	   paint.setPen(QPen(blue, 1, Qt::SolidLine));
218 andreas 3781
 
222 andreas 3782
	// Information on right side
218 andreas 3783
	if (cuType < 2)
3784
	   paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
3785
	else
3786
	   paint.drawText((height + 4) * -1, width - 1 - lineHeight, height - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Speed (mph)" : "Speed (km/h)"));
3787
 
88 andreas 3788
	paint.restore();
232 andreas 3789
	paint.setPen(QPen(mark, 1, Qt::SolidLine));
222 andreas 3790
	// Draw the time scale on the bottom of the graphic
249 andreas 3791
	for (i = 0; (unsigned int)i < (max_time + ds.getPauseTime()); i++)
88 andreas 3792
	{
3793
	   if (i > 0 && !(i % 600))	// every 10 minutes
3794
	   {
3795
	      x1 = x2 = margin_left + w_tick * i;
3796
 
3797
	      if (x1 == (width - margin_right))
3798
		 continue;
3799
 
3800
	      y1 = 2;
3801
	      y2 = height - margin_bottom;
3802
	      paint.drawLine(x1, y1, x2, y2);
3803
	      QTime tm(0, 0, 0);
3804
	      tm = tm.addSecs(i);
232 andreas 3805
	      paint.setPen(QPen(frame, 1, Qt::SolidLine));
230 andreas 3806
//	      paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((i >= 3600) ? "hh:mm:ss" : "mm:ss"));
3807
	      paint.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime (tm, (i >= 3600) ? true : false));
232 andreas 3808
	      paint.setPen(QPen(mark, 1, Qt::SolidLine));
88 andreas 3809
	   }
3810
	}
222 andreas 3811
 
3812
	// This is the total time, with pauses included, at the lower right
3813
	// corner of the graphic.
88 andreas 3814
	QTime tm(0, 0, 0);
3815
	QString qs;
249 andreas 3816
	tm = tm.addSecs(max_time + ds.getPauseTime());
232 andreas 3817
	paint.setPen(QPen(frame, 1, Qt::SolidLine));
230 andreas 3818
//	paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, tm.toString((max_time >= 3600) ? "hh:mm:ss" : "mm:ss"));
3819
	paint.drawText(width - margin_right - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
88 andreas 3820
 
222 andreas 3821
	// Draw the minimal elevation, speed and/or heart rate
218 andreas 3822
	if (max_height > 0.0 || max_speed > 0.0)
88 andreas 3823
	{
222 andreas 3824
	   // left side
218 andreas 3825
	   if (cuType == 1)
222 andreas 3826
	   {
232 andreas 3827
	      paint.setPen(QPen(red, 1, Qt::SolidLine));
218 andreas 3828
	      paint.drawText(12, height - margin_bottom - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minSpeed));
222 andreas 3829
	   }
218 andreas 3830
	   else
222 andreas 3831
	   {
232 andreas 3832
	      paint.setPen(QPen(barcol, 1, Qt::SolidLine));
218 andreas 3833
	      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 3834
	   }
88 andreas 3835
	}
3836
 
222 andreas 3837
	if (max_hr > 0 || max_speed > 0.0)
88 andreas 3838
	{
222 andreas 3839
	   // right side
3840
	   if (cuType == 2)
3841
	   {
232 andreas 3842
	      paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3843
	      paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", minSpeed));
3844
	   }
3845
	   else
3846
	   {
232 andreas 3847
	      paint.setPen(QPen(blue, 1, Qt::SolidLine));
222 andreas 3848
	      paint.drawText(width - margin_right + 2, height - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
3849
	   }
88 andreas 3850
	}
3851
 
232 andreas 3852
	paint.setPen(QPen(mark, 1, Qt::SolidLine));
88 andreas 3853
 
3854
	// Grid horizontal
218 andreas 3855
	int factor = 0;
3856
	int target = 0;
3857
 
222 andreas 3858
	if (cuType == 0)	// Elevation and heart rate
218 andreas 3859
	{
222 andreas 3860
	   factor = (meter) ? (maxHeight - minHeight) / (rh / 12) : (maxHr - minHr) / (rh / 12);
3861
	   target = (meter) ? (int)(maxHeight - minHeight) : (maxHr - minHr);
3862
	}
3863
	else if (cuType == 1)	// Speed and heart rate
3864
	{
218 andreas 3865
	   factor = (meter) ? (maxSpeed - minSpeed) / (rh / 12) : (maxHr - minHr) / (rh / 12);
3866
	   target = (meter) ? (int)(maxSpeed - minSpeed) : (maxHr - minHr);
3867
	}
222 andreas 3868
	else			// Elevation and speed
218 andreas 3869
	{
222 andreas 3870
	   factor = (meter) ? (maxHeight - minHeight) / (rh /12) : (maxSpeed - minSpeed) / (rh / 12);
3871
	   target = (meter) ? (int)(maxHeight - minHeight) : (int)(maxSpeed - minSpeed);
218 andreas 3872
	}
3873
 
222 andreas 3874
	// To prevent a division by zero error, we check the <factor>
3875
	if (factor == 0)
3876
	   factor = 1;
3877
 
3878
	// Beside the horizontal part of the grid, we draw the scale on the
3879
	// left and the right side.
88 andreas 3880
	int oldy = height;
3881
 
3882
	for (i = 0; i < target; i++)
3883
	{
3884
	   if (i > 0 && !(i % factor))
3885
	   {
3886
	      x1 = margin_left + 1;
3887
	      x2 = width - margin_right - 1;
3888
	      y1 = y2 = rh - h_tick * i;
3889
 
3890
	      if (y1 < 12)
3891
		 break;
3892
 
3893
	      paint.drawLine(x1, y1, x2, y2);
3894
 
3895
	      if (y1 < (oldy - lineHeight))
3896
	      {
3897
		 if (meter)
3898
		 {
232 andreas 3899
		    paint.setPen(QPen(barcol, 1, Qt::SolidLine));
222 andreas 3900
		    // left side
218 andreas 3901
		    if (cuType == 1)
222 andreas 3902
		    {
232 andreas 3903
		       paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3904
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + i));
3905
		    }
218 andreas 3906
		    else
3907
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", (Units == 1) ? (minHeight + i) / 0.304 : minHeight + i));
3908
 
222 andreas 3909
		    // right side
3910
		    if (maxHr > 0 && cuType != 2)
88 andreas 3911
		    {
3912
		       double hrscale = (double)(maxHr - minHr) / (double)target;
232 andreas 3913
		       paint.setPen(QPen(blue, 1, Qt::SolidLine));
88 andreas 3914
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", (int)((double)minHr + hrscale * (double)i)));
3915
		    }
222 andreas 3916
		    else
3917
		    {
3918
		       double spscale = (maxSpeed - minSpeed) / (double)target;
3919
 
3920
		       if (cuType == 2)
232 andreas 3921
			  paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3922
		       else
232 andreas 3923
			  paint.setPen(QPen(blue, 1, Qt::SolidLine));
222 andreas 3924
 
3925
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", (minSpeed + spscale * (double)i)));
3926
		    }
88 andreas 3927
		 }
3928
		 else
3929
		 {
222 andreas 3930
		    // right side
3931
		    if (cuType == 2)
3932
		    {
232 andreas 3933
		       paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3934
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", minSpeed + i));
3935
		    }
3936
		    else
3937
		    {
232 andreas 3938
		       paint.setPen(QPen(blue, 1, Qt::SolidLine));
222 andreas 3939
		       paint.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
3940
		    }
88 andreas 3941
 
222 andreas 3942
		    // left side
3943
		    if ((cuType == 0 || cuType == 2) && max_height > 0)
88 andreas 3944
		    {
3945
		       double hrscale = (maxHeight - minHeight) / (double)target;
232 andreas 3946
		       paint.setPen(QPen(barcol, 1, Qt::SolidLine));
88 andreas 3947
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.0f", minHeight + hrscale * (double)i));
3948
		    }
222 andreas 3949
		    else if (max_speed > 0 && cuType == 1)
218 andreas 3950
		    {
3951
		       double hrscale = (maxSpeed - minSpeed) / (double)target;
232 andreas 3952
		       paint.setPen(QPen(red, 1, Qt::SolidLine));
222 andreas 3953
		       paint.drawText(12, y1 - lineHeight / 2, margin_left - 14, lineHeight, Qt::AlignRight, qs.sprintf("%.1f", minSpeed + hrscale * (double)i));
218 andreas 3954
		    }
88 andreas 3955
		}
3956
 
232 andreas 3957
		 paint.setPen(QPen(mark, 1, Qt::SolidLine));
88 andreas 3958
		 oldy = y1;
3959
	      }
3960
	   }
3961
	}
3962
 
168 andreas 3963
	// To make our graphics more beautiful, we draw lines for the
88 andreas 3964
	// heart rate limits and the average heart rate.
222 andreas 3965
	if (max_hr > 0 && cuType != 2)
88 andreas 3966
	{
3967
	int ay1, ay2, ay3, ay4, ay5;
3968
 
3969
	   x1 = margin_left + 1;
3970
	   x2 = width - margin_right - 1;
3971
 
3972
	   if (meter)
3973
	   {
3974
	      double hrscale = rh / (double)(maxHr - minHr);
3975
	      ay1 = (double)rh - (double)(lower1 - minHr) * hrscale;
3976
	      ay2 = (double)rh - (double)(lower2 - minHr) * hrscale;
3977
	      ay3 = (double)rh - (double)(lower3 - minHr) * hrscale;
3978
	      ay4 = (double)rh - (double)(upper3 - minHr) * hrscale;
3979
	      ay5 = (double)rh - (double)(avg_hr - minHr) * hrscale;
3980
	   }
3981
	   else
3982
	   {
3983
	      ay1 = (double)rh - (double)(lower1 - minHr) * h_tick;
3984
	      ay2 = (double)rh - (double)(lower2 - minHr) * h_tick;
3985
	      ay3 = (double)rh - (double)(lower3 - minHr) * h_tick;
3986
	      ay4 = (double)rh - (double)(upper3 - minHr) * h_tick;
3987
	      ay5 = (double)rh - (double)(avg_hr - minHr) * h_tick;
3988
	   }
3989
 
232 andreas 3990
	   paint.setPen(QPen(barcol2, 1, Qt::DashLine));	// color for limits
88 andreas 3991
 
3992
	   if (lower1 > minHr && lower1 < maxHr)
3993
	      paint.drawLine(x1, ay1, x2, ay1);
3994
 
3995
	   if (lower2 > minHr && lower2 < maxHr)
3996
	      paint.drawLine(x1, ay2, x2, ay2);
3997
 
3998
	   if (lower3 > minHr && lower3 < maxHr)
3999
	      paint.drawLine(x1, ay3, x2, ay3);
4000
 
4001
	   if (upper3 > minHr && upper3 < maxHr)
4002
	      paint.drawLine(x1, ay4, x2, ay4);
4003
 
232 andreas 4004
	   paint.setPen(QPen(red, 1, Qt::DashDotLine));	// color for average heart rate
88 andreas 4005
 
4006
	   if (avg_hr > minHr && avg_hr < maxHr)
4007
	      paint.drawLine(x1, ay5, x2, ay5);
4008
	}
4009
 
4010
	// Now we have a grid and we've done the scaling.
4011
	// This is the point where we draw the curves itself.
223 andreas 4012
	// We use different colors to draw the lines:
4013
	//
4014
	// Green: Elevation
4015
	// Red:   Speed
4016
	// Blue   Heart Rate
4017
	//
88 andreas 4018
	x1 = x2 = y1 = y2 = 0;
148 andreas 4019
	int hy1, hy2, hx1, hx2;
222 andreas 4020
	int sy1, sy2, sx1, sx2;
88 andreas 4021
	hy1 = hy2 = hx1 = hx2 = 0;
222 andreas 4022
	sy1 = sy2 = sx1 = sx2 = 0;
169 andreas 4023
	int hEc = 0;
4024
	i = 0;
4025
	AVGHEIGHT *avgHakt, *avgHfirst, *avgHlast, *avgHeight = 0;
170 andreas 4026
	avgHfirst = avgHlast = 0;
169 andreas 4027
	// To even the surface lines, we store every altitude in the
4028
	// memory, by building a chain. Then, if the user has set in the
4029
	// settings (Contour == true), we will even the line by calculating
4030
	// the average of 10 messure points and setting every value to the
4031
	// average, who is up or down more than 2 meters from the average.
4032
	while ((point = ds.getPoint(i)) != 0)
4033
	{
4034
	   if (point->alt > 20000.0 || point->alt < -1000.0)
4035
	   {
4036
	      i++;
4037
	      continue;
4038
	   }
168 andreas 4039
 
169 andreas 4040
	   if (!avgHeight)
4041
	   {
4042
	      avgHeight = new AVGHEIGHT;
4043
	      avgHeight->alt = point->alt;
4044
	      avgHeight->pos = hEc;
4045
	      avgHeight->prev = 0;
4046
	      avgHeight->next = 0;
4047
	      avgHakt = avgHeight;
4048
	      avgHfirst = avgHeight;
4049
	   }
4050
	   else
4051
	   {
4052
	      avgHakt = new AVGHEIGHT;
4053
	      avgHakt->alt = point->alt;
4054
	      avgHakt->pos = hEc;
4055
	      avgHakt->next = 0;
4056
	      avgHakt->prev = avgHeight;
4057
	      avgHeight->next = avgHakt;
4058
	      avgHeight = avgHakt;
4059
	   }
4060
 
4061
	   // FIXME: Currently we can not draw below 0 meters, because the
4062
	   // base line is always 0!
222 andreas 4063
	   if (avgHakt->alt < minHeight)
4064
	      avgHakt->alt = minHeight;
169 andreas 4065
 
4066
	   hEc++;
4067
	   i++;
4068
	}
4069
 
4070
	avgHlast = avgHeight;
4071
	// If wanted, even the lines
218 andreas 4072
	if (Contour && hEc > 0 && cuType != 0)
169 andreas 4073
	{
213 andreas 4074
	double alt[100], avg, avg1, avg2, avg3, avg4;
4075
	int a, pos;
169 andreas 4076
 
213 andreas 4077
	   for (i = 0; i < (hEc + 100); i += 100)
169 andreas 4078
	   {
213 andreas 4079
	      avg = avg1 = avg2 = avg3 = avg4 = 0.0;
4080
	      pos = 0;
169 andreas 4081
 
213 andreas 4082
	      for (a = 0; a < 100; a++)
169 andreas 4083
	      {
4084
		 alt[a] = getAvgAlt(avgHfirst, i + a);
4085
		 avg += alt[a];
213 andreas 4086
 
4087
		 if (a < 25)
4088
		    avg1 += alt[a];
4089
		 else if (a < 50)
4090
		    avg2 += alt[a];
4091
		 else if (a < 75)
4092
		    avg3 += alt[a];
4093
		 else
4094
		    avg4 += alt[a];
169 andreas 4095
	      }
4096
 
213 andreas 4097
	      if ((i + 100) >= hEc)
169 andreas 4098
		 avg /= (double)(hEc - i) + 1.0;
4099
	      else
213 andreas 4100
		 avg /= 100.0;
169 andreas 4101
 
213 andreas 4102
	      for (a = 0; a < 100; a++)
169 andreas 4103
	      {
4104
		 if ((avgHakt = getAvgPtr(avgHfirst, i + a)) != 0)
4105
		 {
4106
		    if ((avgHakt->alt - avg) > 2 || (avgHakt->alt - avg) < -2)
4107
		       avgHakt->alt = avg;
4108
		 }
4109
	      }
4110
	   }
4111
	}
4112
 
222 andreas 4113
	// plot the elevation, speed and/or heart rate. Depends on <cuType>)
168 andreas 4114
	i = 0;
169 andreas 4115
	int j = 0;
218 andreas 4116
	POINT *oldPoint = 0;
222 andreas 4117
	double speed = 0.0;	// calculated speed
4118
	bool pause = false;	// filter pause out of speed
4119
	unsigned long t1, t2;
4120
	t1 = t2 = 0;
218 andreas 4121
 
88 andreas 4122
	while ((point = ds.getPoint(i)) != 0)
4123
	{
218 andreas 4124
	   if (!oldPoint)
4125
	      oldPoint = point;
4126
 
88 andreas 4127
	   // calculate the y position based on the time
4128
	   qt = garmin_dtime(point->time);
4129
	   secs = zeit.secsTo(qt->time());
4130
	   delete qt;
4131
	   x2 = secs * w_tick + margin_left + 1;
4132
	   hx2 = x2;
222 andreas 4133
	   sx2 = x2;
88 andreas 4134
 
4135
	   if (x1 == 0)
4136
	      x1 = x2;
4137
 
4138
	   if (hx1 == 0)
4139
	      hx1 = hx2;
4140
 
222 andreas 4141
	   if (sx1 == 0)
4142
	      sx1 = sx2;
4143
 
4144
	   // The speed is not very exact, because smallest time is
4145
	   // one second. This allows a maximum error of 99 hundredths
4146
	   // of a second, what is very close to one second. Because of
4147
	   // this, speed seems to hop for every messure point. This
4148
	   // looks ugly, but currently I don't know how to make it
4149
	   // better.
4150
	   if (cuType == 1 || cuType == 2)	// Draw speed?
88 andreas 4151
	   {
218 andreas 4152
	      double dist;
4153
	      double sc;
168 andreas 4154
 
222 andreas 4155
	      if (!pause && point->distance > 1.0e10)
218 andreas 4156
	      {
222 andreas 4157
		 pause = true;
4158
		 t1 = point->time;
4159
	      }
4160
	      else if (pause)
4161
	      {
4162
		 pause = false;
4163
		 t2 = point->time;
4164
		 i += 2;
4165
		 continue;
4166
	      }
4167
 
4168
	      if (point->distance >= 0.1 && point->distance < 1.0e10)
4169
	      {
218 andreas 4170
		 dist = point->distance - oldPoint->distance;
4171
		 sc = point->time - oldPoint->time;
223 andreas 4172
		 LAP *runde = ds.getLapT (point->time);
222 andreas 4173
 
4174
		 if (t2 > t1)
4175
		 {
4176
		    sc -= t2 - t1;
4177
 
4178
		    if (sc <= 0.0)
4179
		       sc = 1.0;		// at least 1 second!
4180
		 }
4181
 
218 andreas 4182
		 speed = (dist / sc) * 3.6;
168 andreas 4183
 
223 andreas 4184
		 if (runde && runde->max_speed > 0.0 && speed > (runde->max_speed * 3.6))
4185
		    speed = runde->max_speed * 3.6;
4186
 
218 andreas 4187
		 if (Units == 1)
4188
		    speed /= 1.609344;
4189
 
222 andreas 4190
		 if (speed < minSpeed || speed > 400.0)
4191
		    speed = minSpeed;
218 andreas 4192
 
222 andreas 4193
		 if ((meter && cuType == 1) || (!meter && cuType == 2))
218 andreas 4194
		    y2 = (double)rh - (speed - minSpeed) * h_tick;
4195
		 else
4196
		 {
4197
		    double hrscale = rh / (maxSpeed - minSpeed);
4198
		    y2 = (double)rh - (speed - minSpeed) * hrscale;
4199
		 }
4200
 
4201
		 if (y1 == 0)
4202
		    y1 = y2;
4203
 
232 andreas 4204
		 paint.setPen(QPen(red, 1, Qt::SolidLine));
218 andreas 4205
		 paint.drawLine(x1, y1, x2, y2);
4206
		 y1 = y2;
4207
		 x1 = x2;
222 andreas 4208
		 t1 = t2 = 0;
4209
		 oldPoint = point;
218 andreas 4210
	      }
4211
	   }
222 andreas 4212
 
4213
	   if (cuType == 0 || cuType == 2)		// Draw elevation?
218 andreas 4214
	   {
4215
	      if (point->alt < 20000.0 && point->alt > -1000.0)
88 andreas 4216
	      {
218 andreas 4217
	      double alt = getAvgAlt(avgHfirst, j);
88 andreas 4218
 
218 andreas 4219
		 j++;
4220
 
4221
		 if (meter)
222 andreas 4222
		    sy2 = (double)rh - (alt - minHeight) * h_tick;
218 andreas 4223
		 else
4224
		 {
4225
		    double hrscale = rh / (maxHeight - minHeight);
222 andreas 4226
		    sy2 = (double)rh - (alt - minHeight) * hrscale;
218 andreas 4227
		 }
4228
 
222 andreas 4229
		 if (sy1 == 0)
4230
		    sy1 = sy2;
218 andreas 4231
 
232 andreas 4232
		 paint.setPen(QPen(barcol, 1, Qt::SolidLine));
222 andreas 4233
		 paint.drawLine(sx1, sy1, sx2, sy2);
4234
		 sy1 = sy2;
4235
		 sx1 = sx2;
218 andreas 4236
	      }
88 andreas 4237
	   }
4238
 
222 andreas 4239
	   if (point->heart_rate > 0 && cuType < 2)	// Draw heart rate?
88 andreas 4240
	   {
4241
	      if (meter)
4242
	      {
4243
		 double hrscale = rh / (double)(maxHr - minHr);
4244
		 hy2 = (double)rh - (double)(point->heart_rate - minHr) * hrscale;
4245
	      }
4246
	      else
4247
		 hy2 = (double)rh - (double)(point->heart_rate - minHr) * h_tick;
4248
 
4249
	      if (hy1 == 0)
4250
		 hy1 = hy2;
4251
 
232 andreas 4252
	      paint.setPen(QPen(blue, 1, Qt::SolidLine));
88 andreas 4253
	      paint.drawLine(hx1, hy1, hx2, hy2);
4254
	      hy1 = hy2;
4255
	      hx1 = hx2;
4256
	   }
4257
 
4258
	   i++;
4259
	}
4260
 
4261
	paint.end();
245 andreas 4262
	ui_sportwatcherWidgetBase.imgProfile->setPixmap(pmProfile);
88 andreas 4263
 
169 andreas 4264
	// free the chain of altitudes
4265
	avgHakt = avgHfirst;
4266
 
4267
	while (avgHakt)
4268
	{
4269
	   avgHeight = avgHakt->next;
4270
	   delete avgHakt;
4271
	   avgHakt = avgHeight;
4272
	}
4273
 
246 andreas 4274
	DIRTY = false;
88 andreas 4275
}
4276
 
280 andreas 4277
void sportwatcherWidget::showThreeCurve(int pw, int ph)
250 andreas 4278
{
4279
QPainter ptHR, ptElevation, ptSpeed;
4280
int width, height, wdHR, htHR, wdElev, htElev, wdSpeed, htSpeed;
4281
int i, secs, cuType;
4282
int lineHeight, margin_left, margin_right, margin_bottom;
4283
int x1, y1, x2, y2;		// Coordinates
274 andreas 4284
bool meterHR;
250 andreas 4285
double maxHeight, minHeight, maxSpeed, minSpeed;
4286
int maxHr, minHr, rh, rhHR, rhElev, rhSpeed;
4287
POINT *point;
4288
RUN_NODE *rn;
4289
LAP *lp;
4290
double wtiHR, htiHR, wtiElev, htiElev, wtiSpeed, htiSpeed;
4291
double w_tick, h_tick;		// Number of pixels one "tick" has;
4292
				// This depends on the width and height
4293
				// of the image.
4294
	// First we draw a grid based on the min and max
4295
	// values detected in the function showLap(). In case
4296
	// all values are 0, we exit here.
4297
	if (min_hr == 0 && max_hr == 0 && min_height == 0.0 && max_height == 0.0)
4298
	   return;
4299
 
280 andreas 4300
	if (!ActivePrint && (!DIRTY || curTab != 2))
250 andreas 4301
	   return;
4302
 
4303
	// Get the dimensions of the available draw area
4304
	// First for heart rate
280 andreas 4305
	if (!ActivePrint)
4306
	{
4307
	   wdHR = ui_sportwatcherWidgetBase.grHR->width() - 2;
4308
	   htHR = ui_sportwatcherWidgetBase.grHR->height();
4309
	   pmHR = QPixmap(wdHR, htHR);
4310
	   // Then for elevation
4311
	   wdElev = ui_sportwatcherWidgetBase.grElevation->width() - 2;
4312
	   htElev = ui_sportwatcherWidgetBase.grElevation->height();
4313
	   pmElevation = QPixmap(wdElev, htElev);
4314
	   // And at last for speed
4315
	   wdSpeed = ui_sportwatcherWidgetBase.grSpeed->width() - 2;
4316
	   htSpeed = ui_sportwatcherWidgetBase.grSpeed->height();
4317
	   pmSpeed = QPixmap(wdSpeed, htSpeed);
4318
	   // Initialize QPainter
4319
	   ptHR.begin(&pmHR);
4320
	   ptElevation.begin(&pmElevation);
4321
	   ptSpeed.begin(&pmSpeed);
4322
	}
4323
	else if (ActivePrint && pw > 0 && ph > 0)
4324
	{
4325
	   wdHR = wdElev = wdSpeed = pw;
4326
	   htHR = htElev = htSpeed = ph;
4327
	   prHR = prElevation = prSpeed = QPixmap(pw, ph);
4328
	   ptHR.begin(&prHR);
4329
	   ptElevation.begin(&prElevation);
4330
	   ptSpeed.begin(&prSpeed);
4331
	}
4332
	else
4333
	   return;
250 andreas 4334
 
4335
	// we need a somewhat bigger area to draw our curves than
4336
	// we have with the real min and max values.
4337
	if (max_height > 0.0)
4338
	{
4339
	double add = (max_height - min_height) / 100.0 * 5.0;	// Percent
4340
 
4341
	   maxHeight = max_height + add;
4342
	   minHeight = min_height - add;
4343
 
4344
	   if (minHeight < 0.0)		// make sure, we are not too deep
4345
	      minHeight = 0.0;
4346
	}
4347
	else
4348
	   maxHeight = minHeight = 0.0;
4349
 
4350
	if (max_speed > 0.0)
4351
	{
4352
	double add = (max_speed - min_speed) / 100.0 * 5.0;	// Percent
4353
 
4354
	   maxSpeed = max_speed + add;
4355
	   minSpeed = min_speed - add;
4356
 
4357
	   if (minSpeed < 0.0)		// make sure, we are not too deep
4358
	      minSpeed = 0.0;
4359
	}
4360
	else
4361
	   maxSpeed = minSpeed = 0.0;
4362
 
4363
	if (max_hr > 0)
4364
	{
4365
	   maxHr = max_hr + 10;
4366
	   minHr = min_hr - 10;
4367
 
4368
	   if (minHr < 0)
4369
	      minHr = 0;
4370
	}
4371
	else
4372
	   maxHr = minHr = 0;
4373
 
4374
	// Define colors
4375
	QColor background(220, 220, 220);	// Background of graphic
4376
	QColor mark(255, 255, 255);		// Lines inside curve area
4377
	QColor hlight(180, 180, 180);		// area of current lap
4378
	hlight.setAlpha(128);			// 50% transparent
4379
	QColor frame(0, 0, 0);			// Text and borders
4380
	QColor barcol(151, 190, 13);		// heart rate
4381
	QColor barcol2(190, 151, 13);		// height over NN
4382
	QColor red(220, 128, 128);		// speed
4383
	QColor blue(0, 0, 240);
4384
	QFont fntNormal("Helvetica");
4385
//	QFont fntBold("Helvetica", 10, QFont::Bold);
4386
	fntNormal.setPixelSize(10);
4387
	fntNormal.setStyleHint(QFont::Helvetica);
4388
//	fntBold.setPixelSize(10);
4389
//	fntBold.setStyleHint(QFont::Helvetica);
4390
	// Calculate ticks
4391
	margin_left = 1;
4392
	margin_right = 40;
4393
	margin_bottom = 12;
4394
	lineHeight = 10;
4395
//	rh = height - margin_bottom - 1;
4396
 
4397
	// Calculate the ticks for width and height for every draw area
4398
	for (i = 0; i < 3; i++)
4399
	{
4400
	   if (i == 2)	// Speed?
4401
	   {
4402
	      rhSpeed = htSpeed - margin_bottom - 1;
4403
	      wtiSpeed = (double)(wdSpeed - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
4404
	      htiSpeed = (double)rhSpeed / (maxSpeed - minSpeed);		// 1 tick = 1 km/h
4405
	   }
4406
	   else if (i == 1)	// Elevation?
4407
	   {
4408
	      rhElev = htElev - margin_bottom - 1;
4409
	      wtiElev = (double)(wdElev - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
4410
	      htiElev = (double)rhElev / (maxHeight - minHeight);		// 1 tick = 1 meter
4411
	   }
4412
	   else			// heart rate
4413
	   {
4414
	      rhHR = htHR - margin_bottom - 1;
4415
	      wtiHR = (double)(wdHR - (margin_left + margin_right)) / (max_time + ds.getPauseTime());	// 1 tick = 1 second
4416
	      htiHR = (double)rhHR / ((double)maxHr - (double)minHr);	// 1 tick = 1 bpm
4417
	   }
4418
	}
4419
 
4420
	// Fill background with background colors
4421
	ptHR.fillRect(0, 0, wdHR + 4, htHR + 4, background);
4422
	ptElevation.fillRect(0, 0, wdElev + 4, htElev + 4, background);
4423
	ptSpeed.fillRect(0, 0, wdSpeed + 4, htSpeed + 4, background);
4424
	// Draw a grid with markers at every 10 minutes
4425
	ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4426
	ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4427
	ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4428
	// Bottom border line
4429
	x1 = margin_left;
4430
 
4431
	y1 = htHR - margin_bottom;
4432
	x2 = wdHR - margin_right;
4433
	y2 = y1;
4434
	ptHR.drawLine(x1, y1, x2, y2);
4435
 
4436
	y1 = htElev - margin_bottom;
4437
	x2 = wdElev - margin_right;
4438
	y2 = y1;
4439
	ptElevation.drawLine(x1, y1, x2, y2);
4440
 
4441
	y1 = htSpeed - margin_bottom;
4442
	x2 = wdSpeed - margin_right;
4443
	y2 = y1;
4444
	ptSpeed.drawLine(x1, y1, x2, y2);
4445
 
4446
	// Left border line
4447
	x1 = x2 = margin_left;
4448
	y1 = 2;
4449
	y2 = htHR - margin_bottom;
4450
	ptHR.drawLine(x1, y1, x2, y2);
4451
 
4452
	y2 = htElev - margin_bottom;
4453
	ptElevation.drawLine(x1, y1, x2, y2);
4454
 
4455
	y2 = htSpeed - margin_bottom;
4456
	ptSpeed.drawLine(x1, y1, x2, y2);
4457
 
4458
	// right border line
4459
	x1 = x2 = wdHR - margin_right;
4460
	ptHR.drawLine(x1, y1, x2, y2);
4461
 
4462
	x1 = x2 = wdElev - margin_right;
4463
	ptElevation.drawLine(x1, y1, x2, y2);
4464
 
4465
	x1 = x2 = wdSpeed - margin_right;
4466
	ptSpeed.drawLine(x1, y1, x2, y2);
4467
 
4468
	// Draw some darker lines to show the laps, if we have one
4469
	QDateTime *qt;
4470
	QTime zeit = StartTime.time();
4471
	rn = ds.getRunNode();
4472
	ptHR.setPen(QPen(hlight, 1, Qt::SolidLine));
4473
	ptElevation.setPen(QPen(hlight, 1, Qt::SolidLine));
4474
	ptSpeed.setPen(QPen(hlight, 1, Qt::SolidLine));
4475
 
4476
	for (i = rn->run->first_lap_index; (unsigned int)i <= rn->run->last_lap_index; i++)
4477
	{
4478
	   if ((lp = ds.getLap(i)) == NULL)
4479
	      continue;
4480
 
4481
	   qt = garmin_dtime(lp->start_time);
4482
	   secs = zeit.secsTo(qt->time());
4483
	   delete qt;
4484
	   // heart rate
4485
	   x1 = secs * wtiHR + margin_left + 1;
4486
	   ptHR.drawLine(x1, 2, x1, htHR - margin_bottom);
4487
	   // Elevation
4488
	   x1 = secs * wtiElev + margin_left + 1;
4489
	   ptElevation.drawLine(x1, 2, x1, htElev - margin_bottom);
4490
	   // Speed
4491
	   x1 = secs * wtiSpeed + margin_left + 1;
4492
	   ptSpeed.drawLine(x1, 2, x1, htSpeed - margin_bottom);
4493
	}
4494
 
4495
	// Grid vertical
4496
	ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4497
	ptHR.setFont(fntNormal);
4498
	ptHR.drawText(margin_left, htHR - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));
4499
 
4500
	ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4501
	ptElevation.setFont(fntNormal);
4502
	ptElevation.drawText(margin_left, htElev - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));
4503
 
4504
	ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4505
	ptSpeed.setFont(fntNormal);
4506
	ptSpeed.drawText(margin_left, htSpeed - lineHeight, 40, lineHeight, Qt::AlignLeft, QString("0"));
4507
 
4508
	ptHR.save();
4509
	ptHR.rotate(270);
4510
	ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
4511
 
4512
	ptElevation.save();
4513
	ptElevation.rotate(270);
4514
	ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
4515
 
4516
	ptSpeed.save();
4517
	ptSpeed.rotate(270);
4518
	ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
4519
 
4520
	// Information on right side
4521
	ptHR.drawText((htHR + 4) * -1, wdHR - 1 - lineHeight, htHR - 2, lineHeight, Qt::AlignCenter, i18n("Heart Rate (bpm)"));
4522
	ptElevation.drawText((htElev + 4) * -1, wdElev - 1 - lineHeight, htElev - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Elevation (ft)" : "Elevation (m)"));
4523
	ptSpeed.drawText((htSpeed + 4) * -1, wdSpeed - 1 - lineHeight, htSpeed - 2, lineHeight, Qt::AlignCenter, i18n((Units == 1) ? "Speed (mph)" : "Speed (km/h)"));
4524
 
4525
	// restore to normal
4526
	ptHR.restore();
4527
	ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4528
 
4529
	ptElevation.restore();
4530
	ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4531
 
4532
	ptSpeed.restore();
4533
	ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
4534
	// Draw the time scale on the bottom of the graphic
4535
	for (i = 0; (unsigned int)i < (max_time + ds.getPauseTime()); i++)
4536
	{
4537
	bool loop = false;
4538
 
4539
	   if (i > 0 && !(i % 600))	// every 10 minutes
4540
	   {
4541
	      for (int j = 0; j < 3; j++)
4542
	      {
4543
		 switch (j)
4544
		 {
4545
		    case 0: w_tick = wtiHR; width = wdHR; height = htHR; break;
4546
		    case 1: w_tick = wtiElev; width = wdElev; height = htElev; break;
4547
		    case 2: w_tick = wtiSpeed; width = wdSpeed; height = htSpeed; break;
4548
		 }
4549
 
4550
		 x1 = x2 = margin_left + w_tick * i;
4551
 
4552
		 if (x1 == (width - margin_right - 25))
4553
		 {
4554
		    loop = true;
4555
		    break;
4556
		 }
4557
 
4558
		 y1 = 2;
4559
		 y2 = height - margin_bottom;
4560
		 QTime tm(0, 0, 0);
4561
		 tm = tm.addSecs(i);
4562
 
4563
		 if (j == 0)
4564
		 {
4565
		    ptHR.drawLine(x1, y1, x2, y2);
4566
		    ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4567
		    ptHR.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime (tm, (i >= 3600) ? true : false));
4568
		    ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4569
		 }
4570
		 else if (j == 1)
4571
		 {
4572
		    ptElevation.drawLine(x1, y1, x2, y2);
4573
		    ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4574
		    ptElevation.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime (tm, (i >= 3600) ? true : false));
4575
		    ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4576
		 }
4577
		 else
4578
		 {
4579
		    ptSpeed.drawLine(x1, y1, x2, y2);
4580
		    ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4581
		    ptSpeed.drawText(x1 - 25, height - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime (tm, (i >= 3600) ? true : false));
4582
		    ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
4583
		 }
4584
	      }
4585
 
4586
	      if (loop)
4587
	      {
4588
		 loop = false;
4589
		 continue;
4590
	      }
4591
	   }
4592
	}
4593
 
4594
	// This is the total time, with pauses included, at the lower right
4595
	// corner of the graphic.
4596
	QTime tm(0, 0, 0);
4597
	QString qs;
4598
	tm = tm.addSecs(max_time + ds.getPauseTime());
4599
	ptHR.setPen(QPen(frame, 1, Qt::SolidLine));
4600
	ptHR.drawText(wdHR - margin_right - 25, htHR - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
4601
 
4602
	ptElevation.setPen(QPen(frame, 1, Qt::SolidLine));
4603
	ptElevation.drawText(wdElev - margin_right - 25, htElev - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
4604
 
4605
	ptSpeed.setPen(QPen(frame, 1, Qt::SolidLine));
4606
	ptSpeed.drawText(wdSpeed - margin_right - 25, htSpeed - lineHeight, 50, lineHeight, Qt::AlignCenter, kl->formatTime(tm, (max_time >= 3600) ? true : false));
4607
 
4608
	// Draw the minimal elevation, speed and heart rate
4609
	// Heart rate
4610
	ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
4611
	ptHR.drawText(wdHR - margin_right + 2, htHR - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr));
4612
	// Elevation
4613
	ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
4614
	ptElevation.drawText(wdElev - margin_right + 2, htElev - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", (Units == 1) ? minHeight / 0.304 : minHeight));
4615
	// Speed
4616
	ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
4617
	ptSpeed.drawText(wdSpeed - margin_right + 2, htSpeed - margin_bottom - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", minSpeed));
4618
 
4619
	ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4620
	ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4621
	ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
4622
 
4623
	// Grid horizontal
4624
	int factor = 0;
4625
	int target = 0;
4626
 
4627
	for (int j = 0; j < 3; j++)
4628
	{
4629
	   switch (j)
4630
	   {
4631
	      case 0: width = wdHR; height = htHR; w_tick = wtiHR; h_tick = htiHR; rh = rhHR;
4632
		      factor = (maxHr - minHr) / (rhHR / 12);
4633
		      target = (maxHr - minHr);
4634
	      break;
4635
 
4636
	      case 1: width = wdElev; height = htElev; w_tick = wtiElev; h_tick = htiElev; rh = rhElev;
4637
		      factor = (maxHeight - minHeight) / (rhElev / 12);
4638
		      target = (int)(maxHeight - minHeight);
4639
	      break;
4640
 
4641
	      case 2: width = wdSpeed; height = htSpeed; w_tick = wtiSpeed; h_tick = htiSpeed; rh = rhSpeed;
4642
		      factor = (maxSpeed - minSpeed) / (rhSpeed / 12);
4643
		      target = (int)(maxSpeed - minSpeed);
4644
	      break;
4645
	   }
4646
 
4647
	   // To prevent a division by zero error, we check the <factor>
4648
	   if (factor == 0)
4649
	      factor = 1;
4650
 
4651
	   // Beside the horizontal part of the grid, we draw the scale on the
4652
	   // the right side too.
4653
	   int oldy = height;
4654
 
4655
	   for (i = 0; i < target; i++)
4656
	   {
4657
	      if (i > 0 && !(i % factor))
4658
	      {
4659
		 x1 = margin_left + 1;
4660
		 x2 = width - margin_right - 1;
4661
		 y1 = y2 = rh - h_tick * i;
4662
 
4663
		 if (y1 < 12)
4664
		    break;
4665
 
4666
		 switch (j)
4667
		 {
4668
		    case 0:
4669
		       ptHR.drawLine(x1, y1, x2, y2);
4670
		       ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
4671
		       ptHR.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%d", minHr + i));
4672
		       ptHR.setPen(QPen(mark, 1, Qt::SolidLine));
4673
		    break;
4674
 
4675
		    case 1:
4676
		       ptElevation.drawLine(x1, y1, x2, y2);
4677
		       ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
4678
		       ptElevation.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.0f", (Units == 1) ? (minHeight + i) / 0.304 : minHeight + i));
4679
		       ptElevation.setPen(QPen(mark, 1, Qt::SolidLine));
4680
		    break;
4681
 
4682
		    case 2:
4683
		       ptSpeed.drawLine(x1, y1, x2, y2);
4684
		       ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
4685
		       ptSpeed.drawText(width - margin_right + 2, y1 - lineHeight / 2, margin_right - 14, lineHeight, Qt::AlignLeft, qs.sprintf("%.1f", minSpeed + i));
4686
		       ptSpeed.setPen(QPen(mark, 1, Qt::SolidLine));
4687
		    break;
4688
		 }
4689
 
4690
		 oldy = y1;
4691
	      }
4692
	   }
4693
	}
4694
 
4695
	// To make our graphics more beautiful, we draw lines for the
4696
	// heart rate limits and the average heart rate.
4697
	if (max_hr > 0)
4698
	{
4699
	int ay1, ay2, ay3, ay4, ay5;
4700
 
4701
	   x1 = margin_left + 1;
4702
	   x2 = wdHR - margin_right - 1;
4703
 
4704
	   if (meterHR)
4705
	   {
4706
	      double hrscale = rh / (double)(maxHr - minHr);
4707
	      ay1 = (double)rh - (double)(lower1 - minHr) * hrscale;
4708
	      ay2 = (double)rh - (double)(lower2 - minHr) * hrscale;
4709
	      ay3 = (double)rh - (double)(lower3 - minHr) * hrscale;
4710
	      ay4 = (double)rh - (double)(upper3 - minHr) * hrscale;
4711
	      ay5 = (double)rh - (double)(avg_hr - minHr) * hrscale;
4712
	   }
4713
	   else
4714
	   {
4715
	      ay1 = (double)rh - (double)(lower1 - minHr) * htiHR;
4716
	      ay2 = (double)rh - (double)(lower2 - minHr) * htiHR;
4717
	      ay3 = (double)rh - (double)(lower3 - minHr) * htiHR;
4718
	      ay4 = (double)rh - (double)(upper3 - minHr) * htiHR;
4719
	      ay5 = (double)rh - (double)(avg_hr - minHr) * htiHR;
4720
	   }
4721
 
4722
	   ptHR.setPen(QPen(barcol2, 1, Qt::DashLine));	// color for limits
4723
 
4724
	   if (lower1 > minHr && lower1 < maxHr)
4725
	      ptHR.drawLine(x1, ay1, x2, ay1);
4726
 
4727
	   if (lower2 > minHr && lower2 < maxHr)
4728
	      ptHR.drawLine(x1, ay2, x2, ay2);
4729
 
4730
	   if (lower3 > minHr && lower3 < maxHr)
4731
	      ptHR.drawLine(x1, ay3, x2, ay3);
4732
 
4733
	   if (upper3 > minHr && upper3 < maxHr)
4734
	      ptHR.drawLine(x1, ay4, x2, ay4);
4735
 
4736
	   ptHR.setPen(QPen(red, 1, Qt::DashDotLine));	// color for average heart rate
4737
 
4738
	   if (avg_hr > minHr && avg_hr < maxHr)
4739
	      ptHR.drawLine(x1, ay5, x2, ay5);
4740
	}
4741
 
4742
	// Now we have a grid and we've done the scaling.
4743
	// This is the point where we draw the curves itself.
4744
	// We use different colors to draw the lines:
4745
	//
4746
	// Green: Elevation
4747
	// Red:   Speed
4748
	// Blue   Heart Rate
4749
	//
4750
	x1 = x2 = y1 = y2 = 0;
4751
	int hy1, hy2, hx1, hx2;
4752
	int sy1, sy2, sx1, sx2;
4753
	hy1 = hy2 = hx1 = hx2 = 0;
4754
	sy1 = sy2 = sx1 = sx2 = 0;
4755
	int hEc = 0;
4756
	i = 0;
4757
	AVGHEIGHT *avgHakt, *avgHfirst, *avgHlast, *avgHeight = 0;
4758
	avgHfirst = avgHlast = 0;
4759
	// To even the surface lines, we store every altitude in the
4760
	// memory, by building a chain. Then, if the user has set in the
4761
	// settings (Contour == true), we will even the line by calculating
4762
	// the average of 10 messure points and setting every value to the
4763
	// average, who is up or down more than 2 meters from the average.
4764
	while ((point = ds.getPoint(i)) != 0)
4765
	{
4766
	   if (point->alt > 20000.0 || point->alt < -1000.0)
4767
	   {
4768
	      i++;
4769
	      continue;
4770
	   }
4771
 
4772
	   if (!avgHeight)
4773
	   {
4774
	      avgHeight = new AVGHEIGHT;
4775
	      avgHeight->alt = point->alt;
4776
	      avgHeight->pos = hEc;
4777
	      avgHeight->prev = 0;
4778
	      avgHeight->next = 0;
4779
	      avgHakt = avgHeight;
4780
	      avgHfirst = avgHeight;
4781
	   }
4782
	   else
4783
	   {
4784
	      avgHakt = new AVGHEIGHT;
4785
	      avgHakt->alt = point->alt;
4786
	      avgHakt->pos = hEc;
4787
	      avgHakt->next = 0;
4788
	      avgHakt->prev = avgHeight;
4789
	      avgHeight->next = avgHakt;
4790
	      avgHeight = avgHakt;
4791
	   }
4792
 
4793
	   // FIXME: Currently we can not draw below 0 meters, because the
4794
	   // base line is always 0!
4795
	   if (avgHakt->alt < minHeight)
4796
	      avgHakt->alt = minHeight;
4797
 
4798
	   hEc++;
4799
	   i++;
4800
	}
4801
 
4802
	avgHlast = avgHeight;
4803
	// If wanted, even the lines
4804
	if (Contour && hEc > 0 && cuType != 0)
4805
	{
4806
	double alt[100], avg, avg1, avg2, avg3, avg4;
4807
	int a, pos;
4808
 
4809
	   for (i = 0; i < (hEc + 100); i += 100)
4810
	   {
4811
	      avg = avg1 = avg2 = avg3 = avg4 = 0.0;
4812
	      pos = 0;
4813
 
4814
	      for (a = 0; a < 100; a++)
4815
	      {
4816
		 alt[a] = getAvgAlt(avgHfirst, i + a);
4817
		 avg += alt[a];
4818
 
4819
		 if (a < 25)
4820
		    avg1 += alt[a];
4821
		 else if (a < 50)
4822
		    avg2 += alt[a];
4823
		 else if (a < 75)
4824
		    avg3 += alt[a];
4825
		 else
4826
		    avg4 += alt[a];
4827
	      }
4828
 
4829
	      if ((i + 100) >= hEc)
4830
		 avg /= (double)(hEc - i) + 1.0;
4831
	      else
4832
		 avg /= 100.0;
4833
 
4834
	      for (a = 0; a < 100; a++)
4835
	      {
4836
		 if ((avgHakt = getAvgPtr(avgHfirst, i + a)) != 0)
4837
		 {
4838
		    if ((avgHakt->alt - avg) > 2 || (avgHakt->alt - avg) < -2)
4839
		       avgHakt->alt = avg;
4840
		 }
4841
	      }
4842
	   }
4843
	}
4844
 
4845
	// plot the elevation, speed and/or heart rate. Depends on <cuType>)
4846
	i = 0;
4847
	int j = 0;
4848
	POINT *oldPoint = 0;
4849
	double speed = 0.0;	// calculated speed
4850
	bool pause = false;	// filter pause out of speed
4851
	unsigned long t1, t2;
4852
	t1 = t2 = 0;
4853
 
4854
	while ((point = ds.getPoint(i)) != 0)
4855
	{
4856
	bool loop = false;
4857
 
4858
	   if (!oldPoint)
4859
	      oldPoint = point;
4860
 
4861
	   // calculate the y position based on the time
4862
	   qt = garmin_dtime(point->time);
4863
	   secs = zeit.secsTo(qt->time());
4864
	   delete qt;
4865
 
4866
	   for (int c = 0; c < 3; c++)
4867
	   {
4868
	      if (c == 0)
4869
	      {
4870
		 x2 = secs * wtiHR + margin_left + 1;
4871
		 hx2 = x2;
4872
		 sx2 = x2;
4873
 
4874
		 if (x1 == 0)
4875
		    x1 = x2;
4876
 
4877
		 if (hx1 == 0)
4878
		    hx1 = hx2;
4879
 
4880
		 if (sx1 == 0)
4881
		    sx1 = sx2;
4882
	      }
4883
	      else if (c == 1)
4884
	      {
4885
		 x2 = secs * wtiElev + margin_left + 1;
4886
		 hx2 = x2;
4887
		 sx2 = x2;
4888
 
4889
		 if (x1 == 0)
4890
		    x1 = x2;
4891
 
4892
		 if (hx1 == 0)
4893
		    hx1 = hx2;
4894
 
4895
		 if (sx1 == 0)
4896
		    sx1 = sx2;
4897
	      }
4898
	      else
4899
	      {
4900
		 x2 = secs * wtiSpeed + margin_left + 1;
4901
		 hx2 = x2;
4902
		 sx2 = x2;
4903
 
4904
		 if (x1 == 0)
4905
		    x1 = x2;
4906
 
4907
		 if (hx1 == 0)
4908
		    hx1 = hx2;
4909
 
4910
		 if (sx1 == 0)
4911
		    sx1 = sx2;
4912
	      }
4913
	      // The speed is not very exact, because smallest time is
4914
	      // one second. This allows a maximum error of 99 hundredths
4915
	      // of a second, what is very close to one second. Because of
4916
	      // this, speed seems to hop for every messure point. This
4917
	      // looks ugly, but currently I don't know how to make it
4918
	      // better.
4919
	      if (c == 2)	// Draw speed?
4920
	      {
4921
	      double dist;
4922
	      double sc;
4923
 
4924
		 if (!pause && point->distance > 1.0e10)
4925
		 {
4926
		    pause = true;
4927
		    t1 = point->time;
4928
		 }
4929
		 else if (pause)
4930
		 {
4931
		    pause = false;
4932
		    t2 = point->time;
4933
		    i += 2;
4934
		    loop = true;
4935
		 }
4936
 
4937
		 if (point->distance >= 0.1 && point->distance < 1.0e10)
4938
		 {
4939
		    dist = point->distance - oldPoint->distance;
4940
		    sc = point->time - oldPoint->time;
4941
		    LAP *runde = ds.getLapT (point->time);
4942
 
4943
		    if (t2 > t1)
4944
		    {
4945
		       sc -= t2 - t1;
4946
 
4947
		       if (sc <= 0.0)
4948
			  sc = 1.0;		// at least 1 second!
4949
		    }
4950
 
4951
		    speed = (dist / sc) * 3.6;
4952
 
4953
		    if (runde && runde->max_speed > 0.0 && speed > (runde->max_speed * 3.6))
4954
		       speed = runde->max_speed * 3.6;
4955
 
4956
		    if (Units == 1)
4957
		       speed /= 1.609344;
4958
 
4959
		    if (speed < minSpeed || speed > 400.0)
4960
		       speed = minSpeed;
4961
 
4962
		    y2 = (double)rh - (speed - minSpeed) * htiSpeed;
4963
 
4964
		    if (y1 == 0)
4965
		       y1 = y2;
4966
 
4967
		    ptSpeed.setPen(QPen(red, 1, Qt::SolidLine));
4968
		    ptSpeed.drawLine(x1, y1, x2, y2);
4969
		    y1 = y2;
4970
		    x1 = x2;
4971
		    t1 = t2 = 0;
4972
		    oldPoint = point;
4973
		 }
4974
	      }
4975
 
4976
	      if (c == 1)		// Draw elevation?
4977
	      {
4978
		 if (point->alt < 20000.0 && point->alt > -1000.0)
4979
		 {
4980
		 double alt = getAvgAlt(avgHfirst, j);
4981
 
4982
		    j++;
4983
 
4984
		    sy2 = (double)rh - (alt - minHeight) * htiElev;
4985
 
4986
		    if (sy1 == 0)
4987
		       sy1 = sy2;
4988
 
4989
		    ptElevation.setPen(QPen(barcol, 1, Qt::SolidLine));
4990
		    ptElevation.drawLine(sx1, sy1, sx2, sy2);
4991
		    sy1 = sy2;
4992
		    sx1 = sx2;
4993
		 }
4994
	      }
4995
 
4996
	      if (point->heart_rate > 0 && c == 0)	// Draw heart rate?
4997
	      {
4998
		 hy2 = (double)rh - (double)(point->heart_rate - minHr) * htiHR;
4999
 
5000
		 if (hy1 == 0)
5001
		    hy1 = hy2;
5002
 
5003
		 ptHR.setPen(QPen(blue, 1, Qt::SolidLine));
5004
		 ptHR.drawLine(hx1, hy1, hx2, hy2);
5005
		 hy1 = hy2;
5006
		 hx1 = hx2;
5007
	      }
5008
	   }
5009
 
5010
	   if (loop)
5011
	   {
5012
	      loop = false;
5013
	      continue;
5014
	   }
5015
 
5016
	   i++;
5017
	}
5018
 
5019
	ptHR.end();
5020
	ptElevation.end();
5021
	ptSpeed.end();
5022
 
280 andreas 5023
	if (!ActivePrint)
5024
	{
5025
	   ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5026
	   ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5027
	   ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
5028
	}
250 andreas 5029
	// free the chain of altitudes
5030
	avgHakt = avgHfirst;
5031
 
5032
	while (avgHakt)
5033
	{
5034
	   avgHeight = avgHakt->next;
5035
	   delete avgHakt;
5036
	   avgHakt = avgHeight;
5037
	}
5038
 
5039
	DIRTY = false;
5040
}
5041
 
169 andreas 5042
double sportwatcherWidget::getAvgAlt(AVGHEIGHT *avgHeight, int pos)
5043
{
5044
AVGHEIGHT *akt;
5045
 
170 andreas 5046
	if (!avgHeight)
5047
	   return 0.0;
5048
 
169 andreas 5049
	akt = avgHeight;
5050
 
5051
	while (akt)
5052
	{
5053
	   if (akt->pos == pos)
5054
	      return akt->alt;
5055
 
5056
	   akt = akt->next;
5057
	}
5058
 
5059
	return 0.0;
5060
}
5061
 
5062
AVGHEIGHT *sportwatcherWidget::getAvgPtr(AVGHEIGHT *avgHeight, int pos)
5063
{
5064
AVGHEIGHT *akt;
5065
 
5066
	akt = avgHeight;
5067
 
5068
	while (akt)
5069
	{
5070
	   if (akt->pos == pos)
5071
	      return akt;
5072
 
5073
	   akt = akt->next;
5074
	}
5075
 
5076
	return 0;
5077
}
5078
 
246 andreas 5079
void sportwatcherWidget::resizeEvent(QResizeEvent *e)
88 andreas 5080
{
246 andreas 5081
	if (e->size() != e->oldSize())
5082
	   DIRTY=true;
5083
 
132 andreas 5084
	showTrack(zfactor);
88 andreas 5085
	showCurves();
250 andreas 5086
	tabDirt2 = true;
5087
 
5088
	if (curTab == 2)
5089
	{
5090
	   showThreeCurve();
5091
	   tabDirt2 = false;
5092
	}
5093
 
246 andreas 5094
	DIRTY=false;
88 andreas 5095
}
5096
 
132 andreas 5097
void sportwatcherWidget::mouseMoveEvent(QMouseEvent *e)
5098
{
5099
QPoint pos(0, 0);
245 andreas 5100
QPoint ev = ui_sportwatcherWidgetBase.imgMap->mapFrom(this, e->pos());
132 andreas 5101
static QRect coord;
88 andreas 5102
 
246 andreas 5103
	DIRTY=true;
5104
 
250 andreas 5105
	if (curTab == 0)
132 andreas 5106
	{
250 andreas 5107
	   if (!stateHand)
5108
	      return;
5109
 
5110
	   if (ev.x() >= pos.x() &&
5111
	       ev.y() >= pos.y() &&
5112
	       ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.imgMap->geometry().width()) &&
5113
	       ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.imgMap->geometry().height()))
132 andreas 5114
	   {
250 andreas 5115
	      if (lmbPressed == 1)
5116
	      {
5117
		 coord.setCoords(ev.x(), ev.y(), 0, 0);
5118
		 lmbPressed = 0;
5119
	      }
5120
	      else
5121
	      {
5122
		 coord.setRight(ev.x());
5123
		 coord.setBottom(ev.y());
5124
	      }
5125
 
5126
	      if (lmbPressed == 2)
5127
	      {
5128
		 showTrack(zfactor, coord, mapLap);
5129
		 lmbPressed = 0;
5130
	      }
132 andreas 5131
	   }
250 andreas 5132
	}
5133
 
5134
	if (curTab == 2)
5135
	{
5136
	   // look in which of the three QLabels the mouse is, if it is in
5137
	   // one of them.
5138
	   ev = ui_sportwatcherWidgetBase.grHR->mapFrom(this, e->pos());
5139
 
5140
	   if (ev.x() >= pos.x() &&
5141
	       ev.y() >= pos.y() &&
5142
	       ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grHR->geometry().width()) &&
5143
	       ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grHR->geometry().height()))
132 andreas 5144
	   {
250 andreas 5145
	      drawGrHR (ev.x(), ev.y());
5146
	      drawGrElev (ev.x(), -1);
5147
	      drawGrSpeed (ev.x(), -1);
132 andreas 5148
	   }
5149
 
250 andreas 5150
	   ev = ui_sportwatcherWidgetBase.grElevation->mapFrom(this, e->pos());
5151
 
5152
	   if (ev.x() >= pos.x() &&
5153
	       ev.y() >= pos.y() &&
5154
	       ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grElevation->geometry().width()) &&
5155
	       ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grElevation->geometry().height()))
132 andreas 5156
	   {
250 andreas 5157
	      drawGrHR (ev.x(), -1);
5158
	      drawGrElev (ev.x(), ev.y());
5159
	      drawGrSpeed (ev.x(), -1);
132 andreas 5160
	   }
250 andreas 5161
 
5162
	   ev = ui_sportwatcherWidgetBase.grSpeed->mapFrom(this, e->pos());
5163
 
5164
	   if (ev.x() >= pos.x() &&
5165
	       ev.y() >= pos.y() &&
5166
	       ev.x() <= (pos.x() + ui_sportwatcherWidgetBase.grSpeed->geometry().width()) &&
5167
	       ev.y() <= (pos.y() + ui_sportwatcherWidgetBase.grSpeed->geometry().height()))
5168
	   {
5169
	      drawGrHR (ev.x(), -1);
5170
	      drawGrElev (ev.x(), -1);
5171
	      drawGrSpeed (ev.x(), ev.y());
5172
	   }
132 andreas 5173
	}
246 andreas 5174
 
5175
	DIRTY=false;
132 andreas 5176
}
5177
 
5178
void sportwatcherWidget::mousePressEvent(QMouseEvent *e)
5179
{
232 andreas 5180
	if (stateHand && e->button() == Qt::LeftButton)
132 andreas 5181
	   lmbPressed = 1;	// Left Mouse Button is pressed
5182
	else if (stateHand)
5183
	   lmbPressed = 0;	// Wrong button is pressed
5184
 
5185
	if (stateGlas)
5186
	{
232 andreas 5187
	   if (e->button() == Qt::LeftButton)
132 andreas 5188
	      btGlasPlusSlot();
232 andreas 5189
	   else if (e->button() == Qt::RightButton)
132 andreas 5190
	      btGlasMinusSlot();
5191
	}
5192
}
5193
 
5194
void sportwatcherWidget::mouseReleaseEvent(QMouseEvent *e)
5195
{
232 andreas 5196
	if (stateHand && e->button() == Qt::LeftButton)
132 andreas 5197
	{
5198
	   lmbPressed = 2;	// Left Mouse Button was released
5199
	   mouseMoveEvent(e);
5200
	}
5201
}
5202
 
88 andreas 5203
/*
250 andreas 5204
 * Private functions to draw cross and/or a bar to reflect the mouse
5205
 * pointer on tab 2.
5206
 */
5207
void sportwatcherWidget::drawGrHR (int x, int y)
5208
{
5209
int width, height;
5210
QPixmap pm = pmHR.copy(pmHR.rect());
5211
QPainter paint;
5212
 
5213
	width = ui_sportwatcherWidgetBase.grHR->width();
5214
	height = ui_sportwatcherWidgetBase.grHR->height();
5215
	ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5216
 
5217
	if (x > (width - 40) || y > (height - 12) || x < 1)
5218
	{
5219
	   ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5220
	   ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
5221
	   return;
5222
	}
5223
 
5224
	if (tabDirt2)
5225
	{
5226
	   DIRTY = true;
5227
	   showThreeCurve ();
5228
	   tabDirt2 = false;
5229
	   DIRTY = false;
5230
	}
5231
 
5232
	paint.begin(&pm);
5233
	QColor black(0, 0, 0);
5234
	black.setAlpha (128);
5235
	paint.setPen(QPen(black, 1, Qt::SolidLine));
5236
	// horizontal line, if y != -1
5237
	if (y >= 0)
5238
	   paint.drawLine(2, y, width - 41, y);
5239
 
5240
	// vertical line
5241
	paint.drawLine(x, 1, x, height - 13);
5242
	paint.end();
5243
	ui_sportwatcherWidgetBase.grHR->setPixmap(pm);
5244
}
5245
 
5246
void sportwatcherWidget::drawGrElev (int x, int y)
5247
{
5248
int width, height;
5249
QPixmap pm = pmElevation.copy(pmElevation.rect());
5250
QPainter paint;
5251
 
5252
	width = ui_sportwatcherWidgetBase.grElevation->width();
5253
	height = ui_sportwatcherWidgetBase.grElevation->height();
5254
	ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5255
 
5256
	if (x > (width - 40) || y > (height - 12) || x < 1)
5257
	{
5258
	   ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5259
	   ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
5260
	   return;
5261
	}
5262
 
5263
	if (tabDirt2)
5264
	{
5265
	   DIRTY = true;
5266
	   showThreeCurve ();
5267
	   tabDirt2 = false;
5268
	   DIRTY = false;
5269
	}
5270
 
5271
	paint.begin(&pm);
5272
	QColor black(0, 0, 0);
5273
	black.setAlpha (128);
5274
	paint.setPen(QPen(black, 1, Qt::SolidLine));
5275
	// horizontal line, if y != -1
5276
	if (y >= 0)
5277
	   paint.drawLine(2, y, width - 41, y);
5278
 
5279
	// vertical line
5280
	paint.drawLine(x, 1, x, height - 13);
5281
	paint.end();
5282
	ui_sportwatcherWidgetBase.grElevation->setPixmap(pm);
5283
}
5284
 
5285
void sportwatcherWidget::drawGrSpeed (int x, int y)
5286
{
5287
int width, height;
5288
QPixmap pm = pmSpeed.copy(pmSpeed.rect());
5289
QPainter paint;
5290
 
5291
	width = ui_sportwatcherWidgetBase.grSpeed->width();
5292
	height = ui_sportwatcherWidgetBase.grSpeed->height();
5293
	ui_sportwatcherWidgetBase.grSpeed->setPixmap(pmSpeed);
5294
 
5295
	if (x > (width - 40) || y > (height - 12) || x < 1)
5296
	{
5297
	   ui_sportwatcherWidgetBase.grHR->setPixmap(pmHR);
5298
	   ui_sportwatcherWidgetBase.grElevation->setPixmap(pmElevation);
5299
	   return;
5300
	}
5301
 
5302
	if (tabDirt2)
5303
	{
5304
	   DIRTY = true;
5305
	   showThreeCurve ();
5306
	   tabDirt2 = false;
5307
	   DIRTY = false;
5308
	}
5309
 
5310
	paint.begin(&pm);
5311
	QColor black(0, 0, 0);
5312
	black.setAlpha (128);
5313
	paint.setPen(QPen(black, 1, Qt::SolidLine));
5314
	// horizontal line, if y != -1
5315
	if (y >= 0)
5316
	   paint.drawLine(2, y, width - 41, y);
5317
 
5318
	// vertical line
5319
	paint.drawLine(x, 1, x, height - 13);
5320
	paint.end();
5321
	ui_sportwatcherWidgetBase.grSpeed->setPixmap(pm);
5322
}
5323
 
5324
/*
88 andreas 5325
 * Private functions to help decode the data
5326
 */
5327
QDateTime *sportwatcherWidget::garmin_dtime (uint32 t)
5328
{
5329
time_t     tval;
5330
struct tm  tmval;
5331
QTime ti;
5332
QDate dt;
5333
QDateTime *qt;
5334
 
5335
	if (t == 0)
5336
	   return new QDateTime(QDate(1900, 1, 1), QTime(0, 0, 0, 0));
5337
 
5338
	tval = t + TIME_OFFSET;
5339
	localtime_r (&tval, &tmval);
5340
	qt = new QDateTime();
5341
	qt->setDate(QDate(tmval.tm_year+1900, tmval.tm_mon+1, tmval.tm_mday));
5342
	qt->setTime(QTime(tmval.tm_hour, tmval.tm_min, tmval.tm_sec, 0));
5343
	/* OK.  Done. */
5344
	return qt;
5345
}
5346
 
104 andreas 5347
bool sportwatcherWidget::writeTag(const QFile &fn, const QString &str, int indent)
5348
{
5349
QString qs;
232 andreas 5350
char *p;
5351
//QCString qcs;
104 andreas 5352
int i;
88 andreas 5353
 
171 andreas 5354
	if (indent > 0)
5355
	   qs.fill(' ', indent * 3);
5356
 
104 andreas 5357
	qs.append(str);
232 andreas 5358
//	qcs = qs.utf8();
5359
//	qstrcpy(p, qcs);
5360
	p = strdup (qs.toUtf8().data());
104 andreas 5361
	i = strlen(p);
5362
 
5363
	if (write(fn.handle(), p, i) != i)
5364
	{
232 andreas 5365
	   free (p);
104 andreas 5366
	   return false;
5367
	}
5368
 
232 andreas 5369
	free (p);
104 andreas 5370
	return true;
5371
}
5372
 
232 andreas 5373
#if defined HAVE_GDAL
151 andreas 5374
bool sportwatcherWidget::writeWMSTag(double llat, double llon, double rlat, double rlon, int width, int height)
5375
{
5376
QFile fl(MAP);
152 andreas 5377
QString xml, s, srs, crs, styles, bSize, ext;
5378
QDir dir = QDir::home();
232 andreas 5379
QString path = dir.absolutePath();
157 andreas 5380
int item, isrs;
5381
double _llat, _llon, _rlat, _rlon;
5382
bool offline, square;
151 andreas 5383
 
232 andreas 5384
	if (!fl.open(QIODevice::ReadWrite | QIODevice::Truncate))
151 andreas 5385
	{
5386
	   KMessageBox::error (this, i18n("Error opening or creating the WMS tag file!\nPlease check file name and/or permissions."));
5387
	   return false;
5388
	}
5389
 
232 andreas 5390
	KConfig cfg (QString("sportwatcher.rc"), KConfig::SimpleConfig);
5391
	KConfigGroup wms (&cfg, "WMS");
5392
	square = wms.readEntry("Square", false);
5393
	styles = wms.readEntry("Styles", QString(""));
152 andreas 5394
 
151 andreas 5395
	xml = "<GDAL_WMS>\n";
5396
	xml += "   <Service name=\"WMS\">\n";
5397
	xml += "      <Version>1.1.1</Version>\n";
232 andreas 5398
	xml += "      <ServerURL>" + wms.readEntry("ServerURL", "http://onearth.jpl.nasa.gov/wms.cgi") + "?</serverURL>\n";
5399
	isrs = wms.readEntry("SRS", 0);
157 andreas 5400
	_llon = llon;
5401
	_llat = llat;
5402
	_rlon = rlon;
5403
	_rlat = rlat;
5404
	offline = false;
152 andreas 5405
 
157 andreas 5406
	switch (isrs)
152 andreas 5407
	{
5408
	   case 0: srs = QString("EPSG:4326"); break;
157 andreas 5409
 
5410
	   case 1:
5411
	      srs = QString("EPSG:31257");
5412
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31257, width, height, square);
5413
	   break;
5414
 
5415
	   case 2:
5416
	      srs = QString("EPSG:31258");
5417
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31258, width, height, square);
5418
	   break;
5419
 
5420
	   case 3:
5421
	      srs = QString("EPSG:31259");
5422
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31259, width, height, square);
5423
	   break;
5424
 
5425
	   case 4:
5426
	      srs = QString("EPSG:31286");
5427
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31286, width, height, square);
5428
	   break;
5429
 
5430
	   case 5:
5431
	      srs = QString("EPSG:31287");
5432
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31287, width, height, square);
5433
	   break;
5434
 
5435
	   case 6:
5436
	      srs = QString("EPSG:31288");
5437
	      offline = transCoords(&_llat, &_llon, &_rlat, &_rlon, 31288, width, height, square);
5438
	   break;
5439
 
152 andreas 5440
	   default: srs = QString("EPSG:4326");
5441
	}
5442
 
5443
	xml += "      <SRS>" + srs + "</SRS>\n";
232 andreas 5444
	item = wms.readEntry("CRS", 0);
152 andreas 5445
 
5446
	switch (item)
5447
	{
5448
	   case 0: crs = QString("CRS:83"); break;
157 andreas 5449
	   case 1: crs = QString("CRS:84"); break;
5450
	   case 2: crs = QString("EPSG:4326"); break;
5451
	   case 3: crs = QString("EPSG:31259"); break;
5452
	   case 4: crs = QString("EPSG:31287"); break;
152 andreas 5453
	   default: crs = QString("CRS:83"); break;
5454
	}
5455
 
5456
	xml += "      <CRS>" + crs + "</CRS>\n";
232 andreas 5457
	item = wms.readEntry("Image", 2);
152 andreas 5458
	xml += "      <ImageFormat>image/";
5459
 
5460
	switch (item)
5461
	{
5462
	   case 0: xml += "gif"; ext = QString(".gif"); break;
5463
	   case 1: xml += "jpeg"; ext = QString(".jpg"); break;
5464
	   case 2: xml += "png"; ext = QString(".png"); break;
5465
	   case 3: xml += "tiff"; ext = QString(".tif"); break;
5466
	   default: xml += "png"; ext = QString(".png");
5467
	}
5468
 
5469
	xml += "</ImageFormat>\n";
5470
 
232 andreas 5471
	xml += "      <Layers>" + wms.readEntry("Layer", QString("")) + "</Layers>\n";
152 andreas 5472
 
5473
	if (!styles.isEmpty())
5474
	   xml += "      <Styles>" + styles + "</Styles>\n";
5475
 
151 andreas 5476
	xml += "      <BBoxOrder>xyXY</BBoxOrder>\n";
5477
	xml += "   </Service>\n";
5478
	xml += "   <DataWindow>\n";
157 andreas 5479
	s.sprintf ("%f", _llat);
151 andreas 5480
	xml += "      <UpperLeftX>" + s + "</UpperLeftX>\n";
157 andreas 5481
	s.sprintf ("%f", _llon);
151 andreas 5482
	xml += "      <UpperLeftY>" + s + "</UpperLeftY>\n";
157 andreas 5483
	s.sprintf ("%f", _rlat);
151 andreas 5484
	xml += "      <LowerRightX>" + s + "</LowerRightX>\n";
157 andreas 5485
	s.sprintf ("%f", _rlon);
151 andreas 5486
	xml += "      <LowerRightY>" + s + "</LowerRightY>\n";
5487
	s.sprintf ("%d", width);
5488
	xml += "      <SizeX>" + s + "</SizeX>\n";
5489
	s.sprintf ("%d", height);
5490
	xml += "      <SizeY>" + s + "</SizeY>\n";
5491
	xml += "   </DataWindow>\n";
157 andreas 5492
 
5493
/*	switch (isrs)
5494
	{
5495
	   case 0: srs = QString("EPSG:4326"); break;
5496
	   case 1: srs = QString("EPSG:31259"); break;
5497
	   case 2: srs = QString("EPSG:31286"); break;
5498
	   case 3: srs = QString("EPSG:31287"); break;
5499
	   case 4: srs = QString("EPSG:31288"); break;
5500
	   default: srs = QString("EPSG:4326");
5501
	}
5502
*/
5503
//	srs = QString("EPSG:4326");
5504
	xml += "   <Projection>" + srs + "</Projection>\n";
232 andreas 5505
	xml += "   <BandsCount>" + wms.readEntry("Bands", QString("3")) + "</BandsCount>\n";
5506
	item = wms.readEntry("Tile", 2);
152 andreas 5507
 
5508
	switch (item)
5509
	{
5510
	   case 0: bSize = QString("64"); break;
5511
	   case 1: bSize = QString("128"); break;
5512
	   case 2: bSize = QString("256"); break;
5513
	   case 3: bSize = QString("512"); break;
5514
	   case 4: bSize = QString("1024"); break;
5515
	   default: bSize = QString("256");
5516
	}
5517
 
5518
	xml += "   <BlockSizeX>" + bSize + "</BlockSizeX>\n";
5519
	xml += "   <BlockSizeY>" + bSize + "</BlockSizeY>\n";
232 andreas 5520
	xml += "   <OverviewCount>" + wms.readEntry("Overview", QString("10")) + "</OverviewCount>\n";
151 andreas 5521
	xml += "   <Cache>\n";
152 andreas 5522
	xml += "      <Path>" + path + "/.gdalwmscache" + "</Path>\n";
232 andreas 5523
	xml += "      <Depth>" + wms.readEntry("Depth", QString("2")) + "</Depth>\n";
152 andreas 5524
	xml += "      <Extension>" + ext + "</Extension>\n";
151 andreas 5525
	xml += "   </Cache>\n";
232 andreas 5526
	QString off((wms.readEntry("Offline", false)) ? "true" : "false");
5527
	QString adv((wms.readEntry("Advice", false)) ? "true" : "false");
5528
	QString ver((wms.readEntry("Verify", true)) ? "true" : "false");
157 andreas 5529
 
5530
	if (offline)
5531
	   xml += "   <OfflineMode>true</OfflineMode>\n";
5532
	else
5533
	   xml += "   <OfflineMode>" + off + "</OfflineMode>\n";
5534
 
152 andreas 5535
	xml += "   <AdviseRead>" + adv + "</AdviseRead>\n";
5536
	xml += "   <VerifyAdviseRead>" + ver + "</VerifyAdviseRead>\n";
151 andreas 5537
	xml += "</GDAL_WMS>\n";
5538
 
232 andreas 5539
	write (fl.handle(), xml.toAscii().data(), strlen (xml.toAscii().data()));
151 andreas 5540
	fl.close();
5541
	return true;
5542
}
5543
 
157 andreas 5544
bool sportwatcherWidget::transCoords (double *x1, double *y1, double *x2, double *y2, int code, int width, int height, bool square)
151 andreas 5545
{
157 andreas 5546
OGRSpatialReference oSourceSRS, oTargetSRS;
5547
OGRCoordinateTransformation *poCT;
5548
 
5549
	oSourceSRS.SetWellKnownGeogCS ("WGS84");
5550
	oTargetSRS.importFromEPSG(code);
5551
	poCT = OGRCreateCoordinateTransformation (&oSourceSRS, &oTargetSRS);
5552
 
5553
	if (poCT == NULL || !poCT->Transform( 1, x1, y1))
5554
	{
5555
	   KMessageBox::error(this, i18n("Translation between coordinate systems failed!"));
5556
 
5557
	   if (poCT != NULL)
5558
	      delete poCT;
5559
 
5560
	   return true;
5561
	}
5562
 
5563
	if (poCT != NULL)
5564
	{
5565
	   poCT->Transform (1, x2, y2);
5566
	   delete poCT;
5567
	}
5568
 
5569
	if (square)
5570
	{
5571
	double wdiff = (double)((long)(*x1 - *x2) / (width / 2 * 2) * (width / 2 * 2));
5572
	double hdiff = (double)((long)(*y2 - *y1) / (height / 2 * 2) * (height / 2 * 2));
5573
 
5574
	   *x2 = *x1 - wdiff; // * (double)mFactor;
5575
	   *y2 = *y1 + hdiff; // * (double)mFactor;
5576
//	   *x2 = *x1 - (double)((long)(wdiff / mFactor * mFactor));
5577
//	   *y2 = *y1 - (double)((long)(hdiff / mFactor * mFactor));
5578
/*	   wdiff = wdiff - (*x1 - *x2);
5579
	   hdiff = hdiff - (*y2 - *y1);
5580
	   *x1 -= wdiff / 2.0;
5581
	   *x2 -= wdiff / 2.0;
5582
	   *y1 += hdiff / 2.0;
5583
	   *y2 += hdiff / 2.0; */
5584
	}
5585
 
5586
	return false;
151 andreas 5587
}
5588
 
158 andreas 5589
QString *sportwatcherWidget::getProjection (int isrs, QString *srs)
5590
{
5591
	switch (isrs)
5592
	{
5593
	   case 0: *srs = QString("EPSG:4326"); break;
5594
	   case 1: *srs = QString("EPSG:31257"); break;
5595
	   case 2: *srs = QString("EPSG:31258"); break;
5596
	   case 3: *srs = QString("EPSG:31259"); break;
5597
	   case 4: *srs = QString("EPSG:31286"); break;
5598
	   case 5: *srs = QString("EPSG:31287"); break;
5599
	   case 6: *srs = QString("EPSG:31288"); break;
5600
	   default: *srs = QString("EPSG:4326");
5601
	}
5602
 
5603
	return srs;
5604
}
5605
 
5606
bool sportwatcherWidget::warpImage(QString fn, QString *fName)
5607
{
5608
GDALDatasetH  hSrcDS, hDstDS;
5609
GDALDataset *inSet, *outSet;
5610
GDALDataType eDT;
5611
GDALRasterBand *poBand;
5612
GDALDriverH hDriver;
5613
char hv0[256];
5614
int nXSize, nYSize;
5615
double adfGeoTransform[6];
5616
double oriLeftLon, oriRightLon, oriLeftLat, oriRightLat;
5617
 
159 andreas 5618
 
5619
	// Loading the user set geo coords of our source image and
5620
	// load the projection used for that image
232 andreas 5621
	KConfig cfg (QString("sportwatcher.rc"), KConfig::SimpleConfig);
5622
	KConfigGroup ic (&cfg, "ImageCoords");
5623
	oriLeftLon = ic.readEntry("LeftLon", 0.0);
5624
	oriLeftLat = ic.readEntry("LeftLat", 0.0);
5625
	oriRightLon = ic.readEntry("RightLon", 0.0);
5626
	oriRightLat = ic.readEntry("RightLat", 0.0);
5627
	int isrs = ic.readEntry("SRS", 0);
159 andreas 5628
 
158 andreas 5629
	// Create a temporary file name for our output file
5630
	strcpy (hv0, "/tmp/SportWatcherTIFFXXXXXX");
216 andreas 5631
	mkdtemp (&hv0[0]);
158 andreas 5632
	*fName = QString(hv0) + ".tif";
5633
 
5634
	// Open input and output files.
232 andreas 5635
	if ((hSrcDS = GDALOpen(fn.toAscii().data(), GA_ReadOnly)) == NULL)
158 andreas 5636
	{
5637
	   KMessageBox::error(this, i18n("Error opening an image file!"));
5638
	   return false;
5639
	}
5640
 
5641
	inSet = (GDALDataset *)hSrcDS;
5642
	// Create output with same datatype as first input band.
5643
	poBand = inSet->GetRasterBand (1);
5644
	eDT = poBand->GetRasterDataType ();
5645
 
5646
	if ((hDriver = GDALGetDriverByName ("GTiff")) == NULL)
5647
	{
5648
	   KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
5649
	   GDALClose (hSrcDS);
5650
	   return false;
5651
	}
5652
 
5653
	// Get dimensions of image and set transform data
5654
	int nRasterCount = inSet->GetRasterCount();
5655
	nXSize = inSet->GetRasterXSize();
5656
	nYSize = inSet->GetRasterYSize();
5657
 
159 andreas 5658
	// cut the wanted region out of image
5659
	transform *tf = new transform (oriLeftLat, oriLeftLon, oriRightLat, oriRightLon);
5660
	tf->setDimensions(nXSize, nYSize);
158 andreas 5661
 
159 andreas 5662
	if (!tf->cutImage (geoRect.llat, geoRect.llon, geoRect.rlat, geoRect.rlon, fn))
5663
	{
5664
	   GDALClose (hSrcDS);
5665
	   return false;
5666
	}
158 andreas 5667
 
159 andreas 5668
	GDALClose (hSrcDS);
5669
	QString nfn = fn + "_tmp.png";
158 andreas 5670
 
159 andreas 5671
	// repeat the part above and open the now cutted part of the image.
5672
	// Open input and output files.
232 andreas 5673
	if ((hSrcDS = GDALOpen(nfn.toAscii().data(), GA_ReadOnly)) == NULL)
159 andreas 5674
	{
5675
	   KMessageBox::error(this, i18n("Error opening an image file!"));
5676
	   return false;
5677
	}
158 andreas 5678
 
159 andreas 5679
	inSet = (GDALDataset *)hSrcDS;
5680
	// Create output with same datatype as first input band.
5681
	poBand = inSet->GetRasterBand (1);
5682
	eDT = poBand->GetRasterDataType ();
158 andreas 5683
 
159 andreas 5684
	if ((hDriver = GDALGetDriverByName ("GTiff")) == NULL)
158 andreas 5685
	{
159 andreas 5686
	   KMessageBox::error(this, i18n("Error loading the TIFF driver!"));
5687
	   GDALClose (hSrcDS);
5688
	   return false;
158 andreas 5689
	}
5690
 
159 andreas 5691
	// Get dimensions of image and set transform data
5692
	nRasterCount = inSet->GetRasterCount();
5693
	nXSize = inSet->GetRasterXSize();
5694
	nYSize = inSet->GetRasterYSize();
5695
 
158 andreas 5696
	// Set the values needed to transform the image
5697
	OGRSpatialReference iSRS;
5698
	const char *iWKT;
5699
 
5700
	switch (isrs)
5701
	{
5702
	   case 0: iSRS.importFromEPSG(4326); break;
5703
	   case 1: iSRS.importFromEPSG(31257); break;
5704
	   case 2: iSRS.importFromEPSG(31258); break;
5705
	   case 3: iSRS.importFromEPSG(31259); break;
5706
	   case 4: iSRS.importFromEPSG(31286); break;
5707
	   case 5: iSRS.importFromEPSG(31287); break;
5708
	   case 6: iSRS.importFromEPSG(31288); break;
5709
	   default: iSRS.importFromEPSG(4326);
5710
	}
5711
 
5712
	iSRS.exportToWkt ((char **)&iWKT);
5713
 
5714
	if (inSet->SetProjection (iWKT) != CE_None)
5715
	{
5716
	   KMessageBox::error(this, i18n("Error setting projection on source!"));
5717
	   GDALClose (hSrcDS);
5718
	   return false;
5719
	}
5720
 
159 andreas 5721
	adfGeoTransform[0] = geoRect.llon;
5722
	adfGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)nXSize;
158 andreas 5723
	adfGeoTransform[2] = 0.0;
159 andreas 5724
	adfGeoTransform[3] = geoRect.llat;
158 andreas 5725
	adfGeoTransform[4] = 0.0;
159 andreas 5726
	adfGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)nYSize);
158 andreas 5727
 
5728
	if (inSet->SetGeoTransform (&adfGeoTransform[0]) != CE_None)
5729
	{
5730
	   KMessageBox::error(this, i18n("Error setting geo transform data to source!"));
5731
	   GDALClose (hSrcDS);
5732
	   return false;
5733
	}
5734
 
159 andreas 5735
	// Get Source coordinate system.
158 andreas 5736
	const char *pszSrcWKT, *pszDstWKT = NULL;
5737
 
5738
	if ((pszSrcWKT = GDALGetProjectionRef (hSrcDS)) == NULL)
5739
	{
5740
	   KMessageBox::error(this, i18n("Error getting the projection reference"));
5741
	   GDALClose (hSrcDS);
5742
	   return false;
5743
	}
5744
 
5745
	// Setup output coordinate system that is UTM ? WGS84.
5746
	OGRSpatialReference oSRS;
5747
 
159 andreas 5748
//	oSRS.SetUTM( 0, TRUE );
158 andreas 5749
	oSRS.SetWellKnownGeogCS("WGS84");
5750
	oSRS.exportToWkt ((char **)&pszDstWKT);
5751
 
159 andreas 5752
	// Create the output file.
158 andreas 5753
	double adfDstGeoTransform[6];
159 andreas 5754
	adfDstGeoTransform[0] = geoRect.llon;
5755
	adfDstGeoTransform[1] = (geoRect.rlon - geoRect.llon) / (double)geoRect.width;
158 andreas 5756
	adfDstGeoTransform[2] = 0.0;
5757
	adfDstGeoTransform[3] = geoRect.llat;
5758
	adfDstGeoTransform[4] = 0.0;
159 andreas 5759
	adfDstGeoTransform[5] = -1.0 * ((geoRect.llat - geoRect.rlat) / (double)geoRect.height);
158 andreas 5760
 
232 andreas 5761
	if ((hDstDS = GDALCreate(hDriver, fName->toAscii().data(), geoRect.width, geoRect.height,
158 andreas 5762
			nRasterCount, eDT, NULL )) == NULL)
5763
	{
232 andreas 5764
	   KMessageBox::error(this, i18n("Error creating a temporary image file! (%1)").arg(*fName));
158 andreas 5765
	   GDALClose (hSrcDS);
5766
	   return false;
5767
	}
5768
 
5769
	outSet = (GDALDataset *)hDstDS;
5770
 
159 andreas 5771
	for (int i = 0; i < nRasterCount; i++)
5772
	{
5773
	   poBand = outSet->GetRasterBand (i+1);
5774
	   poBand->Fill (0.0);
5775
	}
5776
 
158 andreas 5777
	if (outSet->SetProjection (pszDstWKT) != CE_None)
5778
	{
5779
	   KMessageBox::error(this, i18n("Error setting projection on destination!"));
5780
	   GDALClose (hDstDS);
5781
	   GDALClose (hSrcDS);
232 andreas 5782
	   unlink (fName->toAscii().data());
158 andreas 5783
	   return false;
5784
	}
5785
 
5786
	if (outSet->SetGeoTransform (&adfDstGeoTransform[0]) != CE_None)
5787
	{
159 andreas 5788
	   KMessageBox::error(this, i18n("Error setting geo transform data to destination!"));
158 andreas 5789
	   GDALClose (hDstDS);
5790
	   GDALClose (hSrcDS);
232 andreas 5791
	   unlink (fName->toAscii().data());
158 andreas 5792
	   return false;
5793
	}
159 andreas 5794
 
158 andreas 5795
	// Copy the color table, if required.
5796
	GDALColorTableH hCT;
5797
 
5798
	for (int i = 0; i < nRasterCount; i++)
5799
	{
5800
	   hCT = GDALGetRasterColorTable (inSet->GetRasterBand (i+1));
5801
 
5802
	   if (hCT != NULL)
5803
              GDALSetRasterColorTable (outSet->GetRasterBand (i+1), hCT);
5804
	}
5805
 
5806
	// Setup warp options.
5807
	GDALWarpOptions *psWarpOptions = GDALCreateWarpOptions();
5808
 
5809
	psWarpOptions->hSrcDS = hSrcDS;
5810
	psWarpOptions->hDstDS = hDstDS;
5811
 
5812
	psWarpOptions->nBandCount = nRasterCount;
5813
	psWarpOptions->panSrcBands =
5814
        	(int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount );
5815
	psWarpOptions->panDstBands =
5816
		(int *) CPLMalloc(sizeof(int) * psWarpOptions->nBandCount );
5817
 
5818
	for (int i = 0; i < nRasterCount; i++)
5819
	{
5820
	   psWarpOptions->panSrcBands[i] = i+1;
5821
	   psWarpOptions->panDstBands[i] = i+1;
5822
	}
5823
 
159 andreas 5824
//	psWarpOptions->pfnProgress = GDALTermProgress;
158 andreas 5825
 
5826
	// Establish reprojection transformer.
5827
	psWarpOptions->pTransformerArg =
5828
        	GDALCreateGenImgProjTransformer(hSrcDS,
5829
					 GDALGetProjectionRef(hSrcDS), 
5830
					 hDstDS,
5831
					 GDALGetProjectionRef(hDstDS),
159 andreas 5832
					 FALSE, 0.0, 1);
158 andreas 5833
 
5834
	psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
5835
 
5836
	// Initialize and execute the warp operation.
5837
	GDALWarpOperation oOperation;
5838
 
5839
	if (oOperation.Initialize (psWarpOptions) != CE_None)
5840
	{
5841
	   KMessageBox::error(this, i18n("Error initializing warp operation!"));
5842
	   GDALClose (hDstDS);
5843
	   GDALClose (hSrcDS);
232 andreas 5844
	   unlink (fName->toAscii().data());
158 andreas 5845
	   return false;
5846
	}
5847
 
159 andreas 5848
	oOperation.ChunkAndWarpMulti (0, 0, geoRect.width, geoRect.height);
158 andreas 5849
	GDALDestroyGenImgProjTransformer (psWarpOptions->pTransformerArg);
5850
	GDALDestroyWarpOptions(psWarpOptions);
5851
 
5852
	GDALClose (hDstDS);
5853
	GDALClose (hSrcDS);
232 andreas 5854
	unlink (nfn.toAscii().data());
158 andreas 5855
	return true;
5856
}
5857
 
151 andreas 5858
#endif
5859
 
88 andreas 5860
#include "sportwatcherwidget.moc"
5861