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

« back to all changes in this revision

Viewing changes to .pc/patch-caching-bug/src/backend/filters/transform.cpp

  • Committer: Package Import Robot
  • Author(s): D Haley
  • Date: 2014-01-20 06:25:38 UTC
  • mfrom: (10.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20140120062538-66167npw2uayux1r
Tags: 0.0.15-2
* Really remove unit tests (Closes: #730100)
* Adjust ac_header for mgl detection
* Apply upstream patch for cache bug
* Add missing files to debian/copyright

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      transform.cpp - Perform geometrical transform operations on point clouds
 
3
 *      Copyright (C) 2013, 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
#include "transform.h"
 
19
 
 
20
#include "filterCommon.h"
 
21
 
 
22
 
 
23
 
 
24
 
 
25
enum
 
26
{
 
27
        KEY_MODE,
 
28
        KEY_SCALEFACTOR,
 
29
        KEY_SCALEFACTOR_ANISOTROPIC,
 
30
        KEY_ORIGIN,
 
31
        KEY_TRANSFORM_SHOWORIGIN,
 
32
        KEY_ORIGINMODE,
 
33
        KEY_NOISELEVEL,
 
34
        KEY_NOISETYPE,
 
35
        KEY_ROTATE_ANGLE,
 
36
        KEY_ROTATE_AXIS,
 
37
        KEY_ORIGIN_VALUE
 
38
};
 
39
 
 
40
//Possible transform modes (scaling, rotation etc)
 
41
enum
 
42
{
 
43
        MODE_TRANSLATE,
 
44
        MODE_SCALE_ISOTROPIC,
 
45
        MODE_SCALE_ANISOTROPIC,
 
46
        MODE_ROTATE,
 
47
        MODE_VALUE_SHUFFLE,
 
48
        MODE_SPATIAL_NOISE,
 
49
        MODE_TRANSLATE_VALUE,
 
50
        MODE_ENUM_END
 
51
};
 
52
 
 
53
//!Possible mode for selection of origin in transform filter
 
54
enum
 
55
{
 
56
        ORIGINMODE_SELECT,
 
57
        ORIGINMODE_CENTREBOUND,
 
58
        ORIGINMODE_MASSCENTRE,
 
59
        ORIGINMODE_END, // Not actually origin mode, just end of enum
 
60
};
 
61
 
 
62
//!Possible noise modes
 
63
enum
 
64
{
 
65
        NOISETYPE_GAUSSIAN,
 
66
        NOISETYPE_WHITE,
 
67
        NOISETYPE_END
 
68
};
 
69
 
 
70
//!Error codes
 
71
enum
 
72
{
 
73
        ERR_CALLBACK_FAIL=1,
 
74
        ERR_NOMEM
 
75
};
 
76
 
 
77
const char *TRANSFORM_MODE_STRING[] = { NTRANS("Translate"),
 
78
                                        NTRANS("Scale (isotropic)"),
 
79
                                        NTRANS("Scale (anisotropic)"),
 
80
                                        NTRANS("Rotate"),
 
81
                                        NTRANS("Value Shuffle"),
 
82
                                        NTRANS("Spatial Noise"),
 
83
                                        NTRANS("Translate Value")
 
84
                                        };
 
85
 
 
86
const char *TRANSFORM_ORIGIN_STRING[]={ 
 
87
                                        NTRANS("Specify"),
 
88
                                        NTRANS("Boundbox Centre"),
 
89
                                        NTRANS("Mass Centre")
 
90
                                        };
 
91
                                        
 
92
        
 
93
        
 
94
//=== Transform filter === 
 
95
TransformFilter::TransformFilter()
 
96
{
 
97
        COMPILE_ASSERT(THREEDEP_ARRAYSIZE(TRANSFORM_MODE_STRING) == MODE_ENUM_END);
 
98
        COMPILE_ASSERT(THREEDEP_ARRAYSIZE(TRANSFORM_ORIGIN_STRING) == ORIGINMODE_END);
 
99
 
 
100
        randGen.initTimer();
 
101
        transformMode=MODE_TRANSLATE;
 
102
        originMode=ORIGINMODE_SELECT;
 
103
        noiseType=NOISETYPE_WHITE;
 
104
        //Set up default value
 
105
        vectorParams.resize(1);
 
106
        vectorParams[0] = Point3D(0,0,0);
 
107
        
 
108
        showPrimitive=true;
 
109
        showOrigin=false;
 
110
 
 
111
        cacheOK=false;
 
112
        cache=false; 
 
113
}
 
114
 
 
115
Filter *TransformFilter::cloneUncached() const
 
116
{
 
117
        TransformFilter *p=new TransformFilter();
 
118
 
 
119
        //Copy the values
 
120
        p->vectorParams.resize(vectorParams.size());
 
121
        p->scalarParams.resize(scalarParams.size());
 
122
        
 
123
        std::copy(vectorParams.begin(),vectorParams.end(),p->vectorParams.begin());
 
124
        std::copy(scalarParams.begin(),scalarParams.end(),p->scalarParams.begin());
 
125
 
 
126
        p->showPrimitive=showPrimitive;
 
127
        p->originMode=originMode;
 
128
        p->transformMode=transformMode;
 
129
        p->showOrigin=showOrigin;
 
130
        p->noiseType=noiseType;
 
131
        //We are copying wether to cache or not,
 
132
        //not the cache itself
 
133
        p->cache=cache;
 
134
        p->cacheOK=false;
 
135
        p->userString=userString;
 
136
        return p;
 
137
}
 
138
 
 
139
size_t TransformFilter::numBytesForCache(size_t nObjects) const
 
140
{
 
141
        return nObjects*sizeof(IonHit);
 
142
}
 
143
 
 
144
DrawStreamData* TransformFilter::makeMarkerSphere(SelectionDevice* &s) const
 
145
{
 
146
        //construct a new primitive, do not cache
 
147
        DrawStreamData *drawData=new DrawStreamData;
 
148
        drawData->parent=this;
 
149
        //Add drawable components
 
150
        DrawSphere *dS = new DrawSphere;
 
151
        dS->setOrigin(vectorParams[0]);
 
152
        dS->setRadius(1);
 
153
        //FIXME: Alpha blending is all screwed up. May require more
 
154
        //advanced drawing in scene. (front-back drawing).
 
155
        //I have set alpha=1 for now.
 
156
        dS->setColour(0.2,0.2,0.8,1.0);
 
157
        dS->setLatSegments(40);
 
158
        dS->setLongSegments(40);
 
159
        dS->wantsLight=true;
 
160
        drawData->drawables.push_back(dS);
 
161
 
 
162
        s=0;
 
163
        //Set up selection "device" for user interaction
 
164
        //Note the order of s->addBinding is critical,
 
165
        //as bindings are selected by first match.
 
166
        //====
 
167
        //The object is selectable
 
168
        if (originMode == ORIGINMODE_SELECT )
 
169
        {
 
170
                dS->canSelect=true;
 
171
 
 
172
                s=new SelectionDevice(this);
 
173
                SelectionBinding b;
 
174
 
 
175
                b.setBinding(SELECT_BUTTON_LEFT,0,DRAW_SPHERE_BIND_ORIGIN,
 
176
                             BINDING_SPHERE_ORIGIN,dS->getOrigin(),dS);
 
177
                b.setInteractionMode(BIND_MODE_POINT3D_TRANSLATE);
 
178
                s->addBinding(b);
 
179
 
 
180
        }
 
181
        drawData->cached=0;     
 
182
 
 
183
        return drawData;
 
184
}
 
185
 
 
186
unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *> &dataIn,
 
187
        std::vector<const FilterStreamData *> &getOut, ProgressData &progress, bool (*callback)(bool))
 
188
{
 
189
        //use the cached copy if we have it.
 
190
        if(cacheOK)
 
191
        {
 
192
                propagateStreams(dataIn,getOut, STREAM_TYPE_IONS,false);
 
193
                propagateCache(getOut);
 
194
                return 0;
 
195
        }
 
196
 
 
197
 
 
198
        //The user is allowed to choose the mode by which the origin is computed
 
199
        //so set the origin variable depending upon this
 
200
        switch(originMode)
 
201
        {
 
202
                case ORIGINMODE_CENTREBOUND:
 
203
                {
 
204
                        BoundCube masterB;
 
205
                        masterB.setInverseLimits();
 
206
                        #pragma omp parallel for
 
207
                        for(unsigned int ui=0;ui<dataIn.size() ;ui++)
 
208
                        {
 
209
                                BoundCube thisB;
 
210
 
 
211
                                if(dataIn[ui]->getStreamType() == STREAM_TYPE_IONS)
 
212
                                {
 
213
                                        const IonStreamData* ions;
 
214
                                        ions = (const IonStreamData*)dataIn[ui];
 
215
                                        if(ions->data.size())
 
216
                                        {
 
217
                                                IonHit::getBoundCube(ions->data,thisB);
 
218
                                                #pragma omp critical
 
219
                                                masterB.expand(thisB);
 
220
                                        }
 
221
                                }
 
222
                        }
 
223
 
 
224
                        if(!masterB.isValid())
 
225
                                vectorParams[0]=Point3D(0,0,0);
 
226
                        else
 
227
                                vectorParams[0]=masterB.getCentroid();
 
228
                        break;
 
229
                }
 
230
                case ORIGINMODE_MASSCENTRE:
 
231
                {
 
232
                        Point3D massCentre(0,0,0);
 
233
                        size_t numCentres=0;
 
234
                        #pragma omp parallel for
 
235
                        for(unsigned int ui=0;ui<dataIn.size() ;ui++)
 
236
                        {
 
237
                                Point3D massContrib;
 
238
                                if(dataIn[ui]->getStreamType() == STREAM_TYPE_IONS)
 
239
                                {
 
240
                                        const IonStreamData* ions;
 
241
                                        ions = (const IonStreamData*)dataIn[ui];
 
242
 
 
243
                                        if(ions->data.size())
 
244
                                        {
 
245
                                                Point3D thisCentre;
 
246
                                                thisCentre=Point3D(0,0,0);
 
247
                                                for(unsigned int uj=0;uj<ions->data.size();uj++)
 
248
                                                        thisCentre+=ions->data[uj].getPosRef();
 
249
                                                massContrib=thisCentre*1.0/(float)ions->data.size();
 
250
                                                #pragma omp critical
 
251
                                                massCentre+=massContrib;
 
252
                                                numCentres++;
 
253
                                        }
 
254
                                }
 
255
                        }
 
256
                        vectorParams[0]=massCentre*1.0/(float)numCentres;
 
257
                        break;
 
258
 
 
259
                }
 
260
                case ORIGINMODE_SELECT:
 
261
                        break;
 
262
                default:
 
263
                        ASSERT(false);
 
264
        }
 
265
 
 
266
        //If the user is using a transform mode that requires origin selection 
 
267
        if(showOrigin && (transformMode == MODE_ROTATE ||
 
268
                        transformMode == MODE_SCALE_ANISOTROPIC || 
 
269
                        transformMode == MODE_SCALE_ISOTROPIC) )
 
270
        {
 
271
                SelectionDevice *s;
 
272
                DrawStreamData *d=makeMarkerSphere(s);
 
273
                if(s)
 
274
                        devices.push_back(s);
 
275
                if(cache)
 
276
                {
 
277
                        d->cached=1;
 
278
                        filterOutputs.push_back(d);
 
279
                }
 
280
                else
 
281
                        d->cached=0;
 
282
                
 
283
                getOut.push_back(d);
 
284
        }
 
285
                        
 
286
        //Apply the transformations to the incoming 
 
287
        //ion streams, generating new outgoing ion streams with
 
288
        //the modified positions
 
289
        size_t totalSize=numElements(dataIn);
 
290
 
 
291
        //If there are no ions, nothing to do.
 
292
        // just copy non-ion input to output 
 
293
        if(!totalSize)
 
294
        {
 
295
                for(unsigned int ui=0;ui<dataIn.size();ui++)
 
296
                {
 
297
                        if(dataIn[ui]->getStreamType() == STREAM_TYPE_IONS)
 
298
                                continue;
 
299
 
 
300
                        getOut.push_back(dataIn[ui]);
 
301
                }
 
302
                return 0;
 
303
        }
 
304
 
 
305
        if( transformMode != MODE_VALUE_SHUFFLE)
 
306
        {
 
307
                //Dont cross the streams. Why? It would be bad.
 
308
                //  - Im fuzzy on the whole good-bad thing, what do you mean bad?"
 
309
                //  - Every ion in the data body can be operated on independently.
 
310
                //
 
311
                //  OK, important safety tip.
 
312
                size_t n=0;
 
313
                for(unsigned int ui=0;ui<dataIn.size() ;ui++)
 
314
                {
 
315
                        switch(transformMode)
 
316
                        {
 
317
                                case MODE_SCALE_ISOTROPIC:
 
318
                                {
 
319
                                        //We are going to scale the incoming point data
 
320
                                        //around the specified origin.
 
321
                                        ASSERT(vectorParams.size() == 1);
 
322
                                        ASSERT(scalarParams.size() == 1);
 
323
                                        float scaleFactor=scalarParams[0];
 
324
                                        Point3D origin=vectorParams[0];
 
325
 
 
326
                                        switch(dataIn[ui]->getStreamType())
 
327
                                        {
 
328
                                                case STREAM_TYPE_IONS:
 
329
                                                {
 
330
                                                        //Set up scaling output ion stream 
 
331
                                                        IonStreamData *d=new IonStreamData;
 
332
                                                        d->parent=this;
 
333
                                                        const IonStreamData *src = (const IonStreamData *)dataIn[ui];
 
334
 
 
335
                                                        try
 
336
                                                        {
 
337
                                                                d->data.resize(src->data.size());
 
338
                                                        }
 
339
                                                        catch(std::bad_alloc)
 
340
                                                        {
 
341
                                                                delete d;
 
342
                                                                return ERR_NOMEM;
 
343
                                                        }
 
344
                                                        d->r = src->r;
 
345
                                                        d->g = src->g;
 
346
                                                        d->b = src->b;
 
347
                                                        d->a = src->a;
 
348
                                                        d->ionSize = src->ionSize;
 
349
                                                        d->valueType=src->valueType;
 
350
 
 
351
                                                        ASSERT(src->data.size() <= totalSize);
 
352
                                                        unsigned int curProg=NUM_CALLBACK;
 
353
#ifdef _OPENMP
 
354
                                                        //Parallel version
 
355
                                                        bool spin=false;
 
356
                                                        #pragma omp parallel for shared(spin)
 
357
                                                        for(unsigned int ui=0;ui<src->data.size();ui++)
 
358
                                                        {
 
359
                                                                unsigned int thisT=omp_get_thread_num();
 
360
                                                                if(spin)
 
361
                                                                        continue;
 
362
 
 
363
                                                                if(!curProg--)
 
364
                                                                {
 
365
                                                                        #pragma omp critical
 
366
                                                                        {
 
367
                                                                        n+=NUM_CALLBACK;
 
368
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
369
                                                                        }
 
370
 
 
371
 
 
372
                                                                        if(thisT == 0)
 
373
                                                                        {
 
374
                                                                                if(!(*callback)(false))
 
375
                                                                                        spin=true;
 
376
                                                                        }
 
377
                                                                }
 
378
 
 
379
 
 
380
                                                                //set the position for the given ion
 
381
                                                                d->data[ui].setPos((src->data[ui].getPosRef() - origin)*scaleFactor+origin);
 
382
                                                                d->data[ui].setMassToCharge(src->data[ui].getMassToCharge());
 
383
                                                        }
 
384
                                                        if(spin)
 
385
                                                        {                       
 
386
                                                                delete d;
 
387
                                                                return ERR_CALLBACK_FAIL;
 
388
                                                        }
 
389
 
 
390
#else
 
391
                                                        //Single threaded version
 
392
                                                        size_t pos=0;
 
393
                                                        //Copy across the ions into the target
 
394
                                                        for(vector<IonHit>::const_iterator it=src->data.begin();
 
395
                                                                       it!=src->data.end(); ++it)
 
396
                                                        {
 
397
                                                                //set the position for the given ion
 
398
                                                                d->data[pos].setPos((it->getPosRef() - origin)*scaleFactor+origin);
 
399
                                                                d->data[pos].setMassToCharge(it->getMassToCharge());
 
400
                                                                //update progress every CALLBACK ions
 
401
                                                                if(!curProg--)
 
402
                                                                {
 
403
                                                                        n+=NUM_CALLBACK;
 
404
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
405
                                                                        if(!(*callback)(false))
 
406
                                                                        {
 
407
                                                                                delete d;
 
408
                                                                                return ERR_CALLBACK_FAIL;
 
409
                                                                        }
 
410
                                                                        curProg=NUM_CALLBACK;
 
411
                                                                }
 
412
                                                                pos++;
 
413
                                                        }
 
414
 
 
415
                                                        ASSERT(pos == d->data.size());
 
416
#endif
 
417
                                                        ASSERT(d->data.size() == src->data.size());
 
418
 
 
419
                                                        if(cache)
 
420
                                                        {
 
421
                                                                d->cached=1;
 
422
                                                                filterOutputs.push_back(d);
 
423
                                                                cacheOK=true;
 
424
                                                        }
 
425
                                                        else
 
426
                                                                d->cached=0;
 
427
 
 
428
                                                        getOut.push_back(d);
 
429
                                                        break;
 
430
                                                }
 
431
                                                default:
 
432
                                                        //Just copy across the ptr, if we are unfamiliar with this type
 
433
                                                        getOut.push_back(dataIn[ui]);   
 
434
                                                        break;
 
435
                                        }
 
436
                                        break;
 
437
                                }
 
438
                                case MODE_SCALE_ANISOTROPIC:
 
439
                                {
 
440
                                        //We are going to scale the incoming point data
 
441
                                        //around the specified origin.
 
442
                                        ASSERT(vectorParams.size() == 2);
 
443
                                        
 
444
                                        
 
445
                                        Point3D origin=vectorParams[0];
 
446
                                        Point3D transformVec=vectorParams[1];
 
447
                                        switch(dataIn[ui]->getStreamType())
 
448
                                        {
 
449
                                                case STREAM_TYPE_IONS:
 
450
                                                {
 
451
                                                        //Set up scaling output ion stream 
 
452
                                                        IonStreamData *d=new IonStreamData;
 
453
                                                        d->parent=this;
 
454
                                                        const IonStreamData *src = (const IonStreamData *)dataIn[ui];
 
455
 
 
456
                                                        try
 
457
                                                        {
 
458
                                                                d->data.resize(src->data.size());
 
459
                                                        }
 
460
                                                        catch(std::bad_alloc)
 
461
                                                        {
 
462
                                                                delete d;
 
463
                                                                return ERR_NOMEM;
 
464
                                                        }
 
465
                                                        d->r = src->r;
 
466
                                                        d->g = src->g;
 
467
                                                        d->b = src->b;
 
468
                                                        d->a = src->a;
 
469
                                                        d->ionSize = src->ionSize;
 
470
                                                        d->valueType=src->valueType;
 
471
 
 
472
                                                        ASSERT(src->data.size() <= totalSize);
 
473
                                                        unsigned int curProg=NUM_CALLBACK;
 
474
#ifdef _OPENMP
 
475
                                                        //Parallel version
 
476
                                                        bool spin=false;
 
477
                                                        #pragma omp parallel for shared(spin)
 
478
                                                        for(unsigned int ui=0;ui<src->data.size();ui++)
 
479
                                                        {
 
480
                                                                unsigned int thisT=omp_get_thread_num();
 
481
                                                                if(spin)
 
482
                                                                        continue;
 
483
 
 
484
                                                                if(!curProg--)
 
485
                                                                {
 
486
                                                                        #pragma omp critical
 
487
                                                                        {
 
488
                                                                        n+=NUM_CALLBACK;
 
489
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
490
                                                                        }
 
491
 
 
492
 
 
493
                                                                        if(thisT == 0)
 
494
                                                                        {
 
495
                                                                                if(!(*callback)(false))
 
496
                                                                                        spin=true;
 
497
                                                                        }
 
498
                                                                }
 
499
 
 
500
 
 
501
                                                                //set the position for the given ion
 
502
                                                                d->data[ui].setPos((src->data[ui].getPosRef() - origin)*transformVec+origin);
 
503
                                                                d->data[ui].setMassToCharge(src->data[ui].getMassToCharge());
 
504
                                                        }
 
505
                                                        if(spin)
 
506
                                                        {                       
 
507
                                                                delete d;
 
508
                                                                return ERR_CALLBACK_FAIL;
 
509
                                                        }
 
510
 
 
511
#else
 
512
                                                        //Single threaded version
 
513
                                                        size_t pos=0;
 
514
                                                        //Copy across the ions into the target
 
515
                                                        for(vector<IonHit>::const_iterator it=src->data.begin();
 
516
                                                                       it!=src->data.end(); ++it)
 
517
                                                        {
 
518
                                                                //set the position for the given ion
 
519
                                                                d->data[pos].setPos((it->getPosRef() - origin)*transformVec+origin);
 
520
                                                                d->data[pos].setMassToCharge(it->getMassToCharge());
 
521
                                                                //update progress every CALLBACK ions
 
522
                                                                if(!curProg--)
 
523
                                                                {
 
524
                                                                        n+=NUM_CALLBACK;
 
525
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
526
                                                                        if(!(*callback)(false))
 
527
                                                                        {
 
528
                                                                                delete d;
 
529
                                                                                return ERR_CALLBACK_FAIL;
 
530
                                                                        }
 
531
                                                                        curProg=NUM_CALLBACK;
 
532
                                                                }
 
533
                                                                pos++;
 
534
                                                        }
 
535
 
 
536
                                                        ASSERT(pos == d->data.size());
 
537
#endif
 
538
                                                        ASSERT(d->data.size() == src->data.size());
 
539
 
 
540
                                                        if(cache)
 
541
                                                        {
 
542
                                                                d->cached=1;
 
543
                                                                filterOutputs.push_back(d);
 
544
                                                                cacheOK=true;
 
545
                                                        }
 
546
                                                        else
 
547
                                                                d->cached=0;
 
548
 
 
549
                                                        getOut.push_back(d);
 
550
                                                        break;
 
551
                                                }
 
552
                                                default:
 
553
                                                        //Just copy across the ptr, if we are unfamiliar with this type
 
554
                                                        getOut.push_back(dataIn[ui]);   
 
555
                                                        break;
 
556
                                        }
 
557
 
 
558
 
 
559
                                        
 
560
 
 
561
                                        break;
 
562
                                }
 
563
                                case MODE_TRANSLATE:
 
564
                                {
 
565
                                        //We are going to scale the incoming point data
 
566
                                        //around the specified origin.
 
567
                                        ASSERT(vectorParams.size() == 1);
 
568
                                        ASSERT(scalarParams.size() == 0);
 
569
                                        Point3D origin =vectorParams[0];
 
570
                                        switch(dataIn[ui]->getStreamType())
 
571
                                        {
 
572
                                                case STREAM_TYPE_IONS:
 
573
                                                {
 
574
                                                        //Set up scaling output ion stream 
 
575
                                                        IonStreamData *d=new IonStreamData;
 
576
                                                        d->parent=this;
 
577
                                                        
 
578
                                                        const IonStreamData *src = (const IonStreamData *)dataIn[ui];
 
579
                                                        try
 
580
                                                        {
 
581
                                                                d->data.resize(src->data.size());
 
582
                                                        }
 
583
                                                        catch(std::bad_alloc)
 
584
                                                        {
 
585
                                                                delete d;
 
586
                                                                return ERR_NOMEM;
 
587
                                                        }
 
588
                                                        d->r = src->r;
 
589
                                                        d->g = src->g;
 
590
                                                        d->b = src->b;
 
591
                                                        d->a = src->a;
 
592
                                                        d->ionSize = src->ionSize;
 
593
                                                        d->valueType=src->valueType;
 
594
                                                        
 
595
                                                        ASSERT(src->data.size() <= totalSize);
 
596
                                                        unsigned int curProg=NUM_CALLBACK;
 
597
#ifdef _OPENMP
 
598
                                                        //Parallel version
 
599
                                                        bool spin=false;
 
600
#pragma omp parallel for shared(spin)
 
601
                                                        for(unsigned int ui=0;ui<src->data.size();ui++)
 
602
                                                        {
 
603
                                                                unsigned int thisT=omp_get_thread_num();
 
604
                                                                if(spin)
 
605
                                                                        continue;
 
606
                                                                
 
607
                                                                if(!curProg--)
 
608
                                                                {
 
609
#pragma omp critical
 
610
                                                                        {
 
611
                                                                                n+=NUM_CALLBACK;
 
612
                                                                                progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
613
                                                                        }
 
614
                                                                        
 
615
                                                                        
 
616
                                                                        if(thisT == 0)
 
617
                                                                        {
 
618
                                                                                if(!(*callback)(false))
 
619
                                                                                        spin=true;
 
620
                                                                        }
 
621
                                                                }
 
622
                                                                
 
623
                                                                
 
624
                                                                //set the position for the given ion
 
625
                                                                d->data[ui].setPos((src->data[ui].getPosRef() - origin));
 
626
                                                                d->data[ui].setMassToCharge(src->data[ui].getMassToCharge());
 
627
                                                        }
 
628
                                                        if(spin)
 
629
                                                        {                       
 
630
                                                                delete d;
 
631
                                                                return ERR_CALLBACK_FAIL;
 
632
                                                        }
 
633
                                                        
 
634
#else
 
635
                                                        //Single threaded version
 
636
                                                        size_t pos=0;
 
637
                                                        //Copy across the ions into the target
 
638
                                                        for(vector<IonHit>::const_iterator it=src->data.begin();
 
639
                                                                it!=src->data.end(); ++it)
 
640
                                                        {
 
641
                                                                //set the position for the given ion
 
642
                                                                d->data[pos].setPos((it->getPosRef() - origin));
 
643
                                                                d->data[pos].setMassToCharge(it->getMassToCharge());
 
644
                                                                //update progress every CALLBACK ions
 
645
                                                                if(!curProg--)
 
646
                                                                {
 
647
                                                                        n+=NUM_CALLBACK;
 
648
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
649
                                                                        if(!(*callback)(false))
 
650
                                                                        {
 
651
                                                                                delete d;
 
652
                                                                                return ERR_CALLBACK_FAIL;
 
653
                                                                        }
 
654
                                                                        curProg=NUM_CALLBACK;
 
655
                                                                }
 
656
                                                                pos++;
 
657
                                                        }
 
658
                                                        ASSERT(pos == d->data.size());
 
659
#endif
 
660
                                                        ASSERT(d->data.size() == src->data.size());
 
661
                                                        if(cache)
 
662
                                                        {
 
663
                                                                d->cached=1;
 
664
                                                                filterOutputs.push_back(d);
 
665
                                                                cacheOK=true;
 
666
                                                        }
 
667
                                                        else
 
668
                                                                d->cached=0;
 
669
                                                        
 
670
                                                        getOut.push_back(d);
 
671
                                                        break;
 
672
                                                }
 
673
                                                default:
 
674
                                                        //Just copy across the ptr, if we are unfamiliar with this type
 
675
                                                        getOut.push_back(dataIn[ui]);   
 
676
                                                        break;
 
677
                                        }
 
678
                                        break;
 
679
                                }
 
680
                                case MODE_TRANSLATE_VALUE:
 
681
                                {
 
682
                                        //We are going to scale the incoming point data
 
683
                                        //around the specified origin.
 
684
                                        ASSERT(vectorParams.size() == 0);
 
685
                                        ASSERT(scalarParams.size() == 1);
 
686
                                        float origin =scalarParams[0];
 
687
                                        switch(dataIn[ui]->getStreamType())
 
688
                                        {
 
689
                                                case STREAM_TYPE_IONS:
 
690
                                                {
 
691
                                                        //Set up scaling output ion stream 
 
692
                                                        IonStreamData *d=new IonStreamData;
 
693
                                                        d->parent=this;
 
694
                                                        
 
695
                                                        const IonStreamData *src = (const IonStreamData *)dataIn[ui];
 
696
                                                        try
 
697
                                                        {
 
698
                                                                d->data.resize(src->data.size());
 
699
                                                        }
 
700
                                                        catch(std::bad_alloc)
 
701
                                                        {
 
702
                                                                delete d;
 
703
                                                                return ERR_NOMEM;
 
704
                                                        }
 
705
                                                        d->r = src->r;
 
706
                                                        d->g = src->g;
 
707
                                                        d->b = src->b;
 
708
                                                        d->a = src->a;
 
709
                                                        d->ionSize = src->ionSize;
 
710
                                                        d->valueType=src->valueType;
 
711
                                                        
 
712
                                                        ASSERT(src->data.size() <= totalSize);
 
713
                                                        unsigned int curProg=NUM_CALLBACK;
 
714
#ifdef _OPENMP
 
715
                                                        //Parallel version
 
716
                                                        bool spin=false;
 
717
#pragma omp parallel for shared(spin)
 
718
                                                        for(unsigned int ui=0;ui<src->data.size();ui++)
 
719
                                                        {
 
720
                                                                unsigned int thisT=omp_get_thread_num();
 
721
                                                                if(spin)
 
722
                                                                        continue;
 
723
                                                                
 
724
                                                                if(!curProg--)
 
725
                                                                {
 
726
#pragma omp critical
 
727
                                                                        {
 
728
                                                                                n+=NUM_CALLBACK;
 
729
                                                                                progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
730
                                                                        }
 
731
                                                                        
 
732
                                                                        
 
733
                                                                        if(thisT == 0)
 
734
                                                                        {
 
735
                                                                                if(!(*callback)(false))
 
736
                                                                                        spin=true;
 
737
                                                                        }
 
738
                                                                }
 
739
                                                                
 
740
                                                                
 
741
                                                                //set the position for the given ion
 
742
                                                                d->data[ui].setPos((src->data[ui].getPosRef()));
 
743
                                                                d->data[ui].setMassToCharge(src->data[ui].getMassToCharge()+origin);
 
744
                                                        }
 
745
                                                        if(spin)
 
746
                                                        {                       
 
747
                                                                delete d;
 
748
                                                                return ERR_CALLBACK_FAIL;
 
749
                                                        }
 
750
                                                        
 
751
#else
 
752
                                                        //Single threaded version
 
753
                                                        size_t pos=0;
 
754
                                                        //Copy across the ions into the target
 
755
                                                        for(vector<IonHit>::const_iterator it=src->data.begin();
 
756
                                                                it!=src->data.end(); ++it)
 
757
                                                        {
 
758
                                                                //set the position for the given ion
 
759
                                                                d->data[pos].setPos((it->getPosRef()));
 
760
                                                                d->data[pos].setMassToCharge(it->getMassToCharge() + origin);
 
761
                                                                //update progress every CALLBACK ions
 
762
                                                                if(!curProg--)
 
763
                                                                {
 
764
                                                                        n+=NUM_CALLBACK;
 
765
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
766
                                                                        if(!(*callback)(false))
 
767
                                                                        {
 
768
                                                                                delete d;
 
769
                                                                                return ERR_CALLBACK_FAIL;
 
770
                                                                        }
 
771
                                                                        curProg=NUM_CALLBACK;
 
772
                                                                }
 
773
                                                                pos++;
 
774
                                                        }
 
775
                                                        ASSERT(pos == d->data.size());
 
776
#endif
 
777
                                                        ASSERT(d->data.size() == src->data.size());
 
778
                                                        if(cache)
 
779
                                                        {
 
780
                                                                d->cached=1;
 
781
                                                                filterOutputs.push_back(d);
 
782
                                                                cacheOK=true;
 
783
                                                        }
 
784
                                                        else
 
785
                                                                d->cached=0;
 
786
                                                        
 
787
                                                        getOut.push_back(d);
 
788
                                                        break;
 
789
                                                }
 
790
                                                default:
 
791
                                                        //Just copy across the ptr, if we are unfamiliar with this type
 
792
                                                        getOut.push_back(dataIn[ui]);   
 
793
                                                        break;
 
794
                                        }
 
795
                                        break;
 
796
                                }
 
797
                                case MODE_ROTATE:
 
798
                                {
 
799
                                        Point3D origin=vectorParams[0];
 
800
                                        switch(dataIn[ui]->getStreamType())
 
801
                                        {
 
802
                                                case STREAM_TYPE_IONS:
 
803
                                                {
 
804
 
 
805
                                                        const IonStreamData *src = (const IonStreamData *)dataIn[ui];
 
806
                                                        //Set up output ion stream 
 
807
                                                        IonStreamData *d=new IonStreamData;
 
808
                                                        d->parent=this;
 
809
                                                        try
 
810
                                                        {
 
811
                                                                d->data.resize(src->data.size());
 
812
                                                        }
 
813
                                                        catch(std::bad_alloc)
 
814
                                                        {
 
815
                                                                delete d;
 
816
                                                                return ERR_NOMEM;
 
817
                                                        }
 
818
                                                        d->r = src->r;
 
819
                                                        d->g = src->g;
 
820
                                                        d->b = src->b;
 
821
                                                        d->a = src->a;
 
822
                                                        d->ionSize = src->ionSize;
 
823
                                                        d->valueType=src->valueType;
 
824
 
 
825
                                                        //We are going to rotate the incoming point data
 
826
                                                        //around the specified origin.
 
827
                                                        ASSERT(vectorParams.size() == 2);
 
828
                                                        ASSERT(scalarParams.size() == 1);
 
829
                                                        Point3D axis =vectorParams[1];
 
830
                                                        axis.normalise();
 
831
                                                        float angle=scalarParams[0]*M_PI/180.0f;
 
832
 
 
833
                                                        unsigned int curProg=NUM_CALLBACK;
 
834
 
 
835
                                                        Point3f rotVec,p;
 
836
                                                        rotVec.fx=axis[0];
 
837
                                                        rotVec.fy=axis[1];
 
838
                                                        rotVec.fz=axis[2];
 
839
 
 
840
                                                        Quaternion q1;
 
841
 
 
842
                                                        //Generate the rotating quaternion
 
843
                                                        quat_get_rot_quat(&rotVec,-angle,&q1);
 
844
                                                        ASSERT(src->data.size() <= totalSize);
 
845
 
 
846
 
 
847
                                                        size_t pos=0;
 
848
 
 
849
                                                        //TODO: Parallelise rotation
 
850
                                                        //Copy across the ions into the target
 
851
                                                        for(vector<IonHit>::const_iterator it=src->data.begin();
 
852
                                                                       it!=src->data.end(); ++it)
 
853
                                                        {
 
854
                                                                p.fx=it->getPosRef()[0]-origin[0];
 
855
                                                                p.fy=it->getPosRef()[1]-origin[1];
 
856
                                                                p.fz=it->getPosRef()[2]-origin[2];
 
857
                                                                quat_rot_apply_quat(&p,&q1);
 
858
                                                                //set the position for the given ion
 
859
                                                                d->data[pos].setPos(p.fx+origin[0],
 
860
                                                                                p.fy+origin[1],p.fz+origin[2]);
 
861
                                                                d->data[pos].setMassToCharge(it->getMassToCharge());
 
862
                                                                //update progress every CALLBACK ions
 
863
                                                                if(!curProg--)
 
864
                                                                {
 
865
                                                                        n+=NUM_CALLBACK;
 
866
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 
867
                                                                        if(!(*callback)(false))
 
868
                                                                        {
 
869
                                                                                delete d;
 
870
                                                                                return ERR_CALLBACK_FAIL;
 
871
                                                                        }
 
872
                                                                        curProg=NUM_CALLBACK;
 
873
                                                                }
 
874
                                                                pos++;
 
875
                                                        }
 
876
 
 
877
                                                        ASSERT(d->data.size() == src->data.size());
 
878
                                                        if(cache)
 
879
                                                        {
 
880
                                                                d->cached=1;
 
881
                                                                filterOutputs.push_back(d);
 
882
                                                                cacheOK=true;
 
883
                                                        }
 
884
                                                        else
 
885
                                                                d->cached=0;
 
886
                                                        
 
887
                                                        getOut.push_back(d);
 
888
                                                        break;
 
889
                                                }
 
890
                                                default:
 
891
                                                        getOut.push_back(dataIn[ui]);
 
892
                                                        break;
 
893
                                        }
 
894
 
 
895
                                        break;
 
896
                                }
 
897
                                case MODE_SPATIAL_NOISE:
 
898
                                {
 
899
                                        ASSERT(scalarParams.size() ==1 &&
 
900
                                                        vectorParams.size()==0);
 
901
                                        switch(dataIn[ui]->getStreamType())
 
902
                                        {
 
903
                                                case STREAM_TYPE_IONS:
 
904
                                                {
 
905
                                                        //Set up scaling output ion stream 
 
906
                                                        IonStreamData *d=new IonStreamData;
 
907
                                                        d->parent=this;
 
908
 
 
909
                                                        const IonStreamData *src = (const IonStreamData *)dataIn[ui];
 
910
                                                        try
 
911
                                                        {
 
912
                                                                d->data.resize(src->data.size());
 
913
                                                        }
 
914
                                                        catch(std::bad_alloc)
 
915
                                                        {
 
916
                                                                delete d;
 
917
                                                                return ERR_NOMEM;
 
918
                                                        }
 
919
                                                        d->r = src->r;
 
920
                                                        d->g = src->g;
 
921
                                                        d->b = src->b;
 
922
                                                        d->a = src->a;
 
923
                                                        d->ionSize = src->ionSize;
 
924
                                                        d->valueType=src->valueType;
 
925
 
 
926
                                                        float scaleFactor=scalarParams[0];
 
927
                                                        ASSERT(src->data.size() <= totalSize);
 
928
                                                        unsigned int curProg=NUM_CALLBACK;
 
929
 
 
930
                                                        //NOTE: This *cannot* be parallelised without parallelising the random
 
931
                                                        // number generator safely. If using multiple random number generators,
 
932
                                                        // one would need to ensure sufficient entropy in EACH generator. This
 
933
                                                        // is not trivial to prove, and so has not been done here. Bootstrapping
 
934
                                                        // each random number generator using non-random seeds could be problematic
 
935
                                                        // same as feeding back a random number into other rng instances 
 
936
                                                        //
 
937
                                                        // One solution is to use the unix /dev/urandom interface or the windows
 
938
                                                        // cryptographic API, alternatively use the TR1 header's Mersenne twister with
 
939
                                                        // multi-seeding:
 
940
                                                        //  http://theo.phys.sci.hiroshima-u.ac.jp/~ishikawa/PRNG/mt_stream_en.html
 
941
                                                        switch(noiseType)
 
942
                                                        {
 
943
                                                                case NOISETYPE_WHITE:
 
944
                                                                {
 
945
                                                                        for(size_t ui=0;ui<src->data.size();ui++)
 
946
                                                                        {
 
947
                                                                                Point3D pt;
 
948
 
 
949
                                                                                pt.setValue(0,randGen.genUniformDev()-0.5f);
 
950
                                                                                pt.setValue(1,randGen.genUniformDev()-0.5f);
 
951
                                                                                pt.setValue(2,randGen.genUniformDev()-0.5f);
 
952
 
 
953
                                                                                pt*=scaleFactor;
 
954
 
 
955
                                                                                //set the position for the given ion
 
956
                                                                                d->data[ui].setPos(src->data[ui].getPosRef() + pt);
 
957
                                                                                d->data[ui].setMassToCharge(src->data[ui].getMassToCharge());
 
958
                                                                                
 
959
                                                                                
 
960
                                                                                if(!curProg--)
 
961
                                                                                {
 
962
                                                                                        curProg=NUM_CALLBACK;
 
963
                                                                                        progress.filterProgress= (unsigned int)((float)(ui)/((float)totalSize)*100.0f);
 
964
                                                                                        if(!(*callback)(false))
 
965
                                                                                        {
 
966
                                                                                                delete d;
 
967
                                                                                                return ERR_CALLBACK_FAIL;
 
968
                                                                                        }
 
969
                                                                                }
 
970
                                                                        }
 
971
                                                                        break;
 
972
                                                                }
 
973
                                                                case NOISETYPE_GAUSSIAN:
 
974
                                                                {
 
975
                                                                        for(size_t ui=0;ui<src->data.size();ui++)
 
976
                                                                        {
 
977
                                                                                Point3D pt;
 
978
 
 
979
                                                                                pt.setValue(0,randGen.genGaussDev());
 
980
                                                                                pt.setValue(1,randGen.genGaussDev());
 
981
                                                                                pt.setValue(2,randGen.genGaussDev());
 
982
 
 
983
                                                                                pt*=scaleFactor;
 
984
 
 
985
                                                                                //set the position for the given ion
 
986
                                                                                d->data[ui].setPos(src->data[ui].getPosRef() + pt);
 
987
                                                                                d->data[ui].setMassToCharge(src->data[ui].getMassToCharge());
 
988
                                                                                
 
989
                                                                                
 
990
                                                                                if(!curProg--)
 
991
                                                                                {
 
992
                                                                                        curProg=NUM_CALLBACK;
 
993
                                                                                        progress.filterProgress= (unsigned int)((float)(ui)/((float)totalSize)*100.0f);
 
994
                                                                                        if(!(*callback)(false))
 
995
                                                                                        {
 
996
                                                                                                delete d;
 
997
                                                                                                return ERR_CALLBACK_FAIL;
 
998
                                                                                        }
 
999
                                                                                }
 
1000
                                                                        }
 
1001
 
 
1002
                                                                        break;
 
1003
                                                                }
 
1004
                                                        }
 
1005
                                                        
 
1006
                                                        ASSERT(d->data.size() == src->data.size());
 
1007
                                                        if(cache)
 
1008
                                                        {
 
1009
                                                                d->cached=1;
 
1010
                                                                filterOutputs.push_back(d);
 
1011
                                                                cacheOK=true;
 
1012
                                                        }
 
1013
                                                        else
 
1014
                                                                d->cached=0;
 
1015
                                                        
 
1016
                                                        getOut.push_back(d);
 
1017
                                                        break;
 
1018
                                                }
 
1019
                                                default:
 
1020
                                                        getOut.push_back(dataIn[ui]);
 
1021
                                                        break;
 
1022
                                        }
 
1023
                                        break;
 
1024
                                }
 
1025
                        }
 
1026
                }
 
1027
        }
 
1028
        else
 
1029
        {
 
1030
                progress.step=1;
 
1031
                progress.filterProgress=0;
 
1032
                progress.stepName=TRANS("Collate");
 
1033
                progress.maxStep=3;
 
1034
                if(!(*callback)(true))
 
1035
                        return ERR_CALLBACK_FAIL;
 
1036
                //we have to cross the streams (I thought that was bad?) 
 
1037
                //  - Each dataset is no longer independent, and needs to
 
1038
                //  be mixed with the other datasets. Bugger; sounds mem. expensive.
 
1039
                
 
1040
                //Set up output ion stream 
 
1041
                IonStreamData *d=new IonStreamData;
 
1042
                d->parent=this;
 
1043
                
 
1044
                //TODO: Better output colouring/size
 
1045
                //Set up ion metadata
 
1046
                d->r = 0.5;
 
1047
                d->g = 0.5;
 
1048
                d->b = 0.5;
 
1049
                d->a = 0.5;
 
1050
                d->ionSize = 2.0;
 
1051
                d->valueType=TRANS("Mass-to-Charge (amu/e)");
 
1052
 
 
1053
                size_t curPos=0;
 
1054
                
 
1055
                vector<float> massData;
 
1056
 
 
1057
                //TODO: Ouch. Memory intensive -- could do a better job
 
1058
                //of this?
 
1059
                try
 
1060
                {
 
1061
                        massData.resize(totalSize);
 
1062
                        d->data.resize(totalSize);
 
1063
                }
 
1064
                catch(std::bad_alloc)
 
1065
                {
 
1066
                        return ERR_NOMEM; 
 
1067
                }
 
1068
 
 
1069
                //merge the datasets
 
1070
                for(size_t ui=0;ui<dataIn.size() ;ui++)
 
1071
                {
 
1072
                        switch(dataIn[ui]->getStreamType())
 
1073
                        {
 
1074
                                case STREAM_TYPE_IONS:
 
1075
                                {
 
1076
                
 
1077
                                        const IonStreamData *src = (const IonStreamData *)dataIn[ui];
 
1078
 
 
1079
                                        //Loop through the ions in this stream, and copy its data value
 
1080
#pragma omp parallel for shared(massData,d,curPos,src) 
 
1081
                                        for(size_t uj=0;uj<src->data.size();uj++)
 
1082
                                        {
 
1083
                                                massData[uj+curPos] = src->data[uj].getMassToCharge();
 
1084
                                                d->data[uj+curPos].setPos(src->data[uj].getPos());
 
1085
                                        }
 
1086
                                
 
1087
                                        if(!(*callback)(true))
 
1088
                                        {
 
1089
                                                delete d;
 
1090
                                                return ERR_CALLBACK_FAIL;
 
1091
                                        }
 
1092
 
 
1093
                                        curPos+=src->data.size();
 
1094
                                        break;
 
1095
                                }
 
1096
                                default:
 
1097
                                        getOut.push_back(dataIn[ui]);
 
1098
                                        break;
 
1099
                        }
 
1100
                }
 
1101
 
 
1102
        
 
1103
                progress.step=2;
 
1104
                progress.filterProgress=0;
 
1105
                progress.stepName=TRANS("Shuffle");
 
1106
                if(!(*callback)(true))
 
1107
                {
 
1108
                        delete d;
 
1109
                        return ERR_CALLBACK_FAIL;
 
1110
                }
 
1111
                //Shuffle the value data.TODO: callback functor 
 
1112
                std::random_shuffle(massData.begin(),massData.end());
 
1113
                if(!(*callback)(true))
 
1114
                {
 
1115
                        delete d;
 
1116
                        return ERR_CALLBACK_FAIL;
 
1117
                }
 
1118
 
 
1119
                progress.step=3;
 
1120
                progress.filterProgress=0;
 
1121
                progress.stepName=TRANS("Splice");
 
1122
                if(!(*callback)(true))
 
1123
                {
 
1124
                        delete d;
 
1125
                        return ERR_CALLBACK_FAIL;
 
1126
                }
 
1127
                
 
1128
                
 
1129
 
 
1130
                //Set the output data by splicing together the
 
1131
                //shuffled values and the original position info
 
1132
#pragma omp parallel for shared(d,massData) 
 
1133
                for(size_t uj=0;uj<totalSize;uj++)
 
1134
                        d->data[uj].setMassToCharge(massData[uj]);
 
1135
                
 
1136
                if(!(*callback)(true))
 
1137
                {
 
1138
                        delete d;
 
1139
                        return ERR_CALLBACK_FAIL;
 
1140
                }
 
1141
 
 
1142
                massData.clear();
 
1143
 
 
1144
                if(cache)
 
1145
                {
 
1146
                        d->cached=1;
 
1147
                        filterOutputs.push_back(d);
 
1148
                        cacheOK=true;
 
1149
                }
 
1150
                else
 
1151
                        d->cached=0;
 
1152
 
 
1153
                getOut.push_back(d);
 
1154
                
 
1155
        }
 
1156
        return 0;
 
1157
}
 
1158
 
 
1159
 
 
1160
void TransformFilter::getProperties(FilterPropGroup &propertyList) const
 
1161
{
 
1162
 
 
1163
        FilterProperty p;
 
1164
        size_t curGroup=0;
 
1165
        string tmpStr;
 
1166
        vector<pair<unsigned int,string> > choices;
 
1167
        for(unsigned int ui=0;ui<MODE_ENUM_END; ui++)
 
1168
                choices.push_back(make_pair(ui,TRANS(TRANSFORM_MODE_STRING[ui])));
 
1169
        
 
1170
        tmpStr=choiceString(choices,transformMode);
 
1171
        choices.clear();
 
1172
        
 
1173
        p.name=TRANS("Mode");
 
1174
        p.data=tmpStr;
 
1175
        p.type=PROPERTY_TYPE_CHOICE;
 
1176
        p.helpText=TRANS("Algorithm to use to transform point data");
 
1177
        p.key=KEY_MODE;
 
1178
        propertyList.addProperty(p,curGroup);
 
1179
        
 
1180
        curGroup++;     
 
1181
        
 
1182
        //non-translation transforms require a user to select an origin 
 
1183
        if( (transformMode == MODE_SCALE_ISOTROPIC  || transformMode == MODE_SCALE_ANISOTROPIC
 
1184
                                || transformMode == MODE_ROTATE))
 
1185
        {
 
1186
                vector<pair<unsigned int,string> > choices;
 
1187
                for(unsigned int ui=0;ui<ORIGINMODE_END;ui++)
 
1188
                        choices.push_back(make_pair(ui,getOriginTypeString(ui)));
 
1189
                
 
1190
                tmpStr= choiceString(choices,originMode);
 
1191
 
 
1192
                p.name=TRANS("Origin mode");
 
1193
                p.data=tmpStr;
 
1194
                p.type=PROPERTY_TYPE_CHOICE;
 
1195
                p.helpText=TRANS("Select how transform origin is computed");
 
1196
                p.key=KEY_ORIGINMODE;
 
1197
                propertyList.addProperty(p,curGroup);
 
1198
        
 
1199
                stream_cast(tmpStr,showOrigin); 
 
1200
                p.name=TRANS("Show marker");
 
1201
                p.data=tmpStr;
 
1202
                p.type=PROPERTY_TYPE_BOOL;
 
1203
                if( originMode == ORIGINMODE_SELECT)
 
1204
                        p.helpText=TRANS("Display an interactive object to set transform origin");
 
1205
                else
 
1206
                        p.helpText=TRANS("Display a small marker to denote transform origin");
 
1207
                p.key=KEY_TRANSFORM_SHOWORIGIN;
 
1208
                propertyList.addProperty(p,curGroup);
 
1209
        }
 
1210
 
 
1211
        
 
1212
 
 
1213
        bool haveProps=true;
 
1214
        switch(transformMode)
 
1215
        {
 
1216
                case MODE_TRANSLATE:
 
1217
                {
 
1218
                        ASSERT(vectorParams.size() == 1);
 
1219
                        ASSERT(scalarParams.size() == 0);
 
1220
                        
 
1221
                        stream_cast(tmpStr,vectorParams[0]);
 
1222
                        p.name=TRANS("Translation");
 
1223
                        p.data=tmpStr;
 
1224
                        p.type=PROPERTY_TYPE_POINT3D;
 
1225
                        p.helpText=TRANS("Translation vector for transform");
 
1226
                        p.key=KEY_ORIGIN;
 
1227
                        propertyList.addProperty(p,curGroup);
 
1228
                        break;
 
1229
                }
 
1230
                case MODE_TRANSLATE_VALUE:
 
1231
                {
 
1232
                        ASSERT(vectorParams.size() == 0);
 
1233
                        ASSERT(scalarParams.size() == 1);
 
1234
                        
 
1235
                        
 
1236
                        stream_cast(tmpStr,scalarParams[0]);
 
1237
                        p.name=TRANS("Offset");
 
1238
                        p.data=tmpStr;
 
1239
                        p.key=KEY_ORIGIN_VALUE;
 
1240
                        p.type=PROPERTY_TYPE_REAL;
 
1241
                        p.helpText=TRANS("Scalar to use to offset each point's associated value");
 
1242
                        propertyList.addProperty(p,curGroup);
 
1243
                        break;
 
1244
                }
 
1245
                case MODE_SCALE_ISOTROPIC:
 
1246
                {
 
1247
                        ASSERT(vectorParams.size() == 1);
 
1248
                        ASSERT(scalarParams.size() == 1);
 
1249
                        
 
1250
                        
 
1251
                        if(originMode == ORIGINMODE_SELECT)
 
1252
                        {
 
1253
                                stream_cast(tmpStr,vectorParams[0]);
 
1254
                                p.key=KEY_ORIGIN;
 
1255
                                p.name=TRANS("Origin");
 
1256
                                p.data=tmpStr;
 
1257
                                p.type=PROPERTY_TYPE_POINT3D;
 
1258
                                p.helpText=TRANS("Origin of scale trasnform");
 
1259
                                propertyList.addProperty(p,curGroup);
 
1260
                        }
 
1261
                        
 
1262
                        stream_cast(tmpStr,scalarParams[0]);
 
1263
                        
 
1264
                        p.key=KEY_SCALEFACTOR;
 
1265
                        p.name=TRANS("Scale Fact.");
 
1266
                        p.data=tmpStr;
 
1267
                        p.type=PROPERTY_TYPE_REAL;
 
1268
                        p.helpText=TRANS("Enlargement factor for scaling around origin");
 
1269
                        propertyList.addProperty(p,curGroup);
 
1270
 
 
1271
                        break;
 
1272
                }
 
1273
                case MODE_SCALE_ANISOTROPIC:
 
1274
                {
 
1275
                        ASSERT(vectorParams.size() == 2);
 
1276
                        
 
1277
                        
 
1278
                        if(originMode == ORIGINMODE_SELECT)
 
1279
                        {
 
1280
                                stream_cast(tmpStr,vectorParams[0]);
 
1281
                                p.key=KEY_ORIGIN;
 
1282
                                p.name=TRANS("Origin");
 
1283
                                p.data=tmpStr;
 
1284
                                p.type=PROPERTY_TYPE_POINT3D;
 
1285
                                p.helpText=TRANS("Origin of scale trasnform");
 
1286
                                propertyList.addProperty(p,curGroup);
 
1287
                        }
 
1288
                        
 
1289
                        stream_cast(tmpStr,vectorParams[1]);
 
1290
                        
 
1291
                        p.key=KEY_SCALEFACTOR_ANISOTROPIC;
 
1292
                        p.name=TRANS("Scale Fact.");
 
1293
                        p.data=tmpStr;
 
1294
                        p.type=PROPERTY_TYPE_REAL;
 
1295
                        p.helpText=TRANS("Enlargement factor for scaling around origin");
 
1296
                        propertyList.addProperty(p,curGroup);
 
1297
 
 
1298
                        break;
 
1299
                }
 
1300
                case MODE_ROTATE:
 
1301
                {
 
1302
                        ASSERT(vectorParams.size() == 2);
 
1303
                        ASSERT(scalarParams.size() == 1);
 
1304
                        if(originMode == ORIGINMODE_SELECT)
 
1305
                        {
 
1306
                                stream_cast(tmpStr,vectorParams[0]);
 
1307
                                p.key=KEY_ORIGIN;
 
1308
                                p.name=TRANS("Origin");
 
1309
                                p.data=tmpStr;
 
1310
                                p.type=PROPERTY_TYPE_POINT3D;
 
1311
                                p.helpText=TRANS("Origin of rotation");
 
1312
                                propertyList.addProperty(p,curGroup);
 
1313
                        }
 
1314
                        stream_cast(tmpStr,vectorParams[1]);
 
1315
                        p.key=KEY_ROTATE_AXIS;
 
1316
                        p.name=TRANS("Axis");
 
1317
                        p.data=tmpStr;
 
1318
                        p.type=(PROPERTY_TYPE_POINT3D);
 
1319
                        p.helpText=TRANS("Axis around which to revolve");
 
1320
                        propertyList.addProperty(p,curGroup);
 
1321
 
 
1322
                        stream_cast(tmpStr,scalarParams[0]);
 
1323
                        p.key=KEY_ROTATE_ANGLE;
 
1324
                        p.name=TRANS("Angle (deg)");
 
1325
                        p.data=tmpStr;
 
1326
                        p.type=PROPERTY_TYPE_REAL;
 
1327
                        p.helpText=TRANS("Angle to perform rotation (ACW, as viewed from axis towards origin)");
 
1328
                        propertyList.addProperty(p,curGroup);
 
1329
                        break;
 
1330
                }
 
1331
                case MODE_VALUE_SHUFFLE:
 
1332
                {
 
1333
                        //No options...
 
1334
                        haveProps=false;
 
1335
                        break;  
 
1336
                }
 
1337
                case MODE_SPATIAL_NOISE:
 
1338
                {
 
1339
                        for(unsigned int ui=0;ui<NOISETYPE_END;ui++)
 
1340
                                choices.push_back(make_pair(ui,getNoiseTypeString(ui)));
 
1341
                        tmpStr= choiceString(choices,noiseType);
 
1342
                        choices.clear();
 
1343
                        
 
1344
                        p.name=TRANS("Noise Type");
 
1345
                        p.data=tmpStr;
 
1346
                        p.type=PROPERTY_TYPE_CHOICE;
 
1347
                        p.helpText=TRANS("Method to use to degrade point data");
 
1348
                        p.key=KEY_NOISETYPE;
 
1349
                        propertyList.addProperty(p,curGroup);
 
1350
 
 
1351
 
 
1352
                        stream_cast(tmpStr,scalarParams[0]);
 
1353
                        if(noiseType == NOISETYPE_WHITE)
 
1354
                                p.name=TRANS("Noise level");
 
1355
                        else if(noiseType == NOISETYPE_GAUSSIAN)
 
1356
                                p.name=TRANS("Standard dev.");
 
1357
                        else
 
1358
                        {
 
1359
                                ASSERT(false);
 
1360
                        }
 
1361
                        
 
1362
                        p.data=tmpStr;
 
1363
                        p.type=PROPERTY_TYPE_REAL;
 
1364
                        p.helpText=TRANS("Amplitude of noise");
 
1365
                        p.key=KEY_NOISELEVEL;
 
1366
                        propertyList.addProperty(p,curGroup);
 
1367
 
 
1368
 
 
1369
                        break;  
 
1370
                }
 
1371
                default:
 
1372
                        ASSERT(false);
 
1373
        }
 
1374
 
 
1375
        if(haveProps)
 
1376
                propertyList.setGroupTitle(curGroup,TRANS("Transform Params"));
 
1377
 
 
1378
}
 
1379
 
 
1380
bool TransformFilter::setProperty(  unsigned int key,
 
1381
                                        const std::string &value, bool &needUpdate)
 
1382
{
 
1383
 
 
1384
        needUpdate=false;
 
1385
        switch(key)
 
1386
        {
 
1387
                case KEY_MODE:
 
1388
                {
 
1389
                        size_t tmp=-1;
 
1390
                        for(size_t ui=0;ui<MODE_ENUM_END;ui++)
 
1391
                        {
 
1392
                                if(value == TRANS(TRANSFORM_MODE_STRING[ui]))
 
1393
                                        tmp=ui;
 
1394
                        }
 
1395
                        if(tmp==(size_t)-1)
 
1396
                        {
 
1397
                                ASSERT(false); // This should not happen
 
1398
                                return false;
 
1399
                        }
 
1400
                        transformMode=tmp;
 
1401
 
 
1402
                        vectorParams.clear();
 
1403
                        scalarParams.clear();
 
1404
                        switch(transformMode)
 
1405
                        {
 
1406
                                case MODE_SCALE_ISOTROPIC:
 
1407
                                        vectorParams.push_back(Point3D(0,0,0));
 
1408
                                        scalarParams.push_back(1.0f);
 
1409
                                        break;
 
1410
                                case MODE_SCALE_ANISOTROPIC:
 
1411
                                        vectorParams.push_back(Point3D(0,0,0));
 
1412
                                        vectorParams.push_back(Point3D(1,1,1));
 
1413
                                        break;
 
1414
                                case MODE_TRANSLATE:
 
1415
                                        vectorParams.push_back(Point3D(0,0,0));
 
1416
                                        break;
 
1417
                                case MODE_TRANSLATE_VALUE:
 
1418
                                        scalarParams.push_back(100.0f);
 
1419
                                        break;
 
1420
                                case MODE_ROTATE:
 
1421
                                        vectorParams.push_back(Point3D(0,0,0));
 
1422
                                        vectorParams.push_back(Point3D(1,0,0));
 
1423
                                        scalarParams.push_back(0.0f);
 
1424
                                        break;
 
1425
                                case MODE_VALUE_SHUFFLE:
 
1426
                                        break;
 
1427
                                case MODE_SPATIAL_NOISE:
 
1428
                                        scalarParams.push_back(0.1f);
 
1429
                                        break;
 
1430
                                default:
 
1431
                                        ASSERT(false);
 
1432
                        }
 
1433
                        needUpdate=true;        
 
1434
                        clearCache();
 
1435
                        break;
 
1436
                }
 
1437
                //The rotation angle, and the scale factor are both stored
 
1438
                //in scalaraparams[0]. All we need ot do is set that,
 
1439
                //as either can take any valid floating pt value
 
1440
                case KEY_ROTATE_ANGLE:
 
1441
                case KEY_SCALEFACTOR:
 
1442
                case KEY_NOISELEVEL:
 
1443
                case KEY_ORIGIN_VALUE:
 
1444
                {
 
1445
                        ASSERT(scalarParams.size());
 
1446
 
 
1447
                        float newScale;
 
1448
                        if(stream_cast(newScale,value))
 
1449
                                return false;
 
1450
 
 
1451
                        if(scalarParams[0] != newScale )
 
1452
                        {
 
1453
                                scalarParams[0] = newScale;
 
1454
                                needUpdate=true;
 
1455
                                clearCache();
 
1456
                        }
 
1457
                        return true;
 
1458
                }
 
1459
                case KEY_SCALEFACTOR_ANISOTROPIC:
 
1460
                {
 
1461
                        Point3D newPt;
 
1462
                        if(!newPt.parse(value))
 
1463
                                return false;
 
1464
 
 
1465
                        if(!(vectorParams[1] == newPt ))
 
1466
                        {
 
1467
                                vectorParams[1] = newPt;
 
1468
                                needUpdate=true;
 
1469
                                clearCache();
 
1470
                        }
 
1471
 
 
1472
                        return true;
 
1473
                }
 
1474
                case KEY_ORIGIN:
 
1475
                {
 
1476
                        Point3D newPt;
 
1477
                        if(!newPt.parse(value))
 
1478
                                return false;
 
1479
 
 
1480
                        if(!(vectorParams[0] == newPt ))
 
1481
                        {
 
1482
                                vectorParams[0] = newPt;
 
1483
                                needUpdate=true;
 
1484
                                clearCache();
 
1485
                        }
 
1486
 
 
1487
                        return true;
 
1488
                }
 
1489
                case KEY_ROTATE_AXIS:
 
1490
                {
 
1491
                        ASSERT(vectorParams.size() ==2);
 
1492
                        ASSERT(scalarParams.size() ==1);
 
1493
                        Point3D newPt;
 
1494
                        if(!newPt.parse(value))
 
1495
                                return false;
 
1496
 
 
1497
                        if(newPt.sqrMag() < std::numeric_limits<float>::epsilon())
 
1498
                                return false;
 
1499
 
 
1500
                        if(!(vectorParams[1] == newPt ))
 
1501
                        {
 
1502
                                vectorParams[1] = newPt;
 
1503
                                needUpdate=true;
 
1504
                                clearCache();
 
1505
                        }
 
1506
 
 
1507
                        return true;
 
1508
                }
 
1509
                case KEY_ORIGINMODE:
 
1510
                {
 
1511
                        size_t i;
 
1512
                        for (i = 0; i < ORIGINMODE_END; i++)
 
1513
                                if (value == TRANS(getOriginTypeString(i).c_str())) break;
 
1514
                
 
1515
                        if( i == ORIGINMODE_END)
 
1516
                                return false;
 
1517
 
 
1518
                        if(originMode != i)
 
1519
                        {
 
1520
                                originMode = i;
 
1521
                                needUpdate=true;
 
1522
                                clearCache();
 
1523
                        }
 
1524
                        return true;
 
1525
                }
 
1526
                case KEY_TRANSFORM_SHOWORIGIN:
 
1527
                {
 
1528
                        string stripped=stripWhite(value);
 
1529
 
 
1530
                        if(!(stripped == "1"|| stripped == "0"))
 
1531
                                return false;
 
1532
 
 
1533
                        showOrigin=(stripped=="1");
 
1534
 
 
1535
                        needUpdate=true;
 
1536
 
 
1537
                        break;
 
1538
                }
 
1539
                case KEY_NOISETYPE:
 
1540
                {
 
1541
                        size_t i;
 
1542
                        for (i = 0; i < NOISETYPE_END; i++)
 
1543
                                if (value == TRANS(getNoiseTypeString(i).c_str())) break;
 
1544
                
 
1545
                        if( i == NOISETYPE_END)
 
1546
                                return false;
 
1547
 
 
1548
                        if(noiseType != i)
 
1549
                        {
 
1550
                                noiseType = i;
 
1551
                                needUpdate=true;
 
1552
                                clearCache();
 
1553
                        }
 
1554
                        break;
 
1555
                }
 
1556
                default:
 
1557
                        ASSERT(false);
 
1558
        }       
 
1559
        return true;
 
1560
}
 
1561
 
 
1562
 
 
1563
std::string  TransformFilter::getErrString(unsigned int code) const
 
1564
{
 
1565
 
 
1566
        switch(code)
 
1567
        {
 
1568
                //User aborted in a callback
 
1569
                case ERR_CALLBACK_FAIL:
 
1570
                        return std::string(TRANS("Aborted"));
 
1571
                //Caught a memory issue
 
1572
                case ERR_NOMEM:
 
1573
                        return std::string(TRANS("Unable to allocate memory"));
 
1574
        }
 
1575
        ASSERT(false);
 
1576
}
 
1577
 
 
1578
bool TransformFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const
 
1579
{
 
1580
        using std::endl;
 
1581
        switch(format)
 
1582
        {
 
1583
                case STATE_FORMAT_XML:
 
1584
                {       
 
1585
                        f << tabs(depth) << "<" << trueName() << ">" << endl;
 
1586
                        f << tabs(depth+1) << "<userstring value=\""<< escapeXML(userString) << "\"/>"  << endl;
 
1587
                        f << tabs(depth+1) << "<transformmode value=\"" << transformMode<< "\"/>"<<endl;
 
1588
                        f << tabs(depth+1) << "<originmode value=\"" << originMode<< "\"/>"<<endl;
 
1589
                        
 
1590
                        f << tabs(depth+1) << "<noisetype value=\"" << noiseType<< "\"/>"<<endl;
 
1591
 
 
1592
                        string tmpStr;
 
1593
                        if(showOrigin)
 
1594
                                tmpStr="1";
 
1595
                        else
 
1596
                                tmpStr="0";
 
1597
                        f << tabs(depth+1) << "<showorigin value=\"" << tmpStr <<  "\"/>"<<endl;
 
1598
                        writeVectorsXML(f,"vectorparams",vectorParams,depth);
 
1599
                        writeScalarsXML(f,"scalarparams",scalarParams,depth);
 
1600
                        f << tabs(depth) << "</" << trueName() << ">" << endl;
 
1601
                        break;
 
1602
                }
 
1603
                default:
 
1604
                        ASSERT(false);
 
1605
                        return false;
 
1606
        }
 
1607
 
 
1608
        return true;
 
1609
}
 
1610
 
 
1611
bool TransformFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir)
 
