#include #include #include "linmath.h" #include #include #define PTS 32 #define MAX_CHECKS 20000 #define MIN_HITS_FOR_VALID 10 FLT hmd_points[PTS*3]; FLT hmd_norms[PTS*3]; FLT hmd_point_angles[PTS*2]; int hmd_point_counts[PTS*2]; int best_hmd_target = 0; int LoadData( char Camera ); //Values used for RunTest() FLT LighthousePos[3] = { 0, 0, 0 }; FLT LighthouseQuat[4] = { 1, 0, 0, 0 }; FLT BarrelRotate[4]; //XXX TODO: Concatenate these. //Actual values XXX TODO: I don't think this is needed. FLT xyz[3] = { 0, 0, 0 }; FLT RunOpti( int print ); FLT RunTest( int print ); void PrintOpti(); int main() { int i; //Load either 'L' (LH1) or 'R' (LH2) data. if( LoadData( 'L' ) ) return 5; int opti = 0; int cycle = 0; int axis = 0; FLT dx, dy, dz; FLT bestxyz[3]; memcpy( bestxyz, xyz, sizeof( xyz ) ); //STAGE1 1: Detemine vectoral position from lighthouse to target. Does not determine lighthouse-target distance. //This also is constantly optimizing the lighthouse quaternion for optimal spotting. FLT fullrange = 5; //Maximum search space for positions. (Relative to HMD) for( cycle = 0; cycle < 30; cycle ++ ) { //Adjust position, one axis at a time, over and over until we zero in. { FLT bestxyzrunning[3]; FLT beste = 1e20; FLT splits = 2; if( cycle == 0 ) splits = 25; //Try a bunch of points in this axis. for( dz = 0; dz <= fullrange; dz += fullrange/splits ) for( dy = -fullrange; dy <= fullrange; dy += fullrange/splits ) for( dx = -fullrange; dx <= fullrange; dx += fullrange/splits ) { //Specificially adjust one axis at a time, searching for the best. memcpy( xyz, bestxyz, sizeof( xyz ) ); xyz[0] += dx; xyz[1] += dy; xyz[2] += dz; //if( axis == 2 && xyz[2] < 0 ) continue; FLT ft; //Try refining the search for the best orientation several times. ft = RunOpti(0); if( ft < beste ) { beste = ft; memcpy( bestxyzrunning, xyz, sizeof( xyz ) ); } //printf( " %f %f %f %f\n", xyz[0], xyz[1], xyz[2], ft ); } memcpy( bestxyz, bestxyzrunning, sizeof( bestxyz ) ); //Print out the quality of the lock this time. FLT dist = sqrt(bestxyz[0]*bestxyz[0] + bestxyz[1]*bestxyz[1] + bestxyz[2]*bestxyz[2]); printf( "%f %f %f (%f) = %f\n", bestxyz[0], bestxyz[1], bestxyz[2], dist, beste ); } //Every cycle, tighten up the search area. fullrange *= 0.6; } //Use bestxyz memcpy( LighthousePos, bestxyz, sizeof( xyz ) ); memcpy( xyz, bestxyz, sizeof( xyz ) ); //Optimize the quaternion for lighthouse rotation RunOpti(1); //STAGE 2: Determine optimal distance from target { FLT dist = 0.1; FLT best_dist = 0; FLT best_err = 1e20; for( ; dist < 10; dist+=0.1 ) { FLT nrmvect[3]; normalize3d( nrmvect, bestxyz ); scale3d( LighthousePos, nrmvect, dist ); FLT res = RunTest( 0 ); printf( "%f = %f\n", dist, res ); if( res < best_err ) { best_dist = dist; best_err = res; } } best_dist = 3; //Apply the best res. normalize3d( LighthousePos, bestxyz ); scale3d( LighthousePos, LighthousePos, best_dist ); printf( "Best distance: %f\n", best_dist ); } //Print out plane accuracies with these settings. FLT ft = RunTest(1); printf( "Final RMS: %f\n", ft ); } FLT RunOpti( int print ) { int i; FLT UsToTarget[3]; { memcpy( LighthousePos, xyz, sizeof(xyz) ); //XXX TODO: We should use several points to determine initial rotation optimization to object. //By using only one point the "best" we could be rotating somewhere wrong. We do use //several points for the rotate-about-this-vector rotation in stage 2. //Find out where our ray shoots forth from. FLT ax = hmd_point_angles[best_hmd_target*2+0]; FLT ay = hmd_point_angles[best_hmd_target*2+1]; //NOTE: Inputs may never be output with cross product. //Create a fictitious normalized ray. Imagine the lighthouse is pointed //straight in the +z direction, this is the lighthouse ray to the point. FLT RayShootOut[3] = { sin(ax), sin(ay), 0 }; RayShootOut[2] = sqrt( 1 - (RayShootOut[0]*RayShootOut[0] + RayShootOut[1]*RayShootOut[1]) ); //Find a ray from us to the target point. sub3d( UsToTarget, &hmd_points[best_hmd_target*3], LighthousePos ); normalize3d( UsToTarget, UsToTarget ); FLT AxisToRotate[3]; cross3d( AxisToRotate, RayShootOut, UsToTarget ); //Rotate the lighthouse around this axis to point at the HMD. FLT RotateAmount = acos( dot3d( RayShootOut, UsToTarget ) ); quatfromaxisangle( LighthouseQuat, AxisToRotate, RotateAmount ); //Tested, working! } //Now our lighthouse's ray is pointed at the HMD's dot, but, we need to //rotate the lighthouse such that it is oriented optimally. We do this //by finding what the optimal rotation aroud our face would be for all //remaining points. FLT rotate_radians = 0; int points_found_to_rotate = 0; float rots[PTS]; for( i = 0; i < PTS; i++ ) { if( i == best_hmd_target ) continue; int xhits = hmd_point_counts[i*2+0]; int yhits = hmd_point_counts[i*2+1]; int xyhits = (xhits hmd_point_counts[targpd*2+1] ) hits = hmd_point_counts[targpd*2+1]; //Need an X and a Y lock. if( hits > maxhits ) { maxhits = hits; best_hmd_target = targpd; } } if( maxhits < MIN_HITS_FOR_VALID ) { fprintf( stderr, "Error: Not enough data for a primary fix.\n" ); } return 0; }