~ubuntu-branches/ubuntu/saucy/3depict/saucy

« back to all changes in this revision

Viewing changes to src/backend/filters/voxelise.cpp

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      voxelise.cpp - Compute 3D binning (voxelisation) of 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
 
 
19
#include "voxelise.h"
 
20
 
 
21
#include "filterCommon.h"
 
22
 
 
23
#include <map>
 
24
 
 
25
enum
 
26
{
 
27
        KEY_FIXEDWIDTH,
 
28
        KEY_NBINSX,
 
29
        KEY_NBINSY,
 
30
        KEY_NBINSZ,
 
31
        KEY_WIDTHBINSX,
 
32
        KEY_WIDTHBINSY,
 
33
        KEY_WIDTHBINSZ,
 
34
        KEY_COUNT_TYPE,
 
35
        KEY_NORMALISE_TYPE,
 
36
        KEY_SPOTSIZE,
 
37
        KEY_TRANSPARANCY,
 
38
        KEY_COLOUR,
 
39
        KEY_ISOLEVEL,
 
40
        KEY_VOXEL_REPRESENTATION_MODE,
 
41
        KEY_FILTER_MODE,
 
42
        KEY_FILTER_BOUNDARY_MODE,
 
43
        KEY_FILTER_BINS,
 
44
        KEY_ENABLE_NUMERATOR,
 
45
        KEY_ENABLE_DENOMINATOR
 
46
};
 
47
 
 
48
//!Normalisation method
 
49
enum
 
50
{
 
51
        VOXELISE_NORMALISETYPE_NONE,// straight count
 
52
        VOXELISE_NORMALISETYPE_VOLUME,// density
 
53
        VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL, // concentration
 
54
        VOXELISE_NORMALISETYPE_COUNT2INVOXEL,// ratio count1/count2
 
55
        VOXELISE_NORMALISETYPE_MAX // keep this at the end so it's a bookend for the last value
 
56
};
 
57
 
 
58
//!Filtering mode
 
59
enum
 
60
{
 
61
        VOXELISE_FILTERTYPE_NONE,
 
62
        VOXELISE_FILTERTYPE_GAUSS,
 
63
        VOXELISE_FILTERTYPE_MAX // keep this at the end so it's a bookend for the last value
 
64
};
 
65
 
 
66
 
 
67
//Boundary behaviour for filtering 
 
68
enum
 
69
{
 
70
        VOXELISE_FILTERBOUNDMODE_ZERO,
 
71
        VOXELISE_FILTERBOUNDMODE_BOUNCE,
 
72
        VOXELISE_FILTERBOUNDMODE_MAX// keep this at the end so it's a bookend for the last value
 
73
};
 
74
 
 
75
enum
 
76
{
 
77
        VOXELISE_ABORT_ERR,
 
78
        VOXELISE_MEMORY_ERR,
 
79
        VOXELISE_CONVOLVE_ERR,
 
80
        VOXELISE_BOUNDS_INVALID_ERR
 
81
};
 
82
 
 
83
const char *NORMALISE_TYPE_STRING[] = {
 
84
                NTRANS("None (Raw count)"),
 
85
                NTRANS("Volume (Density)"),
 
86
                NTRANS("All Ions (conc)"),
 
87
                NTRANS("Ratio (Num/Denom)"),
 
88
        };
 
89
 
 
90
const char *REPRESENTATION_TYPE_STRING[] = {
 
91
                NTRANS("Point Cloud"),
 
92
                NTRANS("Isosurface")
 
93
        };
 
94
 
 
95
const char *VOXELISE_FILTER_TYPE_STRING[]={
 
96
        NTRANS("None"),
 
97
        NTRANS("Gaussian (2𝜎)"),
 
98
        };
 
99
 
 
100
const char *VOXELISE_FILTER_BOUND_STRING[] ={
 
101
        NTRANS("Zero"),
 
102
        NTRANS("Bounce")
 
103
        };
 
104
 
 
105
//This is not a member of voxels.h, as the voxels do not have any concept of the IonHit
 
106
int countPoints(Voxels<float> &v, const std::vector<IonHit> &points, 
 
107
                                bool noWrap,bool (*callback)(bool))
 
108
{
 
109
 
 
110
        size_t x,y,z;
 
111
        size_t binCount[3];
 
112
        v.getSize(binCount[0],binCount[1],binCount[2]);
 
113
 
 
114
        unsigned int downSample=MAX_CALLBACK;
 
115
        for (size_t ui=0; ui<points.size(); ui++)
 
116
        {
 
117
                if(!downSample--)
 
118
                {
 
119
                        if(!(*callback)(false))
 
120
                                return 1;
 
121
                        downSample=MAX_CALLBACK;
 
122
                }
 
123
                v.getIndexWithUpper(x,y,z,points[ui].getPos());
 
124
                //Ensure it lies within the dataset
 
125
                if (x < binCount[0] && y < binCount[1] && z< binCount[2])
 
126
                {
 
127
                        {
 
128
                                float value;
 
129
                                value=v.getData(x,y,z)+1.0f;
 
130
 
 
131
                                //Prevent wrap-around errors
 
132
                                if (noWrap) {
 
133
                                        if (value > v.getData(x,y,z))
 
134
                                                v.setData(x,y,z,value);
 
135
                                } else {
 
136
                                        v.setData(x,y,z,value);
 
137
                                }
 
138
                        }
 
139
                }
 
140
        }
 
141
        return 0;
 
142
}
 
143
 
 
144
// == Voxels filter ==
 
145
VoxeliseFilter::VoxeliseFilter() 
 
146
: fixedWidth(false), normaliseType(VOXELISE_NORMALISETYPE_NONE)
 
147
{
 
148
        COMPILE_ASSERT(THREEDEP_ARRAYSIZE(NORMALISE_TYPE_STRING) ==  VOXELISE_NORMALISETYPE_MAX);
 
149
        COMPILE_ASSERT(THREEDEP_ARRAYSIZE(VOXELISE_FILTER_TYPE_STRING) == VOXELISE_FILTERTYPE_MAX );
 
150
        COMPILE_ASSERT(THREEDEP_ARRAYSIZE(VOXELISE_FILTER_BOUND_STRING) ==  VOXELISE_FILTERBOUNDMODE_MAX);
 
151
 
 
152
        COMPILE_ASSERT(THREEDEP_ARRAYSIZE(REPRESENTATION_TYPE_STRING) == VOXEL_REPRESENT_END);
 
153
 
 
154
        splatSize=1.0f;
 
155
        a=0.9f;
 
156
        r=g=b=0.5;
 
157
        isoLevel=0.5;
 
158
        
 
159
        filterBins=3;
 
160
        filterMode=VOXELISE_FILTERTYPE_NONE;
 
161
        filterBoundaryMode=VOXELISE_FILTERBOUNDMODE_BOUNCE;
 
162
        gaussDev=0.5;   
 
163
        
 
164
        representation=VOXEL_REPRESENT_POINTCLOUD;
 
165
 
 
166
 
 
167
        //Ficticious bounds.
 
168
        bc.setBounds(Point3D(0,0,0),Point3D(1,1,1));
 
169
 
 
170
        for (unsigned int i = 0; i < INDEX_LENGTH; i++) 
 
171
                nBins[i] = 50;
 
172
 
 
173
        calculateWidthsFromNumBins(binWidth,nBins);
 
174
 
 
175
        numeratorAll = false;
 
176
        denominatorAll = true;
 
177
 
 
178
        cacheOK=false;
 
179
        cache=true; //By default, we should cache, but decision is made higher up
 
180
 
 
181
 
 
182
        rsdIncoming=0;
 
183
}
 
184
 
 
185
 
 
186
Filter *VoxeliseFilter::cloneUncached() const
 
187
{
 
188
        VoxeliseFilter *p=new VoxeliseFilter();
 
189
        p->splatSize=splatSize;
 
190
        p->a=a;
 
191
        p->r=r;
 
192
        p->g=g;
 
193
        p->b=b;
 
194
 
 
195
        p->isoLevel=isoLevel;
 
196
        
 
197
        p->filterMode=filterMode;
 
198
        p->filterBoundaryMode=filterBoundaryMode;
 
199
        p->filterBins=filterBins;
 
200
        p->gaussDev=gaussDev;
 
201
 
 
202
        p->representation=representation;
 
203
        p->splatSize=splatSize;
 
204
 
 
205
        p->normaliseType=normaliseType;
 
206
        p->numeratorAll=numeratorAll;
 
207
        p->denominatorAll=denominatorAll;
 
208
 
 
209
        p->bc=bc;
 
210
 
 
211
        for(size_t ui=0;ui<INDEX_LENGTH;ui++)
 
212
        {
 
213
                p->nBins[ui] = nBins[ui];
 
214
                p->binWidth[ui] = binWidth[ui];
 
215
        }
 
216
 
 
217
        p->enabledIons[0].resize(enabledIons[0].size());
 
218
        std::copy(enabledIons[0].begin(),enabledIons[0].end(),p->enabledIons[0].begin());
 
219
        
 
220
        p->enabledIons[1].resize(enabledIons[1].size());
 
221
        std::copy(enabledIons[1].begin(),enabledIons[1].end(),p->enabledIons[1].begin());
 
222
 
 
223
        if(rsdIncoming)
 
224
        {
 
225
                p->rsdIncoming=new RangeStreamData();
 
226
                *(p->rsdIncoming) = *rsdIncoming;
 
227
        }
 
228
        else
 
229
                p->rsdIncoming=0;
 
230
 
 
231
        p->cache=cache;
 
232
        p->cacheOK=false;
 
233
        p->userString=userString;
 
234
        return p;
 
235
}
 