1612
{
 
1613
        //Retrieve user string
 
1614
        //===
 
1615
        if(XMLHelpFwdToElem(nodePtr,"userstring"))
 
1616
                return false;
 
1617
 
 
1618
        xmlChar *xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value");
 
1619
        if(!xmlString)
 
1620
                return false;
 
1621
        userString=(char *)xmlString;
 
1622
        xmlFree(xmlString);
 
1623
        //===
 
1624
 
 
1625
        //Retrieve transformation type 
 
1626
        //====
 
1627
        if(!XMLGetNextElemAttrib(nodePtr,transformMode,"transformmode","value"))
 
1628
                return false;
 
1629
        if(transformMode>= MODE_ENUM_END)
 
1630
               return false;    
 
1631
        //====
 
1632
        
 
1633
        //Retrieve origination type 
 
1634
        //====
 
1635
        if(!XMLGetNextElemAttrib(nodePtr,originMode,"originmode","value"))
 
1636
                return false;
 
1637
        if(originMode>= ORIGINMODE_END)
 
1638
               return false;    
 
1639
        //====
 
1640
        
 
1641
        //Retrieve origination type 
 
1642
        //====
 
1643
        if(!XMLGetNextElemAttrib(nodePtr,originMode,"noisetype","value"))
 
1644
                return false;
 
1645
        if(noiseType>= NOISETYPE_END)
 
1646
               return false;    
 
1647
        //====
 
1648
        
 
1649
        //Retrieve origination type 
 
1650
        //====
 
1651
        if(!XMLGetNextElemAttrib(nodePtr,originMode,"showorigin","value"))
 
1652
                return false;
 
1653
        //====
 
1654
        
 
1655
        //Retrieve vector parameters
 
1656
        //===
 
1657
        if(XMLHelpFwdToElem(nodePtr,"vectorparams"))
 
1658
                return false;
 
1659
        xmlNodePtr tmpNode=nodePtr;
 
1660
 
 
1661
        if(!readVectorsXML(nodePtr,vectorParams))
 
1662
                return false;
 
1663
        //===   
 
1664
 
 
1665
        nodePtr=tmpNode;
 
1666
        //Retrieve scalar parameters
 
1667
        //===
 
1668
        if(XMLHelpFwdToElem(nodePtr,"scalarparams"))
 
1669
                return false;
 
1670
 
 
1671
        if(!readScalarsXML(nodePtr,scalarParams))
 
1672
                return false;
 
1673
        //===   
 
1674
 
 
1675
        //Check the scalar params match the selected primitive  
 
1676
        switch(transformMode)
 
1677
        {
 
1678
                case MODE_TRANSLATE:
 
1679
                        if(vectorParams.size() != 1 || scalarParams.size() !=0)
 
1680
                                return false;
 
1681
                        break;
 
1682
                case MODE_SCALE_ISOTROPIC:
 
1683
                        if(vectorParams.size() != 1 || scalarParams.size() !=1)
 
1684
                                return false;
 
1685
                        break;
 
1686
                case MODE_SCALE_ANISOTROPIC:
 
1687
                        if(vectorParams.size() != 2 || scalarParams.size() !=0)
 
1688
                                return false;
 
1689
                        break;
 
1690
                case MODE_ROTATE:
 
1691
                        if(vectorParams.size() != 2 || scalarParams.size() !=1)
 
1692
                                return false;
 
1693
                        break;
 
1694
                case MODE_TRANSLATE_VALUE:
 
1695
                        if(vectorParams.size() != 0 || scalarParams.size() !=1)
 
1696
                                return false;
 
1697
                        break;
 
1698
                case MODE_VALUE_SHUFFLE:
 
1699
                case MODE_SPATIAL_NOISE:
 
1700
                        break;
 
1701
                default:
 
1702
                        ASSERT(false);
 
1703
                        return false;
 
1704
        }
 
1705
        return true;
 
1706
}
 
