Qt Virtual Chart Table (QVCT)
CChartGDAL.cpp
Go to the documentation of this file.
1 // INDENTING (emacs/vi): -*- mode:c++; tab-width:2; c-basic-offset:2; intent-tabs-mode:nil; -*- ex: set tabstop=2 expandtab:
2 
3 /*
4  * Qt Virtual Chart Table (QVCT)
5  * Copyright (C) 2012 Cedric Dufour <http://cedric.dufour.name>
6  * Author: Cedric Dufour <http://cedric.dufour.name>
7  *
8  * The Qt Virtual Chart Table (QVCT) is free software:
9  * you can redistribute it and/or modify it under the terms of the GNU General
10  * Public License as published by the Free Software Foundation, Version 3.
11  *
12  * The Qt Virtual Chart Table (QVCT) is distributed in the hope
13  * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
14  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * See the GNU General Public License for more details.
17  */
18 
19 // C/C++
20 #include <cmath>
21 #include <cstring>
22 
23 // QT
24 #include <QImage>
25 #include <QPainter>
26 #include <QPixmap>
27 #include <QPoint>
28 #include <QRect>
29 #include <QSize>
30 
31 // GDAL
32 #include <cpl_string.h>
33 #include <gdal.h>
34 #include <gdal_alg.h>
35 #include <gdal_priv.h>
36 #include <ogr_spatialref.h>
37 
38 // QVCT
39 #include "data/CDataPosition.hpp"
40 #include "charts/CChartGDAL.hpp"
41 
42 
43 //------------------------------------------------------------------------------
44 // CONSTRUCTORS / DESTRUCTOR
45 //------------------------------------------------------------------------------
46 
48  : eStatus( QVCT::UNDEFINED )
49  , poGDALDataset( NULL )
50  , pGDALProjectionTransformer( NULL )
51  , piGDALBandMap( NULL )
52 {}
53 
55 {
56  if( poGDALDataset ) GDALClose( poGDALDataset );
57  if( pGDALProjectionTransformer ) GDALDestroyGenImgProjTransformer( pGDALProjectionTransformer );
58  if( piGDALBandMap ) delete piGDALBandMap;
59 }
60 
61 void CChartGDAL::open( const QString& _rqsFileName )
62 {
64 
65  // Save file name
66  qsFileName = _rqsFileName;
67 
68  // Open chart as GDAL dataset
69  GDALAllRegister();
70  poGDALDataset = (GDALDataset*)GDALOpen( _rqsFileName.toLocal8Bit().constData(), GA_ReadOnly );
71  if( !poGDALDataset )
72  {
73  qCritical( "ERROR[%s]: Failed to open dataset (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
74  return;
75  }
76 
77  // Retrieve/save dataset geometry
78  qRectGeometry.setCoords( 0, 0, poGDALDataset->GetRasterXSize()-1, poGDALDataset->GetRasterYSize()-1 );
79 
80  // Create the GDAL projection transformer corresponding to the opened dataset
81  OGRSpatialReference __oOGRSpatialReference;
82  char* __pcProjectionDefinitionString;
83  if( __oOGRSpatialReference.importFromProj4( "+proj=longlat +ellps=WGS84 +datum=WGS84" ) != OGRERR_NONE
84  || __oOGRSpatialReference.exportToWkt( &__pcProjectionDefinitionString ) != OGRERR_NONE )
85  {
86  qCritical( "ERROR[%s]: Failed to initialize projection system", Q_FUNC_INFO );
87  return;
88  }
89  char **__ppcGDALProjectionOptions = CSLSetNameValue( NULL, "DST_SRS", __pcProjectionDefinitionString );
90  CPLFree( __pcProjectionDefinitionString );
91  pGDALProjectionTransformer = GDALCreateGenImgProjTransformer2( poGDALDataset, NULL, __ppcGDALProjectionOptions );
92  CSLDestroy( __ppcGDALProjectionOptions );
94  {
95  qCritical( "ERROR[%s]: Failed to create projection transformer for dataset (%s)\n[...]: Use 'gdalinfo' to check your dataset projection data", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
96  return;
97  }
98 
99  // Validate dataset central (geographical) position
100  double __fdX = (double)qRectGeometry.center().x(), __fdY = (double)qRectGeometry.center().y(), __fdZ = 0;
101  int __iSuccess = TRUE;
102  GDALGenImgProjTransform( pGDALProjectionTransformer, false, 1, &__fdX, &__fdY, &__fdZ, &__iSuccess );
103  if( __iSuccess != TRUE )
104  {
105  qCritical( "ERROR[%s]: Failed to perform dataset projection transformation (%s)\n[...]: Use 'gdalinfo' to check your dataset projection data", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
106  return;
107  }
108  if( __fdX < -180 || __fdX > 180 || __fdY < -90 || __fdY > 90 )
109  {
110  qCritical( "ERROR[%s]: Dataset projection transformation leads to invalid results (%s)\n[...]: Use 'gdalinfo' to check your dataset projection data", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
111  return;
112  }
113 
114  // Retrieve dataset color (encoding) type
115  bool __bHasGDALBandA = false, __bHasGDALBandR = false, __bHasGDALBandG = false, __bHasGDALBandB = false;
116  bool __bHasGDALBandY = false, __bHasGDALBandCb = false, __bHasGDALBandCr = false;
117  GDALRasterBand* __poGDALRasterBand = NULL;
118  GDALColorTable* __poGDALColorTable = NULL;
119  int __iGDALBandCount = poGDALDataset->GetRasterCount();
120  switch( __iGDALBandCount )
121  {
122 
123  case 0: // switch( __iGDALBandCount )
124  qCritical( "ERROR[%s]: Dataset has no raster band (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
125  return;
126 
127  case 1: // switch( __iGDALBandCount )
128  __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
129  if( !__poGDALRasterBand )
130  {
131  qCritical( "ERROR[%s]: Failed to retrieve raster band (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
132  return;
133  }
134  switch( __poGDALRasterBand->GetColorInterpretation() )
135  {
136 
137  case GCI_GrayIndex: // switch( __poGDALRasterBand->GetColorInterpretation() )
138  switch( __poGDALRasterBand->GetRasterDataType() )
139  {
140  case GDT_Byte: eColorEncoding = GRAY; break;
141  case GDT_UInt16: eColorEncoding = GRAY_U16; break;
142  case GDT_Int16: eColorEncoding = GRAY_S16; break;
143  case GDT_UInt32: eColorEncoding = GRAY_U32; break;
144  case GDT_Int32: eColorEncoding = GRAY_S32; break;
145  case GDT_Float32: eColorEncoding = GRAY_F32; break;
146  case GDT_Float64: eColorEncoding = GRAY_F64; break;
147  default:
148  qCritical( "ERROR[%s]: Unsupported data type (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
149  return;
150  }
151  break;
152 
153  case GCI_PaletteIndex: // switch( __poGDALRasterBand->GetColorInterpretation() )
154  __poGDALColorTable = __poGDALRasterBand->GetColorTable();
155  if( !__poGDALColorTable )
156  {
157  qCritical( "ERROR[%s]: Failed to retrieve color table (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
158  return;
159  }
160  switch( __poGDALColorTable->GetPaletteInterpretation() )
161  {
162  case GPI_Gray: eColorEncoding = PALETTE_GRAY; break;
163  case GPI_RGB: eColorEncoding = PALETTE_RGB; break;
164  case GPI_CMYK: eColorEncoding = PALETTE_CMYK; break;
165  case GPI_HLS: eColorEncoding = PALETTE_HSL; break;
166  default:
167  qCritical( "ERROR[%s]: Unsupported palette interpretation for single-band dataset (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
168  return;
169  }
170  break;
171 
172  default: // switch( __poGDALRasterBand->GetColorInterpretation() )
173  qCritical( "ERROR[%s]: Unsupported color interpretation for single-band dataset (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
174  return;
175 
176  } // switch( __poGDALRasterBand->GetColorInterpretation() )
177  break;
178 
179  default: // switch( __iGDALBandCount )
180  for( int __iGDALBandIndex = 1; __iGDALBandIndex <= __iGDALBandCount; __iGDALBandIndex++ )
181  {
182  __poGDALRasterBand = poGDALDataset->GetRasterBand( __iGDALBandIndex );
183  if( !__poGDALRasterBand )
184  {
185  qCritical( "ERROR[%s]: Failed to retrieve raster band (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
186  return;
187  }
188  switch( __poGDALRasterBand->GetColorInterpretation() )
189  {
190  case GCI_AlphaBand: __bHasGDALBandA = true; break;
191  case GCI_RedBand: __bHasGDALBandR = true; break;
192  case GCI_GreenBand: __bHasGDALBandG = true; break;
193  case GCI_BlueBand: __bHasGDALBandB = true; break;
194  case GCI_YCbCr_YBand: __bHasGDALBandY = true; break;
195  case GCI_YCbCr_CbBand: __bHasGDALBandCb = true; break;
196  case GCI_YCbCr_CrBand: __bHasGDALBandCr = true; break;
197  default:; // other bands are not used
198  }
199  }
200  if( __bHasGDALBandR && __bHasGDALBandG && __bHasGDALBandB )
201  {
202  eColorEncoding = __bHasGDALBandA ? ARGB : RGB;
203  }
204  else if( __bHasGDALBandY && __bHasGDALBandCb && __bHasGDALBandCr )
205  {
206  // NOTE: we should never get here since GDAL converts YCbCr color space to RGB intrinsecally
208  qCritical( "ERROR[%s]: YCbCr color interpretation not implemented (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
209  return;
210  }
211  else
212  {
213  qCritical( "ERROR[%s]: Unsupported color interpretations for multi-band dataset (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
214  return;
215  }
216 
217  } // switch( __iGDALBandCount )
218 
219  // Initialize color resources
220  const GDALColorEntry* __poGDALColorEntry;
221  qColorTable.clear();
222  piGDALBandMap = new int[4];
223  for( int i=0; i<4; i++ ) piGDALBandMap[i] = -1;
224  switch( eColorEncoding )
225  {
226 
227  case GRAY: // switch( eColorEncoding )
228  case GRAY_U16:
229  case GRAY_S16:
230  case GRAY_U32:
231  case GRAY_S32:
232  case GRAY_F32:
233  case GRAY_F64:
234  for( int __iColorComponent = 0; __iColorComponent < 256; __iColorComponent++ )
235  {
236  qColorTable.append( qRgba( __iColorComponent, __iColorComponent, __iColorComponent, 255 ) );
237  }
238  break;
239 
240  case PALETTE_GRAY: // switch( eColorEncoding )
241  for( int __iPaletteIndex = 0; __iPaletteIndex < __poGDALColorTable->GetColorEntryCount(); __iPaletteIndex++ )
242  {
243  __poGDALColorEntry = __poGDALColorTable->GetColorEntry( __iPaletteIndex );
244  if( !__poGDALColorEntry )
245  {
246  qCritical( "ERROR[%s]: Failed to retrieve color table entry (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
247  return;
248  }
249  qColorTable.append( qRgb( __poGDALColorEntry->c1, __poGDALColorEntry->c1, __poGDALColorEntry->c1 ) );
250  }
251  break;
252 
253  case PALETTE_RGB: // switch( eColorEncoding )
254  for( int __iPaletteIndex = 0; __iPaletteIndex < __poGDALColorTable->GetColorEntryCount(); __iPaletteIndex++ )
255  {
256  __poGDALColorEntry = __poGDALColorTable->GetColorEntry( __iPaletteIndex );
257  if( !__poGDALColorEntry )
258  {
259  qCritical( "ERROR[%s]: Failed to retrieve color table entry (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
260  return;
261  }
262  qColorTable.append( qRgba( __poGDALColorEntry->c1, __poGDALColorEntry->c2, __poGDALColorEntry->c3, __poGDALColorEntry->c4 ) );
263  }
264  break;
265 
266  case PALETTE_CMYK: // switch( eColorEncoding )
267  for( int __iPaletteIndex = 0; __iPaletteIndex < __poGDALColorTable->GetColorEntryCount(); __iPaletteIndex++ )
268  {
269  __poGDALColorEntry = __poGDALColorTable->GetColorEntry( __iPaletteIndex );
270  if( !__poGDALColorEntry )
271  {
272  qCritical( "ERROR[%s]: Failed to retrieve color table entry (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
273  return;
274  }
275  qColorTable.append( QColor::fromCmyk( __poGDALColorEntry->c1, __poGDALColorEntry->c2, __poGDALColorEntry->c3, __poGDALColorEntry->c4 ).rgb() );
276  }
277  break;
278 
279  case PALETTE_HSL: // switch( eColorEncoding )
280  for( int __iPaletteIndex = 0; __iPaletteIndex < __poGDALColorTable->GetColorEntryCount(); __iPaletteIndex++ )
281  {
282  __poGDALColorEntry = __poGDALColorTable->GetColorEntry( __iPaletteIndex );
283  if( !__poGDALColorEntry )
284  {
285  qCritical( "ERROR[%s]: Failed to retrieve color table entry (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
286  return;
287  }
288  qColorTable.append( QColor::fromHsl( __poGDALColorEntry->c1, __poGDALColorEntry->c3, __poGDALColorEntry->c2 ).rgb() ); // WARNING: GDAL uses HLS colortable; QT uses HSL (S and L are swapped)
289  }
290  break;
291 
292  case ARGB: // switch( eColorEncoding )
293  {
294  QRgb __qRgbPixel = qRgba( GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand );
295  for( int __iGDALBandIndex = 1; __iGDALBandIndex <= __iGDALBandCount; __iGDALBandIndex++ )
296  {
297  GDALColorInterp __eGDALColorInterp = poGDALDataset->GetRasterBand( __iGDALBandIndex )->GetColorInterpretation();
298  switch( __eGDALColorInterp )
299  {
300  case GCI_AlphaBand:
301  case GCI_RedBand:
302  case GCI_GreenBand:
303  case GCI_BlueBand:
304  for( int __iGDALBandOffset = 0; __iGDALBandOffset < 4 ; __iGDALBandOffset++ )
305  if( __eGDALColorInterp == *(((quint8 *)&__qRgbPixel)+__iGDALBandOffset) )
306  piGDALBandMap[ __iGDALBandOffset ] = __iGDALBandIndex;
307  break;
308  default:; // other bands are not used
309  }
310  }
311  }
312  break;
313 
314  case RGB: // switch( eColorEncoding )
315  {
316  QRgb __qRgbPixel = qRgba( GCI_RedBand, GCI_GreenBand, GCI_BlueBand, GCI_AlphaBand );
317  for( int __iGDALBandIndex = 1; __iGDALBandIndex <= __iGDALBandCount; __iGDALBandIndex++ )
318  {
319  GDALColorInterp __eGDALColorInterp = poGDALDataset->GetRasterBand( __iGDALBandIndex )->GetColorInterpretation();
320  switch( __eGDALColorInterp )
321  {
322  case GCI_RedBand:
323  case GCI_GreenBand:
324  case GCI_BlueBand:
325  for( int __iGDALBandOffset = 0; __iGDALBandOffset < 4 ; __iGDALBandOffset++ )
326  if( __eGDALColorInterp == *(((quint8 *)&__qRgbPixel)+__iGDALBandOffset) )
327  piGDALBandMap[ __iGDALBandOffset ] = __iGDALBandIndex;
328  break;
329  default:; // other bands are not used
330  }
331  }
332  }
333  break;
334 
335  case YUV: // switch( eColorEncoding )
336  // NOTE: we should never get here since GDAL converts YCbCr color space to RGB intrinsecally
337  qCritical( "ERROR[%s]: YCbCr color interpretation not implemented (%s)", Q_FUNC_INFO, qPrintable( _rqsFileName ) );
338  break;
339 
340  default:; // other color types do not require a color table or band mapping
341 
342  } // switch( eColorEncoding )
343 
344  eStatus = QVCT::OK;
345 }
346 
347 
348 //------------------------------------------------------------------------------
349 // METHODS
350 //------------------------------------------------------------------------------
351 
352 //
353 // OTHER
354 //
355 
356 CDataPosition CChartGDAL::toGeoPosition( const QPointF& _rqPointFDatPosition ) const
357 {
358  CDataPosition __oGeoPosition;
359  if( eStatus != QVCT::OK ) return __oGeoPosition;
360  double __fdX = (double)_rqPointFDatPosition.x(), __fdY = (double)_rqPointFDatPosition.y(), __fdZ = 0;
361  int __iSuccess = TRUE;
362  GDALGenImgProjTransform( pGDALProjectionTransformer, false, 1, &__fdX, &__fdY, &__fdZ, &__iSuccess );
363  if( __iSuccess != TRUE ) return __oGeoPosition;
364  __oGeoPosition.setPosition( __fdX, __fdY, CDataPosition::UNDEFINED_ELEVATION );
365  return __oGeoPosition;
366 }
367 
368 QPointF CChartGDAL::toDatPosition( const CDataPosition& _roGeoPosition ) const
369 {
370  QPointF __qPointFDatPosition;
371  if( eStatus != QVCT::OK ) return __qPointFDatPosition;
372  if( _roGeoPosition == CDataPosition::UNDEFINED ) return __qPointFDatPosition;
373  double __fdX = (double)_roGeoPosition.getLongitude(), __fdY = (double)_roGeoPosition.getLatitude(), __fdZ = _roGeoPosition.getElevation();
374  if( __fdZ == CDataPosition::UNDEFINED_ELEVATION ) __fdZ = 0;
375  int __iSuccess = TRUE;
376  GDALGenImgProjTransform( pGDALProjectionTransformer, true, 1, &__fdX, &__fdY, &__fdZ, &__iSuccess );
377  if( __iSuccess != TRUE ) return __qPointFDatPosition;
378  __qPointFDatPosition.setX( __fdX );
379  __qPointFDatPosition.setY( __fdY );
380  return __qPointFDatPosition;
381 }
382 
383 double CChartGDAL::getResolution( const QPointF& _rqPointFDatPosition ) const
384 {
385  QPointF __qPointFDatPositionNorth( _rqPointFDatPosition.x(), _rqPointFDatPosition.y() - 50.0 );
386  QPointF __qPointFDatPositionSouth( _rqPointFDatPosition.x(), _rqPointFDatPosition.y() + 50.0 );
387  CDataPosition __oGeoPositionNorth = toGeoPosition( __qPointFDatPositionNorth );
388  CDataPosition __oGeoPositionSouth = toGeoPosition( __qPointFDatPositionSouth );
389  return( ( __oGeoPositionNorth.getLatitude() - __oGeoPositionSouth.getLatitude() ) * 1111.2 ); // delta(Latitude) * 60nm * 1852m/nm / 100px [m/px]
390 }
391 
392 void CChartGDAL::draw( QPainter* _pqPainter, const QPointF& _rqPointFDatPosition, double _fdZoom )
393 {
394  // Compute dataset region to rasterize
395  // ... fix silly zoom factor
396  if( _fdZoom <= 0 ) _fdZoom = 1;
397  // ... "wished" pixmap area based on the painter's device size
398  QSize __qSizePixmapWished( _pqPainter->device()->width(), _pqPainter->device()->height() );
399 
400  // Redraw pixmap only if required
401  if( qPixmapBuffer.size() != __qSizePixmapWished || qPointFDatPositionWished != _rqPointFDatPosition || fdZoomWished != _fdZoom )
402  {
403  //qDebug( "DEBUG[%s] Rendering", Q_FUNC_INFO );
404 
405  // Reset pixmap buffer
406  if( qPixmapBuffer.size() != __qSizePixmapWished ) qPixmapBuffer = QPixmap( __qSizePixmapWished );
407  qPixmapBuffer.fill( Qt::black );
408  qPointFDatPositionWished = _rqPointFDatPosition;
409  fdZoomWished = _fdZoom;
410  //qDebug( "DEBUG[%s] qPointFDatPositionWished: %f, %f", Q_FUNC_INFO, qPointFDatPositionWished.x(), qPointFDatPositionWished.y() );
411  //qDebug( "DEBUG[%s] fdZoomWidhed: %f", Q_FUNC_INFO, fdZoomWished );
412 
413  // Compute dataset region to rasterize (cont'd)
414  // ... "wished" dataset area based on center position and zoom factor
415  QSize __qSizeGDALWished( (double)__qSizePixmapWished.width() / _fdZoom + 0.5, (double)__qSizePixmapWished.height() / _fdZoom + 0.5 );
416  //qDebug( "DEBUG[%s] __qSizeGDALWished: %d, %d", Q_FUNC_INFO, __qSizeGDALWished.width(), __qSizeGDALWished.height() );
417  QPoint __qPointDatPositionGDALWished( qPointFDatPositionWished.x() - (double)__qSizeGDALWished.width()/2.0 + 0.5, qPointFDatPositionWished.y() - (double)__qSizeGDALWished.height()/2.0 + 0.5 );
418  //qDebug( "DEBUG[%s] __qPointDatPositionGDALWished: %d, %d", Q_FUNC_INFO, __qPointDatPositionGDALWished.x(), __qPointDatPositionGDALWished.y() );
419  // ... "actual" dataset area by intersecting with the dataset "existing" area
420  QRect __qRectGDALActual( __qPointDatPositionGDALWished.x(), __qPointDatPositionGDALWished.y(), __qSizeGDALWished.width(), __qSizeGDALWished.height() );
421  __qRectGDALActual = __qRectGDALActual.intersected( qRectGeometry );
422  // ... "actual" pixmap area (mirroring the correction made on the dataset area)
423  QSize __qSizePixmapActual( (double)__qRectGDALActual.width() * _fdZoom + 0.5, (double)__qRectGDALActual.height() * _fdZoom + 0.5 );
424  //qDebug( "DEBUG[%s] __qSizePixmapActual: %d, %d", Q_FUNC_INFO, __qSizePixmapActual.width(), __qSizePixmapActual.height() );
425  // ... "actual" pixmap position
426  QPoint __qPointPixmapActual( (double)( __qRectGDALActual.topLeft().x() - __qPointDatPositionGDALWished.x() ) * _fdZoom + 0.5, (double)( __qRectGDALActual.topLeft().y() - __qPointDatPositionGDALWished.y() ) * _fdZoom + 0.5 );
427  //qDebug( "DEBUG[%s] __qPointPixmapActual: %d, %d", Q_FUNC_INFO, __qPointPixmapActual.x(), __qPointPixmapActual.y() );
428  // ... "actual" dataset position
429  //qPointFDatPositionActual.setX( ( (double)__qPointPixmapActual.x() * _fdZoom ) + (double)__qRectGDALActual.topLeft().x() + ( (double)__qSizePixmapWished.width() / _fdZoom )/2.0 );
430  //qPointFDatPositionActual.setY( ( (double)__qPointPixmapActual.y() * _fdZoom ) + (double)__qRectGDALActual.topLeft().y() + ( (double)__qSizePixmapWished.height() / _fdZoom )/2.0 );
431  qPointFDatPositionActual.setX( (double)__qRectGDALActual.topLeft().x() + ( (double)__qSizePixmapWished.width() / _fdZoom )/2.0 - ( (double)__qPointPixmapActual.x() / _fdZoom ) );
432  qPointFDatPositionActual.setY( (double)__qRectGDALActual.topLeft().y() + ( (double)__qSizePixmapWished.height() / _fdZoom )/2.0 - ( (double)__qPointPixmapActual.y() / _fdZoom ) );
433  //qDebug( "DEBUG[%s] qPointFDatPositionActual: %f, %f", Q_FUNC_INFO, qPointFDatPositionActual.x(), qPointFDatPositionActual.y() );
434  // ... "actual" dataset zoom
435  fdZoomActual = _fdZoom;
436  //qDebug( "DEBUG[%s] fdZoomActual: %f", Q_FUNC_INFO, fdZoomActual );
437  // ... "actual" image size (corrected to match the QImage-required mod-4 pixel width)
438  QSize __qSizeImageActual( ( __qSizePixmapActual.width() + 3 ) & 0xFFFFFFFC, __qSizePixmapActual.height() );
439  //qDebug( "DEBUG[%s] __qSizeImageActual: %d, %d", Q_FUNC_INFO, __qSizeImageActual.width(), __qSizeImageActual.height() );
440 
441  // GDAL::RasterIO
442  if( __qSizePixmapActual.isValid() )
443  {
444  QPainter __qPainter( &qPixmapBuffer );
445  switch( eColorEncoding )
446  {
447 
448  case GRAY_U16: // switch( eColorEncoding )
449  {
450  QImage __qImage( __qSizeImageActual, QImage::Format_Indexed8 );
451  __qImage.setColorTable( qColorTable );
452  // Rasterize to through data-type buffer
453  QVector<quint16> __qVector( __qImage.width()*__qImage.height() );
454  GDALRasterBand* __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
455  CPLErr tCPLErr = __poGDALRasterBand->RasterIO( GF_Read,
456  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
457  __qRectGDALActual.width(), __qRectGDALActual.height(),
458  __qVector.data(),
459  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
460  GDT_UInt16,
461  sizeof(quint16), sizeof(quint16)*__qImage.width() );
462  if( tCPLErr != CE_None )
463  {
464  qCritical( "ERROR[%s]: Failed to rasterize typed dataset", Q_FUNC_INFO );
465  return;
466  }
467  rasterBuffer( &__qImage, __qVector );
468  // Draw image
469  __qPainter.drawImage( __qPointPixmapActual, __qImage );
470  }
471  break;
472 
473  case GRAY_S16: // switch( eColorEncoding )
474  {
475  QImage __qImage( __qSizeImageActual, QImage::Format_Indexed8 );
476  __qImage.setColorTable( qColorTable );
477  // Rasterize to through data-type buffer
478  QVector<qint16> __qVector( __qImage.width()*__qImage.height() );
479  GDALRasterBand* __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
480  CPLErr tCPLErr = __poGDALRasterBand->RasterIO( GF_Read,
481  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
482  __qRectGDALActual.width(), __qRectGDALActual.height(),
483  __qVector.data(),
484  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
485  GDT_Int16,
486  sizeof(qint16), sizeof(qint16)*__qImage.width() );
487  if( tCPLErr != CE_None )
488  {
489  qCritical( "ERROR[%s]: Failed to rasterize typed dataset", Q_FUNC_INFO );
490  return;
491  }
492  rasterBuffer( &__qImage, __qVector );
493  // Draw image
494  __qPainter.drawImage( __qPointPixmapActual, __qImage );
495  }
496  break;
497 
498  case GRAY_U32: // switch( eColorEncoding )
499  {
500  QImage __qImage( __qSizeImageActual, QImage::Format_Indexed8 );
501  __qImage.setColorTable( qColorTable );
502  // Rasterize to through data-type buffer
503  QVector<quint32> __qVector( __qImage.width()*__qImage.height() );
504  GDALRasterBand* __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
505  CPLErr tCPLErr = __poGDALRasterBand->RasterIO( GF_Read,
506  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
507  __qRectGDALActual.width(), __qRectGDALActual.height(),
508  __qVector.data(),
509  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
510  GDT_UInt32,
511  sizeof(quint32), sizeof(quint32)*__qImage.width() );
512  if( tCPLErr != CE_None )
513  {
514  qCritical( "ERROR[%s]: Failed to rasterize typed dataset", Q_FUNC_INFO );
515  return;
516  }
517  rasterBuffer( &__qImage, __qVector );
518  // Draw image
519  __qPainter.drawImage( __qPointPixmapActual, __qImage );
520  }
521  break;
522 
523  case GRAY_S32: // switch( eColorEncoding )
524  {
525  QImage __qImage( __qSizeImageActual, QImage::Format_Indexed8 );
526  __qImage.setColorTable( qColorTable );
527  // Rasterize to through data-type buffer
528  QVector<qint32> __qVector( __qImage.width()*__qImage.height() );
529  GDALRasterBand* __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
530  CPLErr tCPLErr = __poGDALRasterBand->RasterIO( GF_Read,
531  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
532  __qRectGDALActual.width(), __qRectGDALActual.height(),
533  __qVector.data(),
534  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
535  GDT_Int32,
536  sizeof(qint32), sizeof(qint32)*__qImage.width() );
537  if( tCPLErr != CE_None )
538  {
539  qCritical( "ERROR[%s]: Failed to rasterize typed dataset", Q_FUNC_INFO );
540  return;
541  }
542  rasterBuffer( &__qImage, __qVector );
543  // Draw image
544  __qPainter.drawImage( __qPointPixmapActual, __qImage );
545  }
546  break;
547 
548  case GRAY_F32: // switch( eColorEncoding )
549  {
550  QImage __qImage( __qSizeImageActual, QImage::Format_Indexed8 );
551  __qImage.setColorTable( qColorTable );
552  // Rasterize to through data-type buffer
553  QVector<float> __qVector( __qImage.width()*__qImage.height() );
554  GDALRasterBand* __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
555  CPLErr tCPLErr = __poGDALRasterBand->RasterIO( GF_Read,
556  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
557  __qRectGDALActual.width(), __qRectGDALActual.height(),
558  __qVector.data(),
559  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
560  GDT_Float32,
561  sizeof(float), sizeof(float)*__qImage.width() );
562  if( tCPLErr != CE_None )
563  {
564  qCritical( "ERROR[%s]: Failed to rasterize typed dataset", Q_FUNC_INFO );
565  return;
566  }
567  rasterBuffer( &__qImage, __qVector );
568  // Draw image
569  __qPainter.drawImage( __qPointPixmapActual, __qImage );
570  }
571  break;
572 
573  case GRAY_F64: // switch( eColorEncoding )
574  {
575  QImage __qImage( __qSizeImageActual, QImage::Format_Indexed8 );
576  __qImage.setColorTable( qColorTable );
577  // Rasterize to through data-type buffer
578  QVector<double> __qVector( __qImage.width()*__qImage.height() );
579  GDALRasterBand* __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
580  CPLErr tCPLErr = __poGDALRasterBand->RasterIO( GF_Read,
581  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
582  __qRectGDALActual.width(), __qRectGDALActual.height(),
583  __qVector.data(),
584  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
585  GDT_Float64,
586  sizeof(double), sizeof(double)*__qImage.width() );
587  if( tCPLErr != CE_None )
588  {
589  qCritical( "ERROR[%s]: Failed to rasterize typed dataset", Q_FUNC_INFO );
590  return;
591  }
592  rasterBuffer( &__qImage, __qVector );
593  // Draw image
594  __qPainter.drawImage( __qPointPixmapActual, __qImage );
595  }
596  break;
597 
598  case GRAY: // switch( eColorEncoding )
599  case PALETTE_GRAY:
600  case PALETTE_RGB:
601  case PALETTE_CMYK:
602  case PALETTE_HSL:
603  {
604  QImage __qImage( __qSizeImageActual, QImage::Format_Indexed8 );
605  __qImage.setColorTable( qColorTable );
606  // Rasterize directly to QImage bitmap
607  GDALRasterBand* __poGDALRasterBand = poGDALDataset->GetRasterBand( 1 );
608  CPLErr tCPLErr = __poGDALRasterBand->RasterIO( GF_Read,
609  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
610  __qRectGDALActual.width(), __qRectGDALActual.height(),
611  __qImage.bits(),
612  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
613  GDT_Byte,
614  1, __qImage.width() );
615  if( tCPLErr != CE_None )
616  {
617  qCritical( "ERROR[%s]: Failed to rasterize palette dataset", Q_FUNC_INFO );
618  return;
619  }
620  // Draw image
621  __qPainter.drawImage( __qPointPixmapActual, __qImage );
622  }
623  break;
624 
625  case ARGB: // switch( eColorEncoding )
626  {
627  QImage __qImage( __qSizeImageActual, QImage::Format_ARGB32 );
628  // Rasterize directly to QImage bitmap
629  CPLErr tCPLErr = poGDALDataset->RasterIO( GF_Read,
630  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
631  __qRectGDALActual.width(), __qRectGDALActual.height(),
632  __qImage.bits(),
633  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
634  GDT_Byte,
635  4, piGDALBandMap, 4, 4*__qImage.width(), 1 );
636  if( tCPLErr != CE_None )
637  {
638  qCritical( "ERROR[%s]: Failed to rasterize ARGB dataset", Q_FUNC_INFO );
639  return;
640  }
641  // Draw image
642  __qPainter.drawImage( __qPointPixmapActual, __qImage );
643  }
644  break;
645 
646  case RGB: // switch( eColorEncoding )
647  {
648  QImage __qImage( __qSizeImageActual, QImage::Format_RGB32 );
649  // Rasterize directly to QImage bitmap
650  CPLErr tCPLErr = poGDALDataset->RasterIO( GF_Read,
651  __qRectGDALActual.topLeft().x(), __qRectGDALActual.topLeft().y(),
652  __qRectGDALActual.width(), __qRectGDALActual.height(),
653  __qImage.bits()+( piGDALBandMap[0]<0 ? 1 : 0 ),
654  __qSizePixmapActual.width(), __qSizePixmapActual.height(),
655  GDT_Byte,
656  3, piGDALBandMap, 4, 4*__qImage.width(), 1 );
657  if( tCPLErr != CE_None )
658  {
659  qCritical( "ERROR[%s]: Failed to rasterize ARGB dataset", Q_FUNC_INFO );
660  return;
661  }
662  // Draw image
663  __qPainter.drawImage( __qPointPixmapActual, __qImage );
664  }
665  break;
666 
667  case YUV: // switch( eColorEncoding )
668  // NOTE: we should never get here since GDAL converts YCbCr color space to RGB intrinsecally
669  qCritical( "ERROR[%s]: YCbCr color interpretation not implemented", Q_FUNC_INFO );
670  return;
671  break;
672 
673  } // switch( eColorEncoding )
674 
675  } // if( __qSizePixmapActual.isValid() )
676 
677  } // if( qPixmapBuffer.size() != __qSizePixmapWished || qPointFDatPositionPixmap != _rqPointFDatPosition || fdZoomPixmap != _fdZoom )
678 
679  _pqPainter->drawPixmap( 0, 0, qPixmapBuffer );
680 
681 }
682 
683 void CChartGDAL::move( const QPointF& _rqPointFDatPosition, double _fdZoom )
684 {
685  qPixmapBuffer = QPixmap(); // re-rendering shall be required
686  qPointFDatPositionActual = _rqPointFDatPosition;
687  fdZoomActual = _fdZoom;
688 }
689 
690 void CChartGDAL::rasterBuffer( QImage* _pqImage, const QVector<quint16>& _rqVector ) const
691 {
692  uchar* __pqImageBit = _pqImage->bits();
693  const quint16* __pqVectorBit = _rqVector.data();
694  for( int x=_pqImage->width()-1; x>=0; x-- )
695  for( int y=_pqImage->height()-1; y>=0; y-- )
696  *__pqImageBit++ = *__pqVectorBit++ >> 8;
697 }
698 
699 void CChartGDAL::rasterBuffer( QImage* _pqImage, const QVector<qint16>& _rqVector ) const
700 {
701  uchar* __pqImageBit = _pqImage->bits();
702  const qint16* __pqVectorBit = _rqVector.data();
703  for( int x=_pqImage->width()-1; x>=0; x-- )
704  for( int y=_pqImage->height()-1; y>=0; y-- )
705  *__pqImageBit++ = ( *__pqVectorBit++ >> 8 ) + 127;
706 }
707 
708 void CChartGDAL::rasterBuffer( QImage* _pqImage, const QVector<quint32>& _rqVector ) const
709 {
710  uchar* __pqImageBit = _pqImage->bits();
711  const quint32* __pqVectorBit = _rqVector.data();
712  for( int x=_pqImage->width()-1; x>=0; x-- )
713  for( int y=_pqImage->height()-1; y>=0; y-- )
714  *__pqImageBit++ = *__pqVectorBit++ >> 24;
715 }
716 
717 void CChartGDAL::rasterBuffer( QImage* _pqImage, const QVector<qint32>& _rqVector ) const
718 {
719  uchar* __pqImageBit = _pqImage->bits();
720  const qint32* __pqVectorBit = _rqVector.data();
721  for( int x=_pqImage->width()-1; x>=0; x-- )
722  for( int y=_pqImage->height()-1; y>=0; y-- )
723  *__pqImageBit++ = ( *__pqVectorBit++ >> 24 ) + 127;
724 }
725 
726 void CChartGDAL::rasterBuffer( QImage* _pqImage, const QVector<float>& _rqVector ) const
727 {
728  uchar* __pqImageBit = _pqImage->bits();
729  const float* __pqVectorBit = _rqVector.data();
730  for( int x=_pqImage->width()-1; x>=0; x-- )
731  for( int y=_pqImage->height()-1; y>=0; y-- )
732  *__pqImageBit++ = *__pqVectorBit++;
733 }
734 
735 void CChartGDAL::rasterBuffer( QImage* _pqImage, const QVector<double>& _rqVector ) const
736 {
737  uchar* __pqImageBit = _pqImage->bits();
738  const double* __pqVectorBit = _rqVector.data();
739  for( int x=_pqImage->width()-1; x>=0; x-- )
740  for( int y=_pqImage->height()-1; y>=0; y-- )
741  *__pqImageBit++ = *__pqVectorBit++;
742 }
virtual void rasterBuffer(QImage *_pqImage, const QVector< quint16 > &_rqVector) const
Rasterizes UInt16 buffer.
Definition: CChartGDAL.cpp:690
QString qsFileName
Chart (GDAL dataset) file name.
Definition: CChartGDAL.hpp:77
void open(const QString &_rqsFileName)
Opens the underlying GDAL dataset.
Definition: CChartGDAL.cpp:61
void draw(QPainter *_pqPainter, const QPointF &_rqPointFDatPosition, double _fdZoom)
Draws chart, centered on given chart (GDAL dataset) point [px] and zoomed according to given factor.
Definition: CChartGDAL.cpp:392
CDataPosition toGeoPosition(const QPointF &_rqPointFDatPosition) const
Converts the given chart pixel position to geographical position.
Definition: CChartGDAL.cpp:356
void move(const QPointF &_rqPointFDatPosition, double _fdZoom)
Moves the chart, centered on given chart (GDAL dataset) point [px] and zoomed according to given fact...
Definition: CChartGDAL.cpp:683
void * pGDALProjectionTransformer
Underlying GDAL dataset projection transformer (to internal WGS84)
Definition: CChartGDAL.hpp:98
int * piGDALBandMap
Underlying GDAL dataset band mapping (for ARGB/RGB/YUV color encodings)
Definition: CChartGDAL.hpp:100
double getResolution(const QPointF &_rqPointFDatPosition) const
Returns the resolution at given chart (GDAL dataset) point [px], in meters per pixel [m/px].
Definition: CChartGDAL.cpp:383
QPointF qPointFDatPositionActual
Last drawn chart (GDAL dataset) center pixel position (actually rendered)
Definition: CChartGDAL.hpp:85
double fdZoomActual
Last drawn chart (GDAL dataset) zoom factor (actually rendered)
Definition: CChartGDAL.hpp:89
QRect qRectGeometry
Chart (GDAL dataset) geometry (size)
Definition: CChartGDAL.hpp:79
EColorEncoding eColorEncoding
Chart (GDAL dataset) color encoding.
Definition: CChartGDAL.hpp:81
QPixmap qPixmapBuffer
Pixmap buffer where the chart (GDAL dataset) is rendered (rasterized)
Definition: CChartGDAL.hpp:107
QPointF toDatPosition(const CDataPosition &_roGeoPosition) const
Converts the given (geographical) position [long,lat,elev] to chart (GDAL dataset) point [px].
Definition: CChartGDAL.cpp:368
double fdZoomWished
Last drawn chart (GDAL dataset) zoom factor (requested by user)
Definition: CChartGDAL.hpp:87
virtual ~CChartGDAL()
Definition: CChartGDAL.cpp:54
QVCT::EStatus eStatus
Chart internal status.
Definition: CChartGDAL.hpp:75
GDALDataset * poGDALDataset
Underlying GDAL dataset.
Definition: CChartGDAL.hpp:96
QVector< QRgb > qColorTable
Color table (for GRAY/PALETTE_* color encodings)
Definition: CChartGDAL.hpp:109
QPointF qPointFDatPositionWished
Last drawn chart (GDAL dataset) center pixel position (requested by user)
Definition: CChartGDAL.hpp:83
(Geographical) Position data [long,lat,elev]
double getLongitude() const
Returns this position's longitude, in degrees.
double getElevation() const
Returns this position's elevation, in meters.
double getLatitude() const
Returns this position's latitude, in degrees.
static const CDataPosition UNDEFINED
Specific value for an undefined position.
void setPosition(double _fdLongitude, double _fdLatitude, double _fdElevation=UNDEFINED_ELEVATION)
Sets new coordinates.
static constexpr double UNDEFINED_ELEVATION
Specific value for an undefined elevation.
Global/base application container.
Definition: QVCT.hpp:34
@ ERROR
Definition: QVCT.hpp:41
@ OK
Definition: QVCT.hpp:41