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

« back to all changes in this revision

Viewing changes to src/basics.h

  • 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
 
 *      basics.h - Basic functionality header 
3
 
 *      Copyright (C) 2011, D Haley 
4
 
 
5
 
 *      This program is free software: you can redistribute it and/or modify
6
 
 *      it under the terms of the GNU General Public License as published by
7
 
 *      the Free Software Foundation, either version 3 of the License, or
8
 
 *      (at your option) any later version.
9
 
 
10
 
 *      This program is distributed in the hope that it will be useful,
11
 
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *      GNU General Public License for more details.
14
 
 
15
 
 *      You should have received a copy of the GNU General Public License
16
 
 *      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 
*/
18
 
 
19
 
 
20
 
#ifndef BASICS_H
21
 
#define BASICS_H
22
 
//!Basic objects header file
23
 
 
24
 
#include "assertion.h"
25
 
#include "mathfuncs.h"
26
 
 
27
 
#include <iostream>
28
 
#include <cmath>
29
 
#include <vector>
30
 
#include <cstdlib>
31
 
#include <sstream>
32
 
#include <list>
33
 
#include <utility>
34
 
#include <fstream>
35
 
#include <algorithm>
36
 
 
37
 
class K3DTree;
38
 
 
39
 
 
40
 
std::string boolStrEnc(bool b);
41
 
 
42
 
bool dummyCallback(bool);
43
 
 
44
 
extern const char *DTD_NAME;
45
 
extern const char *PROGRAM_NAME;
46
 
extern const char *PROGRAM_VERSION;
47
 
extern const char *FONT_FILE;
48
 
 
49
 
#define ARRAYSIZE(f) (sizeof (f) / sizeof(*f))
50
 
 
51
 
 
52
 
 
53
 
//C file peek function
54
 
inline int fpeek(FILE *stream)
55
 
{
56
 
        int c;
57
 
 
58
 
        c = fgetc(stream);
59
 
        ungetc(c, stream);
60
 
 
61
 
        return c;
62
 
}
63
 
 
64
 
 
65
 
 
66
 
//!Text file loader errors
67
 
enum
68
 
{
69
 
        ERR_FILE_OPEN=1,
70
 
        ERR_FILE_FORMAT,
71
 
        ERR_FILE_NUM_FIELDS,
72
 
        ERR_FILE_ENUM_END // not an error, just end of enum
73
 
};
74
 
 
75
 
extern const char *TEXT_LOAD_ERR_STRINGS[];
76
 
 
77
 
        
78
 
        template<class T1, class T2>
79
 
bool hasFirstInPairVec(const std::vector<std::pair<T1,T2> > &v, const std::pair<T1,T2> &r)
80
 
{
81
 
        for(size_t ui=0;ui<v.size();ui++)
82
 
        {
83
 
                if(v[ui].first == r.first)
84
 
                        return true;
85
 
        }
86
 
        return false;
87
 
}
88
 
 
89
 
//!Convert a path format into a native path from unix format
90
 
std::string convertFileStringToNative(const std::string &s);
91
 
 
92
 
//!Convert a path format into a unix path from native format
93
 
std::string convertFileStringToCanonical(const std::string &s);
94
 
 
95
 
//!Convert a normal string to a latex one, using charachter replacement
96
 
void tickSpacingsFromInterspace(float start, float end, 
97
 
                float interSpacing, std::vector<float> &spacings);
98
 
 
99
 
void tickSpacingsFromFixedNum(float start, float end, 
100
 
                unsigned int nTicks, std::vector<float> &spacings);
101
 
 
102
 
//!Get a "human-like" version of the time elapsed between new and original time period
103
 
std::string veryFuzzyTimeSince( time_t origTime, time_t newTime);
104
 
 
105
 
 
106
 
//!A routine for loading numeric data from a text file
107
 
unsigned int loadTextData(const char *cpFilename, 
108
 
                std::vector<std::vector<float> > &dataVec,
109
 
                std::vector<std::string> &header,const char *delim);
110
 
 
111
 
 
112
 
 
113
 
template<class T>
114
 
bool writeTextFile(const char *cpFilename, 
115
 
                const std::vector<std::pair<T, T> > &dataVec, const char delim='\t')