1707
 
 
1708
 
 
1709
unsigned int TransformFilter::getRefreshBlockMask() const
 
1710
{
 
1711
        //Only ions cannot go through this filter.
 
1712
        return STREAM_TYPE_IONS;
 
1713
}
 
1714
 
 
1715
unsigned int TransformFilter::getRefreshEmitMask() const
 
1716
{
 
1717
        if(showPrimitive)
 
1718
                return STREAM_TYPE_IONS | STREAM_TYPE_DRAW;
 
1719
        else
 
1720
                return STREAM_TYPE_IONS;
 
1721
}
 
1722
 
 
1723
unsigned int TransformFilter::getRefreshUseMask() const
 
1724
{
 
1725
        return STREAM_TYPE_IONS;
 
1726
}
 
1727
 
 
1728
void TransformFilter::setPropFromBinding(const SelectionBinding &b)
 
1729
{
 
1730
        switch(b.getID())
 
1731
        {
 
1732
                case BINDING_SPHERE_ORIGIN:
 
1733
                        b.getValue(vectorParams[0]);
 
1734
                        break;
 
1735
                default:
 
1736
                        ASSERT(false);
 
1737
        }
 
1738
        clearCache();
 
1739
}
 
1740
 
 
1741
std::string TransformFilter::getOriginTypeString(unsigned int i)
 
