Subversion Repositories public

Rev

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