1 module des.math.util.valuelim;
2 
3 import std.traits;
4 import std.algorithm;
5 
6 ///
7 struct ValueLimiter(size_t CNT,T=float)
8 if( CNT > 0 && isFloatingPoint!T )
9 {
10 protected:
11     T min_limit;
12     T max_limit;
13 
14     ///
15     T[CNT] values;
16 
17 public:
18     @property
19     {
20         ///
21         T minLimit() const { return min_limit; }
22 
23         ///
24         T minLimit( T v )
25         {
26             min_limit = v > max_limit ? max_limit : v;
27             correctValuesMinMax();
28             return min_limit;
29         }
30 
31         ///
32         T maxLimit() const { return max_limit; }
33 
34         ///
35         T maxLimit( T v )
36         {
37             max_limit = v < min_limit ? min_limit : v;
38             correctValuesMinMax();
39             return max_limit;
40         }
41     }
42 
43     ///
44     T set( size_t i, T v )
45     in{ assert( i < CNT ); }
46     body
47     {
48         values[i] = min( max( min_limit, v ), max_limit );
49         moveValues(i);
50         return values[i];
51     }
52 
53     ///
54     T setNorm( size_t i, T nv )
55     in
56     {
57         assert( i < CNT );
58         assert( nv <= 1.0 );
59     }
60     body
61     {
62         auto v = full(nv);
63         set(i,v);
64         return getNorm(i);
65     }
66 
67     ///
68     T get( size_t i )
69     in{ assert( i < CNT ); }
70     body { return values[i]; }
71 
72     ///
73     T getNorm( size_t i )
74     in{ assert( i < CNT ); }
75     body { return norm( get(i) ); }
76 
77 protected:
78 
79     void correctValuesMinMax() { foreach( ref v; values ) correctMinMax( v ); }
80 
81     void correctMinMax( ref T v )
82     { v = ( v >= min_limit ? ( v <= max_limit ? v : max_limit ) : min_limit ); }
83 
84     void moveValues( size_t k )
85     {
86         foreach( i, ref v; values )
87         {
88             if( i == k ) continue;
89             if( i < k && v > values[k] )
90                 v = values[k];
91             if( i > k && v < values[k] )
92                 v = values[k];
93         }
94     }
95 
96     T norm( T v ) const
97     { return (v - min_limit) / (max_limit - min_limit); }
98 
99     T full( T v ) const
100     { return min_limit + v * (max_limit - min_limit); }
101 }
102 
103 ///
104 unittest
105 {
106     auto vh = ValueLimiter!(2,float)();
107 
108     vh.minLimit = 0;
109     vh.maxLimit = 10;
110 
111     vh.set( 0, 5 );
112     vh.set( 1, 7 );
113 
114     assert( vh.get(0) == 5 );
115     assert( vh.get(1) == 7 );
116 
117     vh.set(1,3);
118 
119     assert( vh.get(0) == 3 );
120     assert( vh.get(1) == 3 );
121 
122     vh.set(1,20);
123     assert( vh.get(0) == 3 );
124     assert( vh.get(1) == 10 );
125 }
126 
127 unittest
128 {
129     auto vh = ValueLimiter!2();
130 
131     vh.minLimit = 0;
132     vh.maxLimit = 10;
133 
134     vh.setNorm( 0, 0.5 );
135     vh.setNorm( 1, 0.7 );
136 
137     assert( vh.get(0) == 5 );
138     assert( vh.get(1) == 7 );
139 
140     vh.setNorm( 0, 0.8 );
141 
142     assert( vh.get(0) == 8 );
143     assert( vh.get(1) == 8 );
144 
145     import std.math;
146 
147     assert( abs( vh.getNorm(0) - .8 ) < float.epsilon * 2 );
148     assert( abs( vh.getNorm(1) - .8 ) < float.epsilon * 2 );
149 }