126 lines
2.8 KiB
C
126 lines
2.8 KiB
C
#include "common.h"
|
|
|
|
inline bool zero(double d)
|
|
{
|
|
return fabs(d) < 700 * DBL_EPSILON;
|
|
// For reference musl (64bit double) uses:
|
|
// DBL_EPSILON 2.22044604925031308085e-16
|
|
}
|
|
|
|
/*
|
|
* a == 0 \implies b == 0
|
|
* and
|
|
* d == 0 \implies c == 0
|
|
*/
|
|
void case_trivial(const double* m, Tags* t)
|
|
{
|
|
t->scale_x = m[0];
|
|
t->scale_y = m[3];
|
|
t->fax = zero(m[0]) ? 0 : (m[1] / m[0]); // case condition
|
|
t->fay = zero(m[3]) ? 0 : (m[2] / m[3]); // case condition
|
|
if(t->scale_x < 0) {
|
|
t->rot_y = true;
|
|
t->scale_x = fabs(t->scale_x);
|
|
}
|
|
if(t->scale_y < 0) {
|
|
t->rot_x = true;
|
|
t->scale_y = fabs(t->scale_y);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* |0 b| |0 0| |0 b| |0 b| |a b|
|
|
* |0 0|, |c 0|, |c 0|, |c d| or |c 0| with letters non-zero
|
|
* (i.e. c==0 \implies d==0 and a==0 \implies d==0)
|
|
*
|
|
* apply rot_z of 90° to get
|
|
* |a b| |-scale_y*fay -scale_y |
|
|
* |c d| = | scale_x scale_x*fax|
|
|
*/
|
|
void case_rowswap(const double* m, Tags* t)
|
|
{
|
|
t->rot_z = 90;
|
|
t->scale_x = m[2];
|
|
t->scale_y = -m[1];
|
|
t->fax = zero(m[2]) ? 0 : (m[3] / m[2]); // case condition
|
|
t->fay = zero(m[1]) ? 0 : (m[0] / m[1]); // case condition
|
|
if(t->scale_x < 0) {
|
|
t->rot_x = true;
|
|
t->scale_x = fabs(t->scale_x);
|
|
}
|
|
if(t->scale_y < 0) {
|
|
t->rot_y = true;
|
|
t->scale_y = fabs(t->scale_y);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* |a 0|
|
|
* |c 0| with letters non-zero
|
|
*/
|
|
void case_zerocol_r(const double* m, Tags* t)
|
|
{
|
|
t->scale_y = 0;
|
|
t->fax = 0;
|
|
t->fay = 0; // Arbitrary
|
|
t->scale_x = sqrt(m[0] * m[0] + m[2] * m[2]);
|
|
t->rot_z = atan(m[2] / m[0]) * 180 / C_PI;
|
|
if (m[0] < 0) // atan always yields positive cos
|
|
t->rot_z += 180;
|
|
}
|
|
|
|
/**
|
|
* |0 b|
|
|
* |0 d| with letters non-zero
|
|
*/
|
|
void case_zerocol_l(const double* m, Tags* t)
|
|
{
|
|
t->scale_x = 0;
|
|
t->fay = 0;
|
|
t->fax = 0; // Arbitrary
|
|
t->scale_y = sqrt(m[1] * m[1] + m[3] * m[3]);
|
|
t->rot_z = atan(-m[1] / m[3]) * 180 / C_PI;
|
|
if (m[3] < 0) // atan always yields positive cos
|
|
t->rot_z += 180;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
double tar[4] = {0};
|
|
|
|
if(!parse_args(argc, argv, tar))
|
|
exit(5);
|
|
|
|
print_matrix("target", tar);
|
|
|
|
Tags tags = {0};
|
|
if(
|
|
!( (zero(tar[0]) && !zero(tar[1]))
|
|
|| (zero(tar[3]) && !zero(tar[2])) )
|
|
) {
|
|
printf(" --trivial\n");
|
|
case_trivial(tar, &tags);
|
|
} else if(
|
|
!( (zero(tar[1]) && !zero(tar[0]))
|
|
|| (zero(tar[2]) && !zero(tar[3])) )
|
|
) {
|
|
printf(" --rowswap\n");
|
|
case_rowswap(tar, &tags);
|
|
} else if(
|
|
zero(tar[0]) && zero(tar[2]) && !zero(tar[1]) && !zero(tar[3])
|
|
) {
|
|
printf(" --zerocol_l\n");
|
|
case_zerocol_l(tar, &tags);
|
|
} else if(
|
|
!zero(tar[0]) && !zero(tar[2]) && zero(tar[1]) && zero(tar[3])
|
|
) {
|
|
printf(" --zerocol_r\n");
|
|
case_zerocol_r(tar, &tags);
|
|
} else {
|
|
fprintf(stderr, "Oupsie, unknown matrix-case encountered. This shouldn't happen :P\n");
|
|
exit(6);
|
|
}
|
|
|
|
return evaluate_result(tar, &tags);
|
|
}
|