mirror of
https://github.com/collabora/libsurvive.git
synced 2026-08-04 00:51:21 -04:00
187 lines
6.9 KiB
C
187 lines
6.9 KiB
C
#define _USE_MATH_DEFINES
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <survive_reproject.h>
|
|
#include <survive_reproject_gen2.h>
|
|
|
|
#include "force_O3.h"
|
|
|
|
#include "generated/survive_reproject.generated.h"
|
|
|
|
/***
|
|
Using plane equation:
|
|
A*x + B*y + C*z + D = 0;
|
|
|
|
If you are looking at the lighthouse, you have this:
|
|
^
|
|
|
|
|
Y
|
|
|
|
|
<---X---o (objects in front of LH are -Z).
|
|
---- Rotor Direction --->
|
|
|
|
|
|
The first plane is oriented like / and the second is \. When the sensor is on X=0 and Y=0, the colliding planes
|
|
then are X=-Y, X=Y. The normals are then [1, a, 0] and [1, -a, 0]. We define the point at which the sensor plane
|
|
sweeps X=Y=0 in both planes as t=0. The projected plane is roughly ~60 degrees off of horizontal. a should be
|
|
tan(90 - <plane angle>).
|
|
|
|
If the object is at X=epsilon, Y=0, Z=1, The rotation hits it slightly sooner; t is slightly negative. The normal
|
|
is then something like [~1-epsilon, a, ~+epsilon], [~1-epsilon, -a, ~+epsilon]
|
|
|
|
We know the planes are mostly centered in the lighthouse, and so we get:
|
|
[cos(t), a, -sin(t)], [cos(t), -a, -sin(t)]
|
|
|
|
For a given X, Y, Z solve for t:
|
|
X * cos(t) - Z * sin(t) = +/-Y*a
|
|
|
|
Simplifies to this; given harmonic addition rules of sin/cos:
|
|
sqrt(X^2 + Z^2) * sin(t + atan2(X, -Z)) = +/-Y*a
|
|
sin(t + atan2(X, -Z)) = +/-Y*a / sqrt(X^2 + Z^2)
|
|
t + atan2(X, -Z) = asin(+/-Y*a / sqrt(X^2 + Z^2))
|
|
t + atan2(X, -Z) = +/-asin(Y*a / sqrt(X^2 + Z^2))
|
|
t = +/-asin(Y*a / sqrt(X^2 + Z^2)) - atan2(X, -Z)
|
|
***/
|
|
|
|
// a_i = a_(i-1) * s + m[i-1]; a[0] = 0
|
|
// m_i = m_(i-1) * s + f[i]; m[0] = f[0]
|
|
// This yields, approx:
|
|
// a_i = \sum f[i] * (N-i) * a^(N-i-1)
|
|
// m_i = \sum f[i] * a^(N-i-1)
|
|
// It's useful to see them as separate eqs but not ultimately useful.
|
|
static inline void calc_cal_series(FLT s, FLT *m, FLT *a) {
|
|
const FLT f[6] = {-8.0108022e-06, 0.0028679863, 5.3685255000000001e-06, 0.0076069798000000001};
|
|
|
|
*m = f[0], *a = 0;
|
|
for (int i = 1; i < 6; i++) {
|
|
*a = *a * s + *m;
|
|
*m = *m * s + f[i];
|
|
}
|
|
}
|
|
|
|
static inline FLT survive_reproject_axis_gen2(const BaseStationCal *bcal, FLT X, FLT Y, FLT Z, bool axis) {
|
|
const FLT phase = bcal->phase;
|
|
const FLT curve = bcal->curve;
|
|
const FLT tilt = bcal->tilt;
|
|
const FLT gibPhase = bcal->gibpha;
|
|
const FLT gibMag = bcal->gibmag;
|
|
const FLT ogeePhase = bcal->ogeephase;
|
|
const FLT ogeeMag = bcal->ogeemag;
|
|
|
|
FLT B = atan2(Z, X);
|
|
|
|
FLT Ydeg = tilt + (axis ? -1 : 1) * LINMATHPI / 6.;
|
|
FLT tanA = FLT_TAN(Ydeg);
|
|
FLT normXZ = FLT_SQRT(X * X + Z * Z);
|
|
|
|
FLT asinArg = tanA * Y / normXZ;
|
|
FLT asinArg_sanitized = linmath_enforce_range(asinArg, -1, 1);
|
|
|
|
FLT sinYdeg = FLT_SIN(Ydeg);
|
|
FLT cosYdeg = FLT_COS(Ydeg);
|
|
|
|
FLT sinPart = FLT_SIN(B - FLT_ASIN(asinArg_sanitized) + ogeePhase) * ogeeMag;
|
|
|
|
FLT normXYZ = FLT_SQRT(X * X + Y * Y + Z * Z);
|
|
|
|
FLT modAsinArg = linmath_enforce_range(Y / normXYZ / cosYdeg, -1, 1);
|
|
|
|
FLT asinOut = FLT_ASIN(modAsinArg);
|
|
|
|
FLT mod, acc;
|
|
calc_cal_series(asinOut, &mod, &acc);
|
|
|
|
FLT BcalCurved = sinPart + curve;
|
|
FLT asinArg2 = linmath_enforce_range(asinArg + mod * BcalCurved / (cosYdeg - acc * BcalCurved * sinYdeg), -1, 1);
|
|
|
|
FLT asinOut2 = FLT_ASIN(asinArg2);
|
|
FLT sinOut2 = sin(B - asinOut2 + gibPhase);
|
|
|
|
FLT rtn = B - asinOut2 + sinOut2 * gibMag - phase - LINMATHPI_2;
|
|
assert(!isnan(rtn));
|
|
return rtn;
|
|
}
|
|
|
|
static inline FLT survive_reproject_axis_x_gen2_inline(const BaseStationCal *bcal, LinmathVec3d const ptInLh) {
|
|
return survive_reproject_axis_gen2(&bcal[0], ptInLh[0], ptInLh[1], -ptInLh[2], 0);
|
|
}
|
|
|
|
static inline FLT survive_reproject_axis_y_gen2_inline(const BaseStationCal *bcal, LinmathVec3d const ptInLh) {
|
|
return survive_reproject_axis_gen2(&bcal[1], ptInLh[0], ptInLh[1], -ptInLh[2], 1);
|
|
}
|
|
|
|
FLT survive_reproject_axis_x_gen2(const BaseStationCal *bcal, LinmathVec3d const ptInLh) {
|
|
return survive_reproject_axis_x_gen2_inline(bcal, ptInLh);
|
|
}
|
|
|
|
FLT survive_reproject_axis_y_gen2(const BaseStationCal *bcal, LinmathVec3d const ptInLh) {
|
|
return survive_reproject_axis_y_gen2_inline(bcal, ptInLh);
|
|
}
|
|
|
|
void survive_reproject_xy_gen2(const BaseStationCal *bcal, LinmathVec3d const ptInLh, SurviveAngleReading out) {
|
|
out[0] = survive_reproject_axis_x_gen2_inline(bcal, ptInLh);
|
|
out[1] = survive_reproject_axis_y_gen2_inline(bcal, ptInLh);
|
|
assert(!isnan(out[0]));
|
|
assert(!isnan(out[1]));
|
|
}
|
|
|
|
void survive_reproject_from_pose_with_bcal_gen2(const BaseStationCal *bcal, const SurvivePose *world2lh,
|
|
LinmathVec3d const ptInWorld, SurviveAngleReading out) {
|
|
LinmathPoint3d ptInLh;
|
|
ApplyPoseToPoint(ptInLh, world2lh, ptInWorld);
|
|
survive_reproject_xy_gen2(bcal, ptInLh, out);
|
|
}
|
|
|
|
void survive_reproject_from_pose_gen2(const SurviveContext *ctx, int lighthouse, const SurvivePose *world2lh,
|
|
LinmathVec3d const pt, SurviveAngleReading out) {
|
|
survive_reproject_from_pose_with_bcal_gen2(ctx->bsd[lighthouse].fcal, world2lh, pt, out);
|
|
}
|
|
|
|
void survive_reproject_gen2(const SurviveContext *ctx, int lighthouse, LinmathVec3d const ptInWorld,
|
|
SurviveAngleReading out) {
|
|
SurvivePose world2lh = InvertPoseRtn(survive_get_lighthouse_position(ctx, lighthouse));
|
|
survive_reproject_from_pose_gen2(ctx, lighthouse, &world2lh, ptInWorld, out);
|
|
}
|
|
|
|
void survive_reproject_full_gen2(const BaseStationCal *bcal, const SurvivePose *world2lh, const SurvivePose *obj2world,
|
|
const LinmathVec3d obj_pt, SurviveAngleReading out) {
|
|
LinmathVec3d world_pt;
|
|
ApplyPoseToPoint(world_pt, obj2world, obj_pt);
|
|
|
|
LinmathPoint3d t_pt;
|
|
ApplyPoseToPoint(t_pt, world2lh, world_pt);
|
|
|
|
survive_reproject_xy_gen2(bcal, t_pt, out);
|
|
}
|
|
|
|
const survive_reproject_model_t survive_reproject_gen2_model = {
|
|
.reprojectAxisFn = {survive_reproject_axis_x_gen2, survive_reproject_axis_y_gen2},
|
|
.reprojectXY = survive_reproject_xy_gen2,
|
|
.reprojectAxisFullFn = {gen_reproject_axis_x_gen2, gen_reproject_axis_y_gen2},
|
|
|
|
.reprojectAxisJacobFn = {gen_reproject_axis_x_gen2_jac_obj_p, gen_reproject_axis_y_gen2_jac_obj_p},
|
|
.reprojectFullJacObjPose = gen_reproject_gen2_jac_obj_p,
|
|
.reprojectFullJacLhPose = gen_reproject_gen2_jac_lh_p,
|
|
.reprojectAxisJacobLhPoseFn = {gen_reproject_axis_x_gen2_jac_lh_p, gen_reproject_axis_y_gen2_jac_lh_p},
|
|
|
|
.reprojectAxisangleFullXyFn =
|
|
{
|
|
gen_reproject_axis_x_gen2_axis_angle,
|
|
gen_reproject_axis_y_gen2_axis_angle,
|
|
},
|
|
.reprojectAxisAngleFullJacObjPose = gen_reproject_gen2_jac_obj_p_axis_angle,
|
|
.reprojectAxisAngleAxisJacobFn = {gen_reproject_axis_x_gen2_jac_obj_p_axis_angle,
|
|
gen_reproject_axis_y_gen2_jac_obj_p_axis_angle},
|
|
|
|
.reprojectAxisAngleFullJacLhPose = gen_reproject_gen2_jac_lh_p_axis_angle,
|
|
.reprojectAxisAngleAxisJacobLhPoseFn = {gen_reproject_axis_x_gen2_jac_lh_p_axis_angle,
|
|
gen_reproject_axis_y_gen2_jac_lh_p_axis_angle},
|
|
.reprojectAxisJacobSensorPt =
|
|
{
|
|
gen_reproject_axis_x_gen2_jac_sensor_pt,
|
|
gen_reproject_axis_y_gen2_jac_sensor_pt,
|
|
},
|
|
.reprojectAxisAngleAxisJacobSensorPt = {
|
|
gen_reproject_axis_x_gen2_jac_sensor_pt_axis_angle,
|
|
gen_reproject_axis_y_gen2_jac_sensor_pt_axis_angle,
|
|
}};
|