1 module des.mc.calibrate.multipoint; 2 3 import des.mc.calibrate.point; 4 import des.mc.calibrate.util; 5 6 float toRad( float deg ) pure nothrow { return deg / 180.0 * PI; } 7 8 interface MultiPointCalibrator 9 { 10 void reset(); 11 void nextPoint(); 12 PointCalibrationResult filter( in fSeg seg ); 13 14 const @property 15 { 16 const(vec3)[] points(); 17 bool done(); 18 size_t currentIndex(); 19 } 20 } 21 22 class BaseMultiPointCalibrator : MultiPointCalibrator 23 { 24 protected: 25 PointCalibrator[] calibrators; 26 size_t current; 27 PointCalibratorParam calibrator_params; 28 29 public: 30 this( size_t point_count, PointCalibratorParam pcp ) 31 { 32 calibrator_params = pcp; 33 foreach( i; 0 .. point_count ) 34 calibrators ~= new PointCalibrator( pcp ); 35 } 36 37 void reset() 38 { 39 foreach( pc; calibrators ) 40 pc = new PointCalibrator( calibrator_params ); 41 } 42 43 void nextPoint() { current = ( current + 1 ) % calibrators.length; } 44 45 PointCalibrationResult filter( in fSeg seg ) 46 { return calibrators[current].filter( seg ); } 47 48 const @property 49 { 50 const(vec3)[] points() { return array( map!(a=>a.point)( calibrators ) ); } 51 bool done() { return all(points); } 52 size_t currentIndex() { return current; } 53 } 54 } 55 56 unittest 57 { 58 fSeg[] rays = 59 [ 60 fSeg( vec3(0,0,-0.1), vec3(1,1,0) ), fSeg( vec3(2,0,0.1), vec3(-1,1,0) ), 61 fSeg( vec3(0,3,0), vec3(2,1,0) ), fSeg( vec3(0,4,0), vec3(1,0,0) ), 62 ]; 63 64 size_t cur_ray = 0; 65 66 vec3[] res = [ vec3(1,1,0), vec3(2,4,0) ]; 67 68 auto bmpc = new BaseMultiPointCalibrator( 2, PointCalibratorParam(10,0.15,0.4,0.9) ); 69 70 bool normalCalcFirstPoint = false; 71 foreach( i; 0 .. 20 ) 72 { 73 auto q = bmpc.filter( rays[cur_ray] + rndSeg() ); 74 if( q.state == PointCalibrationResult.State.ACCEPTED ) 75 { 76 assert( abs( i - 10 ) < 2 ); 77 normalCalcFirstPoint = true; 78 break; 79 } 80 } 81 assert(normalCalcFirstPoint); 82 83 void appendNextRay() 84 { 85 cur_ray++; 86 foreach( i; 0 .. 20 ) 87 { 88 auto yx = bmpc.filter( rays[cur_ray] + rndSeg() ); 89 if( yx.state == PointCalibrationResult.State.ACCEPTED ) break; 90 } 91 } 92 93 appendNextRay(); 94 assert( !bmpc.done ); 95 assert( bmpc.currentIndex == 0 ); 96 bmpc.nextPoint(); 97 assert( bmpc.currentIndex == 1 ); 98 appendNextRay(); 99 assert( !bmpc.done ); 100 appendNextRay(); 101 assert( bmpc.done ); 102 import std.range; 103 assert( all!(a=>a.len2<0.1)( map!(a=>a[0]-a[1])( zip(bmpc.points, res) ) ) ); 104 } 105 106 interface MultiPointCalibratorPrinter 107 { 108 void nextPoint(); 109 void accepted(size_t,PointCalibrationResult); 110 void aborted(size_t,PointCalibrationResult); 111 void done(in vec3[]); 112 } 113 114 class CBMultiPointCalibrator : BaseMultiPointCalibrator 115 { 116 MultiPointCalibratorPrinter printer; 117 118 this( size_t point_count, in PointCalibratorParam pcp, 119 MultiPointCalibratorPrinter prntr=null ) 120 { 121 super( point_count, pcp ); 122 printer = prntr; 123 } 124 125 override PointCalibrationResult filter( in fSeg seg ) 126 { 127 auto res = super.filter( seg ); 128 if( printer ) 129 { 130 if( res.state == PointCalibrationResult.State.ACCEPTED ) 131 printer.accepted( currentIndex, res ); 132 if( res.state == PointCalibrationResult.State.ABORTED ) 133 printer.aborted( currentIndex, res ); 134 if( done ) printer.done( points ); 135 } 136 return res; 137 } 138 139 override void nextPoint() 140 { 141 super.nextPoint(); 142 if( printer ) printer.nextPoint(); 143 } 144 } 145 146 abstract class BehaviorMultiPointCalibrator : MultiPointCalibrator 147 { 148 protected: 149 MultiPointCalibrator calibrator; 150 151 public: 152 this( MultiPointCalibrator mpc ) { calibrator = mpc; } 153 154 void reset() { calibrator.reset(); } 155 void nextPoint() { calibrator.nextPoint(); } 156 157 const @property 158 { 159 const(vec3)[] points() { return calibrator.points; } 160 bool done() { return calibrator.done; } 161 size_t currentIndex() { return calibrator.currentIndex; } 162 } 163 } 164 165 /+ калибровка каждой точки по отдельности +/ 166 class EachMultiPointCalibrator : BehaviorMultiPointCalibrator 167 { 168 this( MultiPointCalibrator mpc ) { super(mpc); } 169 170 auto filter( in fSeg seg ) 171 { 172 auto res = calibrator.filter( seg ); 173 if( res.done ) nextPoint(); 174 return res; 175 } 176 } 177 178 unittest 179 { 180 fSeg[] rays = 181 [ 182 fSeg( vec3(0,0,-0.1), vec3(1,1,0) ), fSeg( vec3(2,0,0.1), vec3(-1,1,0) ), 183 fSeg( vec3(0,3,0), vec3(2,1,0) ), fSeg( vec3(0,4,0), vec3(1,0,0) ), 184 ]; 185 186 size_t cur_ray = 0; 187 188 vec3[] res = [ vec3(1,1,0), vec3(2,4,0) ]; 189 190 size_t next_point_call_count = 0; 191 192 class TestPrinter : MultiPointCalibratorPrinter 193 { 194 void nextPoint() { next_point_call_count++; } 195 void accepted(size_t,PointCalibrationResult) { cur_ray++; } 196 void aborted(size_t,PointCalibrationResult) {} 197 void done(in vec3[]) {} 198 } 199 200 auto buf_len = 10; 201 auto cbmpc = new CBMultiPointCalibrator( 2, PointCalibratorParam(buf_len,0.15,0.4), new TestPrinter ); 202 auto eachmp = new EachMultiPointCalibrator( cbmpc ); 203 204 size_t steps = 0; 205 while( !eachmp.done ) 206 { 207 steps++; 208 eachmp.filter( rays[cur_ray]+rndSeg() ); 209 } 210 assert( abs( steps - buf_len * 4 ) < 3 ); 211 assert( next_point_call_count == 2 ); 212 import std.range; 213 assert( all!(a=>a.len2<0.1)( map!(a=>a[0]-a[1])( zip(eachmp.points, res) ) ) ); 214 } 215 216 /+ калибровка серии точек из одного положения +/ 217 class SeriesMultiPointCalibrator : BehaviorMultiPointCalibrator 218 { 219 protected: 220 float min_next_point_angle; 221 222 public: 223 this( MultiPointCalibrator mpc, float mnpa ) 224 { 225 super(mpc); 226 min_next_point_angle = abs(mnpa); 227 } 228 229 override auto filter( in fSeg seg ) 230 { 231 auto res = calibrator.filter( seg ); 232 if( res.state != PointCalibrationResult.State.BUFFERED && 233 checkRay( res.avg_ray ) ) nextPoint(); 234 return res; 235 } 236 237 protected: 238 239 fSeg last_ray; 240 241 bool checkRay( in fSeg ray ) 242 { 243 if( last_ray.dir.len == 0 ) 244 { 245 last_ray = ray; 246 return true; 247 } 248 249 auto a = last_ray.dir.e; 250 auto b = ray.dir.e; 251 return acos(dot( a, b )) > min_next_point_angle; 252 } 253 }