source: ntrip/trunk/BNC/qwtpolar/qwt_polar_renderer.cpp@ 9763

Last change on this file since 9763 was 8127, checked in by stoecker, 7 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 11.4 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2 * QwtPolar Widget Library
3 * Copyright (C) 2008 Uwe Rathmann
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the Qwt License, Version 1.0
7 *****************************************************************************/
8
9#include "qwt_polar_renderer.h"
10#include "qwt_polar_plot.h"
11#include "qwt_polar_layout.h"
12#include <qwt_legend.h>
13#include <qwt_dyngrid_layout.h>
14#include <qwt_text_label.h>
15#include <qwt_text.h>
16#include <qpainter.h>
17#include <qprinter.h>
18#include <qprintdialog.h>
19#include <qfiledialog.h>
20#include <qimagewriter.h>
21#include <qfileinfo.h>
22#include <qmath.h>
23#ifndef QWT_NO_POLAR_POLAR_SVG
24#ifdef QT_SVG_LIB
25#include <qsvggenerator.h>
26#endif
27#endif
28
29
30static inline double qwtDistance(
31 const QPointF &p1, const QPointF &p2 )
32{
33 double dx = p2.x() - p1.x();
34 double dy = p2.y() - p1.y();
35 return qSqrt( dx * dx + dy * dy );
36}
37
38class QwtPolarRenderer::PrivateData
39{
40public:
41 PrivateData():
42 plot( NULL )
43 {
44 }
45
46 QwtPolarPlot *plot;
47};
48
49/*!
50 Constructor
51 \param parent Parent object
52 */
53QwtPolarRenderer::QwtPolarRenderer( QObject *parent ):
54 QObject( parent )
55{
56 d_data = new PrivateData;
57}
58
59//! Destructor
60QwtPolarRenderer::~QwtPolarRenderer()
61{
62 delete d_data;
63}
64
65/*!
66 Render a polar plot to a file
67
68 The format of the document will be autodetected from the
69 suffix of the filename.
70
71 \param plot Plot widget
72 \param fileName Path of the file, where the document will be stored
73 \param sizeMM Size for the document in millimeters.
74 \param resolution Resolution in dots per Inch (dpi)
75*/
76void QwtPolarRenderer::renderDocument( QwtPolarPlot *plot,
77 const QString &fileName, const QSizeF &sizeMM, int resolution )
78{
79 renderDocument( plot, fileName,
80 QFileInfo( fileName ).suffix(), sizeMM, resolution );
81}
82
83/*!
84 Render a plot to a file
85
86 Supported formats are:
87
88 - pdf\n
89 - ps\n
90 - svg\n
91 - all image formats supported by Qt, see QImageWriter::supportedImageFormats()
92
93 \param plot Plot widget
94 \param fileName Path of the file, where the document will be stored
95 \param format Format for the document
96 \param sizeMM Size for the document in millimeters.
97 \param resolution Resolution in dots per Inch (dpi)
98
99 \sa renderTo(), render(), QwtPainter::setRoundingAlignment()
100*/
101void QwtPolarRenderer::renderDocument( QwtPolarPlot *plot,
102 const QString &fileName, const QString &format,
103 const QSizeF &sizeMM, int resolution )
104{
105 if ( plot == NULL || sizeMM.isEmpty() || resolution <= 0 )
106 return;
107
108 QString title = plot->title().text();
109 if ( title.isEmpty() )
110 title = "Plot Document";
111
112 const double mmToInch = 1.0 / 25.4;
113 const QSizeF size = sizeMM * mmToInch * resolution;
114
115 const QRectF documentRect( 0.0, 0.0, size.width(), size.height() );
116
117 const QString fmt = format.toLower();
118 if ( format == "pdf" )
119 {
120#ifndef QT_NO_PRINTER
121 QPrinter printer;
122 printer.setColorMode( QPrinter::Color );
123 printer.setFullPage( true );
124 printer.setPaperSize( sizeMM, QPrinter::Millimeter );
125 printer.setDocName( title );
126 printer.setOutputFileName( fileName );
127 printer.setOutputFormat( QPrinter::PdfFormat );
128 printer.setResolution( resolution );
129
130 QPainter painter( &printer );
131 render( plot, &painter, documentRect );
132#endif
133 }
134 else if ( format == "ps" )
135 {
136#if QT_VERSION < 0x050000
137#ifndef QT_NO_PRINTER
138 QPrinter printer;
139 printer.setColorMode( QPrinter::Color );
140 printer.setFullPage( true );
141 printer.setPaperSize( sizeMM, QPrinter::Millimeter );
142 printer.setDocName( title );
143 printer.setOutputFileName( fileName );
144 printer.setOutputFormat( QPrinter::PostScriptFormat );
145 printer.setResolution( resolution );
146
147 QPainter painter( &printer );
148 render( plot, &painter, documentRect );
149#endif
150#endif
151 }
152#ifndef QWT_NO_POLAR_SVG
153#ifdef QT_SVG_LIB
154#if QT_VERSION >= 0x040500
155 else if ( format == "svg" )
156 {
157 QSvgGenerator generator;
158 generator.setTitle( title );
159 generator.setFileName( fileName );
160 generator.setResolution( resolution );
161 generator.setViewBox( documentRect );
162
163 QPainter painter( &generator );
164 render( plot, &painter, documentRect );
165 }
166#endif
167#endif
168#endif
169 else
170 {
171 if ( QImageWriter::supportedImageFormats().indexOf(
172 format.toLatin1() ) >= 0 )
173 {
174 const QRect imageRect = documentRect.toRect();
175 const int dotsPerMeter = qRound( resolution * mmToInch * 1000.0 );
176
177 QImage image( imageRect.size(), QImage::Format_ARGB32 );
178 image.setDotsPerMeterX( dotsPerMeter );
179 image.setDotsPerMeterY( dotsPerMeter );
180 image.fill( QColor( Qt::white ).rgb() );
181
182 QPainter painter( &image );
183 render( plot, &painter, imageRect );
184 painter.end();
185
186 image.save( fileName, format.toLatin1() );
187 }
188 }
189}
190
191/*!
192 \brief Render the plot to a \c QPaintDevice
193
194 This function renders the contents of a QwtPolarPlot instance to
195 \c QPaintDevice object. The target rectangle is derived from
196 its device metrics.
197
198 \param plot Plot to be rendered
199 \param paintDevice device to paint on, f.e a QImage
200
201 \sa renderDocument(), render(), QwtPainter::setRoundingAlignment()
202*/
203
204void QwtPolarRenderer::renderTo(
205 QwtPolarPlot *plot, QPaintDevice &paintDevice ) const
206{
207 int w = paintDevice.width();
208 int h = paintDevice.height();
209
210 QPainter p( &paintDevice );
211 render( plot, &p, QRectF( 0, 0, w, h ) );
212}
213
214
215/*!
216 \brief Render the plot to a QPrinter
217
218 This function renders the contents of a QwtPolarPlot instance to
219 \c QPaintDevice object. The size is derived from the printer
220 metrics.
221
222 \param plot Plot to be rendered
223 \param printer Printer to paint on
224
225 \sa renderDocument(), render(), QwtPainter::setRoundingAlignment()
226*/
227
228void QwtPolarRenderer::renderTo(
229 QwtPolarPlot *plot, QPrinter &printer ) const
230{
231 int w = printer.width();
232 int h = printer.height();
233
234 QRectF rect( 0, 0, w, h );
235 double aspect = rect.width() / rect.height();
236 if ( ( aspect < 1.0 ) )
237 rect.setHeight( aspect * rect.width() );
238
239 QPainter p( &printer );
240 render( plot, &p, rect );
241}
242
243#ifndef QWT_NO_POLAR_SVG
244#ifdef QT_SVG_LIB
245#if QT_VERSION >= 0x040500
246
247/*!
248 \brief Render the plot to a QSvgGenerator
249
250 If the generator has a view box, the plot will be rendered into it.
251 If it has no viewBox but a valid size the target coordinates
252 will be (0, 0, generator.width(), generator.height()). Otherwise
253 the target rectangle will be QRectF(0, 0, 800, 600);
254
255 \param plot Plot to be rendered
256 \param generator SVG generator
257*/
258void QwtPolarRenderer::renderTo(
259 QwtPolarPlot *plot, QSvgGenerator &generator ) const
260{
261 QRectF rect = generator.viewBoxF();
262 if ( rect.isEmpty() )
263 rect.setRect( 0, 0, generator.width(), generator.height() );
264
265 if ( rect.isEmpty() )
266 rect.setRect( 0, 0, 800, 600 ); // something
267
268 QPainter p( &generator );
269 render( plot, &p, rect );
270}
271#endif
272#endif
273#endif
274
275/*!
276 \brief Render the plot to a given rectangle ( f.e QPrinter, QSvgRenderer )
277
278 \param plot Plot widget to be rendered
279 \param painter Painter
280 \param plotRect Bounding rectangle for the plot
281*/
282void QwtPolarRenderer::render( QwtPolarPlot *plot,
283 QPainter *painter, const QRectF &plotRect ) const
284{
285 if ( plot == NULL || painter == NULL || !painter->isActive() ||
286 !plotRect.isValid() || plot->size().isNull() )
287 {
288 return;
289 }
290
291 d_data->plot = plot;
292
293 /*
294 The layout engine uses the same methods as they are used
295 by the Qt layout system. Therefore we need to calculate the
296 layout in screen coordinates and paint with a scaled painter.
297 */
298 QTransform transform;
299 transform.scale(
300 double( painter->device()->logicalDpiX() ) / plot->logicalDpiX(),
301 double( painter->device()->logicalDpiY() ) / plot->logicalDpiY() );
302
303 const QRectF layoutRect = transform.inverted().mapRect( plotRect );
304
305 QwtPolarLayout *layout = plot->plotLayout();
306
307 // All paint operations need to be scaled according to
308 // the paint device metrics.
309
310 QwtPolarLayout::Options layoutOptions =
311 QwtPolarLayout::IgnoreScrollbars | QwtPolarLayout::IgnoreFrames;
312
313 layout->activate( plot, layoutRect, layoutOptions );
314
315 painter->save();
316 painter->setWorldTransform( transform, true );
317
318 painter->save();
319 renderTitle( painter, layout->titleRect() );
320 painter->restore();
321
322 painter->save();
323 renderLegend( plot, painter, layout->legendRect() );
324 painter->restore();
325
326 const QRectF canvasRect = layout->canvasRect();
327
328 painter->save();
329 painter->setClipRect( canvasRect );
330 plot->drawCanvas( painter, canvasRect );
331 painter->restore();
332
333 painter->restore();
334
335 layout->invalidate();
336
337 d_data->plot = NULL;
338}
339
340/*!
341 Render the title into a given rectangle.
342
343 \param painter Painter
344 \param rect Bounding rectangle
345*/
346
347void QwtPolarRenderer::renderTitle( QPainter *painter, const QRectF &rect ) const
348{
349 QwtTextLabel *title = d_data->plot->titleLabel();
350
351 painter->setFont( title->font() );
352
353 const QColor color = title->palette().color(
354 QPalette::Active, QPalette::Text );
355
356 painter->setPen( color );
357 title->text().draw( painter, rect );
358}
359
360/*!
361 Render the legend into a given rectangle.
362
363 \param plot Plot widget
364 \param painter Painter
365 \param rect Bounding rectangle
366*/
367void QwtPolarRenderer::renderLegend( const QwtPolarPlot *plot,
368 QPainter *painter, const QRectF &rect ) const
369{
370 if ( plot->legend() )
371 plot->legend()->renderLegend( painter, rect, true );
372}
373
374/*!
375 \brief Execute a file dialog and render the plot to the selected file
376
377 The document will be rendered in 85 dpi for a size 30x30 cm
378
379 \param plot Plot widget
380 \param documentName Default document name
381 \param sizeMM Size for the document in millimeters.
382 \param resolution Resolution in dots per Inch (dpi)
383
384 \sa renderDocument()
385*/
386bool QwtPolarRenderer::exportTo( QwtPolarPlot *plot,
387 const QString &documentName, const QSizeF &sizeMM, int resolution )
388{
389 if ( plot == NULL )
390 return false;
391
392 QString fileName = documentName;
393
394 // What about translation
395
396#ifndef QT_NO_FILEDIALOG
397 const QList<QByteArray> imageFormats =
398 QImageWriter::supportedImageFormats();
399
400 QStringList filter;
401#ifndef QT_NO_PRINTER
402 filter += QString( "PDF " ) + tr( "Documents" ) + " (*.pdf)";
403#endif
404#ifndef QWT_NO_SVG
405 filter += QString( "SVG " ) + tr( "Documents" ) + " (*.svg)";
406#endif
407#ifndef QT_NO_PRINTER
408 filter += QString( "Postscript " ) + tr( "Documents" ) + " (*.ps)";
409#endif
410
411 if ( imageFormats.size() > 0 )
412 {
413 QString imageFilter( tr( "Images" ) );
414 imageFilter += " (";
415 for ( int i = 0; i < imageFormats.size(); i++ )
416 {
417 if ( i > 0 )
418 imageFilter += " ";
419 imageFilter += "*.";
420 imageFilter += imageFormats[i];
421 }
422 imageFilter += ")";
423
424 filter += imageFilter;
425 }
426
427 fileName = QFileDialog::getSaveFileName(
428 NULL, tr( "Export File Name" ), fileName,
429 filter.join( ";;" ), NULL, QFileDialog::DontConfirmOverwrite );
430#endif
431 if ( fileName.isEmpty() )
432 return false;
433
434 renderDocument( plot, fileName, sizeMM, resolution );
435
436 return true;
437}
Note: See TracBrowser for help on using the repository browser.