236
 
 
237
size_t VoxeliseFilter::numBytesForCache(size_t nObjects) const
 
238
{
 
239
        //if we are using fixed width, we know the answer.
 
240
        //otherwise we dont until we are presented with the boundcube.
 
241
        //TODO: Modify the function description to pass in the boundcube
 
242
        if(!fixedWidth)
 
243
                return  nBins[0]*nBins[1]*nBins[2]*sizeof(float);
 
244
        else
 
245
                return 0;
 
246
}
 
247
 
 
248
void VoxeliseFilter::initFilter(const std::vector<const FilterStreamData *> &dataIn,
 
249
                                                std::vector<const FilterStreamData *> &dataOut)
 
250
{
 
251
        const RangeStreamData *c=0;
 
252
        //Determine if we have an incoming range
 
253
        for (size_t i = 0; i < dataIn.size(); i++) 
 
254
        {
 
255
                if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE)
 
256
                {
 
257
                        c=(const RangeStreamData *)dataIn[i];
 
258
 
 
259
                        break;
 
260
                }
 
261
        }
 
262
 
 
263
        //we no longer (or never did) have any incoming ranges. Not much to do
 
264
        if(!c)
 
265
        {
 
266
                //delete the old incoming range pointer
 
267
                if(rsdIncoming)
 
268
                        delete rsdIncoming;
 
269
                rsdIncoming=0;
 
270
 
 
271
                enabledIons[0].clear(); //clear numerator options
 
272
                enabledIons[1].clear(); //clear denominator options
 
273
 
 
274
                //Prevent normalisation type being set incorrectly
 
275
                // if we have no incoming range data
 
276
                if(normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL || normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL)
 
277
                        normaliseType= VOXELISE_NORMALISETYPE_NONE;
 
278
        }
 
279
        else
 
280
        {
 
281
 
 
282
 
 
283
                //If we didn't have an incoming rsd, then make one up!
 
284
                if(!rsdIncoming)
 
285
                {
 
286
                        rsdIncoming = new RangeStreamData;
 
287
                        *rsdIncoming=*c;
 
288
 
 
289
                        //set the numerator to all disabled
 
290
                        enabledIons[0].resize(rsdIncoming->rangeFile->getNumIons(),0);
 
291
                        //set the denominator to have all enabled
 
292
                        enabledIons[1].resize(rsdIncoming->rangeFile->getNumIons(),1);
 
293
                }
 
294
                else
 
295
                {
 
296
 
 
297
                        //OK, so we have a range incoming already (from last time)
 
298
                        //-- the question is, is it the same
 
299
                        //one we had before 
 
300
                        //Do a pointer comparison (its a hack, yes, but it should work)
 
301
                        if(rsdIncoming->rangeFile != c->rangeFile)
 
302
                        {
 
303
                                //hmm, it is different. well, trash the old incoming rng
 
304
                                delete rsdIncoming;
 
305
 
 
306
                                rsdIncoming = new RangeStreamData;
 
307
                                *rsdIncoming=*c;
 
308
 
 
309
                                //set the numerator to all disabled
 
310
                                enabledIons[0].resize(rsdIncoming->rangeFile->getNumIons(),0);
 
311
                                //set the denominator to have all enabled
 
312
                                enabledIons[1].resize(rsdIncoming->rangeFile->getNumIons(),1);
 
313
                        }
 
314
                }
 
315
 
 
316
        }
 
317
}
 
318
 
 
319
unsigned int VoxeliseFilter::refresh(const std::vector<const FilterStreamData *> &dataIn,
 
320
                  std::vector<const FilterStreamData *> &getOut, ProgressData &progress, bool (*callback)(bool))
 
321
{
 
322
        for(size_t ui=0;ui<dataIn.size();ui++)
 
323
        {
 
324
                //Disallow copying of anything in the blockmask. Copy everything else
 
325
                if(!(dataIn[ui]->getStreamType() & getRefreshBlockMask() ))
 
326
                        getOut.push_back(dataIn[ui]);
 
327
        }
 
328
        
 
329
        //use the cached copy if we have it.
 
330
        if(cacheOK)
 
331
        {
 
332
                for(size_t ui=0;ui<filterOutputs.size();ui++)
 
333
                        getOut.push_back(filterOutputs[ui]);
 
334
                return 0;
 
335
        }
 
336
 
 
337
 
 
338
        Point3D minP,maxP;
 
339
 
 
340
        bc.setInverseLimits();
 
341
                
 
342
        for (size_t i = 0; i < dataIn.size(); i++) 
 
343
        {
 
344
                //Check for ion stream types. Block others from propagation.
 
345
                if (dataIn[i]->getStreamType() != STREAM_TYPE_IONS) continue;
 
346
 
 
347
                const IonStreamData *is = (const IonStreamData *)dataIn[i];
 
348
                //Don't work on empty or single object streams (bounding box needs to be defined)
 
349
                if (is->getNumBasicObjects() < 2) continue;
 
350
        
 
351
                BoundCube bcTmp;
 
352
                bcTmp=getIonDataLimits(is->data);
 
353
 
 
354
                //Bounds could be invalid if, for example, we had coplanar axis aligned points
 
355
                if (!bcTmp.isValid()) continue;
 
356
 
 
357
                bc.expand(bcTmp);
 
358
        }
 
359
        //No bounding box? Tough cookies
 
360
        if (!bc.isValid() || bc.isFlat()) return VOXELISE_BOUNDS_INVALID_ERR;
 
361
 
 
362
        bc.getBounds(minP,maxP);        
 
363
        if (fixedWidth) 
 
364
                calculateNumBinsFromWidths(binWidth, nBins);
 
365
        else
 
366
                calculateWidthsFromNumBins(binWidth, nBins);
 
367
        
 
368
        //Disallow empty bounding boxes (ie, produce no output)
 
369
        if(minP == maxP)
 
370
                return 0;
 
371
                
 
372
        VoxelStreamData *vs = new VoxelStreamData();
 
373
        vs->parent=this;
 
374
        vs->data.setCallbackMethod(callback);
 
375
        vs->data.init(nBins[0], nBins[1], nBins[2], bc);
 
376
        vs->representationType= representation;
 
377
        vs->splatSize = splatSize;
 
378
        vs->isoLevel=isoLevel;
 
379
        vs->data.fill(0);
 
380
        vs->r=r;
 
381
        vs->g=g;
 
382
        vs->b=b;
 
383
        vs->a=a;
 
384
 
 
385
        Voxels<float> vsDenom;
 
386
        if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL ||
 
387
                normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL) {
 
388
                //Check we actually have incoming data
 
389
                ASSERT(rsdIncoming);
 
390
                vsDenom.setCallbackMethod(callback);
 
391
                vsDenom.init(nBins[0], nBins[1], nBins[2], bc);
 
392
                vsDenom.fill(0);
 
393
        }
 
394
 
 
395
        const IonStreamData *is;
 
396
        if(rsdIncoming)
 
397
        {
 
398
 
 
399
                for (size_t i = 0; i < dataIn.size(); i++) 
 
400
                {
 
401
                        
 
402
                        //Check for ion stream types. Don't use anything else in counting
 
403
                        if (dataIn[i]->getStreamType() != STREAM_TYPE_IONS) continue;
 
404
                        
 
405
                        is= (const IonStreamData *)dataIn[i];
 
406
 
 
407
                        
 
408
                        //Count the numerator ions      
 
409
                        if(is->data.size())
 
410
                        {
 
411
                                //Check what Ion type this stream belongs to. Assume all ions
 
412
                                //in the stream belong to the same group
 
413
                                unsigned int ionID;
 
414
                                ionID = getIonstreamIonID(is,rsdIncoming->rangeFile);
 
415
 
 
416
                                bool thisIonEnabled;
 
417
                                if(ionID!=(unsigned int)-1)
 
418
                                        thisIonEnabled=enabledIons[0][ionID];
 
419
                                else
 
420
                                        thisIonEnabled=false;
 
421
 
 
422
                                if(thisIonEnabled)
 
423
                                {
 
424
                                        countPoints(vs->data,is->data,true,callback);
 
425
                                }
 
426
                        }
 
427
                
 
428
                        //If the user requests normalisation, compute the denominator dataset
 
429
                        if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL) {
 
430
                                if(is->data.size())
 
431
                                {
 
432
                                        //Check what Ion type this stream belongs to. Assume all ions
 
433
                                        //in the stream belong to the same group
 
434
                                        unsigned int ionID;
 
435
                                        ionID = rsdIncoming->rangeFile->getIonID(is->data[0].getMassToCharge());
 
436
 
 
437
                                        bool thisIonEnabled;
 
438
                                        if(ionID!=(unsigned int)-1)
 
439
                                                thisIonEnabled=enabledIons[1][ionID];
 
440
                                        else
 
441
                                                thisIonEnabled=false;
 
442
 
 
443
                                        if(thisIonEnabled)
 
444
                                                countPoints(vsDenom,is->data,true,callback);
 
445
                                }
 
446
                        } else if (normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL)
 
447
                        {
 
448
                                countPoints(vsDenom,is->data,true,callback);
 
449
                        }
 
450
 
 
451
                        if(!(*callback)(false))
 
452
                        {
 
453
                                delete vs;
 
454
                                return VOXELISE_ABORT_ERR;
 
455
                        }
 
456
                }
 
