~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.1.2/src/qwt_raster_data.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2009-04-12 23:25:58 UTC
  • mfrom: (1.1.4 upstream) (2.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090412232558-3bl06x785yr8xm8u
Tags: 5.1.2-1
* New upstream release.
* Bump compat/debhelper to 7.
* Bump Standards-Version to 3.8.1. No changes needed.
* Invert Maintainers and Uploaders field.
* Fix lintian warnings:
  - dh_clean _k deprecated.
  - missing dependency on libc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 
2
 * Qwt Widget Library
 
3
 * Copyright (C) 1997   Josef Wilgen
 
4
 * Copyright (C) 2002   Uwe Rathmann
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the Qwt License, Version 1.0
 
8
 *****************************************************************************/
 
9
 
 
10
#include "qwt_raster_data.h"
 
11
 
 
12
class QwtRasterData::Contour3DPoint
 
13
{
 
14
public:
 
15
    inline void setPos(double x, double y)
 
16
    {
 
17
        d_x = x;
 
18
        d_y = y;
 
19
    }
 
20
 
 
21
    inline QwtDoublePoint pos() const
 
22
    {
 
23
        return QwtDoublePoint(d_x, d_y);
 
24
    }
 
25
 
 
26
    inline void setX(double x) { d_x = x; }
 
27
    inline void setY(double y) { d_y = y; }
 
28
    inline void setZ(double z) { d_z = z; }
 
29
 
 
30
    inline double x() const { return d_x; }
 
31
    inline double y() const { return d_y; }
 
32
    inline double z() const { return d_z; }
 
33
 
 
34
private:
 
35
    double d_x;
 
36
    double d_y;
 
37
    double d_z;
 
38
};
 
39
 
 
40
class QwtRasterData::ContourPlane
 
41
{
 
42
public:
 
43
    inline ContourPlane(double z):
 
44
        d_z(z)
 
45
    {
 
46
    }
 
47
 
 
48
    inline bool intersect(const Contour3DPoint vertex[3],
 
49
        QwtDoublePoint line[2], bool ignoreOnPlane) const;
 
50
 
 
51
    inline double z() const { return d_z; }
 
52
 
 
53
private:
 
54
    inline int compare(double z) const;
 
55
    inline QwtDoublePoint intersection(
 
56
        const Contour3DPoint& p1, const Contour3DPoint &p2) const;
 
57
 
 
58
    double d_z;
 
59
};
 
60
 
 
61
inline bool QwtRasterData::ContourPlane::intersect(
 
62
    const Contour3DPoint vertex[3], QwtDoublePoint line[2],
 
63
    bool ignoreOnPlane) const
 
64
{
 
65
    bool found = true;
 
66
 
 
67
    // Are the vertices below (-1), on (0) or above (1) the plan ?
 
68
    const int eq1 = compare(vertex[0].z());
 
69
    const int eq2 = compare(vertex[1].z());
 
70
    const int eq3 = compare(vertex[2].z());
 
71
 
 
72
    /*
 
73
        (a) All the vertices lie below the contour level.
 
74
        (b) Two vertices lie below and one on the contour level.
 
75
        (c) Two vertices lie below and one above the contour level.
 
76
        (d) One vertex lies below and two on the contour level.
 
77
        (e) One vertex lies below, one on and one above the contour level.
 
78
        (f) One vertex lies below and two above the contour level.
 
79
        (g) Three vertices lie on the contour level.
 
80
        (h) Two vertices lie on and one above the contour level.
 
81
        (i) One vertex lies on and two above the contour level.
 
82
        (j) All the vertices lie above the contour level.
 
83
     */
 
84
 
 
85
    static const int tab[3][3][3] =
 
86
    {
 
87
        // jump table to avoid nested case statements
 
88
        { { 0, 0, 8 }, { 0, 2, 5 }, { 7, 6, 9 } },
 
89
        { { 0, 3, 4 }, { 1, 10, 1 }, { 4, 3, 0 } },
 
90
        { { 9, 6, 7 }, { 5, 2, 0 }, { 8, 0, 0 } }
 
91
    };
 
92
 
 
93
    const int edgeType = tab[eq1+1][eq2+1][eq3+1];
 
94
    switch (edgeType)  
 
95
    {
 
96
        case 1:
 
97
            // d(0,0,-1), h(0,0,1)
 
98
            line[0] = vertex[0].pos();
 
99
            line[1] = vertex[1].pos();
 
100
            break;
 
101
        case 2:
 
102
            // d(-1,0,0), h(1,0,0)
 
103
            line[0] = vertex[1].pos();
 
104
            line[1] = vertex[2].pos();
 
105
            break;
 
106
        case 3:
 
107
            // d(0,-1,0), h(0,1,0)
 
108
            line[0] = vertex[2].pos();
 
109
            line[1] = vertex[0].pos();
 
110
            break;
 
111
        case 4:
 
112
            // e(0,-1,1), e(0,1,-1)
 
113
            line[0] = vertex[0].pos();
 
114
            line[1] = intersection(vertex[1], vertex[2]);
 
115
            break;
 
116
        case 5:
 
117
            // e(-1,0,1), e(1,0,-1)
 
118
            line[0] = vertex[1].pos();
 
119
            line[1] = intersection(vertex[2], vertex[0]);
 
120
            break;
 
121
        case 6:
 
122
            // e(-1,1,0), e(1,0,-1)
 
123
            line[0] = vertex[1].pos();
 
124
            line[1] = intersection(vertex[0], vertex[1]);
 
125
            break;
 
126
        case 7:
 
127
            // c(-1,1,-1), f(1,1,-1)
 
128
            line[0] = intersection(vertex[0], vertex[1]);
 
129
            line[1] = intersection(vertex[1], vertex[2]);
 
130
            break;
 
131
        case 8:
 
132
            // c(-1,-1,1), f(1,1,-1)
 
133
            line[0] = intersection(vertex[1], vertex[2]);
 
134
            line[1] = intersection(vertex[2], vertex[0]);
 
135
            break;
 
136
        case 9:
 
137
            // f(-1,1,1), c(1,-1,-1)
 
138
            line[0] = intersection(vertex[2], vertex[0]);
 
139
            line[1] = intersection(vertex[0], vertex[1]);
 
140
            break;
 
141
        case 10:
 
142
            // g(0,0,0)
 
143
            // The CONREC algorithm has no satisfying solution for
 
144
            // what to do, when all vertices are on the plane.
 
145
 
 
146
            if ( ignoreOnPlane )
 
147
                found = false;
 
148
            else
 
149
            {
 
150
                line[0] = vertex[2].pos();
 
151
                line[1] = vertex[0].pos();
 
152
            }
 
153
            break;
 
154
        default:
 
155
            found = false;
 
156
    }
 
157
 
 
158
    return found;
 
159
}
 
160
 
 
161
inline int QwtRasterData::ContourPlane::compare(double z) const
 
162
{
 
163
    if (z > d_z)
 
164
        return 1;
 
165
 
 
166
    if (z < d_z)
 
167
        return -1;
 
168
 
 
169
    return 0;
 
170
}
 
171
 
 
172
inline QwtDoublePoint QwtRasterData::ContourPlane::intersection(
 
173
    const Contour3DPoint& p1, const Contour3DPoint &p2) const
 
174
{
 
175
    const double h1 = p1.z() - d_z;
 
176
    const double h2 = p2.z() - d_z;
 
177
 
 
178
    const double x = (h2 * p1.x() - h1 * p2.x()) / (h2 - h1);
 
179
    const double y = (h2 * p1.y() - h1 * p2.y()) / (h2 - h1);
 
180
 
 
181
    return QwtDoublePoint(x, y);
 
182
}
 
183
 
 
184
QwtRasterData::QwtRasterData()
 
185
{
 
186
}
 
187
 
 
188
QwtRasterData::QwtRasterData(const QwtDoubleRect &boundingRect):
 
189
    d_boundingRect(boundingRect)
 
190
{
 
191
}
 
192
 
 
193
QwtRasterData::~QwtRasterData()
 
194
{
 
195
}
 
196
 
 
197
void QwtRasterData::setBoundingRect(const QwtDoubleRect &boundingRect)
 
198
{
 
199
    d_boundingRect = boundingRect;
 
200
}
 
201
 
 
202
QwtDoubleRect QwtRasterData::boundingRect() const
 
203
{
 
204
    return d_boundingRect;
 
205
}
 
206
 
 
207
/*!
 
208
  \brief Initialize a raster
 
209
 
 
210
  Before the composition of an image QwtPlotSpectrogram calls initRaster,
 
211
  announcing the area and its resolution that will be requested.
 
212
  
 
213
  The default implementation does nothing, but for data sets that
 
214
  are stored in files, it might be good idea to reimplement initRaster,
 
215
  where the data is resampled and loaded into memory.
 
216
  
 
217
  \param rect Area of the raster
 
218
  \param raster Number of horizontal and vertical pixels
 
219
 
 
220
  \sa initRaster(), value()
 
221
*/
 
222
void QwtRasterData::initRaster(const QwtDoubleRect &, const QSize&)
 
223
{
 
224
}
 
225
 
 
226
/*!
 
227
  \brief Discard a raster
 
228
 
 
229
  After the composition of an image QwtPlotSpectrogram calls discardRaster().
 
230
  
 
231
  The default implementation does nothing, but if data has been loaded
 
232
  in initRaster(), it could deleted now.
 
233
 
 
234
  \sa initRaster(), value()
 
235
*/
 
236
void QwtRasterData::discardRaster()
 
237
{
 
238
}
 
239
 
 
240
/*!
 
241
   \brief Find the raster of the data for an area
 
242
 
 
243
   The resolution is the number of horizontal and vertical pixels
 
244
   that the data can return for an area. An invalid resolution
 
245
   indicates that the data can return values for any detail level.
 
246
 
 
247
   The resolution will limit the size of the image that is rendered 
 
248
   from the data. F.e. this might be important when printing a spectrogram
 
249
   to a A0 printer with 600 dpi.
 
250
   
 
251
   The default implementation returns an invalid resolution (size)
 
252
 
 
253
   \param rect In most implementations the resolution of the data doesn't 
 
254
               depend on the requested rectangle.
 
255
 
 
256
   \return Resolution, as number of horizontal and vertical pixels
 
257
*/
 
258
QSize QwtRasterData::rasterHint(const QwtDoubleRect &) const
 
259
{
 
260
    return QSize(); // use screen resolution
 
261
}
 
262
 
 
263
/*!
 
264
   Calculate contour lines
 
265
   
 
266
   An adaption of CONREC, a simple contouring algorithm.
 
267
   http://local.wasp.uwa.edu.au/~pbourke/papers/conrec/
 
268
*/ 
 
269
#if QT_VERSION >= 0x040000
 
270
QwtRasterData::ContourLines QwtRasterData::contourLines(
 
271
    const QwtDoubleRect &rect, const QSize &raster, 
 
272
    const QList<double> &levels, int flags) const
 
273
#else
 
274
QwtRasterData::ContourLines QwtRasterData::contourLines(
 
275
    const QwtDoubleRect &rect, const QSize &raster, 
 
276
    const QValueList<double> &levels, int flags) const
 
277
#endif
 
278
{   
 
279
    ContourLines contourLines;
 
280
    
 
281
    if ( levels.size() == 0 || !rect.isValid() || !raster.isValid() )
 
282
        return contourLines;
 
283
 
 
284
    const double dx = rect.width() / raster.width();
 
285
    const double dy = rect.height() / raster.height();
 
286
 
 
287
    const bool ignoreOnPlane =
 
288
        flags & QwtRasterData::IgnoreAllVerticesOnLevel;
 
289
 
 
290
    const QwtDoubleInterval range = this->range();
 
291
    bool ignoreOutOfRange = false;
 
292
    if ( range.isValid() )
 
293
        ignoreOutOfRange = flags & IgnoreOutOfRange;
 
294
 
 
295
    ((QwtRasterData*)this)->initRaster(rect, raster);
 
296
 
 
297
    for ( int y = 0; y < raster.height() - 1; y++ )
 
298
    {
 
299
        enum Position
 
300
        {
 
301
            Center,
 
302
 
 
303
            TopLeft,
 
304
            TopRight,
 
305
            BottomRight,
 
306
            BottomLeft,
 
307
 
 
308
            NumPositions
 
309
        };
 
310
 
 
311
        Contour3DPoint xy[NumPositions];
 
312
 
 
313
        for ( int x = 0; x < raster.width() - 1; x++ )
 
314
        {
 
315
            const QwtDoublePoint pos(rect.x() + x * dx, rect.y() + y * dy);
 
316
 
 
317
            if ( x == 0 )
 
318
            {
 
319
                xy[TopRight].setPos(pos.x(), pos.y());
 
320
                xy[TopRight].setZ(
 
321
                    value( xy[TopRight].x(), xy[TopRight].y())
 
322
                );
 
323
 
 
324
                xy[BottomRight].setPos(pos.x(), pos.y() + dy);
 
325
                xy[BottomRight].setZ(
 
326
                    value(xy[BottomRight].x(), xy[BottomRight].y())
 
327
                );
 
328
            }
 
329
 
 
330
            xy[TopLeft] = xy[TopRight];
 
331
            xy[BottomLeft] = xy[BottomRight];
 
332
 
 
333
            xy[TopRight].setPos(pos.x() + dx, pos.y());
 
334
            xy[BottomRight].setPos(pos.x() + dx, pos.y() + dy);
 
335
 
 
336
            xy[TopRight].setZ(
 
337
                value(xy[TopRight].x(), xy[TopRight].y())
 
338
            );
 
339
            xy[BottomRight].setZ(
 
340
                value(xy[BottomRight].x(), xy[BottomRight].y())
 
341
            );
 
342
 
 
343
            double zMin = xy[TopLeft].z();
 
344
            double zMax = zMin;
 
345
            double zSum = zMin;
 
346
 
 
347
            for ( int i = TopRight; i <= BottomLeft; i++ )
 
348
            {
 
349
                const double z = xy[i].z();
 
350
 
 
351
                zSum += z;
 
352
                if ( z < zMin )
 
353
                    zMin = z;
 
354
                if ( z > zMax )
 
355
                    zMax = z;
 
356
            }
 
357
 
 
358
            if ( ignoreOutOfRange )
 
359
            {
 
360
                if ( !range.contains(zMin) || !range.contains(zMax) )
 
361
                    continue;
 
362
            }
 
363
 
 
364
            if ( zMax < levels[0] ||
 
365
                zMin > levels[levels.size() - 1] )
 
366
            {
 
367
                continue;
 
368
            }
 
369
 
 
370
            xy[Center].setPos(pos.x() + 0.5 * dx, pos.y() + 0.5 * dy);
 
371
            xy[Center].setZ(0.25 * zSum);
 
372
            const int numLevels = (int)levels.size();
 
373
            for (int l = 0; l < numLevels; l++)
 
374
            {
 
375
                const double level = levels[l];
 
376
                if ( level < zMin || level > zMax )
 
377
                    continue;
 
378
#if QT_VERSION >= 0x040000
 
379
                QPolygonF &lines = contourLines[level];
 
380
#else
 
381
                QwtArray<QwtDoublePoint> &lines = contourLines[level];
 
382
#endif
 
383
                const ContourPlane plane(level);
 
384
 
 
385
                QwtDoublePoint line[2];
 
386
                Contour3DPoint vertex[3];
 
387
 
 
388
                for (int m = TopLeft; m < NumPositions; m++)
 
389
                {
 
390
                    vertex[0] = xy[m];
 
391
                    vertex[1] = xy[0];
 
392
                    vertex[2] = xy[m != BottomLeft ? m + 1 : TopLeft];
 
393
 
 
394
                    const bool intersects =
 
395
                        plane.intersect(vertex, line, ignoreOnPlane);
 
396
                    if ( intersects )
 
397
                    {
 
398
#if QT_VERSION >= 0x040000
 
399
                        lines += line[0];
 
400
                        lines += line[1];
 
401
#else
 
402
                        const int index = lines.size();
 
403
                        lines.resize(lines.size() + 2, QGArray::SpeedOptim);
 
404
 
 
405
                        lines[index] = line[0];
 
406
                        lines[index+1] = line[1];
 
407
#endif
 
408
                    }
 
409
                }
 
410
            }
 
411
        }
 
412
    }
 
413
 
 
414
    ((QwtRasterData*)this)->discardRaster();
 
415
 
 
416
    return contourLines;
 
417
}