ass_transform/cimpl/common.h
2022-04-24 03:09:27 +02:00

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;
}