1742
{
 
1743
        ASSERT(i<ORIGINMODE_END);
 
1744
        return TRANSFORM_ORIGIN_STRING[i];
 
1745
}
 
1746
 
 
1747
std::string TransformFilter::getNoiseTypeString(unsigned int i)
 
1748
{
 
1749
        switch(i)
 
1750
        {
 
1751
                case NOISETYPE_WHITE:
 
1752
                        return std::string(TRANS("White"));
 
1753
                case NOISETYPE_GAUSSIAN:
 
1754
                        return std::string(TRANS("Gaussian"));
 
1755
        }
 
1756
        ASSERT(false);
 
1757
}
 
1758
 
 
1759
 
 
1760
#ifdef DEBUG
 
1761
 
 
1762
//Generate some synthetic data points, that lie within 0->span.
 
1763
//span must be  a 3-wide array, and numPts will be generated.
 
1764
//each entry in the array should be coprime for optimal results.
 
1765
//filter pointer must be deleted.
 
1766
IonStreamData *synthDataPoints(unsigned int span[],unsigned int numPts);
 
1767
bool rotateTest();
 
1768
bool translateTest();
 
1769
bool scaleTest();
 
1770
bool scaleAnisoTest();
 
1771
bool shuffleTest();
 
1772
 
 
1773
class MassCompare
 