116
 
{
117
 
        std::ofstream f(cpFilename);
118
 
 
119
 
        if(!f)
120
 
                return false;
121
 
 
122
 
        for(unsigned int ui=0;ui<dataVec.size();ui++)
123
 
                f << dataVec[ui].first << delim << dataVec[ui].second << std::endl;
124
 
        
125
 
        return true;
126
 
}
127
 
 
128
 
//!Return the default font file to use. Must precede (first) call to getDefaultFontFile
129
 
void setDefaultFontFile(const std::string &font);
130
 
 
131
 
//!Return the default font file to use. 
132
 
//Not valid until you have set it with setDefaultFontFile
133
 
std::string getDefaultFontFile();
134
 
 
135
 
//!Generate string that can be parsed by wxPropertyGrid for combo control
136
 
//String format is CHOICEID:string 1, string 2, string 3,..... string_N
137
 
std::string choiceString(std::vector<std::pair<unsigned int, std::string> > comboString, 
138
 
                                                                unsigned int curChoice);
139
 
 
140
 
 
141
 
//!Generate a string with leading digits up to maxDigit (eg, if maxDigit is 424, and thisDigit is 1
142
 
//leading digit will generate the string 001
143
 
std::string digitString(unsigned int thisDigit, unsigned int maxDigit);
144
 
 
145
 
//!Returns Choice from string (see choiceString(...) for string format)
146
 
std::string getActiveChoice(std::string choiceString);
147
 
 
148
 
//!Convert a choiceString() into something that a wxGridCellChoiceEditor will accept
149
 
std::string wxChoiceParamString(std::string choiceString);
150
 
 
151
 
 
152
 
inline std::string stlWStrToStlStr(const std::wstring& s)
153
 
{
154
 
        std::string temp(s.length(),' ');
155
 
        std::copy(s.begin(), s.end(), temp.begin());
156
 
        return temp; 
157
 
}
158
 
 
159
 
inline std::wstring stlStrToStlWStr(const std::string& s)
160
 
{
161
 
        std::wstring temp(s.length(),L' ');
162
 
        std::copy(s.begin(), s.end(), temp.begin());
163
 
        return temp;
164
 
}
165
 
 
166
 
//!Template function to cast and object to another by the stringstream
167
 
//IO operator
168
 
template<class T1, class T2> bool stream_cast(T1 &result, const T2 &obj)
169
 
{
170
 
    std::stringstream ss;
171
 
    ss << obj;
172
 
    ss >> result;
173
 
    return ss.fail();
174
 
}
175
 
 
176
 
template<class T1, class T2> bool stream_cast_noskip(T1 &result, const T2 &obj)
177
 
{
178
 
    std::stringstream ss;
179
 
    ss >> std::noskipws;
180
 
    ss << obj;
181
 
    ss >> result;
182
 
    return ss.fail();
183
 
}
184
 
 
185
 
//!Replace first instance of marker with null terminator
186
 
void nullifyMarker(char *buffer, char marker);
187
 
 
188
 
//retrieve the active bit in a power of two sequence
189
 
inline unsigned int getBitNum(unsigned int u)
190
 
{
191
 
        ASSERT(u);
192
 
        unsigned int j=0;
193
 
        while(!(u &1) )
194
 
        {
195
 
                u=u>>1;
196
 
                j++;
197
 
        }
198
 
 
199
 
        return j;
200
 
}
201
 
 
202
 
 
203
 
inline bool isVersionNumberString(const std::string &s)
204
 
{
205
 
        for(unsigned int ui=0;ui<s.size();ui++)
206
 
        {
207
 
                if(!isdigit(s[ui]) )
208
 
                {
209
 
 
210
 
                        if(s[ui] !='.' || ui ==0 || ui ==s.size())
211
 
                                return false;
212
 
                }
213
 
        }
214
 
 
215
 
        return true;
216
 
}
217
 
 
218
 
//Strip whitespace from a string
219
 
std::string stripWhite(const std::string &str);
220
 
 
221
 
//!Return a lowercas version for a given string
222
 
std::string lowercase(std::string s);
223
 
 
224
 
void stripZeroEntries(std::vector<std::string> &s);
225
 
 
226
 