457
        
 
458
                //Perform normalsiation 
 
459
                if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME)
 
460
                        vs->data.calculateDensity();
 
461
                else if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL ||
 
462
                                 normaliseType == VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL)
 
463
                        vs->data /= vsDenom;
 
464
        }
 
465
        else
 
466
        {
 
467
                //No range data.  Just count
 
468
                for (size_t i = 0; i < dataIn.size(); i++) 
 
469
                {
 
470
                        
 
471
                        if(dataIn[i]->getStreamType() == STREAM_TYPE_IONS)
 
472
                        {
 
473
                                is= (const IonStreamData *)dataIn[i];
 
474
 
 
475
                                countPoints(vs->data,is->data,true,callback);
 
476
                                
 
477
                                if(!(*callback)(false))
 
478
                                {
 
479
                                        delete vs;
 
480
                                        return VOXELISE_ABORT_ERR;
 
481
                                }
 
482
 
 
483
                        }
 
484
                }
 
485
                ASSERT(normaliseType != VOXELISE_NORMALISETYPE_COUNT2INVOXEL
 
486
                                && normaliseType!=VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL);
 
487
                if (normaliseType == VOXELISE_NORMALISETYPE_VOLUME)
 
488
                        vs->data.calculateDensity();
 
489
        }       
 
490
 
 
491
        vsDenom.clear();
 
492
 
 
493
 
 
494
        //Perform voxel filtering
 
495
        switch(filterMode)
 
496
        {
 
497
                case VOXELISE_FILTERTYPE_NONE:
 
498
                        break;
 
499
                case VOXELISE_FILTERTYPE_GAUSS:
 
500
                {
 
501
                        Voxels<float> kernel,res;
 
502
 
 
503
                        map<unsigned int, unsigned int> modeMap;
 
504
 
 
505
 
 
506
                        modeMap[VOXELISE_FILTERBOUNDMODE_ZERO]=BOUND_ZERO;
 
507
                        modeMap[VOXELISE_FILTERBOUNDMODE_BOUNCE]=BOUND_MIRROR;
 
508
 
 
509
                        //FIXME: This will be SLOW. need to use IIR or some other
 
510
                        //fast technique
 
511
                        
 
512
                        //Construct the gaussian convolution
 
513
                        kernel.setGaussianKernelCube(gaussDev,(float)filterBins,filterBins);
 
514
                        //Normalise the kernel
 
515
                        float sum;
 
516
                        sum=kernel.getSum();
 
517
                        kernel/=sum;
 
518
                
 
519
                        if(res.resize(vs->data))
 
520
                                return VOXELISE_MEMORY_ERR; 
 
521
 
 
522
                        //Gaussian kernel is separable (rank 1)
 
523
                        if(vs->data.separableConvolve(kernel,res,modeMap[filterBoundaryMode]))
 
524
                                return VOXELISE_CONVOLVE_ERR;
 
525
 
 
526
                        vs->data.swap(res);
 
527
 
 
528
                        res.clear();
 
529
                        break;
 
530
                }
 
531
                default:
 
532
                        ASSERT(false);
 
533
        }
 
534
 
 
535
        
 
536
        float min,max;
 
537
        vs->data.minMax(min,max);
 
538
 
 
539
 
 
540
        string sMin,sMax;
 
541
        stream_cast(sMin,min);
 
542
        stream_cast(sMax,max);
 
543
        consoleOutput.push_back(std::string(TRANS("Voxel Limits (min,max): (") + sMin + string(","))
 
544
                        +  sMax + ")");
 
545
        if(cache)
 
546
        {
 
547
                vs->cached=1;
 
548
                cacheOK=true;
 
549
                filterOutputs.push_back(vs);
 
550
        }
 
551
        else
 
552
                vs->cached=0;
 
553
 
 
554
 
 
555
        //Store the voxels on the output
 
556
        getOut.push_back(vs);
 
557
        
 
558
        //Copy the inputs into the outputs, provided they are not voxels
 
559
        return 0;
 
560
}
 
561
 
 
562
std::string VoxeliseFilter::getNormaliseTypeString(int type){
 
563
        ASSERT(type < VOXELISE_NORMALISETYPE_MAX);
 
564
        return TRANS(NORMALISE_TYPE_STRING[type]);
 
565
}
 
566
 
 
567
std::string VoxeliseFilter::getRepresentTypeString(int type) {
 
568
        ASSERT(type<VOXEL_REPRESENT_END);
 
569
        return  std::string(TRANS(REPRESENTATION_TYPE_STRING[type]));
 
570
}
 
571
 
 
572
std::string VoxeliseFilter::getFilterTypeString(int type)
 
573
{
 
574
        ASSERT(type < VOXELISE_FILTERTYPE_MAX);
 
575
        return std::string(TRANS(VOXELISE_FILTER_TYPE_STRING[type]));
 
576
}
 
577
 
 
578
 
 
579
std::string VoxeliseFilter::getFilterBoundTypeString(int type) 
 
580
{
 
581
        ASSERT(type < VOXELISE_FILTERBOUNDMODE_MAX);
 
582
        return std::string(TRANS(VOXELISE_FILTER_BOUND_STRING[type]));
 
583
}
 
584
 
 
585
void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 
586
{
 
587
        FilterProperty p;
 
588
        size_t curGroup=0;
 
589
 
 
590
        string tmpStr;
 
591
        stream_cast(tmpStr, fixedWidth);
 
592
        p.name=TRANS("Fixed width");
 
593
        p.data=tmpStr;
 
594
        p.key=KEY_FIXEDWIDTH;
 
595
        p.type=PROPERTY_TYPE_BOOL;
 
596
        p.helpText=TRANS("If true, use fixed size voxels, otherwise use fixed count");
 
597
        propertyList.addProperty(p,curGroup);
 
598
 
 
599
        if(fixedWidth)
 
600
        {
 
601
                stream_cast(tmpStr,binWidth[0]);
 
602
                p.name=TRANS("Bin width x");
 
603
                p.data=tmpStr;
 
604
                p.key=KEY_WIDTHBINSX;
 
605
                p.type=PROPERTY_TYPE_REAL;
 
606
                p.helpText=TRANS("Voxel size in X direction");
 
607
                propertyList.addProperty(p,curGroup);
 
608
 
 
609
                stream_cast(tmpStr,binWidth[1]);
 
610
                p.name=TRANS("Bin width y");
 
611
                p.data=tmpStr;
 
612
                p.type=PROPERTY_TYPE_REAL;
 
613
                p.helpText=TRANS("Voxel size in Y direction");
 
614
                p.key=KEY_WIDTHBINSY;
 
615
                propertyList.addProperty(p,curGroup);
 
616
 
 
617
 
 
618
                stream_cast(tmpStr,binWidth[2]);
 
619
                p.name=TRANS("Bin width z");
 
620
                p.data=tmpStr;
 
621
                p.type=PROPERTY_TYPE_REAL;
 
622
                p.helpText=TRANS("Voxel size in Z direction");
 
623
                p.key=KEY_WIDTHBINSZ;
 
624
                propertyList.addProperty(p,curGroup);
 
625
        }
 
626
        else
 
627
        {
 
628
                stream_cast(tmpStr,nBins[0]);
 
629
                p.name=TRANS("Num bins x");
 
630
                p.data=tmpStr;
 
631
                p.key=KEY_NBINSX;
 
632
                p.type=PROPERTY_TYPE_INTEGER;
 
633
                p.helpText=TRANS("Number of voxels to use in X direction");
 
634
                propertyList.addProperty(p,curGroup);
 
635
                
 
636
                stream_cast(tmpStr,nBins[1]);
 
637
                p.key=KEY_NBINSY;
 
638
                p.name=TRANS("Num bins y");
 
639
                p.data=tmpStr;
 
640
                p.type=PROPERTY_TYPE_INTEGER;
 
641
                p.helpText=TRANS("Number of voxels to use in Y direction");
 
642
                propertyList.addProperty(p,curGroup);
 
643
                
 
644
                stream_cast(tmpStr,nBins[2]);
 
645
                p.key=KEY_NBINSZ;
 
646
                p.data=tmpStr;
 
647
                p.name=TRANS("Num bins z");
 
648
                p.type=PROPERTY_TYPE_INTEGER;
 
649
                p.helpText=TRANS("Number of voxels to use in Z direction");
 
650
                propertyList.addProperty(p,curGroup);
 
651
        }
 
652
 
 
653
        //Let the user know what the valid values for voxel value types are
 
654
        vector<pair<unsigned int,string> > choices;
 
655
        tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_NONE);
 
