227 lines
5 KiB
C
227 lines
5 KiB
C
#include <assert.h>
|
|
#include <float.h>
|
|
#include <math.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
// Just a quick poc, assumes size_t >= int
|
|
|
|
/* Matrices are represented as row-by-row, ltr, flattened matrix
|
|
* |a b|
|
|
* |c d| to {a, b, c, d}
|
|
*/
|
|
|
|
#define C_PI 3.14159265358979323846 /* matches glibc and musl */
|
|
|
|
typedef struct {
|
|
double scale_x; // >= 0
|
|
double scale_y; // >= 0
|
|
double fax;
|
|
double fay;
|
|
double rot_z;
|
|
bool rot_x; // false: 0; true 180
|
|
bool rot_y; // false: 0; true 180
|
|
} Tags;
|
|
|
|
void print_matrix(const char* name, const double* mat)
|
|
{
|
|
int nlen = strlen(name);
|
|
#define FLP "%8.4f"
|
|
int llen = printf("%*s | "FLP" "FLP" |", nlen, "", mat[0], mat[1]);
|
|
assert(llen > nlen + 5);
|
|
printf("\n%s = |%.*s|\n"
|
|
"%*s | "FLP" "FLP" |\n",
|
|
name, llen-nlen-5,
|
|
" ",
|
|
nlen, "", mat[2], mat[3]);
|
|
#undef FLP
|
|
}
|
|
|
|
void mult_matrices(const double* l, const double* r, double* res)
|
|
{
|
|
#define I(row,col) (col + (row << 1))
|
|
res[0] = l[I(0,0)] * r[I(0,0)] + l[I(0,1)] * r[I(1,0)];
|
|
res[1] = l[I(0,0)] * r[I(0,1)] + l[I(0,1)] * r[I(1,1)];
|
|
res[2] = l[I(1,0)] * r[I(0,0)] + l[I(1,1)] * r[I(1,0)];
|
|
res[3] = l[I(1,0)] * r[I(0,1)] + l[I(1,1)] * r[I(1,1)];
|
|
#undef I
|
|
}
|
|
void identity(double* mat)
|
|
{
|
|
mat[0] = 1.0; mat[1] = 0.0;
|
|
mat[2] = 0.0; mat[3] = 1.0;
|
|
}
|
|
|
|
#define COPY(src,dst) memcpy(dst, src, sizeof(double)*4)
|
|
|
|
bool matrix_equal(const double* a, const double *b, const double eps)
|
|
{
|
|
return fabs(a[0] - b[0]) <= eps
|
|
&& fabs(a[1] - b[1]) <= eps
|
|
&& fabs(a[2] - b[2]) <= eps
|
|
&& fabs(a[3] - b[3]) <= eps;
|
|
}
|
|
|
|
/**
|
|
* 0: same with default tolerance
|
|
* 1: same with 3 * default tolerance
|
|
* 2: same with 5 * default tolerance
|
|
* -1: not the same
|
|
*/
|
|
int matrix_compfuzzy(const double* a, const double* b)
|
|
{
|
|
for(int i = 0; i < 3; ++i) {
|
|
if(matrix_equal(a, b, 2000 * (2*i + 1) * DBL_EPSILON))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Ignores z dimension
|
|
*/
|
|
void tags_to_matrix(const Tags* t, double* mat)
|
|
{
|
|
// ASS applies operations in order:
|
|
// combined-faxy "shear", scale, rot_z, rot_x, rot_y
|
|
double* cur = mat;
|
|
double nextop[4] = {0};
|
|
double tmp[4] = {0};
|
|
|
|
// Shear and Scale
|
|
cur[0] = t->scale_x;
|
|
cur[1] = t->scale_x * t->fax;
|
|
cur[2] = t->scale_y * t->fay;
|
|
cur[3] = t->scale_y;
|
|
|
|
/*print_matrix("scaleshear", cur);
|
|
puts("");*/
|
|
|
|
// Rotation: Z
|
|
double c = cos(t->rot_z * C_PI / 180.0);
|
|
double s = sin(t->rot_z * C_PI / 180.0);
|
|
nextop[0] = c; nextop[1] = -s;
|
|
nextop[2] = s; nextop[3] = c;
|
|
mult_matrices(nextop, cur, tmp);
|
|
COPY(tmp, cur);
|
|
|
|
/*print_matrix(" rotz", nextop);
|
|
print_matrix("rotz-scfa", cur);
|
|
puts("");*/
|
|
|
|
// Rotation: X
|
|
if (t->rot_x) {
|
|
identity(nextop);
|
|
nextop[3] = -1;
|
|
mult_matrices(nextop, cur, tmp);
|
|
COPY(tmp, cur);
|
|
/*print_matrix(" rotx", nextop);
|
|
print_matrix("rotx-zscfa", cur);
|
|
puts("");*/
|
|
}
|
|
|
|
|
|
// Rotation: Y
|
|
if (t->rot_y) {
|
|
identity(nextop);
|
|
nextop[0] = -1;
|
|
mult_matrices(nextop, cur, tmp);
|
|
COPY(tmp, cur);
|
|
/*print_matrix(" roty", nextop);
|
|
print_matrix("roty-xzscfa", cur);
|
|
puts("");*/
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Call with len=0 to get required size for untruncated output
|
|
*/
|
|
int tags_to_string(const Tags* t, char* str, size_t len)
|
|
{
|
|
size_t p = 0;
|
|
if(t->rot_y) {
|
|
size_t tmp = snprintf(str, len, "\\fry180");
|
|
p += tmp;
|
|
if(len <= tmp) {
|
|
len = 0;
|
|
str = NULL;
|
|
} else {
|
|
len -= tmp;
|
|
str += tmp;
|
|
}
|
|
}
|
|
if(t->rot_x) {
|
|
size_t tmp = snprintf(str, len, "\\frx180");
|
|
p += tmp;
|
|
if(len <= tmp) {
|
|
len = 0;
|
|
str = NULL;
|
|
} else {
|
|
len -= tmp;
|
|
str += tmp;
|
|
}
|
|
}
|
|
if(t->rot_z) {
|
|
size_t tmp = snprintf(str, len, "\\frz%.5f ", t->rot_z);
|
|
p += tmp;
|
|
if(len <= tmp) {
|
|
len = 0;
|
|
str = NULL;
|
|
} else {
|
|
len -= tmp;
|
|
str += tmp;
|
|
}
|
|
}
|
|
|
|
p += snprintf(str, len, "\\fscy%.5f\\fscx%.5f \\fay%.5f\\fax%.5f",
|
|
t->scale_y * 100.0, t->scale_x * 100.0, t->fay, t->fax);
|
|
return p;
|
|
}
|
|
|
|
|
|
//const double DEF_TARGET[4] = {-0.06203, 0.19083, -0.0758, 0.00354};
|
|
const double DEF_TARGET[4] = {-0.12395, 0.42227, -0.17882, 0.04262};
|
|
|
|
bool parse_args(int argc, char** argv, double* target)
|
|
{
|
|
if(argc <= 1)
|
|
memcpy(target, DEF_TARGET, sizeof(DEF_TARGET));
|
|
else if(argc == 5) {
|
|
target[0] = strtod(argv[1], NULL);
|
|
target[1] = strtod(argv[2], NULL);
|
|
target[2] = strtod(argv[3], NULL);
|
|
target[3] = strtod(argv[4], NULL);
|
|
} else {
|
|
fprintf(stderr, "Usage: %s [<a> <b> <c> <d>]\n", argv[0]);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int evaluate_result(const double* tar, const Tags* tags)
|
|
{
|
|
double result[4] = {0};
|
|
char tag_str[4096] = {0};
|
|
tags_to_matrix(tags, result);
|
|
tags_to_string(tags, tag_str, 4096);
|
|
printf("\n %s\n", tag_str);
|
|
print_matrix("result", result);
|
|
puts("");
|
|
|
|
int score = matrix_compfuzzy(tar, result);
|
|
const char* score_name;
|
|
switch(score) {
|
|
case 0: score_name = "same(high)"; break;
|
|
case 1: score_name = "same(med)"; break;
|
|
case 2: score_name = "same"; break;
|
|
default: score_name = "FAIL"; break;
|
|
}
|
|
printf("Score: %s\n", score_name);
|
|
return score < 0;
|
|
}
|