1774
{
 
1775
        public:
 
1776
                inline bool operator()(const IonHit &h1,const IonHit &h2) const
 
1777
                {return h1.getMassToCharge()<h2.getMassToCharge();};
 
1778
};
 
1779
 
 
1780
bool TransformFilter::runUnitTests()
 
1781
{
 
1782
        if(!rotateTest())
 
1783
                return false;
 
1784
 
 
1785
        if(!translateTest())
 
1786
                return false;
 
1787
 
 
1788
        if(!scaleTest())
 
1789
                return false;
 
1790
 
 
1791
        if(!scaleAnisoTest())
 
1792
                return false;
 
1793
 
 
1794
        if(!shuffleTest())
 
1795
                return false;
 
1796
 
 
1797
        return true;
 
1798
}
 
1799
 
 
1800
IonStreamData *synthDataPoints(unsigned int span[], unsigned int numPts)
 
1801
{
 
1802
        IonStreamData *d = new IonStreamData;
 
1803
        
 
1804
        for(unsigned int ui=0;ui<numPts;ui++)
 
1805
        {
 
1806
                IonHit h;
 
1807
                h.setPos(Point3D(ui%span[0],
 
1808
                        ui%span[1],ui%span[2]));
 
1809
                h.setMassToCharge(ui);
 
1810
                d->data.push_back(h);
 
1811
        }
 
1812
 
 
1813
        return d;
 
1814
}
 
