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 }