656
        choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_NONE,tmpStr));
 
657
        tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_VOLUME);
 
658
        choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_VOLUME,tmpStr));
 
659
        if(rsdIncoming)
 
660
        {
 
661
                //Concentration mode
 
662
                tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL);
 
663
                choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL,tmpStr));
 
664
                //Ratio is only valid if we have a way of separation for the ions i.e. range
 
665
                tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_COUNT2INVOXEL);
 
666
                choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_COUNT2INVOXEL,tmpStr));
 
667
        }
 
668
 
 
669
        tmpStr= choiceString(choices,normaliseType);
 
670
        p.name=TRANS("Normalise by");
 
671
        p.data=tmpStr;
 
672
        p.type=PROPERTY_TYPE_CHOICE;
 
673
        p.helpText=TRANS("Method to use to normalise scalar value in each voxel");
 
674
        p.key=KEY_NORMALISE_TYPE;
 
675
        propertyList.addProperty(p,curGroup);
 
676
        propertyList.setGroupTitle(curGroup,TRANS("Computation"));
 
677
 
 
678
        curGroup++;
 
679
        
 
680
        // numerator
 
681
        if (rsdIncoming) 
 
682
        {
 
683
                p.name=TRANS("Numerator");
 
684
                p.data=numeratorAll ? "1" : "0";
 
685
                p.type=PROPERTY_TYPE_BOOL;
 
686
                p.helpText=TRANS("Parmeter \"a\" used in fraction (a/b) to get voxel value");
 
687
                p.key=KEY_ENABLE_NUMERATOR;
 
688
                propertyList.addProperty(p,curGroup);
 
689
 
 
690
                ASSERT(rsdIncoming->enabledIons.size()==enabledIons[0].size()); 
 
691
                ASSERT(rsdIncoming->enabledIons.size()==enabledIons[1].size()); 
 
692
 
 
693
                //Look at the numerator 
 
694
                for(unsigned  int ui=0; ui<rsdIncoming->enabledIons.size(); ui++)
 
695
                {
 
696
                        string str;
 
697
                        if(enabledIons[0][ui])
 
698
                                str="1";
 
699
                        else
 
700
                                str="0";
 
701
 
 
702
                        //Append the ion name with a checkbox
 
703
                        p.name=rsdIncoming->rangeFile->getName(ui);
 
704
                        p.data=str;
 
705
                        p.type=PROPERTY_TYPE_BOOL;
 
706
                        p.helpText=TRANS("Enable this ion for numerator");
 
707
                        p.key=KEY_ENABLE_NUMERATOR*1000+ui;
 
708
                        propertyList.addProperty(p,curGroup);
 
709
                }
 
710
        
 
711
                curGroup++;
 
712
        }
 
713
        
 
714
        
 
715
        if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL && rsdIncoming) 
 
716
        {
 
717
                p.name=TRANS("Denominator");
 
718
                p.data=denominatorAll ? "1" : "0";
 
719
                p.type=PROPERTY_TYPE_BOOL;
 
720
                p.helpText=TRANS("Parameter \"b\" used in fraction (a/b) to get voxel value");
 
721
                p.key=KEY_ENABLE_DENOMINATOR;
 
722
 
 
723
                for(unsigned  int ui=0; ui<rsdIncoming->enabledIons.size(); ui++)
 
724
                {                       
 
725
                        string str;
 
726
                        if(enabledIons[1][ui])
 
727
                                str="1";
 
728
                        else
 
729
                                str="0";
 
730
 
 
731
                        //Append the ion name with a checkbox
 
732
                        p.key=KEY_ENABLE_DENOMINATOR*1000 + ui;
 
733
                        p.data=str;
 
734
                        p.name=rsdIncoming->rangeFile->getName(ui);
 
735
                        p.type=PROPERTY_TYPE_BOOL;
 
736
                        p.helpText=TRANS("Enable this ion for denominator contribution");
 
737
 
 
738
                        propertyList.addProperty(p,curGroup);
 
739
                }
 
740
                curGroup++;
 
741
        }
 
742
 
 
743
        //Start a new set for filtering
 
744
        //----
 
745
        //TODO: Other filtering? threshold/median? laplacian? etc
 
746
        
 
747
        choices.clear();
 
748
 
 
749
        //Post-filtering method
 
750
        for(unsigned int ui=0;ui<VOXELISE_FILTERTYPE_MAX; ui++)
 
751
        {
 
752
                tmpStr=getFilterTypeString(ui);
 
753
                choices.push_back(make_pair(ui,tmpStr));
 
754
        }
 
755
        tmpStr= choiceString(choices,filterMode);
 
756
 
 
757
        p.name=TRANS("Filtering");
 
758
        p.data=tmpStr;
 
759
        p.key=KEY_FILTER_MODE;
 
760
        p.type=PROPERTY_TYPE_CHOICE;
 
761
        p.helpText=TRANS("Smoothing method to use on voxels");
 
762
 
 
763
        propertyList.addProperty(p,curGroup);
 
764
        propertyList.setGroupTitle(curGroup,TRANS("Processing"));
 
765
        if(filterMode != VOXELISE_FILTERTYPE_NONE)
 
766
        {
 
767
 
 
768
                //Filter size
 
769
                stream_cast(tmpStr,filterBins);
 
770
                p.name=TRANS("Kernel Bins");
 
771
                p.data=tmpStr;
 
772
                p.key=KEY_FILTER_BINS;
 
773
                p.type=PROPERTY_TYPE_INTEGER;
 
774
                p.helpText=TRANS("Number of bins in convolution kernel");
 
775
                propertyList.addProperty(p,curGroup);
 
776
                //Boundary wrapping mode selection
 
777
                choices.clear();
 
778
                for(unsigned int ui=0;ui<VOXELISE_FILTERBOUNDMODE_MAX; ui++)
 
779
                {
 
780
                        tmpStr=getFilterBoundTypeString(ui);
 
781
                        choices.push_back(make_pair(ui,tmpStr));
 
782
                }
 
783
                
 
784
                tmpStr= choiceString(choices,filterBoundaryMode);
 
785
                p.name=TRANS("Exterior values");
 
786
                p.data=tmpStr;
 
787
                p.type=PROPERTY_TYPE_CHOICE;
 
788
                p.helpText=TRANS("Method to use to treat boundaries of voxel data for convolution");
 
789
                p.key=KEY_FILTER_BOUNDARY_MODE;
 
790
                propertyList.addProperty(p,curGroup);
 
791
        }
 
792
        propertyList.setGroupTitle(curGroup,TRANS("Filtering"));
 
793
        curGroup++;
 
794
        //----
 
795
 
 
796
        //start a new group for the visual representation
 
797
        //----------------------------
 
798
        choices.clear();
 
799
        tmpStr=getRepresentTypeString(VOXEL_REPRESENT_POINTCLOUD);
 
800
        choices.push_back(make_pair((unsigned int)VOXEL_REPRESENT_POINTCLOUD,tmpStr));
 
801
        tmpStr=getRepresentTypeString(VOXEL_REPRESENT_ISOSURF);
 
802
        choices.push_back(make_pair((unsigned int)VOXEL_REPRESENT_ISOSURF,tmpStr));
 
803
        
 
804
        tmpStr= choiceString(choices,representation);
 
805
 
 
806
        p.name=TRANS("Representation");
 
807
        p.data=tmpStr;
 
808
        p.type=PROPERTY_TYPE_CHOICE;
 
809
        p.helpText=TRANS("3D display method");
 
810
        p.key=KEY_VOXEL_REPRESENTATION_MODE;
 
811
        propertyList.addProperty(p,curGroup);
 
812
        propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 
813
 
 
814
        switch(representation)
 