1815
 
 
1816
bool rotateTest()
 
1817
{
 
1818
        //Simulate some data to send to the filter
 
1819
        vector<const FilterStreamData*> streamIn,streamOut;
 
1820
        IonStreamData *d= new IonStreamData;
 
1821
 
 
1822
        RandNumGen rng;
 
1823
        rng.initTimer();
 
1824
 
 
1825
        const unsigned int NUM_PTS=10000;
 
1826
 
 
1827
        
 
1828
        //Build a  sphere of data points
 
1829
        //by rejection method
 
1830
        d->data.reserve(NUM_PTS/2);     
 
1831
        for(unsigned int ui=0;ui<NUM_PTS;ui++)
 
1832
        {
 
1833
                Point3D tmp;
 
1834
                tmp=Point3D(rng.genUniformDev()-0.5f,
 
1835
                                rng.genUniformDev()-0.5f,
 
1836
                                rng.genUniformDev()-0.5f);
 
1837
 
 
1838
                if(tmp.sqrMag() < 1.0f)
 
1839
                {
 
1840
                        IonHit h;
 
1841
                        h.setPos(tmp);
 
1842
                        h.setMassToCharge(1);
 
1843
                        d->data.push_back(h);
 
1844
                }
 
1845
        }
 
1846
                
 
1847
        streamIn.push_back(d);
 
1848
 
 
1849
        //Set up the filter itself
 
1850
        //---
 
1851
        TransformFilter *f=new TransformFilter;
 
1852
        f->setCaching(false);
 
1853
 
 
1854
 
 
1855
        bool needUp;
 
1856
        string s;
 
1857
        TEST(f->setProperty(KEY_MODE,
 
1858
                TRANS(TRANSFORM_MODE_STRING[MODE_ROTATE]),needUp),"Set transform mode");
 
1859
        float tmpVal;
 
1860
        tmpVal=rng.genUniformDev()*M_PI*2.0;
 
1861
        stream_cast(s,tmpVal);
 
1862
        TEST(f->setProperty(KEY_ROTATE_ANGLE,s,needUp),"Set rotate angle");
 
1863
        Point3D tmpPt;
 
1864
 
 
1865
        //NOTE: Technically there is a nonzero chance of this failing.
 
1866
        tmpPt=Point3D(rng.genUniformDev()-0.5f,
 
1867
                        rng.genUniformDev()-0.5f,
 
1868
                        rng.genUniformDev()-0.5f);
 
1869
        stream_cast(s,tmpPt);
 
1870
        TEST(f->setProperty(KEY_ROTATE_AXIS,s,needUp),"set rotate axis");
 
1871
        
 
1872
        TEST(f->setProperty(KEY_ORIGINMODE,
 
1873
                TRANS(TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE]),needUp),"Set origin");
 
