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

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