815
        {
 
816
                case VOXEL_REPRESENT_POINTCLOUD:
 
817
                {
 
818
                        stream_cast(tmpStr,splatSize);
 
819
                        p.name=TRANS("Spot size");
 
820
                        p.data=tmpStr;
 
821
                        p.type=PROPERTY_TYPE_REAL;
 
822
                        p.helpText=TRANS("Size of the spots to use for display");
 
823
                        p.key=KEY_SPOTSIZE;
 
824
                        propertyList.addProperty(p,curGroup);
 
825
 
 
826
                        stream_cast(tmpStr,1.0-a);
 
827
                        p.name=TRANS("Transparency");
 
828
                        p.data=tmpStr;
 
829
                        p.type=PROPERTY_TYPE_REAL;
 
830
                        p.helpText=TRANS("How \"see through\" each point is (0 - opaque, 1 - invisible)");
 
831
                        p.key=KEY_TRANSPARANCY;
 
832
                        propertyList.addProperty(p,curGroup);
 
833
                        break;
 
834
                }
 
835
                case VOXEL_REPRESENT_ISOSURF:
 
836
                {
 
837
                        stream_cast(tmpStr,isoLevel);
 
838
                        p.name=TRANS("Isovalue");
 
839
                        p.data=tmpStr;
 
840
                        p.type=PROPERTY_TYPE_REAL;
 
841
                        p.helpText=TRANS("Scalar value to show as isosurface");
 
842
                        p.key=KEY_ISOLEVEL;
 
843
                        propertyList.addProperty(p,curGroup);
 
844
                
 
845
                                
 
846
 
 
847
                        //Convert the ion colour to a hex string        
 
848
                        genColString((unsigned char)(r*255),(unsigned char)(g*255),
 
849
                                        (unsigned char)(b*255),(unsigned char)(a*255),tmpStr);
 
850
                        p.name=TRANS("Colour");
 
851
                        p.data=tmpStr;
 
852
                        p.type=PROPERTY_TYPE_COLOUR;
 
853
                        p.helpText=TRANS("Colour of isosurface");
 
854
                        p.key=KEY_COLOUR;
 
855
                        propertyList.addProperty(p,curGroup);
 
856
 
 
857
                        stream_cast(tmpStr,1.0-a);
 
858
                        p.name=TRANS("Transparency");
 
859
                        p.data=tmpStr;
 
860
                        p.type=PROPERTY_TYPE_REAL;
 
861
                        p.helpText=TRANS("How \"see through\" each facet is (0 - opaque, 1 - invisible)");
 
862
                        p.key=KEY_TRANSPARANCY;
 
863
                        propertyList.addProperty(p,curGroup);
 
864
                        
 
865
                        break;
 
866
                }
 
867
                default:
 
868
                        ASSERT(false);
 
869
                        ;
 
870
        }
 
871
        
 
872
        //----------------------------
 
873
}
 
874
 
 
875
bool VoxeliseFilter::setProperty(  unsigned int key,
 
876
                                                                          const std::string &value, bool &needUpdate)
 