1874
        TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set no-show origin");
 
1875
        //---
 
1876
 
 
1877
 
 
1878
        //OK, so now do the rotation
 
1879
        //Do the refresh
 
1880
        ProgressData p;
 
1881
        TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code");
 
1882
        delete f;
 
1883
 
 
1884
        TEST(streamOut.size() == 1,"stream count");
 
1885
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
 
1886
        TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance");
 
1887
 
 
1888
        const IonStreamData *outData=(IonStreamData*)streamOut[0];
 
1889
 
 
1890
        Point3D massCentre[2];
 
1891
        massCentre[0]=massCentre[1]=Point3D(0,0,0);
 
1892
        //Now check that the mass centre has not moved
 
1893
        for(unsigned int ui=0;ui<d->data.size();ui++)
 
1894
                massCentre[0]+=d->data[ui].getPos();
 
1895
 
 
1896
        for(unsigned int ui=0;ui<outData->data.size();ui++)
 
1897
                massCentre[1]+=outData->data[ui].getPos();
 
1898
 
 
1899
 
 
1900
        TEST((massCentre[0]-massCentre[1]).sqrMag() < 
 
1901
                        2.0*sqrt(std::numeric_limits<float>::epsilon()),"mass centre invariance");
 
1902
 
 
1903
        //Rotating a sphere around its centre of mass
 
1904
        // should not massively change the bounding box
 
1905
        // however we don't quite have  a sphere, so we could have (at the most extreme,
 
1906
        // a cube)
 
1907
        BoundCube bc[2];
 
1908
        IonHit::getBoundCube(d->data,bc[0]);
 
1909
        IonHit::getBoundCube(outData->data,bc[1]);
 
1910
 
 
1911
        float volumeRat;
 
1912
        volumeRat = bc[0].volume()/bc[1].volume();
 
1913
 
 
1914
        TEST(volumeRat > 0.5f && volumeRat < 2.0f, "volume ratio test");
 
1915
 
 
1916
        delete streamOut[0];
 
1917
        delete d;
 
1918
        return true;
 
1919
}
 
1920
 
 
1921
bool translateTest()
 
