~ubuntu-branches/ubuntu/trusty/3depict/trusty-proposed

« back to all changes in this revision

Viewing changes to src/plot.cpp

  • Committer: Package Import Robot
  • Author(s): D Haley
  • Date: 2013-05-17 00:52:39 UTC
  • mfrom: (3.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20130517005239-7bl4mnhkvrhc2ba6
Tags: 0.0.13-1
Upload to unstable 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *      plot.cpp - mathgl plot wrapper class
3
 
 *      Copyright (C) 2011, D Haley 
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, either version 3 of the License, or
8
 
 *      (at your option) any later version.
9
 
 
10
 
 *      This program is distributed in the hope that it will be useful,
11
 
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *      GNU General Public License for more details.
14
 
 
15
 
 *      You should have received a copy of the GNU General Public License
16
 
 *      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 
*/
18
 
 
19
 
 
20
 
#include "basics.h"
21
 
#include "plot.h"
22
 
 
23
 
 
24
 
#include "translation.h"
25
 
 
26
 
 
27
 
#include <iostream>
28
 
#include <algorithm>
29
 
#ifndef ASSERT
30
 
        #define ASSERT(f)
31
 
#endif
32
 
 
33
 
//Uncomment me if using MGL >=1_10 to 
34
 
//enable plot cutting and colouring
35
 
#define MGL_GTE_1_10
36
 
 
37
 
//!Plot error bar estimation strings
38
 
const char *errModeStrings[] = { 
39
 
                                NTRANS("None"),
40
 
                                NTRANS("Moving avg.")
41
 
                                };
42
 
 
43
 
const char *plotModeStrings[]= {
44
 
        NTRANS("Lines"),
45
 
        NTRANS("Bars"),
46
 
        NTRANS("Steps"),
47
 
        NTRANS("Stem"),
48
 
        NTRANS("Points")
49
 
                                };
50
 
 
51
 
using std::string;
52
 
using std::pair;
53
 
using std::vector;
54
 
 
55
 
 
56
 
//Axis min/max bounding box is disallowed to be exactly zero on any given axis
57
 
// perform a little "push off" by this fudge factor
58
 
const float AXIS_MIN_TOLERANCE=10*sqrtf(std::numeric_limits<float>::epsilon());
59
 
 
60
 
int MGLColourFixer::maxCols=-1;
61
 
 
62
 
void MGLColourFixer::reset()
63
 
{
64
 
        rs.clear();
65
 
        gs.clear();
66
 
        bs.clear();
67
 
}
68
 
 
69
 
char MGLColourFixer::haveExactColour(float r, float g, float b) const
70
 
{
71
 
        ASSERT(rs.size() == gs.size())
72
 
        ASSERT(gs.size() == bs.size())
73
 
 
74
 
        ASSERT(rs.size() <=getMaxColours());
75
 
 
76
 
        for(unsigned int ui=0; ui<rs.size(); ui++)
77
 
        {
78
 
                if( fabs(r-rs[ui]) <std::numeric_limits<float>::epsilon()
79
 
                        && fabs(g-gs[ui]) <std::numeric_limits<float>::epsilon()
80
 
                        && fabs(b-bs[ui]) <std::numeric_limits<float>::epsilon())
81
 
                        return mglColorIds[ui+1].id; //Add one to offset to avoid the reserved "k" 
82
 
        }
83
 
 
84
 
        return 0;
85
 
}
86
 
 
87
 
unsigned int MGLColourFixer::getMaxColours() const
88
 
{
89
 
        //Used cached value if available
90
 
        if(maxCols!=-1)
91
 
                return maxCols;
92
 
 
93
 
        //The array is statically defined in
94
 
        //mgl/mgl_main.cpp, and must end with an id of zero.
95
 
        //
96
 
        //this is not documented at all.
97
 
        maxCols=0;
98
 
        while(mglColorIds[maxCols].id)
99
 
                maxCols++;
100
 
 
101
 
        return maxCols;
102
 
}
103
 
 
104
 
char MGLColourFixer::getNextBestColour(float r, float g, float b) 
105
 
{
106
 
        ASSERT(rs.size() == gs.size());
107
 
        ASSERT(gs.size() == bs.size());
108
 
        
109
 
 
110
 
        //As a special case, mgl has its own black
111
 
        if(r == 0.0f && g == 0.0f && b == 0.0f)
112
 
                return mglColorIds[0].id;
113
 
 
114
 
 
115
 
        ASSERT(graph);
116
 
        unsigned int best=0;
117
 
        if(rs.size() == getMaxColours())
118
 
        {
119
 
                ASSERT(getMaxColours());
120
 
                //Looks like we ran out of pallete colours.
121
 
                //lets just give up and try to match this against our existing colours
122
 
 
123
 
                //TODO: let this modify the existing pallette
124
 
                // to find a better match.
125
 
                float distanceSqr=std::numeric_limits<float>::max();
126
 
                for(unsigned int ui=0; ui<rs.size(); ui++)
127
 
                {
128
 
                        float distanceTmp;
129
 
                        if(r <= 0.5)
130
 
                        {
131
 
                                //3,4,2 weighted euclidean distance. Weights allow for closer human perception
132
 
                                distanceTmp= 3.0*(rs[ui] - r )*(rs[ui] - r ) +4.0*(gs[ui] - g )*(gs[ui] - g )
133
 
                                             + 2.0*(bs[ui] - b )*(bs[ui] - b );
134
 
                        }
135
 
                        else
136
 
                        {
137
 
                                //use alternate weighting for closer colour perception in "non-red" half of colour cube
138
 
                                distanceTmp= 2.0*(rs[ui] - r )*(rs[ui] - r ) +4.0*(gs[ui] - g )*(gs[ui] - g )
139
 
                                             + 3.0*(bs[ui] - b )*(bs[ui] - b );
140
 
                        }
141
 
 
142
 
                        if(distanceTmp < distanceSqr)
143
 
                        {
144
 
                                distanceSqr = (distanceTmp);
145
 
                                best=ui+1; //offset by 1 because mathgl colour 0 is special
146
 
                        }
147
 
 
148
 
                }
149
 
        }
150
 
        else
151
 
        {
152
 
                char exactMatch;
153
 
                //Check to see if we don't already have this
154
 
                // no use wasting palette positions on existing
155
 
                // colours
156
 
                exactMatch=haveExactColour(r,g,b);
157
 
 
158
 
                if(exactMatch)
159
 
                        return exactMatch;
160
 
 
161
 
                //Offset zero is special, for black things, like axes
162
 
                best=rs.size()+1;
163
 
                graph->SetPalColor(best,r,g,b);
164
 
                mglColorIds[best].col = mglColor(r,g,b);
165
 
                
166
 
                rs.push_back(r);
167
 
                gs.push_back(g);
168
 
                bs.push_back(b);
169
 
        }
170
 
 
171
 
        ASSERT(mglColorIds[best].id != 'k');
172
 
        return mglColorIds[best].id;
173
 
}
174
 
 
175
 
 
176
 
//Nasty string conversion functions.
177
 
std::wstring strToWStr(const std::string& s)
178
 
{
179
 
        std::wstring temp(s.length(),L' ');
180
 
        std::copy(s.begin(), s.end(), temp.begin());
181
 
        return temp;
182
 
}
183
 
 
184
 
std::string wstrToStr(const std::wstring& s)
185
 
{
186
 
        std::string temp(s.length(), ' ');
187
 
        std::copy(s.begin(), s.end(), temp.begin());
188
 
        return temp;
189
 
}
190
 
 
191
 
 
192
 
//TODO: Refactor these functions to use a common string map
193
 
//-----------
194
 
string plotString(unsigned int traceType)
195
 
{
196
 
        ASSERT(traceType< PLOT_TRACE_ENDOFENUM);
197
 
        return TRANS(plotModeStrings[traceType]); 
198
 
}
199
 
 
200
 
unsigned int plotID(const std::string &plotString)
201
 
{
202
 
        for(unsigned int ui=0;ui<PLOT_TRACE_ENDOFENUM; ui++)
203
 
        {
204
 
                if(plotString==TRANS(plotModeStrings[ui]))
205
 
                        return ui;
206
 
        }
207
 
 
208
 
        ASSERT(false);
209
 
}
210
 
//-----------
211
 
 
212
 
unsigned int plotErrmodeID(const std::string &s)
213
 
{
214
 
        for(unsigned int ui=0;ui<PLOT_ERROR_ENDOFENUM; ui++)
215
 
        {
216
 
                if(s ==  errModeStrings[ui])
217
 
                        return ui;
218
 
        }
219
 
        ASSERT(false);
220
 
}
221
 
 
222
 
string plotErrmodeString(unsigned int plotID)
223
 
{
224
 
        return errModeStrings[plotID];
225
 
}
226
 
 
227
 
 
228
 
void genErrBars(const std::vector<float> &x, const std::vector<float> &y, 
229
 
                        std::vector<float> &errBars, const PLOT_ERROR &errMode)
230
 
{
231
 
        switch(errMode.mode)
232
 
        {
233
 
                case PLOT_ERROR_NONE:
234
 
                        return; 
235
 
                case PLOT_ERROR_MOVING_AVERAGE:
236
 
                {
237
 
                        ASSERT(errMode.movingAverageNum);
238
 
                        errBars.resize(y.size());
239
 
                        for(int ui=0;ui<y.size();ui++)
240
 
                        {
241
 
                                float mean;
242
 
                                mean=0.0f;
243
 
 
244
 
                                //Compute the local mean
245
 
                                for(int uj=0;uj<errMode.movingAverageNum;uj++)
246
 
                                {
247
 
                                        int idx;
248
 
                                        idx= std::max((int)ui+(int)uj-(int)errMode.movingAverageNum/2,0);
249
 
                                        idx=std::min(idx,(int)(y.size()-1));
250
 
                                        ASSERT(idx<y.size());
251
 
                                        mean+=y[idx];
252
 
                                }
253
 
 
254
 
                                mean/=(float)errMode.movingAverageNum;
255
 
 
256
 
                                //Compute the local stddev
257
 
                                float stddev;
258
 
                                stddev=0;
259
 
                                for(int uj=0;uj<errMode.movingAverageNum;uj++)
260
 
                                {
261
 
                                        int idx;
262
 
                                        idx= std::max((int)ui+(int)uj-(int)errMode.movingAverageNum/2,0);
263
 
                                        idx=std::min(idx,(int)(y.size()-1));
264
 
                                        stddev+=(y[idx]-mean)*(y[idx]-mean);
265
 
                                }
266
 
 
267
 
                                stddev=sqrtf(stddev/(float)errMode.movingAverageNum);
268
 
                                errBars[ui]=stddev;
269
 
                        }
270
 
                        break;
271
 
                }
272
 
        }
273
 
 
274
 
}
275
 
//===
276
 
 
277
 
                //!Constructor
278
 
PlotWrapper::PlotWrapper()
279
 
{
280
 
        COMPILE_ASSERT(ARRAYSIZE(plotModeStrings) == PLOT_TRACE_ENDOFENUM);
281
 
        applyUserBounds=false;
282
 
        plotChanged=true;
283
 
        drawLegend=true;
284
 
}
285
 
 
286
 
unsigned int PlotWrapper::addPlot(PlotBase *p)
287
 
{
288
 
        plottingData.push_back(p);
289
 
 
290
 
#ifdef DEBUG
291
 
        p=0; //zero out pointer, we are in command now.
292
 
#endif
293
 
 
294
 
        //assign a unique identifier to this plot, by which it can be referenced
295
 
        unsigned int uniqueID = plotIDHandler.genId(plottingData.size()-1);
296
 
        plotChanged=true;
297
 
        return uniqueID;
298
 
}
299
 
 
300
 
void PlotWrapper::clear(bool preserveVisiblity)
301
 
{
302
 
 
303
 
        //Do our best to preserve visiblity of
304
 
        //plots. 
305
 
        lastVisiblePlots.clear();
306
 
        if(preserveVisiblity)
307
 
        {
308
 
                //Remember which plots were visible, who owned them, and their index
309
 
                for(unsigned int ui=0;ui<plottingData.size(); ui++)
310
 
                {
311
 
                        if(plottingData[ui]->visible && plottingData[ui]->parentObject)
312
 
                        {
313
 
                                lastVisiblePlots.push_back(std::make_pair(plottingData[ui]->parentObject,
314
 
                                                                plottingData[ui]->parentPlotIndex));
315
 
                        }
316
 
                }
317
 
        }
318
 
        else
319
 
                applyUserBounds=false;
320
 
 
321
 
 
322
 
        //Free the plotting data pointers
323
 
        for(size_t ui=0;ui<plottingData.size();ui++)
324
 
                delete plottingData[ui];
325
 
 
326
 
        plottingData.clear();
327
 
        plotIDHandler.clear();
328
 
        plotChanged=true;
329
 
}
330
 
 
331
 
void PlotWrapper::setStrings(unsigned int plotID, const std::string &x, 
332
 
                                const std::string &y, const std::string &t)
333
 
{
334
 
        unsigned int plotPos=plotIDHandler.getPos(plotID);
335
 
        plottingData[plotPos]->xLabel = strToWStr(x);
336
 
        plottingData[plotPos]->yLabel = strToWStr(y);
337
 
        
338
 
        plottingData[plotPos]->title = strToWStr(t);
339
 
        plotChanged=true;
340
 
}
341
 
 
342
 
void PlotWrapper::setParentData(unsigned int plotID, const void *parentObj, unsigned int idx)
343
 
{
344
 
        unsigned int plotPos=plotIDHandler.getPos(plotID);
345
 
        plottingData[plotPos]->parentObject= parentObj;
346
 
        plottingData[plotPos]->parentPlotIndex=idx;
347
 
        
348
 
        plotChanged=true;
349
 
}
350
 
 
351
 
void PlotWrapper::setTraceStyle(unsigned int plotUniqueID,unsigned int mode)
352
 
{
353
 
 
354
 
        ASSERT(mode<PLOT_TRACE_ENDOFENUM);
355
 
        plottingData[plotIDHandler.getPos(plotUniqueID)]->traceType=mode;
356
 
        plotChanged=true;
357
 
}
358
 
 
359
 
void PlotWrapper::setColours(unsigned int plotUniqueID, float rN,float gN,float bN) 
360
 
{
361
 
        unsigned int plotPos=plotIDHandler.getPos(plotUniqueID);
362
 
        plottingData[plotPos]->r=rN;
363
 
        plottingData[plotPos]->g=gN;
364
 
        plottingData[plotPos]->b=bN;
365
 
        plotChanged=true;
366
 
}
367
 
 
368
 
void PlotWrapper::setBounds(float xMin, float xMax,
369
 
                        float yMin,float yMax)
370
 
{
371
 
        ASSERT(xMin<xMax);
372
 
        ASSERT(yMin<=yMax);
373
 
        xUserMin=xMin;
374
 
        yUserMin=std::max(0.0f,yMin);
375
 
        xUserMax=xMax;
376
 
        yUserMax=yMax;
377
 
 
378
 
 
379
 
 
380
 
        applyUserBounds=true;
381
 
        plotChanged=true;
382
 
}
383
 
 
384
 
void PlotWrapper::disableUserAxisBounds(bool xBound)
385
 
{
386
 
        float xMin,xMax,yMin,yMax;
387
 
        scanBounds(xMin,xMax,yMin,yMax);
388
 
 
389
 
        if(xBound)
390
 
        {
391
 
                xUserMin=xMin;
392
 
                xUserMax=xMax;
393
 
        }
394
 
        else
395
 
        {
396
 
                yUserMin=std::max(0.0f,yMin);
397
 
                yUserMax=yMax;
398
 
        }
399
 
 
400
 
        //Check to see if we have zoomed all the bounds out anyway
401
 
        if(fabs(xUserMin -xMin)<=std::numeric_limits<float>::epsilon() &&
402
 
                fabs(yUserMin -yMin)<=std::numeric_limits<float>::epsilon())
403
 
        {
404
 
                applyUserBounds=false;
405
 
        }
406
 
 
407
 
        plotChanged=true;
408
 
}
409
 
 
410
 
void PlotWrapper::getBounds(float &xMin, float &xMax,
411
 
                        float &yMin,float &yMax) const
412
 
{
413
 
        if(applyUserBounds)
414
 
        {
415
 
                xMin=xUserMin;
416
 
                yMin=yUserMin;
417
 
                xMax=xUserMax;
418
 
                yMax=yUserMax;
419
 
        }
420
 
        else
421
 
                scanBounds(xMin,xMax,yMin,yMax);
422
 
 
423
 
        ASSERT(xMin <xMax && yMin <=yMax);
424
 
}
425
 
 
426
 
void PlotWrapper::scanBounds(float &xMin,float &xMax,float &yMin,float &yMax) const
427
 
{
428
 
        //We are going to have to scan for max/min bounds
429
 
        //from the shown plots 
430
 
        xMin=std::numeric_limits<float>::max();
431
 
        xMax=-std::numeric_limits<float>::max();
432
 
        yMin=std::numeric_limits<float>::max();
433
 
        yMax=-std::numeric_limits<float>::max();
434
 
 
435
 
        for(unsigned int uj=0;uj<plottingData.size(); uj++)
436
 
        {
437
 
                //only consider the bounding boxes from visible plots
438
 
                if(!plottingData[uj]->visible)
439
 
                        continue;
440
 
 
441
 
                //Expand our bounding box to encompass that of this visible plot
442
 
                float tmpXMin,tmpXMax,tmpYMin,tmpYMax;
443
 
                plottingData[uj]->getBounds(tmpXMin,tmpXMax,tmpYMin,tmpYMax);
444
 
 
445
 
                xMin=std::min(xMin,tmpXMin);
446
 
                xMax=std::max(xMax,tmpXMax);
447
 
                yMin=std::min(yMin,tmpYMin);
448
 
                yMax=std::max(yMax,tmpYMax);
449
 
 
450
 
        }
451
 
 
452
 
        ASSERT(xMin < xMax && yMin <=yMax);
453
 
}
454
 
 
455
 
void PlotWrapper::bestEffortRestoreVisibility()
456
 
{
457
 
        //Try to match up the last visible plots to the
458
 
        //new plots. Use index and owner as guiding data
459
 
 
460
 
        for(unsigned int uj=0;uj<plottingData.size(); uj++)
461
 
                plottingData[uj]->visible=false;
462
 
        
463
 
        for(unsigned int ui=0; ui<lastVisiblePlots.size();ui++)
464
 
        {
465
 
                for(unsigned int uj=0;uj<plottingData.size(); uj++)
466
 
                {
467
 
                        if(plottingData[uj]->parentObject == lastVisiblePlots[ui].first
468
 
                                && plottingData[uj]->parentPlotIndex == lastVisiblePlots[ui].second)
469
 
                        {
470
 
                                plottingData[uj]->visible=true;
471
 
                                break;
472
 
                        }
473
 
                
474
 
                }
475
 
        }
476
 
 
477
 
        lastVisiblePlots.clear();
478
 
        plotChanged=true;
479
 
}
480
 
 
481
 
void PlotWrapper::getRawData(vector<vector<vector<float> > > &data,
482
 
                                std::vector<std::vector<std::wstring> > &labels) const
483
 
{
484
 
        if(plottingData.empty())
485
 
                return;
486
 
 
487
 
        //Determine if we have multiple types of plot.
488
 
        //if so, we cannot really return the raw data for this
489
 
        //in a meaningful fashion
490
 
        switch(getVisibleType())
491
 
        {
492
 
                case PLOT_TYPE_ONED:
493
 
                {
494
 
                        //Try to retrieve the raw data from the visible plots
495
 
                        for(unsigned int ui=0;ui<plottingData.size();ui++)
496
 
                        {
497
 
                                if(plottingData[ui]->visible)
498
 
                                {
499
 
                                        vector<vector<float> > thisDat,dummy;
500
 
                                        vector<std::wstring> thisLabel;
501
 
                                        plottingData[ui]->getRawData(thisDat,thisLabel);
502
 
                                        
503
 
                                        //Data title size should hopefully be the same
504
 
                                        //as the label size
505
 
                                        ASSERT(thisLabel.size() == thisDat.size());
506
 
 
507
 
                                        if(thisDat.size())
508
 
                                        {
509
 
                                                data.push_back(dummy);
510
 
                                                data.back().swap(thisDat);
511
 
                                                
512
 
                                                labels.push_back(thisLabel);    
513
 
                                        }
514
 
                                }
515
 
                        }
516
 
                        break;
517
 
                }
518
 
                case PLOT_TYPE_TWOD:
519
 
                {
520
 
                        //Try to retrieve the raw data from the visible plots
521
 
                        for(unsigned int ui=0;ui<plottingData.size();ui++)
522
 
                        {
523
 
                                if(plottingData[ui]->visible)
524
 
                                {
525
 
                                        //FIXME: IMPLEMENT ME
526
 
                                        ASSERT(false);
527
 
                                }
528
 
                        }
529
 
                        break;
530
 
                }
531
 
                case PLOT_TYPE_MIXED:
532
 
                case PLOT_TYPE_ENUM_END:
533
 
                        return;
534
 
                default:
535
 
                        ASSERT(false);
536
 
        }
537
 
}
538
 
 
539
 
unsigned int PlotWrapper::getVisibleType() const
540
 
{
541
 
        unsigned int visibleType=PLOT_TYPE_ENUM_END;
542
 
        for(unsigned int ui=0;ui<plottingData.size() ; ui++)
543
 
        {
544
 
                if(plottingData[ui]->visible &&
545
 
                        plottingData[ui]->plotType!= visibleType)
546
 
                {
547
 
                        if(visibleType == PLOT_TYPE_ENUM_END)
548
 
                        {
549
 
                                visibleType=plottingData[ui]->plotType;
550
 
                                continue;
551
 
                        }
552
 
                        else
553
 
                        {
554
 
                                visibleType=PLOT_TYPE_MIXED;
555
 
                                break;
556
 
                        }
557
 
                }
558
 
        }
559
 
 
560
 
        return visibleType;
561
 
}
562
 
 
563
 
void PlotWrapper::drawPlot(mglGraph *gr) const
564
 
{
565
 
        unsigned int visType = getVisibleType();
566
 
        if(visType == PLOT_TYPE_ENUM_END || 
567
 
                visType == PLOT_TYPE_MIXED)
568
 
                return;
569
 
 
570
 
        //Un-fudger for mathgl plots
571
 
        MGLColourFixer colourFixer;
572
 
        colourFixer.setGraph(gr);
573
 
 
574
 
        bool haveMultiTitles=false;
575
 
        float minX,maxX,minY,maxY;
576
 
        minX=std::numeric_limits<float>::max();
577
 
        maxX=-std::numeric_limits<float>::max();
578
 
        minY=std::numeric_limits<float>::max();
579
 
        maxY=-std::numeric_limits<float>::max();
580
 
 
581
 
        //Compute the bounding box in data coordinates  
582
 
        std::wstring xLabel,yLabel,plotTitle;
583
 
        for(unsigned int ui=0;ui<plottingData.size(); ui++)
584
 
        {
585
 
                if(plottingData[ui]->visible)
586
 
                {
587
 
                        minX=std::min(minX,plottingData[ui]->minX);
588
 
                        maxX=std::max(maxX,plottingData[ui]->maxX);
589
 
                        minY=std::min(minY,plottingData[ui]->minY);
590
 
                        maxY=std::max(maxY,plottingData[ui]->maxY);
591
 
 
592
 
 
593
 
                        if(!xLabel.size())
594
 
                                xLabel=plottingData[ui]->xLabel;
595
 
                        else
596
 
                        {
597
 
 
598
 
                                if(xLabel!=plottingData[ui]->xLabel)
599
 
                                        xLabel=stlStrToStlWStr(TRANS("Multiple types"));
600
 
                        }
601
 
                        if(!yLabel.size())
602
 
                                yLabel=plottingData[ui]->yLabel;
603
 
                        else
604
 
                        {
605
 
 
606
 
                                if(yLabel!=plottingData[ui]->yLabel)
607
 
                                        yLabel=stlStrToStlWStr(TRANS("Multiple types"));
608
 
                        }
609
 
                        if(!haveMultiTitles && !plotTitle.size())
610
 
                                plotTitle=plottingData[ui]->title;
611
 
                        else
612
 
                        {
613
 
 
614
 
                                if(plotTitle!=plottingData[ui]->title)
615
 
                                {
616
 
                                        plotTitle=L"";//L prefix means wide char
617
 
                                        haveMultiTitles=true;
618
 
                                }
619
 
                        }
620
 
 
621
 
 
622
 
                }
623
 
        }
624
 
 
625
 
        string sX,sY;
626
 
        sX.assign(xLabel.begin(),xLabel.end()); //unicode conversion
627
 
        sY.assign(yLabel.begin(),yLabel.end()); //unicode conversion
628
 
        
629
 
        string sT;
630
 
        sT.assign(plotTitle.begin(), plotTitle.end()); //unicode conversion
631
 
        gr->Title(sT.c_str());
632
 
        
633
 
 
634
 
        unsigned int type;
635
 
        type=plottingData[0]->plotType;
636
 
        switch(type)
637
 
        {
638
 
                case PLOT_TYPE_ONED:
639
 
                {
640
 
                        //OneD line plot
641
 
                        bool useLogPlot=false;
642
 
                        bool notLog=false;
643
 
 
644
 
                
645
 
                        for(unsigned int ui=0;ui<plottingData.size(); ui++)
646
 
                        {
647
 
                                if(plottingData[ui]->visible)
648
 
                                {
649
 
                                        if(((Plot1D*)plottingData[ui])->wantLogPlot()) 
650
 
                                                useLogPlot=true;
651
 
                                        else
652
 
                                                notLog=true;
653
 
                                }
654
 
                        }
655
 
                
656
 
                        //work out the bounding box for the plot,
657
 
                        //and where the axis should cross
658
 
                        mglPoint axisCross;
659
 
                        mglPoint min,max;
660
 
                        if(applyUserBounds)
661
 
                        {
662
 
                                ASSERT(yUserMax >=yUserMin);
663
 
                                ASSERT(xUserMax >=xUserMin);
664
 
 
665
 
                                max.x =xUserMax;
666
 
                                max.y=yUserMax;
667
 
                                
668
 
                                min.x =xUserMin;
669
 
                                min.y =yUserMin;
670
 
 
671
 
                                axisCross.x=min.x;
672
 
                                axisCross.y=min.y;
673
 
                                
674
 
                        }
675
 
                        else
676
 
                        {
677
 
                                //Retreive the bounds of the data that is in the plot
678
 
 
679
 
                                min.x=minX;
680
 
                                min.y=minY;
681
 
                                max.x=maxX;
682
 
 
683
 
                                if(useLogPlot && maxY > 0.0f)
684
 
                                        max.y =log10(maxY);
685
 
                                else
686
 
                                        max.y=maxY;
687
 
 
688
 
                                axisCross.x = minX;
689
 
                                axisCross.y = 0;
690
 
                                
691
 
                                gr->Org=axisCross;
692
 
                        }
693
 
                        
694
 
                        //tell mathgl about the bounding box    
695
 
                        gr->Axis(min,max,axisCross);
696
 
 
697
 
                        WARN((fabs(min.x-max.x) > sqrt(std::numeric_limits<float>::epsilon())), "WARNING: Mgl limits (X) too Close! Due to limitiations in MGL, This may inf. loop!");
698
 
                        WARN((fabs(min.y-max.y) > sqrt(std::numeric_limits<float>::epsilon())), "WARNING: Mgl limits (Y) too Close! Due to limitiations in MGL, This may inf. loop!");
699
 
 
700
 
 
701
 
                        //"Push" bounds around to prevent min == max
702
 
                        if(min.x == max.x)
703
 
                        {
704
 
                                min.x-=0.5;
705
 
                                max.x+=0.5;
706
 
                        }
707
 
 
708
 
                        if(min.y == max.y)
709
 
                                max.y+=1;
710
 
 
711
 
                        gr->AdjustTicks("x");
712
 
                        gr->SetXTT("%g"); //Set the tick type
713
 
                        gr->Axis("xy"); //Build an X-Y crossing axis
714
 
 
715
 
                        //Draw regions as faces perp to z.
716
 
                        //this will colour in a region of the graph as a rectangle
717
 
                        for(unsigned int ui=0;ui<plottingData.size();ui++)
718
 
                        {
719
 
                                Plot1D *curPlot;
720
 
                                curPlot=(Plot1D*)plottingData[ui];
721
 
 
722
 
                                //If a plot is not visible, it cannot own a region
723
 
                                //nor have a legend in this run.
724
 
                                if(!curPlot->visible)
725
 
                                        continue;
726
 
 
727
 
 
728
 
                                curPlot->drawRegions(gr,colourFixer,min,max);
729
 
                                curPlot->drawPlot(gr,colourFixer);
730
 
                                
731
 
                                if(drawLegend)
732
 
                                {
733
 
                                        //Fake an mgl colour code
734
 
                                        char colourCode[2];
735
 
                                        colourCode[0]=colourFixer.getNextBestColour(
736
 
                                                        curPlot->r,curPlot->g,curPlot->b);
737
 
                                        colourCode[1]='\0';
738
 
                                        gr->AddLegend(curPlot->title.c_str(),colourCode);
739
 
                                }
740
 
                        }
741
 
 
742
 
                        //Prevent mathgl from dropping lines that straddle the plot bound.
743
 
                        gr->SetCut(false);
744
 
                
745
 
                        if(useLogPlot && !notLog)
746
 
                                sY = string("\\log_{10}(") + sY + ")";
747
 
                        else if (useLogPlot && notLog)
748
 
                        {
749
 
                                sY = string(TRANS("Mixed log/non-log:")) + sY ;
750
 
                        }
751
 
 
752
 
                        break;
753
 
                }
754
 
                default:
755
 
                        ASSERT(false);
756
 
        }
757
 
 
758
 
 
759
 
        gr->Label('x',sX.c_str());
760
 
        gr->Label('y',sY.c_str(),0);
761
 
        
762
 
        if(haveMultiTitles)
763
 
        {
764
 
#ifdef MGL_GTE_1_10 
765
 
                gr->SetLegendBox(false);
766
 
#endif
767
 
                //I have NO idea what this size value is about,
768
 
                //I just kept changing the number until it looked nice.
769
 
                //the library default is -0.85 (why negative??)
770
 
                const float LEGEND_SIZE=-1.1f;
771
 
 
772
 
                //Legend at top right (0x3), in default font "rL" at specified size
773
 
                gr->Legend(0x3,"rL",LEGEND_SIZE);
774
 
        }
775
 
 
776
 
}
777
 
 
778
 
void PlotWrapper::hideAll()
779
 
{
780
 
        for(unsigned int ui=0;ui<plottingData.size(); ui++)
781
 
                plottingData[ui]->visible=false;
782
 
        plotChanged=true;
783
 
}
784
 
 
785
 
void PlotWrapper::setVisible(unsigned int uniqueID, bool setVis)
786
 
{
787
 
        unsigned int plotPos = plotIDHandler.getPos(uniqueID);
788
 
 
789
 
        plottingData[plotPos]->visible=setVis;
790
 
        plotChanged=true;
791
 
}
792
 
 
793
 
bool PlotWrapper::getRegionIdAtPosition(float x, float y, unsigned int &pId, unsigned int &rId) const
794
 
{
795
 
        for(size_t ui=0;ui<plottingData.size(); ui++)
796
 
        {
797
 
                //Regions can only be active for visible plots
798
 
                if(!plottingData[ui]->visible)
799
 
                        continue;
800
 
 
801
 
                if(plottingData[ui]->getRegionIdAtPosition(x,y,rId))
802
 
                {
803
 
                        pId=ui;
804
 
                        return true;
805
 
                }
806
 
        }
807
 
 
808
 
        return false;
809
 
}
810
 
 
811
 
//-----------
812
 
 
813
 
 
814
 
Plot1D::Plot1D()
815
 
{
816
 
        //Set the default plot properties
817
 
        visible=(true);
818
 
        traceType=PLOT_TRACE_LINES;
819
 
        plotType=PLOT_TYPE_ONED;
820
 
        xLabel=(strToWStr(""));
821
 
        yLabel=(strToWStr(""));
822
 
        title=(strToWStr(""));
823
 
        r=(0);g=(0);b=(1);
824
 
}
825
 
 
826
 
void Plot1D::setData(const vector<float> &vX, const vector<float> &vY, 
827
 
                const vector<float> &vErr)
828
 
{
829
 
 
830
 
        ASSERT(vX.size() == vY.size());
831
 
        ASSERT(vErr.size() == vY.size() || !vErr.size());
832
 
 
833
 
 
834
 
        //Fill up vectors with data
835
 
        xValues.resize(vX.size());
836
 
        std::copy(vX.begin(),vX.end(),xValues.begin());
837
 
        yValues.resize(vY.size());
838
 
        std::copy(vY.begin(),vY.end(),yValues.begin());
839
 
        
840
 
        errBars.resize(vErr.size());
841
 
        std::copy(vErr.begin(),vErr.end(),errBars.begin());
842
 
 
843
 
        //Compute minima and maxima of plot data, and keep a copy of it
844
 
        float maxThis=-std::numeric_limits<float>::max();
845
 
        float minThis=std::numeric_limits<float>::max();
846
 
        for(unsigned int ui=0;ui<vX.size();ui++)
847
 
        {
848
 
                minThis=std::min(minThis,vX[ui]);
849
 
                maxThis=std::max(maxThis,vX[ui]);
850
 
        }
851
 
 
852
 
        minX=minThis;
853
 
        maxX=maxThis;
854
 
 
855
 
        if(maxX - minX < AXIS_MIN_TOLERANCE)
856
 
        {
857
 
                minX-=AXIS_MIN_TOLERANCE;
858
 
                maxX+=AXIS_MIN_TOLERANCE;
859
 
        }
860
 
 
861
 
        
862
 
        maxThis=-std::numeric_limits<float>::max();
863
 
        minThis=std::numeric_limits<float>::max();
864
 
        for(unsigned int ui=0;ui<vY.size();ui++)
865
 
        {
866
 
                minThis=std::min(minThis,vY[ui]);
867
 
                maxThis=std::max(maxThis,vY[ui]);
868
 
        }
869
 
        minY=minThis;
870
 
        maxY=maxThis;
871
 
 
872
 
        if(maxY - minY < AXIS_MIN_TOLERANCE)
873
 
        {
874
 
                minY-=AXIS_MIN_TOLERANCE;
875
 
                maxY+=AXIS_MIN_TOLERANCE;
876
 
        }
877
 
}
878
 
 
879
 
void Plot1D::setData(const vector<std::pair<float,float> > &v)
880
 
{
881
 
        vector<float> dummyVar;
882
 
 
883
 
        setData(v,dummyVar);
884
 
 
885
 
}
886
 
void Plot1D::setData(const vector<std::pair<float,float> > &v,const vector<float> &vErr) 
887
 
{
888
 
        //Fill up vectors with data
889
 
        xValues.resize(v.size());
890
 
        yValues.resize(v.size());
891
 
        for(unsigned int ui=0;ui<v.size();ui++)
892
 
        {
893
 
                xValues[ui]=v[ui].first;
894
 
                yValues[ui]=v[ui].second;
895
 
        }
896
 
 
897
 
        errBars.resize(vErr.size());
898
 
        std::copy(vErr.begin(),vErr.end(),errBars.begin());
899
 
 
900
 
        
901
 
 
902
 
        //Compute minima and maxima of plot data, and keep a copy of it
903
 
        float maxThis=-std::numeric_limits<float>::max();
904
 
        float minThis=std::numeric_limits<float>::max();
905
 
        for(unsigned int ui=0;ui<v.size();ui++)
906
 
        {
907
 
                minThis=std::min(minThis,v[ui].first);
908
 
                maxThis=std::max(maxThis,v[ui].first);
909
 
        }
910
 
 
911
 
        minX=minThis;
912
 
        maxX=maxThis;
913
 
        if(maxX - minX < AXIS_MIN_TOLERANCE)
914
 
        {
915
 
                minX-=AXIS_MIN_TOLERANCE;
916
 
                maxX+=AXIS_MIN_TOLERANCE;
917
 
        }
918
 
 
919
 
        maxThis=-std::numeric_limits<float>::max();
920
 
        minThis=std::numeric_limits<float>::max();
921
 
        if(vErr.size())
922
 
        {
923
 
                ASSERT(vErr.size() == v.size());
924
 
                for(unsigned int ui=0;ui<v.size();ui++)
925
 
                {
926
 
                        minThis=std::min(minThis,v[ui].second-vErr[ui]);
927
 
                        maxThis=std::max(maxThis,v[ui].second+vErr[ui]);
928
 
                }
929
 
        }
930
 
        else
931
 
        {
932
 
                for(unsigned int ui=0;ui<v.size();ui++)
933
 
                {
934
 
                        minThis=std::min(minThis,v[ui].second);
935
 
                        maxThis=std::max(maxThis,v[ui].second);
936
 
                }
937
 
 
938
 
        }
939
 
        minY=minThis;
940
 
        maxY=1.10f*maxThis; //The 1.10 is because mathgl chops off data
941
 
        
942
 
        if(maxY - minY < AXIS_MIN_TOLERANCE)
943
 
        {
944
 
                minY-=AXIS_MIN_TOLERANCE;
945
 
                maxY+=AXIS_MIN_TOLERANCE;
946
 
        }
947
 
 
948
 
 
949
 
}
950
 
 
951
 
void Plot1D::getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const
952
 
{
953
 
        //OK, we are going to have to scan for max/min
954
 
        xMin=minX;
955
 
        xMax=maxX;
956
 
        yMin=minY;
957
 
        yMax=maxY;
958
 
 
959
 
        //If we are in log mode, then we need to set the
960
 
        //log of that bound before emitting it.
961
 
        if(logarithmic && yMax)
962
 
        {
963
 
                yMin=log10(std::max(yMin,1.0f));
964
 
                yMax=log10(yMax);
965
 
        }
966
 
}
967
 
 
968
 
void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
969
 
{
970
 
        bool showErrs;
971
 
 
972
 
        mglData xDat,yDat,eDat;
973
 
        ASSERT(visible);
974
 
                
975
 
        float *bufferX,*bufferY,*bufferErr;
976
 
        bufferX = new float[xValues.size()];
977
 
        bufferY = new float[yValues.size()];
978
 
 
979
 
        showErrs=errBars.size();
980
 
        if(showErrs)
981
 
                bufferErr = new float[errBars.size()];
982
 
 
983
 
        if(logarithmic)
984
 
        {
985
 
                for(unsigned int uj=0;uj<xValues.size(); uj++)
986
 
                {
987
 
                        bufferX[uj] = xValues[uj];
988
 
                        
989
 
                        if(yValues[uj] > 0.0)
990
 
                                bufferY[uj] = log10(yValues[uj]);
991
 
                        else
992
 
                                bufferY[uj] = 0;
993
 
 
994
 
                }
995
 
        }
996
 
        else
997
 
        {
998
 
                for(unsigned int uj=0;uj<xValues.size(); uj++)
999
 
                {
1000
 
                        bufferX[uj] = xValues[uj];
1001
 
                        bufferY[uj] = yValues[uj];
1002
 
 
1003
 
                }
1004
 
                if(showErrs)
1005
 
                {
1006
 
                        for(unsigned int uj=0;uj<errBars.size(); uj++)
1007
 
                                bufferErr[uj] = errBars[uj];
1008
 
                }
1009
 
        }
1010
 
        
1011
 
        //Mathgl needs to know where to put the error bars.     
1012
 
        ASSERT(!showErrs  || errBars.size() ==xValues.size());
1013
 
        
1014
 
        xDat.Set(bufferX,xValues.size());
1015
 
        yDat.Set(bufferY,yValues.size());
1016
 
 
1017
 
        eDat.Set(bufferErr,errBars.size());
1018
 
 
1019
 
        char colourCode[2];
1020
 
        colourCode[0]=fixer.getNextBestColour(r,g,b);
1021
 
        colourCode[1]='\0';
1022
 
        //---
1023
 
 
1024
 
        //Plot the appropriate form     
1025
 
        switch(traceType)
1026
 
        {
1027
 
                case PLOT_TRACE_LINES:
1028
 
                        //Unfortunately, when using line plots, mathgl moves the data points to the plot boundary,
1029
 
                        //rather than linear interpolating them back along their paths. I have emailed the author.
1030
 
                        //for now, we shall have to put up with missing lines :( Absolute worst case, I may have to draw them myself.
1031
 
#ifdef MGL_GTE_1_10
1032
 
                        gr->SetCut(true);
1033
 
                        
1034
 
                        gr->Plot(xDat,yDat,colourCode);
1035
 
                        if(showErrs)
1036
 
                                gr->Error(xDat,yDat,eDat,colourCode);
1037
 
                        gr->SetCut(false);
1038
 
#else
1039
 
                        gr->Plot(xDat,yDat);
1040
 
#endif
1041
 
                        break;
1042
 
                case PLOT_TRACE_BARS:
1043
 
#if !defined(__WIN32) && !defined(__WIN64)
1044
 
#ifdef MGL_GTE_1_10
1045
 
                        gr->Bars(xDat,yDat,colourCode);
1046
 
#else
1047
 
                        gr->Bars(xDat,yDat);
1048
 
#endif
1049
 
#endif
1050
 
 
1051
 
                        break;
1052
 
                case PLOT_TRACE_STEPS:
1053
 
                        //Same problem as for line plot. 
1054
 
#ifdef MGL_GTE_1_10
1055
 
                        gr->SetCut(true);
1056
 
                        gr->Step(xDat,yDat,colourCode);
1057
 
                        gr->SetCut(false);
1058
 
#else
1059
 
                        gr->Step(xDat,yDat);
1060
 
#endif
1061
 
                        break;
1062
 
                case PLOT_TRACE_STEM:
1063
 
#ifdef MGL_GTE_1_10
1064
 
                        gr->Stem(xDat,yDat,colourCode);
1065
 
#else
1066
 
                        gr->Stem(xDat,yDat);
1067
 
#endif
1068
 
                        break;
1069
 
 
1070
 
                case PLOT_TRACE_POINTS:
1071
 
                {
1072
 
                        std::string s;
1073
 
                        s = colourCode;
1074
 
                        //Mathgl uses strings to manipulate line styles
1075
 
                        s+=" "; 
1076
 
                                //space means "no line"
1077
 
                        s+="x"; //x shaped point markers
1078
 
 
1079
 
#ifdef MGL_GTE_1_10
1080
 
                        gr->SetCut(true);
1081
 
                                
1082
 
                        gr->Plot(xDat,yDat,s.c_str());
1083
 
                        if(showErrs)
1084
 
                                gr->Error(xDat,yDat,eDat,s.c_str());
1085
 
                        gr->SetCut(false);
1086
 
#else
1087
 
                        gr->Plot(xDat,yDat," x");
1088
 
#endif
1089
 
                        break;
1090
 
                }
1091
 
                default:
1092
 
                        ASSERT(false);
1093
 
                        break;
1094
 
        }
1095
 
 
1096
 
        delete[]  bufferX;
1097
 
        delete[]  bufferY;
1098
 
        if(showErrs)
1099
 
                delete[]  bufferErr;
1100
 
 
1101
 
                        
1102
 
        
1103
 
}
1104
 
 
1105
 
 
1106
 
void Plot1D::addRegion(unsigned int parentPlot,unsigned int regionID,float start, float end, 
1107
 
                        float rNew, float gNew, float bNew, Filter *parentFilter)
1108
 
{
1109
 
        ASSERT(start <end);
1110
 
        ASSERT( rNew>=0.0 && rNew <= 1.0);
1111
 
        ASSERT( gNew>=0.0 && gNew <= 1.0);
1112
 
        ASSERT( bNew>=0.0 && bNew <= 1.0);
1113
 
 
1114
 
        PlotRegion region;
1115
 
        //1D plots only have one bounding direction
1116
 
        region.bounds.push_back(std::make_pair(start,end));
1117
 
        region.boundAxis.push_back(0); // the bounding direction is along the X axis
1118
 
        region.parentFilter = parentFilter;
1119
 
 
1120
 
        //Set the ID and create a unique ID (one that is invariant if regions are added or removed)
1121
 
        //for the  region
1122
 
        region.id = regionID;
1123
 
        region.uniqueID = regionIDHandler.genId(regions.size());
1124
 
 
1125
 
        region.r=rNew;
1126
 
        region.g=gNew;
1127
 
        region.b=bNew;
1128
 
 
1129
 
        regions.push_back(region);
1130
 
}
1131
 
 
1132
 
unsigned int PlotWrapper::getNumVisible() const
1133
 
{
1134
 
        unsigned int num=0;
1135
 
        for(unsigned int ui=0;ui<plottingData.size();ui++)
1136
 
        {
1137
 
                if(plottingData[ui]->visible)
1138
 
                        num++;
1139
 
        }
1140
 
        
1141
 
        
1142
 
        return num;
1143
 
}
1144
 
 
1145
 
bool PlotWrapper::isPlotVisible(unsigned int plotID) const
1146
 
{
1147
 
        return plottingData[plotIDHandler.getPos(plotID)]->visible;
1148
 
}
1149
 
 
1150
 
void PlotWrapper::getRegion(unsigned int plotId, unsigned int regionId, PlotRegion &region) const
1151
 
{
1152
 
        plottingData[plotIDHandler.getPos(plotId)]->getRegion(regionId,region);
1153
 
}
1154
 
 
1155
 
unsigned int PlotWrapper::plotType(unsigned int plotId) const
1156
 
{
1157
 
        return plottingData[plotIDHandler.getPos(plotId)]->plotType;
1158
 
}
1159
 
 
1160
 
 
1161
 
void PlotWrapper::moveRegionLimit(unsigned int plotId, unsigned int regionId,
1162
 
                        unsigned int movementType, float &constrainX, float &constrainY) const
1163
 
{
1164
 
        plottingData[plotIDHandler.getPos(plotId)]->moveRegionLimit(
1165
 
                                regionId,movementType,constrainX,constrainY);
1166
 
}
1167
 
 
1168
 
 
1169
 
void PlotWrapper::moveRegion(unsigned int plotID, unsigned int regionId, unsigned int movementType, 
1170
 
                                                        float newX, float newY) const
1171
 
{
1172
 
        plottingData[plotIDHandler.getPos(plotID)]->moveRegion(regionId,movementType,newX,newY);
1173
 
}
1174
 
//----
1175
 
 
1176
 
void Plot1D::getRawData(std::vector<std::vector< float> > &rawData,
1177
 
                                std::vector<std::wstring> &labels) const
1178
 
{
1179
 
 
1180
 
        vector<float> tmp,dummy;
1181
 
 
1182
 
        tmp.resize(xValues.size());
1183
 
        std::copy(xValues.begin(),xValues.end(),tmp.begin());
1184
 
        rawData.push_back(dummy);
1185
 
        rawData.back().swap(tmp);
1186
 
 
1187
 
        tmp.resize(yValues.size());
1188
 
        std::copy(yValues.begin(),yValues.end(),tmp.begin());
1189
 
        rawData.push_back(dummy);
1190
 
        rawData.back().swap(tmp);
1191
 
 
1192
 
        labels.push_back(xLabel);
1193
 
        labels.push_back(title);
1194
 
        
1195
 
        
1196
 
        if(errBars.size())
1197
 
        {
1198
 
                tmp.resize(errBars.size());
1199
 
                std::copy(errBars.begin(),errBars.end(),tmp.begin());
1200
 
                
1201
 
                rawData.push_back(dummy);
1202
 
                rawData.back().swap(tmp);
1203
 
                labels.push_back(stlStrToStlWStr(TRANS("error")));
1204
 
        }
1205
 
}
1206
 
 
1207
 
 
1208
 
void Plot1D::moveRegionLimit(unsigned int regionID, 
1209
 
                        unsigned int method, float &newPosX, float &newPosY)  const
1210
 
{
1211
 
 
1212
 
        unsigned int region=regionIDHandler.getPos(regionID);
1213
 
        
1214
 
        ASSERT(region<regions.size());
1215
 
 
1216
 
        //Check that moving this range will not cause any overlaps with 
1217
 
        //other regions
1218
 
        float mean;
1219
 
        mean=(regions[region].bounds[0].first + regions[region].bounds[0].second)/2.0f;
1220
 
 
1221
 
        //Who is the owner of the current plot -- we only want to interact with our colleagues
1222
 
        float xMin,xMax,yMin,yMax;
1223
 
        getBounds(xMin,xMax,yMin,yMax);
1224
 
 
1225
 
        switch(method)
1226
 
        {
1227
 
                //Left extend
1228
 
                case REGION_MOVE_EXTEND_XMINUS:
1229
 
                        //Check that the upper bound does not intersect any RHS of 
1230
 
                        //region bounds
1231
 
                        for(unsigned int ui=0; ui<regions.size(); ui++)
1232
 
                        {
1233
 
                                if((regions[ui].bounds[0].second < mean && ui !=region) )
1234
 
                                                newPosX=std::max(newPosX,regions[ui].bounds[0].second);
1235
 
                        }
1236
 
                        //Dont allow past self right
1237
 
                        newPosX=std::min(newPosX,regions[region].bounds[0].second);
1238
 
                        //Dont extend outside plot
1239
 
                        newPosX=std::max(newPosX,xMin);
1240
 
                        break;
1241
 
                //shift
1242
 
                case REGION_MOVE_TRANSLATE_X:
1243
 
                        //Check that the upper bound does not intersect any RHS or LHS of 
1244
 
                        //region bounds
1245
 
                        if(newPosX > mean) 
1246
 
                                
1247
 
                        {
1248
 
                                //Disallow hitting other bounds
1249
 
                                for(unsigned int ui=0; ui<regions.size(); ui++)
1250
 
                                {
1251
 
                                        if((regions[ui].bounds[0].first > mean && ui != region) )
1252
 
                                                newPosX=std::min(newPosX,regions[ui].bounds[0].first);
1253
 
                                }
1254
 
                                newPosX=std::max(newPosX,xMin);
1255
 
                        }
1256
 
                        else
1257
 
                        {
1258
 
                                //Disallow hitting other bounds
1259
 
                                for(unsigned int ui=0; ui<regions.size(); ui++)
1260
 
                                {
1261
 
                                        if((regions[ui].bounds[0].second < mean && ui != region))
1262
 
                                                newPosX=std::max(newPosX,regions[ui].bounds[0].second);
1263
 
                                }
1264
 
                                //Dont extend outside plot
1265
 
                                newPosX=std::min(newPosX,xMax);
1266
 
                        }
1267
 
                        break;
1268
 
                //Right extend
1269
 
                case REGION_MOVE_EXTEND_XPLUS:
1270
 
                        //Disallow hitting other bounds
1271
 
 
1272
 
                        for(unsigned int ui=0; ui<regions.size(); ui++)
1273
 
                        {
1274
 
                                if((regions[ui].bounds[0].second > mean && ui != region))
1275
 
                                        newPosX=std::min(newPosX,regions[ui].bounds[0].first);
1276
 
                        }
1277
 
                        //Dont allow past self left
1278
 
                        newPosX=std::max(newPosX,regions[region].bounds[0].first);
1279
 
                        //Dont extend outside plot
1280
 
                        newPosX=std::min(newPosX,xMax);
1281
 
                        break;
1282
 
                default:
1283
 
                        ASSERT(false);
1284
 
        }
1285
 
 
1286
 
}
1287
 
 
1288
 
 
1289
 
void Plot1D::moveRegion(unsigned int regionID, unsigned int method, float newPosX,float newPosY) const
1290
 
{
1291
 
        //Well, we should have called this externally to determine location
1292
 
        //let us confirm that this is the case 
1293
 
        moveRegionLimit(regionID,method,newPosX,newPosY);
1294
 
 
1295
 
 
1296
 
        unsigned int region=regionIDHandler.getPos(regionID);
1297
 
        ASSERT(regions[region].parentFilter);
1298
 
 
1299
 
        //Pass the filter ID value stored in the region to the filter, along with the new
1300
 
        //value to take for that filter ID
1301
 
        regions[region].parentFilter->setPropFromRegion(method,regions[region].id,newPosX);     
1302
 
 
1303
 
}
1304
 
 
1305
 
 
1306
 
void Plot1D::drawRegions(mglGraph *gr,MGLColourFixer &fixer,
1307
 
                const mglPoint &min,const mglPoint &max) const
1308
 
{
1309
 
        //Mathgl pallette colour name
1310
 
        char colourCode[2];
1311
 
        colourCode[1]='\0';
1312
 
        
1313
 
        for(unsigned int uj=0;uj<regions.size();uj++)
1314
 
        {
1315
 
                //Compute region bounds, such that it will not exceed the axis
1316
 
                float rMinX, rMaxX, rMinY,rMaxY;
1317
 
                rMinY = min.y;
1318
 
                rMaxY = max.y;
1319
 
                rMinX = std::max(min.x,regions[uj].bounds[0].first);
1320
 
                rMaxX = std::min(max.x,regions[uj].bounds[0].second);
1321
 
                
1322
 
                //Prevent drawing inverted regions
1323
 
                if(rMaxX > rMinX && rMaxY > rMinY)
1324
 
                {
1325
 
                        colourCode[0] = fixer.getNextBestColour(regions[uj].r,
1326
 
                                                regions[uj].g,regions[uj].b);
1327
 
                        colourCode[1] = '\0';
1328
 
                        gr->FaceZ(rMinX,rMinY,-1,rMaxX-rMinX,rMaxY-rMinY,
1329
 
                                        colourCode);
1330
 
                                        
1331
 
                }
1332
 
        }
1333
 
}
1334
 
 
1335
 
 
1336
 
void Plot1D::clear( bool preserveVisiblity)
1337
 
{
1338
 
        regions.clear();
1339
 
        regionIDHandler.clear();
1340
 
}
1341
 
 
1342
 
bool Plot1D::getRegionIdAtPosition(float x, float y, unsigned int &id) const
1343
 
{
1344
 
        for(unsigned int ui=0;ui<regions.size();ui++)
1345
 
        {
1346
 
                ASSERT(regions[ui].boundAxis.size() == regions[ui].bounds.size() &&
1347
 
                                regions[ui].boundAxis.size()==1);
1348
 
                ASSERT(regions[ui].boundAxis[0] == 0);
1349
 
 
1350
 
 
1351
 
                if(regions[ui].bounds[0].first < x &&
1352
 
                                regions[ui].bounds[0].second > x )
1353
 
                {
1354
 
                        id=ui;
1355
 
                        return true;
1356
 
                }
1357
 
        }
1358
 
 
1359
 
 
1360
 
        return false;
1361
 
}
1362
 
 
1363
 
void Plot1D::getRegion(unsigned int id, PlotRegion &r) const
1364
 
{
1365
 
        r = regions[regionIDHandler.getPos(id)];
1366
 
}
1367
 
 
1368
 
 
1369
 
//---------
1370
 
 
1371
 
 
1372
 
//Draw the plot onto a given MGL graph
1373
 
void Plot2D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
1374
 
{
1375
 
        bool showErrs;
1376
 
        mglData xDat,yDat,exDat,eyDat;
1377
 
        
1378
 
        ASSERT(visible);
1379
 
        ASSERT(xValues.size() == yValues.size());
1380
 
        
1381
 
        //Allocate buffers for XY data and error bars (as needed)
1382
 
        float *bufferX,*bufferY,*bufferErrX,*bufferErrY;
1383
 
        bufferX = new float[xValues.size()];
1384
 
        bufferY = new float[yValues.size()];
1385
 
 
1386
 
        ASSERT(xErrBars.size() == yErrBars.size() || !xErrBars.size() || !yErrBars.size());     
1387
 
        if(xErrBars.size())
1388
 
                bufferErrX = new float[xErrBars.size()];
1389
 
        if(yErrBars.size())
1390
 
                bufferErrY = new float[yErrBars.size()];
1391
 
 
1392
 
        //Copy data into buffers for mgl
1393
 
        for(unsigned int uj=0;uj<xValues.size(); uj++)
1394
 
        {
1395
 
                bufferX[uj] = xValues[uj];
1396
 
                bufferY[uj] = yValues[uj];
1397
 
        }
1398
 
        if(xErrBars.size())
1399
 
        {
1400
 
                for(unsigned int uj=0;uj<xErrBars.size(); uj++)
1401
 
                        bufferErrX[uj] = xErrBars[uj];
1402
 
                exDat.Set(bufferErrX,xErrBars.size());
1403
 
        }
1404
 
 
1405
 
        if(yErrBars.size())
1406
 
        {
1407
 
                for(unsigned int uj=0;uj<yErrBars.size(); uj++)
1408
 
                        bufferErrY[uj] = yErrBars[uj];
1409
 
                eyDat.Set(bufferErrY,yErrBars.size());
1410
 
        }
1411
 
 
1412
 
        xDat.Set(bufferX,xValues.size());
1413
 
        yDat.Set(bufferY,yValues.size());
1414
 
 
1415
 
        //Mathgl palette colour name
1416
 
        char colourCode[2];
1417
 
        colourCode[0]= fixer.getNextBestColour(r,g,b); 
1418
 
        colourCode[1]='\0';
1419
 
        
1420
 
        //Plot the appropriate form     
1421
 
        switch(traceType)
1422
 
        {
1423
 
                case PLOT_TRACE_LINES:
1424
 
                        //Unfortunately, when using line plots, mathgl moves the data points to the plot boundary,
1425
 
                        //rather than linear interpolating them back along their paths. I have emailed the author.
1426
 
                        //for now, we shall have to put up with missing lines :( Absolute worst case, I may have to draw them myself.
1427
 
#ifdef MGL_GTE_1_10
1428
 
                        gr->SetCut(true);
1429
 
                        
1430
 
                        gr->Plot(xDat,yDat,colourCode);
1431
 
                        if(xErrBars.size() && yErrBars.size())
1432
 
                                gr->Error(xDat,yDat,exDat,eyDat,colourCode);
1433
 
                        else if(xErrBars.size())
1434
 
                        {
1435
 
                                gr->Error(xDat,yDat,exDat,colourCode);
1436
 
                        }
1437
 
                        else if(yErrBars.size())
1438
 
                        {
1439
 
                                //FIXME: Implement me?
1440
 
                                ASSERT(false);
1441
 
                        }
1442
 
                        
1443
 
                        gr->SetCut(false);
1444
 
#else
1445
 
                        gr->Plot(xDat,yDat);
1446
 
#endif
1447
 
                        break;
1448
 
                default:
1449
 
                        ASSERT(false);
1450
 
        }
1451
 
}
1452
 
 
1453
 
//!Scan for the data bounds.
1454
 
void Plot2D::getBounds(float &xMin,float &xMax,
1455
 
                               float &yMin,float &yMax) const
1456
 
{
1457
 
        //OK, we are going to have to scan for max/min
1458
 
        xMin=minX;
1459
 
        xMax=maxX;
1460
 
        yMin=minY;
1461
 
        yMax=maxY;
1462
 
}
1463
 
 
1464
 
//Retrieve the raw data associated with this plot.
1465
 
void Plot2D::getRawData(vector<vector<float> > &rawData,
1466
 
                        std::vector<std::wstring> &labels) const
1467
 
{
1468
 
 
1469
 
        vector<float> tmp,dummy;
1470
 
 
1471
 
        tmp.resize(xValues.size());
1472
 
        std::copy(xValues.begin(),xValues.end(),tmp.begin());
1473
 
        rawData.push_back(dummy);
1474
 
        rawData.back().swap(tmp);
1475
 
 
1476
 
        tmp.resize(yValues.size());
1477
 
        std::copy(yValues.begin(),yValues.end(),tmp.begin());
1478
 
        rawData.push_back(dummy);
1479
 
        rawData.back().swap(tmp);
1480
 
 
1481
 
        labels.push_back(xLabel);
1482
 
        labels.push_back(title);
1483
 
        
1484
 
        
1485
 
        ASSERT(xErrBars.size() == yErrBars.size()  || !xErrBars.size() || !yErrBars.size());
1486
 
        
1487
 
        if(xErrBars.size())
1488
 
        {
1489
 
                tmp.resize(xErrBars.size());
1490
 
                std::copy(xErrBars.begin(),xErrBars.end(),tmp.begin());
1491
 
                
1492
 
                rawData.push_back(dummy);
1493
 
                rawData.back().swap(tmp);
1494
 
                labels.push_back(stlStrToStlWStr(TRANS("x error")));
1495
 
        }
1496
 
        
1497
 
        if(yErrBars.size())
1498
 
        {
1499
 
                tmp.resize(yErrBars.size());
1500
 
                std::copy(yErrBars.begin(),yErrBars.end(),tmp.begin());
1501
 
                
1502
 
                rawData.push_back(dummy);
1503
 
                rawData.back().swap(tmp);
1504
 
                labels.push_back(stlStrToStlWStr(TRANS("y error")));
1505
 
        }
1506
 
}
1507
 
 
1508
 
//!Retrieve the ID of the non-overlapping region in X-Y space
1509
 
bool Plot2D::getRegionIdAtPosition(float x, float y, unsigned int &id) const
1510
 
{
1511
 
        for(unsigned int ui=0;ui<regions.size();ui++)
1512
 
        {
1513
 
                ASSERT(regions[ui].boundAxis.size() == regions[ui].bounds.size())
1514
 
 
1515
 
                bool containedInThis;
1516
 
                containedInThis=true;
1517
 
 
1518
 
                for(unsigned int uj=0; uj<regions[ui].bounds.size();uj++)
1519
 
                {
1520
 
                        unsigned int axis;
1521
 
                        axis = regions[ui].boundAxis[uj];
1522
 
                        if(axis == 0)
1523
 
                        {
1524
 
                                if(regions[ui].bounds[uj].first < x &&
1525
 
                                        regions[ui].bounds[uj].second > x )
1526
 
                                {
1527
 
                                        containedInThis=false;
1528
 
                                        break;
1529
 
                                }
1530
 
                        }
1531
 
                        else
1532
 
                        {
1533
 
                                if(regions[ui].bounds[uj].first < y &&
1534
 
                                        regions[ui].bounds[uj].second > y )
1535
 
                                {
1536
 
                                        containedInThis=false;
1537
 
                                        break;
1538
 
 
1539
 
                                }
1540
 
                        }
1541
 
                }       
1542
 
 
1543
 
                
1544
 
                if(containedInThis)     
1545
 
                {
1546
 
                        id=ui;
1547
 
                        return true;
1548
 
                }
1549
 
        }
1550
 
 
1551
 
        return false;
1552
 
}
1553
 
//!Retrieve a region using its unique ID
1554
 
void Plot2D::getRegion(unsigned int id, PlotRegion &r) const
1555
 
{
1556
 
        r = regions[regionIDHandler.getPos(id)];
1557
 
}
1558
 
 
1559
 
//!Pass the region movement information to the parent filter object
1560
 
void Plot2D::moveRegion(unsigned int regionId, unsigned int method,
1561
 
                        float newX, float newY) const
1562
 
{
1563
 
        ASSERT(false);
1564
 
}
1565
 
 
1566
 
//!Obtain limit of motion for a given region movement type
1567
 
void Plot2D::moveRegionLimit(unsigned int regionId,
1568
 
                             unsigned int movementType, float &maxX, float &maxY) const
1569
 
{
1570
 
        ASSERT(false);
1571
 
}
1572
 
        
1573