877
{
 
878
        
 
879
        needUpdate=false;
 
880
        switch(key)
 
881
        {
 
882
                case KEY_FIXEDWIDTH: 
 
883
                {
 
884
                        bool b;
 
885
                        if(stream_cast(b,value))
 
886
                                return false;
 
887
 
 
888
                        //if the result is different, the
 
889
                        //cache should be invalidated
 
890
                        if(b!=fixedWidth)
 
891
                        {
 
892
                                needUpdate=true;
 
893
                                fixedWidth=b;
 
894
                                clearCache();
 
895
                        }
 
896
                        break;
 
897
                }       
 
898
                case KEY_NBINSX:
 
899
                {
 
900
                         unsigned int i;
 
901
                        if(stream_cast(i,value))
 
902
                                return false;
 
903
                        if(!i)
 
904
                                return false;
 
905
 
 
906
                        needUpdate=true;
 
907
                        nBins[0]=i;
 
908
                        //if the result is different, the
 
909
                        //cache should be invalidated
 
910
                        if(i!=nBins[0])
 
911
                        {
 
912
                                needUpdate=true;
 
913
                                nBins[0]=i;
 
914
                                calculateWidthsFromNumBins(binWidth, nBins);
 
915
                                clearCache();
 
916
                        }
 
917
                        break;
 
918
                }
 
919
                case KEY_NBINSY:
 
920
                {
 
921
                         unsigned int i;
 
922
                        if(stream_cast(i,value))
 
923
                                return false;
 
924
                        if(!i)
 
925
                                return false;
 
926
                        needUpdate=true;
 
927
                        //if the result is different, the
 
928
                        //cache should be invalidated
 
929
                        if(i!=nBins[1])
 
930
                        {
 
931
                                needUpdate=true;
 
932
                                nBins[1]=i;
 
933
                                calculateWidthsFromNumBins(binWidth, nBins);
 
934
                                clearCache();
 
935
                        }
 
936
                        break;
 
937
                }
 
938
                case KEY_NBINSZ:
 
939
                {
 
940
                         unsigned int i;
 
941
                        if(stream_cast(i,value))
 
942
                                return false;
 
943
                        if(!i)
 
944
                                return false;
 
945
                        
 
946
                        //if the result is different, the
 
947
                        //cache should be invalidated
 
948
                        if(i!=nBins[2])
 
949
                        {
 
950
                                needUpdate=true;
 
951
                                nBins[2]=i;
 
952
                                calculateWidthsFromNumBins(binWidth, nBins);
 
953
                                clearCache();
 
954
                        }
 
955
                        break;
 
956
                }
 
957
                case KEY_WIDTHBINSX:
 
958
                {
 
959
                        float f;
 
960
                        if(stream_cast(f,value))
 
961
                                return false;
 
962
                        if(f <= 0.0f)
 
963
                                return false;
 
964
                
 
965
                        if(f!=binWidth[0])
 
966
                        {
 
967
                                needUpdate=true;
 
968
                                binWidth[0]=f;
 
969
                                calculateNumBinsFromWidths(binWidth, nBins);
 
970
                                clearCache();
 
971
                        }
 
972
                        break;
 
973
                }
 
974
                case KEY_WIDTHBINSY:
 
975
                {
 
976
                        float f;
 
977
                        if(stream_cast(f,value))
 
978
                                return false;
 
979
                        if(f <= 0.0f)
 
980
                                return false;
 
981
                        
 
982
                        if(f!=binWidth[1])
 
983
                        {
 
984
                                needUpdate=true;
 
985
                                binWidth[1]=f;
 
986
                                calculateNumBinsFromWidths(binWidth, nBins);
 
987
                                clearCache();
 
988
                        }
 
989
                        break;
 
990
                }
 
991
                case KEY_WIDTHBINSZ:
 
992
                {
 
993
                        float f;
 
994
                        if(stream_cast(f,value))
 
995
                                return false;
 
996
                        if(f <= 0.0f)
 
997
                                return false;
 
998
                        if(f!=binWidth[2])
 
999
                        {
 
1000
                                needUpdate=true;
 
1001
                                binWidth[2]=f;
 
1002
                                calculateNumBinsFromWidths(binWidth, nBins);
 
1003
                                clearCache();
 
1004
                        }
 
1005
                        break;
 
1006
                }
 
1007
                case KEY_NORMALISE_TYPE:
 
1008
                {
 
1009
                        unsigned int i;
 
1010
                        for(i = 0; i < VOXELISE_NORMALISETYPE_MAX; i++)
 
1011
                                if (value == getNormaliseTypeString(i)) break;
 
1012
                        if (i == VOXELISE_NORMALISETYPE_MAX)
 
1013
                                return false;
 
1014
                        if(normaliseType!=i)
 
1015
                        {
 
1016
                                needUpdate=true;
 
1017
                                clearCache();
 
1018
                                normaliseType=i;
 
1019
                        }
 
1020
                        break;
 
1021
                }
 
1022
                case KEY_SPOTSIZE:
 
1023
                {
 
1024
                        float f;
 
1025
                        if(stream_cast(f,value))
 
1026
                                return false;
 
1027
                        if(f <= 0.0f)
 
1028
                                return false;
 
1029
                        if(f !=splatSize)
 
1030
                        {
 
1031
                                splatSize=f;
 
1032
                                needUpdate=true;
 
1033
 
 
1034
                                //Go in and manually adjust the cached
 
1035
                                //entries to have the new value, rather
 
1036
                                //than doing a full recomputation
 
1037
                                if(cacheOK)
 
1038
                                {
 
1039
                                        for(unsigned int ui=0;ui<filterOutputs.size();ui++)
 
1040
                                        {
 
1041
                                                VoxelStreamData *d;
 
1042
                                                d=(VoxelStreamData*)filterOutputs[ui];
 
1043
                                                d->splatSize=splatSize;
 
1044
                                        }
 
1045
                                }
 
1046
 
 
1047
                        }
 
1048
                        break;
 
1049
                }
 
1050
                case KEY_TRANSPARANCY:
 
1051
                {
 
1052
                        float f;
 
1053
                        if(stream_cast(f,value))
 
1054
                                return false;
 
1055
                        if(f < 0.0f || f > 1.0)
 
1056
                                return false;
 
1057
                        needUpdate=true;
 
1058
                        //Alpha is opacity, which is 1-transparancy
 
1059
                        a=1.0f-f;
 
1060
                        //Go in and manually adjust the cached
 
1061
                        //entries to have the new value, rather
 
1062
                        //than doing a full recomputation
 
1063
                        if(cacheOK)
 
1064
                        {
 
1065
                                for(unsigned int ui=0;ui<filterOutputs.size();ui++)
 
1066
                                {
 
1067
                                        VoxelStreamData *d;
 
1068
                                        d=(VoxelStreamData*)filterOutputs[ui];
 
1069
                                        d->a=a;
 
1070
                                }
 
1071
                        }
 
1072
                        break;
 
1073
                }
 
1074
                case KEY_ISOLEVEL:
 
1075
                {
 
1076
                        float f;
 
1077
                        if(stream_cast(f,value))
 
1078
                                return false;
 
1079
                        if(f <= 0.0f)
 
1080
                                return false;
 
1081
                        needUpdate=true;
 
1082
                        isoLevel=f;
 
1083
                        //Go in and manually adjust the cached
 
1084
                        //entries to have the new value, rather
 
1085
                        //than doing a full recomputation
 
1086
                        if(cacheOK)
 
1087
                        {
 
1088
                                for(unsigned int ui=0;ui<filterOutputs.size();ui++)
 
1089
                                {
 
1090
                                        VoxelStreamData *d;
 
1091
                                        d=(VoxelStreamData*)filterOutputs[ui];
 
1092
                                        d->isoLevel=isoLevel;
 
1093
                                }
 
1094
                        }
 
1095
                        break;
 
1096
                }
 
1097
                case KEY_COLOUR:
 
1098
                {
 
1099
                        unsigned char newR,newG,newB,newA;
 
1100
 
 
1101
                        parseColString(value,newR,newG,newB,newA);
 
1102
 
 
1103
                        if(newB != b || newR != r ||
 
1104
                                newG !=g || newA != a)
 
1105
                                needUpdate=true;
 
1106
                        r=newR/255.0;
 
1107
                        g=newG/255.0;
 
1108
                        b=newB/255.0;
 
1109
                        //Go in and manually adjust the cached
 
1110
                        //entries to have the new value, rather
 
1111
                        //than doing a full recomputation
 
1112
                        if(cacheOK)
 
1113
                        {
 
1114
                                for(unsigned int ui=0;ui<filterOutputs.size();ui++)
 
1115
                                {
 
1116
                                        VoxelStreamData *d;
 
1117
                                        d=(VoxelStreamData*)filterOutputs[ui];
 
1118
                                        d->r=r;
 
1119
                                        d->g=g;
 
1120
                                        d->b=b;
 
1121
                                }
 
1122
                        }
 
1123
                        break;
 
1124
                }
 
1125
                case KEY_VOXEL_REPRESENTATION_MODE:
 
1126
                {
 
1127
                         unsigned int i;
 
1128
                        for (i = 0; i < VOXEL_REPRESENT_END; i++)
 
1129
                                if (value == getRepresentTypeString(i)) break;
 
1130
                        if (i == VOXEL_REPRESENT_END)
 
1131
                                return false;
 
1132
                        needUpdate=true;
 
1133
                        representation=i;
 
1134
                        //Go in and manually adjust the cached
 
1135
                        //entries to have the new value, rather
 
1136
                        //than doing a full recomputation
 
1137
                        if(cacheOK)
 
1138
                        {
 
1139
                                for(unsigned int ui=0;ui<filterOutputs.size();ui++)
 
1140
                                {
 
1141
                                        VoxelStreamData *d;
 
1142
                                        d=(VoxelStreamData*)filterOutputs[ui];
 
1143
                                        d->representationType=representation;
 
1144
                                }
 
1145
                        }
 
1146
                        break;
 
1147
                }
 
1148
                case KEY_ENABLE_NUMERATOR:
 
1149
                {
 
1150
                        bool b;
 
1151
                        if(stream_cast(b,value))
 
1152
                                return false;
 
1153
                        //Set them all to enabled or disabled as a group        
 
1154
                        for (size_t i = 0; i < enabledIons[0].size(); i++) 
 
1155
                                enabledIons[0][i] = b;
 
1156
                        numeratorAll = b;
 
1157
                        needUpdate=true;
 
1158
                        clearCache();
 
1159
                        break;
 
1160
                }
 
1161
                case KEY_ENABLE_DENOMINATOR:
 
1162
                {
 
1163
                        bool b;
 
1164
                        if(stream_cast(b,value))
 
1165
                                return false;
 
1166
        
 
1167
                        //Set them all to enabled or disabled as a group        
 
1168
                        for (size_t i = 0; i < enabledIons[1].size(); i++) 
 
1169
                                enabledIons[1][i] = b;
 
1170
                        
 
1171
                        denominatorAll = b;
 
1172
                        needUpdate=true;                        
 
1173
                        clearCache();
 
1174
                        break;
 
1175
                }
 
1176
                case KEY_FILTER_MODE:
 
1177
                {
 
1178
                         unsigned int i;
 
1179
                        for (i = 0; i < VOXEL_REPRESENT_END; i++)
 
1180
                                if (value == getFilterTypeString(i)) break;
 
1181
                        if (i == VOXEL_REPRESENT_END)
 
1182
                                return false;
 
1183
                        if(i!=filterMode)
 
1184
                        {
 
1185
                                needUpdate=true;
 
1186
                                filterMode=i;
 
1187
                                clearCache();
 
1188
                        }
 
1189
                        break;
 
1190
                }
 
1191
                case KEY_FILTER_BOUNDARY_MODE:
 
1192
                {
 
1193
                         unsigned int i;
 
1194
                        for (i = 0; i < VOXELISE_FILTERBOUNDMODE_MAX; i++)
 
1195
                                if (value == getFilterBoundTypeString(i)) break;
 
1196
                        if (i == VOXELISE_FILTERTYPE_MAX)
 
1197
                                return false;
 
1198
                        
 
1199
                        if(i != filterBoundaryMode)
 
1200
                        {
 
1201
                                filterBoundaryMode=i;
 
1202
                                needUpdate=true;
 
1203
                                clearCache();
 
1204
                        }
 
1205
                        break;
 
1206
                }
 
1207
                case KEY_FILTER_BINS:
 
1208
                {
 
1209
                         unsigned int i;
 
1210
                        if(stream_cast(i,value))
 
1211
                                return false;
 
1212
 
 
1213
                        //FIXME: Min restriction is artificial and imposed due to incomplete separable convolution filter implementation
 
1214
                        if(i == 0 || i > std::min(nBins[0],std::min(nBins[1],nBins[2])))
 
1215
                                return false;
 
1216
                        if(i != filterBins)
 
1217
                        {
 
1218
                                needUpdate=true;
 
1219
                                filterBins=i;
 
1220
                                clearCache();
 
1221
                        }
 
1222
                        break;
 
1223
                }
 
1224
                default:
 
1225
                {
 
1226
                        if (key >= KEY_ENABLE_DENOMINATOR*1000) {
 
1227
                                bool b;
 
1228
                                if(stream_cast(b,value))
 
1229
                                        return false;
 
1230
 
 
1231
                                enabledIons[1][key - KEY_ENABLE_DENOMINATOR*1000]=b;
 
1232
                                if (!b) {
 
1233
                                        denominatorAll = false;
 
1234
                                }
 
1235
                                needUpdate=true;                        
 
1236
                                clearCache();
 
1237
                        } else if (key >= KEY_ENABLE_NUMERATOR*1000) {
 
1238
                                bool b;
 
1239
                                if(stream_cast(b,value))
 
1240
                                        return false;
 
1241
                                
 
1242
                                enabledIons[0][key - KEY_ENABLE_NUMERATOR*1000]=b;
 
1243
                                if (!b) {
 
1244
                                        numeratorAll = false;
 
1245
                                }
 
1246
                                needUpdate=true;                        
 
1247
                                        clearCache();
 
1248
                        }
 
1249
                        else
 
1250
                        {
 
1251
                                ASSERT(false);
 
1252
                        }
 
1253
                        break;
 
1254
                }
 
1255
        }
 
1256
        return true;
 
1257
}
 
1258
 
 
1259
std::string  VoxeliseFilter::getErrString(unsigned int code) const
 
1260
{
 
1261
        switch(code)
 
1262
        {
 
1263
                case VOXELISE_ABORT_ERR:
 
1264
                        return std::string(TRANS("Voxelisation aborted"));
 
1265
                case VOXELISE_MEMORY_ERR:
 
1266
                        return std::string(TRANS("Out of memory"));
 
1267
                case VOXELISE_CONVOLVE_ERR:
 
1268
                        return std::string(TRANS("Unable to perform filter convolution"));
 
1269
                case VOXELISE_BOUNDS_INVALID_ERR:
 
1270
                        return std::string(TRANS("Voxelisation bounds are invalid"));
 
1271
        }       
 
1272
        
 
1273
        return std::string("BUG! Should not see this (VoxeliseFilter)");
 
1274
}
 
1275
 
 
1276
bool VoxeliseFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const
 
