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