//Convert a point string from its "C" language respresentation to a point vlaue
227
 
bool parsePointStr(const std::string &str,Point3D &pt);
228
 
 
229
 
bool parseColString(const std::string &str,
230
 
        unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
231
 
 
232
 
void genColString(unsigned char r, unsigned char g, 
233
 
                        unsigned char b, unsigned char a, std::string &s);
234
 
void genColString(unsigned char r, unsigned char g, 
235
 
                        unsigned char b, std::string &s);
236
 
 
237
 
//!Retrieve the maximum version string from a list of version strings
238
 
std::string getMaxVerStr(const std::vector<std::string> &verStrings);
239
 
 
240
 
//!Strip whitespace
241
 
std::string stripWhite(const std::string &str);
242
 
 
243
 
//!Split string references using a single delimeter.
244
 
void splitStrsRef(const char *cpStr, const char delim,std::vector<std::string> &v );
245
 
 
246
 
//!Split string references using any of a given string of delimters
247
 
void splitStrsRef(const char *cpStr, const char *delim,std::vector<std::string> &v );
248
 
 
249
 
//!A class to manage "tear-off" ID values, to allow for indexing without knowing position. 
250
 
//You simply ask for a new unique ID. and it maintains the position->ID mapping
251
 
//TODO: Extend to any unique type, rather than just int (think iterators..., pointers)
252
 
class UniqueIDHandler
253
 
{
254
 
        private:
255
 
                //!position-ID pairings
256
 
                std::list<std::pair<unsigned int, unsigned int > > idList;
257
 
 
258
 
        public:
259
 
                //!Generate  a unique ID value, storing the position ID pair
260
 
                unsigned int genId(unsigned int position);
261
 
                //!Remove a uniqueID using its position
262
 
                void killByPos(unsigned int position);
263
 
                //!Get the position from its unique ID
264
 
                unsigned int getPos(unsigned int id) const;
265
 
                //!Get the uniqueID from the position
266
 
                unsigned int getId(unsigned int pos) const;
267
 
 
268
 
                //!Get all unique IDs
269
 
                void getIds(std::vector<unsigned int> &idvec) const;
270
 
                //!Clear the mapping
271
 
                void clear();
272
 
                //!Get the number of elements stored
273
 
                unsigned int size() const {return idList.size();};
274
 
};
275
 
 
276
 
//!Get total filesize in bytes
277
 
bool getFilesize(const char *fname, size_t  &size);
278
 
 
279
 
//!get total ram in MB
280
 
int getTotalRAM();
281
 
 
282
 
//!Get available ram in MB
283
 
size_t getAvailRAM();
284
 
 
285
 
 
286
 
#ifdef DEBUG
287
 
bool isValidXML(const char *filename);
288
 
#endif
289
 
 
290
 
inline std::string tabs(unsigned int nTabs)
291
 
{
292
 
        std::string s;
293
 
        s.resize(nTabs);
294
 
        std::fill(s.begin(),s.end(),'\t');
295
 
        return s;
296
 
}
297
 
 
298
 
class ComparePairFirst
299
 
{
300
 
        public:
301
 
        template<class T1, class T2>
302
 
        bool operator()(const std::pair<  T1, T2 > &p1, const std::pair<T1,T2> &p2)
303
 
        {
304
 
                return p1.first< p2.first;
305
 
        }
306
 
};
307
 
 
308
 
class ComparePairSecond
309
 
{
310
 
        public:
311
 
        template<class T1, class T2>
312
 
        bool operator()(const std::pair<  T1, T2 > &p1, const std::pair<T1,T2> &p2)
313
 
        {
314
 
                return p1.second< p2.second;
315
 
        }
316
 
};
317
 
 
318
 
 
319
 
class ComparePairFirstReverse
320
 
{
321
 
        public:
322
 
        template<class T1, class T2>
323
 
        bool operator()(const std::pair<  T1, T2 > &p1, const std::pair<T1,T2> &p2)
324
 
        {
325
 
                return p1.first> p2.first;
326
 
        }
327
 
};
328
 
 
329
 
//! A helper class to define a bounding cube
330
 
class BoundCube
331
 
{
332
 
    //!bounding values (x,y,z) (lower,upper)
333
 
    float bounds[3][2];
334
 
    //!Is the cube set?
335
 
    bool valid[3][2];
336
 
public:
337
 
 
338
 
    BoundCube() {
339
 
        setInvalid();
340
 
    }
341
 
 
342
 
    void setBounds(float xMin,float yMin,float zMin,
343
 
                   float xMax,float yMax,float zMax) {
344
 
        bounds[0][0]=xMin; bounds[1][0]=yMin; bounds[2][0]=zMin;
345
 
        bounds[0][1]=xMax; bounds[1][1]=yMax; bounds[2][1]=zMax;
346
 
        valid[0][0]=true; valid[1][0]=true; valid[2][0]=true;
347
 
        valid[0][1]=true; valid[1][1]=true; valid[2][1]=true;
348
 
    }
349
 
 
350
 
    void setBounds(const BoundCube &b)
351
 
    {
352
 
                for(unsigned int ui=0;ui<3;ui++)
353
 
                {
354
 
                        bounds[ui][0] = b.bounds[ui][0];
355
 
                        valid[ui][0] = b.valid[ui][0];
356
 
                        bounds[ui][1] = b.bounds[ui][1];
357
 
                        valid[ui][1] = b.valid[ui][1];
358
 
                }
359
 
    }
360
 
    void setInvalid()
361
 
    {
362
 
        valid[0][0]=false; valid[1][0]=false; valid[2][0]=false;
363
 
        valid[0][1]=false; valid[1][1]=false; valid[2][1]=false;
364
 
    }
365
 
 
366
 
    //Set the cube to be "inside out" at the limits of numeric results;
367
 
    void setInverseLimits();
368
 
 
369
 
    void setBound(unsigned int bound, unsigned int minMax, float value) {
370
 
        ASSERT(bound <3 && minMax < 2);
371
 
        bounds[bound][minMax]=value;
372
 
        valid[bound][minMax]=true;
373
 
    };
374
 
 
375
 
    float getBound(unsigned int bound, unsigned int minMax) const {
376
 
        ASSERT(bound <3 && minMax < 2);
377
 
        ASSERT(valid[bound][minMax]==true);
378
 
        return bounds[bound][minMax];
379
 
    };
380
 
    //!Return the centroid 
381
 
    Point3D getCentroid() const;
382
 
 
383
 
    //!Get the bounds
384
 
    void getBounds(Point3D &low, Point3D &high) const ;
385
 
 
386
 
    //!Return the size
387
 
    float getSize(unsigned int dim) const;
388
 
 
389
 
    //! Returns true if all bounds are valid
390
 
    bool isValid() const;
391
 
 
392
 
    //! Returns true if any bound is of null thickness
393
 
    bool isFlat() const;
394
 
 
395
 
    //!Returns true if any bound of datacube is considered to be "large" in magnitude compared to 
396
 
    // floating pt data type.
397
 
    bool isNumericallyBig() const;
398
 
 
399
 
    //!Obtain bounds from an array of Point3Ds
400
 
    void setBounds( const Point3D *ptArray, unsigned int nPoints);
401
 
    //!Use two points to set bounds -- does not need to be high,low. this is worked out/
402
 
    void setBounds( const Point3D &p, const Point3D &q);
403
 
    //!Obtain bounds from an array of Point3Ds
404
 
    void setBounds(const std::vector<Point3D> &ptArray);
405
 
    //!Checks if a point intersects a sphere of centre Pt, radius^2 sqrRad
406
 
    bool intersects(const Point3D &pt, float sqrRad);
407
 
    //Check to see if the point is contained in, or part of the walls
408
 
    //of the cube
409
 
    bool containsPt(const Point3D &pt) const;
410
 
 
411
 
    //!Is this bounding cube completely contained within a sphere centred on pt of sqr size sqrRad?
412
 
    bool containedInSphere(const Point3D &pt, float sqrRad) const;
413
 
 
414
 
    //!Returns maximum distnace to box corners (which is an upper bound on max box distance). 
415
 
    //Bounding box must be valid.
416
 
    float getMaxDistanceToBox(const Point3D &pt) const;
417
 
 
418
 
    //Get the largest dimension of the bound cube
419
 
    float getLargestDim() const;
420
 
 
421
 
    //Return the rectilinear volume represented by this prism.
422
 
    float volume() const { return (bounds[0][1] - bounds[0][0])*
423
 
                (bounds[1][1] - bounds[1][0])*(bounds[2][1] - bounds[2][0]);}
424
 
    void limits();
425
 
    const BoundCube &operator=(const BoundCube &);
426
 
    //!Expand (as needed) volume such that the argument bounding cube is enclosed by this one
427
 
    void expand(const BoundCube &b);
428
 
    //!Expand such that point is contained in this volume. Existing volume must be valid
429
 
    void expand(const Point3D &p);
430
 
    //!Expand by a specified thickness 
431
 
    void expand(float v);
432
 
 
433
 
 
434
 
    friend  std::ostream &operator<<(std::ostream &stream, const BoundCube& b);
435
 
 
436
 
    //FIXME: Hack!
437
 
    friend class K3DTree;
438
 
    friend class K3DTreeMk2;
439
 
};
440
 
 
441
 
 
442
 
 
443
 
//!Return only the filename component
444
 
std::string onlyFilename( const std::string& path );
445
 
//!Return only  the directory name component of the full path 
446
 
std::string onlyDir( const std::string& path );
447
 
 
448
 
//OK, this is a bit tricky. We override the operators to call
449
 
//a callback, so the UI updates keep happening, even inside the STL function
450
 
//----
451
 
template<class T>
452
 
class GreaterWithCallback 
453
 
{
454
 
        private:
455
 
                bool (*callback)(bool);
456
 
                //!Reduction frequency (use callback every k its)
457
 
                unsigned int redMax;
458
 
                //!Current reduction counter
459
 
                unsigned int reduction;
460
 
                //!pointer to progress value
461
 
                unsigned int *prgPtr;
462
 
        public:
463
 
                //!Second argument is a "reduction" value to set the number of calls
464
 
                //to the random functor before initiating a callback
465
 
                GreaterWithCallback( bool (*ptr)(bool),unsigned int red)
466
 
                        { callback=ptr; reduction=redMax=red;};
467
 
 
468
 
                bool operator()(const T &a, const T &b) 
469
 
                {
470
 
                        if(!reduction--)
471
 
                        {
472
 
                                reduction=redMax;
473
 
                                //Execute callback
474
 
                                (*callback)(false);
475
 
                        }
476
 
 
477
 
                        return a < b;
478
 
                }
479
 
};
480
 
 
481
 
 
482
 
template<class T>
483
 
class EqualWithCallback 
484
 
{
485
 
        private:
486
 
                bool (*callback)(bool);
487
 
                //!Reduction frequency (use callback every k its)
488
 
                unsigned int redMax;
489
 
                //!Current reduction counter
490
 
                unsigned int reduction;
491
 
                //!pointer to progress value
492
 
                unsigned int *prgPtr;
493
 
        public:
494
 
                //!Second argument is a "reduction" value to set the number of calls
495
 
                //to the random functor before initiating a callback
496
 
                EqualWithCallback( bool (*ptr)(bool),unsigned int red)
497
 
                        { callback=ptr; reduction=redMax=red;};
498
 
 
499
 
                bool operator()(const T &a, const T &b) 
500
 
                {
501
 
                        if(!reduction--)
502
 
                        {
503
 
                                reduction=redMax;
504
 
                                //Execute callback
505
 
                                (*callback)(false);
506
 
                        }
507
 
 
508
 
                        return a ==b;
509
 
                }
510
 
};
511
 
//----
512
 
 
513
 
 
514
 
//Randomly select subset. Subset will be (somewhat) sorted on output
515
 
template<class T> size_t randomSelect(std::vector<T> &result, const std::vector<T> &source, 
516
 
                                                        RandNumGen &rng, size_t num,unsigned int &progress,bool (*callback)(bool), bool strongRandom=false)
517
 
{
518
 
        const unsigned int NUM_CALLBACK=50000;
519
 
        //If there are not enough points, just copy it across in whole
520
 
        if(source.size() <= num)
521
 
        {
522
 
                num=source.size();
523
 
                result.resize(source.size());
524
 
                for(size_t ui=0; ui<num; ui++)
525
 
                        result[ui] = source[ui]; 
526
 
        
527
 
                return num;
528
 
        }
529
 
 
530
 
        result.resize(num);
531
 
 
532
 
        if(strongRandom || source.size() < 4)
533
 
        {
534
 
 
535
 
                size_t numTicksNeeded;
536
 
                //If the number of items is larger than half the source size,
537
 
                //switch to tracking vacancies, rather than data
538
 
                if(num < source.size()/2)
539
 
                        numTicksNeeded=num;
540
 
                else
541
 
                        numTicksNeeded=source.size()-num;
542
 
 
543
 
                //Randomly selected items 
544
 
                //---------
545
 
                std::vector<size_t> ticks;
546
 
                ticks.resize(numTicksNeeded);
547
 
 
548
 
                //Create an array of numTicksNeededbers and fill 
549
 
                for(size_t ui=0; ui<numTicksNeeded; ui++)
550
 
                        ticks[ui]=(size_t)(rng.genUniformDev()*(source.size()-1));
551
 
 
552
 
                //Remove duplicates. Intersperse some callbacks to be nice
553
 
                GreaterWithCallback<size_t> gFunctor(callback,50000);
554
 
                std::sort(ticks.begin(),ticks.end(),gFunctor);
555
 
                EqualWithCallback<size_t> eqFunctor(callback,50000);
556
 
                std::vector<size_t>::iterator newLast;
557
 
                newLast=std::unique(ticks.begin(),ticks.end()); 
558
 
                ticks.erase(newLast,ticks.end());
559
 
 
560
 
                std::vector<size_t> moreTicks;
561
 
                //Top up with unique entries
562
 
                while(ticks.size() +moreTicks.size() < numTicksNeeded)
563
 
                {
564
 
                        size_t index;
565
 
 
566
 
                        //This is actually not too bad. the collision probability is at most 50%
567
 
                        //due the switching behaviour above, for any large number of items 
568
 
                        //So this is at worst case nlog(n) (I think)
569
 
                        index =(size_t)(rng.genUniformDev()*(float)(source.size()-1));
570
 
                        if(!binary_search(ticks.begin(),ticks.end(),index) &&
571
 
                                std::find(moreTicks.begin(),moreTicks.end(),index) ==moreTicks.end())
572
 
                                moreTicks.push_back(index);
573
 
 
574
 
                }
575
 
 
576
 
                ticks.reserve(numTicksNeeded);
577
 
                for(size_t ui=0;ui<moreTicks.size();ui++)
578
 
                        ticks.push_back(moreTicks[ui]);
579
 
 
580
 
                moreTicks.clear();
581
 
 
582
 
                ASSERT(ticks.size() == numTicksNeeded);
583
 
                //---------
584
 
                
585
 
                size_t pos=0;
586
 
                //Transfer the output
587
 
                unsigned int curProg=NUM_CALLBACK;
588
 
 
589
 
                if(num < source.size()/2)
590
 
                {
591
 
                        for(std::vector<size_t>::iterator it=ticks.begin();it!=ticks.end();it++)
592
 
                        {
593
 
 
594
 
                                result[pos]=source[*it];
595
 
                                pos++;
596
 
                                if(!curProg--)
597
 
                                {
598
 
                                        progress= (unsigned int)((float)(pos)/((float)num)*100.0f);
599
 
                                        (*callback)(false);
600
 
                                        curProg=NUM_CALLBACK;
601
 
                                }
602
 
                        }
603
 
                }
604
 
                else
605
 
                {
606
 
                        //Sort the ticks properly (mostly sorted anyway..)
607
 
                        std::sort(ticks.begin(),ticks.end(),gFunctor);
608
 
 
609
 
                        unsigned int curTick=0;
610
 
                        for(size_t ui=0;ui<source.size(); ui++)
611
 
                        {
612
 
                                //Don't copy if this is marked
613
 
                                if(ui == ticks[curTick])
614
 
                                        curTick++;
615
 
                                else
616
 
                                {
617
 
                                        ASSERT(result.size() > (ui-curTick));
618
 
                                        result[ui-curTick]=source[ui];
619
 
                                }
620
 
                                
621
 
                                if(!curProg--)
622
 
                                {
623
 
                                        progress= (unsigned int)(((float)(ui)/(float)source.size())*100.0f);
624
 
                                        (*callback)(false);
625
 
                                        curProg=NUM_CALLBACK;
626
 
                                }
627
 
                        }
628
 
                }
629
 
 
630
 
                ticks.clear();
631
 
        }       
632
 
        else
633
 
        {
634
 
                //Use a weak randomisation
635
 
                LinearFeedbackShiftReg l;
636
 
 
637
 
                //work out the mask level we need to use
638
 
                size_t i=1;
639
 
                unsigned int j=0;
640
 
                while(i < (source.size()<<1))
641
 
                {
642
 
                        i=i<<1;
643
 
                        j++;
644
 
                }
645
 
 
646
 
                //linear shift table starts at 3.
647
 
                if(j<3) {
648
 
                        j=3;
649
 
                        i = 1 << j;
650
 
                }
651
 
 
652
 
                size_t start;
653
 
                //start at a random position  in the linear state
654
 
                start =(size_t)(rng.genUniformDev()*i);
655
 
                l.setMaskPeriod(j);
656
 
                l.setState(start);
657
 
 
658
 
                size_t ui=0;    
659
 
                unsigned int curProg=NUM_CALLBACK;
660
 
                //generate unique weak random numbers.
661
 
                while(ui<num)
662
 
                {
663
 
                        size_t res;
664
 
                        res= l.clock();
665
 
                        
666
 
                        //use the source if it lies within range.
667
 
                        //drop it silently if it is out of range
668
 
                        if(res< source.size())
669
 
                        {
670
 
                                result[ui] =source[res];
671
 
                                ui++;
672
 
                        }
673
 
                        if(!curProg--)
674
 
                        {
675
 
                                progress= (unsigned int)((float)(ui)/((float)source.size())*100.0f);
676
 
                                (*callback)(false);
677
 
                                curProg=NUM_CALLBACK;
678
 
                        }
679
 
                }
680
 
 
681
 
        }
682
 
 
683
 
        return num;
684
 
}
685
 
 
686
 
//Randomly select subset. Subset will be (somewhat) sorted on output
687
 
template<class T> size_t randomDigitSelection(std::vector<T> &result, const size_t max,
688
 
                        RandNumGen &rng, size_t num,unsigned int &progress,bool (*callback)(bool),
689
 
                        bool strongRandom=false)
690
 
{
691
 
        //If there are not enough points, just copy it across in whole
692
 
        if(max <=num)
693
 
        {
694
 
                num=max;
695
 
                result.resize(max);
696
 
                for(size_t ui=0; ui<num; ui++)
697
 
                        result[ui] = ui; 
698
 
        
699
 
                return num;
700
 
        }
701
 
 
702
 
        result.resize(num);
703
 
 
704
 
        //If we have strong randomisation, or we have too few items to use the LFSR,
705
 
        //use proper random generation
706
 
        if(strongRandom || max < 3 )
707
 
        {
708
 
 
709
 
                size_t numTicksNeeded;
710
 
                //If the number of items is larger than half the source size,
711
 
                //switch to tracking vacancies, rather than data
712
 
                if(num < max/2)
713
 
                        numTicksNeeded=num;
714
 
                else
715
 
                        numTicksNeeded=max-num;
716
 
 
717
 
                //Randomly selected items 
718
 
                //---------
719
 
                std::vector<size_t> ticks;
720
 
                ticks.resize(numTicksNeeded);
721
 
 
722
 
                //Create an array of numTicksNeededbers and fill 
723
 
                for(size_t ui=0; ui<numTicksNeeded; ui++)
724
 
                        ticks[ui]=(size_t)(rng.genUniformDev()*(max-1));
725
 
 
726
 
                //Remove duplicates. Intersperse some callbacks to be nice
727
 
                GreaterWithCallback<size_t> gFunctor(callback,50000);
728
 
                std::sort(ticks.begin(),ticks.end(),gFunctor);
729
 
                EqualWithCallback<size_t> eqFunctor(callback,50000);
730
 
                
731
 
                std::vector<size_t>::iterator itLast;
732
 
                itLast=std::unique(ticks.begin(),ticks.end(),eqFunctor);        
733
 
                ticks.erase(itLast,ticks.end());
734
 
                std::vector<size_t> moreTicks;
735
 
                //Top up with unique entries
736
 
                while(ticks.size() +moreTicks.size() < numTicksNeeded)
737
 
                {
738
 
                        size_t index;
739
 
 
740
 
                        //This is actually not too bad. the collision probability is at most 50%
741
 
                        //due the switching behaviour above, for any large number of items 
742
 
                        //So this is at worst case nlog(n) (I think)
743
 
                        index =(size_t)(rng.genUniformDev()*(float)(max-1));
744
 
                        if(!binary_search(ticks.begin(),ticks.end(),index) &&
745
 
                                std::find(moreTicks.begin(),moreTicks.end(),index) ==moreTicks.end())
746
 
                                moreTicks.push_back(index);
747
 
 
748
 
                }
749
 
 
750
 
                ticks.reserve(numTicksNeeded);
751
 
                for(size_t ui=0;ui<moreTicks.size();ui++)
752
 
                        ticks.push_back(moreTicks[ui]);
753
 
 
754
 
                moreTicks.clear();
755
 
 
756
 
                ASSERT(ticks.size() == numTicksNeeded);
757
 
                //---------
758
 
                
759
 
                size_t pos=0;
760
 
                //Transfer the output
761
 
                unsigned int curProg=70000;
762
 
 
763
 
                if(num < max/2)
764
 
                {
765
 
                        for(std::vector<size_t>::iterator it=ticks.begin();it!=ticks.end();it++)
766
 
                        {
767
 
 
768
 
                                result[pos]=*it;
769
 
                                pos++;
770
 
                                if(!curProg--)
771
 
                                {
772
 
                                        progress= (unsigned int)((float)(curProg)/((float)num)*100.0f);
773
 
                                        (*callback)(false);
774
 
                                        curProg=70000;
775
 
                                }
776
 
                        }
777
 
                }
778
 
                else
779
 
                {
780
 
                        //Sort the ticks properly (mostly sorted anyway..)
781
 
                        std::sort(ticks.begin(),ticks.end(),gFunctor);
782
 
                        
783
 
                        unsigned int curTick=0;
784
 
                        for(size_t ui=0;ui<numTicksNeeded; ui++)
785
 
                        {
786
 
                                //Don't copy if this is marked
787
 
                                if(ui == ticks[curTick])
788
 
                                        curTick++;
789
 
                                else
790
 
                                        result[ui-curTick]=ui;
791
 
                                
792
 
                                if(!curProg--)
793
 
                                {
794
 
                                        progress= (unsigned int)((float)(curProg)/((float)num)*100.0f);
795
 
                                        (*callback)(false);
796
 
                                        curProg=70000;
797
 
                                }
798
 
                        }
799
 
                }
800
 
 
801
 
                ticks.clear();
802
 
        }
803
 
        else    
804
 
        {
805
 
                //Use a weak randomisation
806
 
                LinearFeedbackShiftReg l;
807
 
 
808
 
                //work out the mask level we need to use
809
 
                size_t i=1;
810
 
                unsigned int j=0;
811
 
                while(i < (max<<1))
812
 
                {
813
 
                        i=i<<1;
814
 
                        j++;
815
 
                }
816
 
                
817
 
                size_t start;
818
 
                //start at a random position  in the linear state
819
 
                start =(size_t)(rng.genUniformDev()*i);
820
 
                l.setMaskPeriod(j);
821
 
                l.setState(start);
822
 
 
823
 
                size_t ui=0;    
824
 
                //generate unique weak random numbers.
825
 
                while(ui<num)
826
 
                {
827
 
                        size_t res;
828
 
                        res= l.clock();
829
 
                        
830
 
                        //use the source if it lies within range.
831
 
                        //drop it silently if it is out of range
832
 
                        if(res<max) 
833
 
                        {
834
 
                                result[ui] =res;
835
 
                                ui++;
836
 
                        }
837
 
                }
838
 
        }
839
 
        return num;
840
 
}
841
 
 
842
 
#endif