1277
{
 
1278
        using std::endl;
 
1279
        switch(format)
 
1280
        {
 
1281
                case STATE_FORMAT_XML:
 
1282
                {       
 
1283
                        f << tabs(depth) << "<" << trueName() << ">" << endl;
 
1284
                        f << tabs(depth+1) << "<userstring value=\"" << escapeXML(userString) << "\"/>" << endl;
 
1285
                        f << tabs(depth+1) << "<fixedwidth value=\""<<fixedWidth << "\"/>"  << endl;
 
1286
                        f << tabs(depth+1) << "<nbins values=\""<<nBins[0] << ","<<nBins[1]<<","<<nBins[2] << "\"/>"  << endl;
 
1287
                        f << tabs(depth+1) << "<binwidth values=\""<<binWidth[0] << ","<<binWidth[1]<<","<<binWidth[2] << "\"/>"  << endl;
 
1288
                        f << tabs(depth+1) << "<normalisetype value=\""<<normaliseType << "\"/>"  << endl;
 
1289
                        f << tabs(depth+1) << "<enabledions>" << endl;
 
1290
 
 
1291
                        f << tabs(depth+2) << "<numerator>" << endl;
 
1292
                        for(unsigned int ui=0;ui<enabledIons[0].size(); ui++)
 
1293
                                f << tabs(depth+3) << "<enabled value=\"" << (enabledIons[0][ui]?1:0) << "\"/>" << endl;
 
1294
                        f << tabs(depth+2) << "</numerator>" << endl;
 
1295
 
 
1296
                        f << tabs(depth+2) << "<denominator>" << endl;
 
1297
                        for(unsigned int ui=0;ui<enabledIons[1].size(); ui++)
 
1298
                                f << tabs(depth+3) << "<enabled value=\"" << (enabledIons[1][ui]?1:0) << "\"/>" << endl;
 
1299
                        f << tabs(depth+2) << "</denominator>" << endl;
 
1300
 
 
1301
                        f << tabs(depth+1) << "</enabledions>" << endl;
 
1302
 
 
1303
                        f << tabs(depth+1) << "<representation value=\""<<representation << "\"/>" << endl;
 
1304
                        f << tabs(depth+1) << "<isovalue value=\""<<isoLevel << "\"/>" << endl;
 
1305
                        f << tabs(depth+1) << "<colour r=\"" <<  r<< "\" g=\"" << g << "\" b=\"" <<b
 
1306
                                << "\" a=\"" << a << "\"/>" <<endl;
 
1307
                        f << tabs(depth) << "</" << trueName() <<">" << endl;
 
1308
                        break;
 
1309
                }
 
1310
                default:
 
1311
                        ASSERT(false);
 
1312
                        return false;
 
1313
        }
 
1314
        
 
1315
        return true;
 
1316
}
 
1317
 
 
1318
bool VoxeliseFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir)
 
1319
{
 
1320
        using std::string;
 
1321
        string tmpStr;
 
1322
        xmlChar *xmlString;
 
1323
        stack<xmlNodePtr> nodeStack;
 
1324
 
 
1325
        //Retrieve user string
 
1326
        //===
 
1327
        if(XMLHelpFwdToElem(nodePtr,"userstring"))
 
1328
                return false;
 
1329
 
 
1330
        xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value");
 
1331
        if(!xmlString)
 
1332
                return false;
 
1333
        userString=(char *)xmlString;
 
1334
        xmlFree(xmlString);
 
1335
        //===
 
1336
 
 
1337
        //Retrieve fixedWidth mode
 
1338
        if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"fixedwidth","value"))
 
1339
                return false;
 
1340
        if(tmpStr == "1") 
 
1341
                fixedWidth=true;
 
1342
        else if(tmpStr== "0")
 
1343
                fixedWidth=false;
 
1344
        else
 
1345
                return false;
 
1346
        
 
1347
        //Retrieve nBins        
 
1348
        if(XMLHelpFwdToElem(nodePtr,"nbins"))
 
1349
                return false;
 
1350
        xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values");
 
1351
        if(!xmlString)
 
1352
                return false;
 
1353
        std::vector<string> v1;
 
1354
        splitStrsRef((char *)xmlString,',',v1);
 
1355
        for (size_t i = 0; i < INDEX_LENGTH && i < v1.size(); i++)
 
1356
        {
 
1357
                if(stream_cast(nBins[i],v1[i]))
 
1358
                        return false;
 
1359
                
 
1360
                if(nBins[i] <= 0)
 
1361
                        return false;
 
1362
        }
 
1363
        xmlFree(xmlString);
 
1364
        
 
1365
        //Retrieve bin width 
 
1366
        if(XMLHelpFwdToElem(nodePtr,"binwidth"))
 
1367
                return false;
 
1368
        xmlString=xmlGetProp(nodePtr,(const xmlChar *)"values");
 
1369
        if(!xmlString)
 
1370
                return false;
 
1371
        std::vector<string> v2;
 
1372
        splitStrsRef((char *)xmlString,',',v2);
 
1373
        for (size_t i = 0; i < INDEX_LENGTH && i < v2.size(); i++)
 
1374
        {
 
1375
                if(stream_cast(binWidth[i],v2[i]))
 
1376
                        return false;
 
1377
                
 
1378
                if(binWidth[i] <= 0)
 
1379
                        return false;
 
1380
        }
 
1381
        xmlFree(xmlString);
 
1382
        
 
1383
        //Retrieve normaliseType
 
1384
        if(!XMLGetNextElemAttrib(nodePtr,normaliseType,"normalisetype","value"))
 
1385
                return false;
 
1386
        if(normaliseType >= VOXELISE_NORMALISETYPE_MAX)
 
1387
                return false;
 
1388
 
 
1389
        //Look for the enabled ions bit
 
1390
        //-------       
 
1391
        //
 
1392
        
 
1393
        if(!XMLHelpFwdToElem(nodePtr,"enabledions"))
 
1394
        {
 
1395
 
 
1396
                nodeStack.push(nodePtr);
 
1397
                if(!nodePtr->xmlChildrenNode)
 
1398
                        return false;
 
1399
                nodePtr=nodePtr->xmlChildrenNode;
 
1400
                
 
1401
                //enabled ions for numerator
 
1402
                if(XMLHelpFwdToElem(nodePtr,"numerator"))
 
1403
                        return false;
 
1404
 
 
1405
                nodeStack.push(nodePtr);
 
1406
 
 
1407
                if(!nodePtr->xmlChildrenNode)
 
1408
                        return false;
 
1409
 
 
1410
                nodePtr=nodePtr->xmlChildrenNode;
 
1411
 
 
1412
                while(nodePtr)
 
1413
                {
 
1414
                        char c;
 
1415
                        //Retrieve representation
 
1416
                        if(!XMLGetNextElemAttrib(nodePtr,c,"enabled","value"))
 
1417
                                break;
 
1418
 
 
1419
                        if(c == '1')
 
1420
                                enabledIons[0].push_back(true);
 
1421
                        else
 
1422
                                enabledIons[0].push_back(false);
 
1423
 
 
1424
 
 
1425
                        nodePtr=nodePtr->next;
 
1426
                }
 
1427
 
 
1428
                nodePtr=nodeStack.top();
 
1429
                nodeStack.pop();
 
1430
 
 
1431
                //enabled ions for denominator
 
1432
                if(XMLHelpFwdToElem(nodePtr,"denominator"))
 
1433
                        return false;
 
1434
 
 
1435
 
 
1436
                if(!nodePtr->xmlChildrenNode)
 
1437
                        return false;
 
1438
 
 
1439
                nodeStack.push(nodePtr);
 
1440
                nodePtr=nodePtr->xmlChildrenNode;
 
1441
 
 
1442
                while(nodePtr)
 
1443
                {
 
1444
                        char c;
 
1445
                        //Retrieve representation
 
1446
                        if(!XMLGetNextElemAttrib(nodePtr,c,"enabled","value"))
 
1447
                                break;
 
1448
 
 
1449
                        if(c == '1')
 
1450
                                enabledIons[1].push_back(true);
 
1451
                        else
 
1452
                                enabledIons[1].push_back(false);
 
1453
                                
 
1454
 
 
1455
                        nodePtr=nodePtr->next;
 
1456
                }
 
1457
 
 
1458
 
 
1459
                nodeStack.pop();
 
1460
                nodePtr=nodeStack.top();
 
1461
                nodeStack.pop();
 
1462
 
 
1463
                //Check that the enabled ions size makes at least some sense...
 
1464
                if(enabledIons[0].size() != enabledIons[1].size())
 
1465
                        return false;
 
1466
 
 
1467
        }
 
1468
 
 
1469
        //-------       
 
1470
        //Retrieve representation
 
1471
        if(!XMLGetNextElemAttrib(nodePtr,representation,"representation","value"))
 
1472
                return false;
 
1473
        if(representation >=VOXEL_REPRESENT_END)
 
1474
                return false;
 
1475
 
 
1476
        //-------       
 
1477
        //Retrieve representation
 
1478
        if(!XMLGetNextElemAttrib(nodePtr,isoLevel,"isovalue","value"))
 
1479
                return false;
 
1480
 
 
1481
        //Retrieve colour
 
1482
        //====
 
1483
        if(XMLHelpFwdToElem(nodePtr,"colour"))
 
1484
                return false;
 
1485
        if(!parseXMLColour(nodePtr,r,g,b,a))
 
1486
                return false;
 
1487
 
 
1488
        //====
 
1489
        return true;
 
1490
        
 
1491
}
 
1492
 
 
1493
unsigned int VoxeliseFilter::getRefreshBlockMask() const
 