1922
{
 
1923
        RandNumGen rng;
 
1924
        rng.initTimer();
 
1925
        
 
1926
        //Simulate some data to send to the filter
 
1927
        vector<const FilterStreamData*> streamIn,streamOut;
 
1928
        IonStreamData *d;
 
1929
        const unsigned int NUM_PTS=10000;
 
1930
 
 
1931
        unsigned int span[]={ 
 
1932
                        5, 7, 9
 
1933
                        };      
 
1934
        d=synthDataPoints(span,NUM_PTS);
 
1935
        streamIn.push_back(d);
 
1936
 
 
1937
        Point3D offsetPt;
 
1938
 
 
1939
        //Set up the filter itself
 
1940
        //---
 
1941
        TransformFilter *f=new TransformFilter;
 
1942
 
 
1943
        bool needUp;
 
1944
        string s;
 
1945
        TEST(f->setProperty(KEY_MODE,
 
1946
                TRANSFORM_MODE_STRING[MODE_TRANSLATE],needUp),"set translate mode");
 
1947
 
 
1948
        //NOTE: Technically there is a nonzero chance of this failing.
 
1949
        offsetPt=Point3D(rng.genUniformDev()-0.5f,
 
1950
                        rng.genUniformDev()-0.5f,
 
1951
                        rng.genUniformDev()-0.5f);
 
1952
        offsetPt[0]*=span[0];
 
1953
        offsetPt[1]*=span[1];
 
1954
        offsetPt[2]*=span[2];
 
1955
 
 
1956
        stream_cast(s,offsetPt);
 
1957
        TEST(f->setProperty(KEY_ORIGIN,s,needUp),"Set Origin");
 
1958
        TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set display origin");
 
1959
        //---
 
1960
        
 
1961
        //Do the refresh
 
1962
        ProgressData p;
 
1963
        TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code");
 
1964
        delete f;
 
1965
        
 
1966
        TEST(streamOut.size() == 1,"stream count");
 
1967
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
 
1968
        TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance");
 
1969
 
 
1970
        const IonStreamData *outData=(IonStreamData*)streamOut[0];
 
1971
 
 
1972
        //Bound cube should move exactly as per the translation
 
1973
        BoundCube bc[2];
 
1974
        IonHit::getBoundCube(d->data,bc[0]);
 
1975
        IonHit::getBoundCube(outData->data,bc[1]);
 
1976
 
 
1977
        for(unsigned int ui=0;ui<3;ui++)
 
1978
        {
 
1979
                for(unsigned int uj=0;uj<2;uj++)
 
1980
                {
 
1981
                        float f;
 
1982
                        f=bc[0].getBound(ui,uj) -bc[1].getBound(ui,uj);
 
1983
                        TEST(fabs(f-offsetPt[ui]) < sqrt(std::numeric_limits<float>::epsilon()), "bound translation");
 
1984
                }
 
1985
        }
 
1986
 
 
1987
        delete d;
 
1988
        delete streamOut[0];
 
1989
 
 
1990
        return true;
 
1991
}
 
1992
 
 
1993
 
 
1994
bool scaleTest() 
 
1995
{
 
1996
        //Simulate some data to send to the filter
 
1997
        vector<const FilterStreamData*> streamIn,streamOut;
 
1998
        IonStreamData *d;
 
1999
 
 
2000
        RandNumGen rng;
 
2001
        rng.initTimer();
 
2002
 
 
2003
        const unsigned int NUM_PTS=10000;
 
2004
 
 
2005
        unsigned int span[]={ 
 
2006
                        5, 7, 9
 
2007
                        };      
 
2008
        d=synthDataPoints(span,NUM_PTS);
 
2009
        streamIn.push_back(d);
 
2010
 
 
2011
        //Set up the filter itself
 
2012
        //---
 
2013
        TransformFilter *f=new TransformFilter;
 
2014
 
 
2015
        bool needUp;
 
2016
        string s;
 
2017
        //Switch to scale mode (isotropic)
 
2018
        TEST(f->setProperty(KEY_MODE,
 
2019
                        TRANS(TRANSFORM_MODE_STRING[MODE_SCALE_ISOTROPIC]),needUp),"Set scale mode");
 
2020
 
 
2021
 
 
2022
        //Switch to mass-centre origin
 
2023
        TEST(f->setProperty(KEY_ORIGINMODE,
 
2024
                TRANS(TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE]),needUp),"Set origin->mass mode");
 
2025
 
 
2026
        float scaleFact;
 
2027
        //Pick some scale, both positive and negative.
 
2028
        if(rng.genUniformDev() > 0.5)
 
2029
                scaleFact=rng.genUniformDev()*10;
 
2030
        else
 
2031
                scaleFact=0.1f/(0.1f+rng.genUniformDev());
 
2032
 
 
2033
        stream_cast(s,scaleFact);
 
2034
 
 
2035
        TEST(f->setProperty(KEY_SCALEFACTOR,s,needUp),"Set scalefactor");
 
2036
        //Don't show origin marker
 
2037
        TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set show origin")
 
2038
        //---
 
2039
 
 
2040
 
 
2041
        //Do the refresh
 
2042
        ProgressData p;
 
2043
        TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code");
 
2044
        delete f;
 
2045
 
 
2046
        TEST(streamOut.size() == 1,"stream count");
 
2047
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
 
2048
        TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance");
 
2049
 
 
2050
        const IonStreamData *outData=(IonStreamData*)streamOut[0];
 
2051
 
 
2052
        //Scaling around its centre of mass
 
2053
        // should scale the bounding box by the cube of the scale factor
 
2054
        BoundCube bc[2];
 
2055
        IonHit::getBoundCube(d->data,bc[0]);
 
2056
        IonHit::getBoundCube(outData->data,bc[1]);
 
2057
 
 
2058
        float cubeOfScale=scaleFact*scaleFact*scaleFact;
 
2059
 
 
2060
        float volumeDelta;
 
2061
        volumeDelta=fabs(bc[1].volume()/cubeOfScale - bc[0].volume() );
 
2062
 
 
2063
        TEST(volumeDelta < 100.0f*sqrt(std::numeric_limits<float>::epsilon()), "scaled volume test");
 
2064
 
 
2065
        delete streamOut[0];
 
2066
        delete d;
 
2067
        return true;
 
2068
}
 
2069
 
 
2070
bool scaleAnisoTest() 
 
2071
{
 
2072
        //Simulate some data to send to the filter
 
2073
        vector<const FilterStreamData*> streamIn,streamOut;
 
2074
        IonStreamData *d;
 
2075
 
 
2076
        RandNumGen rng;
 
2077
        rng.initTimer();
 
2078
 
 
2079
        const unsigned int NUM_PTS=10000;
 
2080
 
 
2081
        unsigned int span[]={ 
 
2082
                        5, 7, 9
 
2083
                        };      
 
2084
        d=synthDataPoints(span,NUM_PTS);
 
2085
        streamIn.push_back(d);
 
2086
 
 
2087
        //Set up the filter itself
 
2088
        //---
 
2089
        TransformFilter *f=new TransformFilter;
 
2090
 
 
2091
        bool needUp;
 
2092
        string s;
 
2093
        //Switch to scale mode (isotropic)
 
2094
        TEST(f->setProperty(KEY_MODE,
 
2095
                        TRANS(TRANSFORM_MODE_STRING[MODE_SCALE_ANISOTROPIC]),needUp),"Set scale mode");
 
2096
 
 
2097
 
 
2098
        //Switch to mass-centre origin
 
2099
        TEST(f->setProperty(KEY_ORIGINMODE,
 
2100
                TRANS(TRANSFORM_ORIGIN_STRING[ORIGINMODE_MASSCENTRE]),needUp),"Set origin->mass mode");
 
2101
 
 
2102
        Point3D scaleFact;
 
2103
        //Pick some random scale vector, both positive and negative.
 
2104
        scaleFact=Point3D(rng.genUniformDev()*10,rng.genUniformDev()*10,rng.genUniformDev()*10);
 
2105
 
 
2106
        stream_cast(s,scaleFact);
 
2107
 
 
2108
        TEST(f->setProperty(KEY_SCALEFACTOR_ANISOTROPIC,s,needUp),"Set scalefactor");
 
2109
        //Don't show origin marker
 
2110
        TEST(f->setProperty(KEY_TRANSFORM_SHOWORIGIN,"0",needUp),"Set show origin")
 
2111
        //---
 
2112
 
 
2113
 
 
2114
        //Do the refresh
 
2115
        ProgressData p;
 
2116
        TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code");
 
2117
        delete f;
 
2118
 
 
2119
        TEST(streamOut.size() == 1,"stream count");
 
2120
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
 
2121
        TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance");
 
2122
 
 
2123
        delete streamOut[0];
 
2124
        delete d;
 
2125
        return true;
 
2126
}
 
2127
bool shuffleTest() 
 
2128
{
 
2129
        //Simulate some data to send to the filter
 
2130
        vector<const FilterStreamData*> streamIn,streamOut;
 
2131
        IonStreamData *d;
 
2132
 
 
2133
        RandNumGen rng;
 
2134
        rng.initTimer();
 
2135
 
 
2136
        const unsigned int NUM_PTS=1000;
 
2137
 
 
2138
        unsigned int span[]={ 
 
2139
                        5, 7, 9
 
2140
                        };      
 
2141
        d=synthDataPoints(span,NUM_PTS);
 
2142
        streamIn.push_back(d);
 
2143
 
 
2144
        //Set up the filter itself
 
2145
        //---
 
2146
        TransformFilter *f=new TransformFilter;
 
2147
 
 
2148
        bool needUp;
 
2149
        //Switch to shuffle mode
 
2150
        TEST(f->setProperty(KEY_MODE,
 
2151
                        TRANS(TRANSFORM_MODE_STRING[MODE_VALUE_SHUFFLE]),needUp),"refresh error code");
 
2152
        //---
 
2153
 
 
2154
 
 
2155
        //OK, so now run the shuffle 
 
2156
        //Do the refresh
 
2157
        ProgressData p;
 
2158
        TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh error code");
 
2159
        delete f;
 
2160
 
 
2161
        TEST(streamOut.size() == 1,"stream count");
 
2162
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
 
2163
        TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance");
 
2164
 
 
2165
        TEST(streamOut[0]->getNumBasicObjects() == d->data.size(),"Ion count invariance");
 
2166
 
 
2167
        IonStreamData *outData=(IonStreamData*)streamOut[0];
 
2168
 
 
2169
        //Check to see that the output masses each exist in the input,
 
2170
        //but are not in  the same sequence
 
2171
        //---
 
2172
        
 
2173
 
 
2174
        bool sequenceDifferent=false;   
 
2175
        for(size_t ui=0;ui<d->data.size();ui++)
 
2176
        {
 
2177
                if(d->data[ui].getMassToCharge() != outData->data[ui].getMassToCharge())
 
2178
                {
 
2179
                        sequenceDifferent=true;
 
2180
                        break;
 
2181
                }
 
2182
        }
 
2183
        TEST(sequenceDifferent,
 
2184
                "Should be shuffled - Prob. of sequence being identical in both orig & shuffled cases is very low");
 
2185
        //Sort masses
 
2186
        MassCompare cmp;
 
2187
        std::sort(outData->data.begin(),outData->data.end(),cmp);
 
2188
        std::sort(d->data.begin(),d->data.end(),cmp);
 
2189
 
 
2190
 
 
2191
        for(size_t ui=0;ui<d->data.size();ui++)
 
2192
        {
 
2193
                TEST(d->data[ui].getMassToCharge() == outData->data[ui].getMassToCharge(),"Shuffle + Sort mass should be the same");
 
2194
        
 
2195
        }
 
2196
 
 
2197
 
 
2198
 
 
2199
        delete streamOut[0];
 
2200
        delete d;
 
2201
        return true;
 
2202
}
 
2203
 
 
2204
#endif