1494
{
 
1495
        //Ions, plots and voxels cannot pass through this filter
 
1496
        return STREAM_TYPE_IONS | STREAM_TYPE_PLOT | STREAM_TYPE_VOXEL;
 
1497
}
 
1498
 
 
1499
unsigned int VoxeliseFilter::getRefreshEmitMask() const
 
1500
{
 
1501
        return STREAM_TYPE_VOXEL | STREAM_TYPE_DRAW;
 
1502
}
 
1503
 
 
1504
unsigned int VoxeliseFilter::getRefreshUseMask() const
 
1505
{
 
1506
        return STREAM_TYPE_IONS | STREAM_TYPE_RANGE;
 
1507
}
 
1508
 
 
1509
void VoxeliseFilter::setPropFromBinding(const SelectionBinding &b)
 
1510
{
 
1511
}       
 
1512
 
 
1513
#ifdef DEBUG
 
1514
bool voxelSingleCountTest()
 
1515
{
 
1516
        //Test counting a single vector
 
1517
        
 
1518
        vector<IonHit> ionVec;
 
1519
 
 
1520
        ionVec.resize(5);
 
1521
        ionVec[0].setPos(Point3D(0.1,0.1,0.1));
 
1522
        ionVec[1].setPos(Point3D(0.1,0.0,0.1));
 
1523
        ionVec[2].setPos(Point3D(0.0,0.1,0.1));
 
1524
        ionVec[3].setPos(Point3D(0.1,0.1,0.0));
 
1525
        ionVec[4].setPos(Point3D(0.0,0.1,0.0));
 
1526
 
 
1527
        for(unsigned int ui=0;ui<ionVec.size();ui++)
 
1528
                ionVec[ui].setMassToCharge(1);
 
1529
 
 
1530
        IonStreamData *ionData = new IonStreamData;
 
1531
        std::swap(ionData->data,ionVec);
 
1532
        
 
1533
        size_t numIons=ionData->data.size();
 
1534
        
 
1535
        VoxeliseFilter *f = new VoxeliseFilter;
 
1536
        f->setCaching(false);
 
1537
 
 
1538
        bool needUpdate;
 
1539
        TEST(f->setProperty(KEY_NBINSX,"4",needUpdate),"num bins x");
 
1540
        TEST(f->setProperty(KEY_NBINSY,"4",needUpdate),"num bins y");
 
1541
        TEST(f->setProperty(KEY_NBINSZ,"4",needUpdate),"num bins z");
 
1542
 
 
1543
 
 
1544
        vector<const FilterStreamData*> streamIn,streamOut;
 
1545
        streamIn.push_back(ionData);
 
1546
 
 
1547
        ProgressData p;
 
1548
        TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code");
 
1549
        delete f;
 
1550
 
 
1551
        TEST(streamOut.size() == 1,"stream count");
 
1552
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_VOXEL,"Stream type");
 
1553
 
 
1554
 
 
1555
        const VoxelStreamData *v= (const VoxelStreamData*)streamOut[0];
 
1556
 
 
1557
        TEST(v->data.max() <=numIons,
 
1558
                        "voxel max less than input stream")
 
1559
 
 
1560
        TEST(v->data.min() >= 0.0f,"voxel counting minimum sanity");
 
1561
 
 
1562
        
 
1563
        float dataSum;
 
1564
        sumVoxels(v->data,dataSum);
 
1565
        TEST(fabs(dataSum - (float)numIons ) < 
 
1566
                sqrt(std::numeric_limits<float>::epsilon()),"voxel counting all input ions ");
 
1567
 
 
1568
        delete ionData;
 
1569
        delete streamOut[0];
 
1570
 
 
1571
        return true;
 
1572
}
 
1573
 
 
1574
bool voxelMultiCountTest()
 
1575
{
 
1576
        //Test counting multiple data streams containing ranged data 
 
1577
        
 
1578
        vector<const FilterStreamData*> streamIn,streamOut;
 
1579
        vector<IonHit> ionVec;
 
1580
 
 
1581
        ionVec.resize(5);
 
1582
        ionVec[0].setPos(Point3D(0.1,0.1,0.1));
 
1583
        ionVec[1].setPos(Point3D(0.1,0.0,0.1));
 
1584
        ionVec[2].setPos(Point3D(0.0,0.1,0.1));
 
1585
        ionVec[3].setPos(Point3D(0.1,0.1,0.0));
 
1586
        ionVec[4].setPos(Point3D(0.0,0.1,0.0));
 
1587
 
 
1588
        IonStreamData *ionData[2];
 
1589
        RangeStreamData *rngStream;
 
1590
        rngStream = new RangeStreamData;
 
1591
        rngStream->rangeFile= new RangeFile;
 
1592
 
 
1593
        RGBf col; col.red=col.green=col.blue=1.0f;
 
1594
 
 
1595
        const unsigned int MAX_NUM_RANGES=2;
 
1596
        for(unsigned int ui=0;ui<MAX_NUM_RANGES;ui++)
 
1597
        {
 
1598
                size_t ionNum;
 
1599
 
 
1600
                //Add a new ion "a1, a2... etc"
 
1601
                string sTmp,sTmp2;
 
1602
                sTmp="a";
 
1603
                stream_cast(sTmp2,ui);
 
1604
                sTmp+=sTmp2;
 
1605
                ionNum=rngStream->rangeFile->addIon(sTmp,sTmp,col);
 
1606
                rngStream->rangeFile->addRange((float)ui-0.5f,(float)ui+0.5f,ionNum);
 
1607
 
 
1608
                //Change m/c value for ion
 
1609
                for(unsigned int uj=0;uj<ionVec.size();uj++)
 
1610
                        ionVec[uj].setMassToCharge(ui);
 
1611
                
 
1612
                ionData[ui]= new IonStreamData;
 
1613
                ionData[ui]->data.resize(ionVec.size());
 
1614
                std::copy(ionVec.begin(),ionVec.end(),ionData[ui]->data.begin());
 
1615
                streamIn.push_back(ionData[ui]);
 
1616
        }
 
1617
 
 
1618
        rngStream->enabledIons.resize(rngStream->rangeFile->getNumIons());
 
1619
        rngStream->enabledRanges.resize(rngStream->rangeFile->getNumRanges());
 
1620
 
 
1621
        streamIn.push_back(rngStream);
 
1622
 
 
1623
        VoxeliseFilter *f = new VoxeliseFilter;
 
1624
 
 
1625
        //Initialise range data
 
1626
        f->initFilter(streamIn,streamOut);
 
1627
 
 
1628
 
 
1629
        f->setCaching(false);
 
1630
        
 
1631
        bool needUpdate;
 
1632
        TEST(f->setProperty(KEY_NBINSX,"4",needUpdate),"num bins x");
 
1633
        TEST(f->setProperty(KEY_NBINSY,"4",needUpdate),"num bins y");
 
1634
        TEST(f->setProperty(KEY_NBINSZ,"4",needUpdate),"num bins z");
 
1635
 
 
1636
 
 
1637
        TEST(f->setProperty(KEY_NORMALISE_TYPE,
 
1638
                TRANS(NORMALISE_TYPE_STRING[VOXELISE_NORMALISETYPE_ALLATOMSINVOXEL]),needUpdate), 
 
1639
                                "Set normalise mode");
 
1640
 
 
1641
        ProgressData p;
 
1642
        TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"Refresh error code");
 
1643
        delete f;
 
1644
        for(unsigned int ui=0;ui<MAX_NUM_RANGES;ui++)
 
1645
                delete streamIn[ui];
 
1646
        TEST(streamOut.size() == 2,"stream count");
 
1647
        TEST(streamOut[1]->getStreamType() == STREAM_TYPE_VOXEL,"Stream type");
 
1648
        
 
1649
        const VoxelStreamData *v= (const VoxelStreamData*)streamOut[1];
 
1650
 
 
1651
        TEST(v->data.max() <=1.0f,
 
1652
                        "voxel max less than input stream")
 
1653
        TEST(v->data.min() >= 0.0f,"voxel counting minimum sanity");
 
1654
 
 
1655
 
 
1656
        for(unsigned int ui=0;ui<v->data.getSize();ui++)
 
1657
        {
 
1658
                float delta;
 
1659
                delta=(v->data.getData(ui) - v->data.getData(0) );
 
1660
                ASSERT( v->data.getData(ui) == 0 || delta < std::numeric_limits<float>::epsilon());
 
1661
        }
 
1662
 
 
1663
        delete v;
 
1664
 
 
1665
        delete rngStream->rangeFile;
 
1666
        delete rngStream;
 
1667
 
 
1668
        return true;
 
1669
}
 
1670
 
 
1671
 
 
1672
bool VoxeliseFilter::runUnitTests()
 
1673
{
 
1674
 
 
1675
        if(!voxelSingleCountTest())
 
1676
                return false;
 
1677
 
 
1678
        if(!voxelMultiCountTest())
 
1679
                return false;
 
1680
 
 
1681
 
 
1682
        return true;
 
1683
}
 
1684
 
 
1685
#endif