Added Oneric code
This commit is contained in:
parent
4dc3353573
commit
b52b163aee
229
ass_transform
Normal file
229
ass_transform
Normal file
|
@ -0,0 +1,229 @@
|
|||
!! Everything here is untested and best check for errors in the calculations !!
|
||||
|
||||
Choose \fay, \fax, \fscx and \fscy to create a (almost) general 2D-transform-matrix
|
||||
(Rotations are sometimes also used)
|
||||
|
||||
(ASS Transform order: combined faxy, scale, frz, frx, fry)
|
||||
|
||||
If shearOrigin == scaleOrigin == rotationOrigin == (0,0)^T
|
||||
(which iirc is true for drawings with \org(0,0)?),
|
||||
and there are no run splits, and if assuming \frz0 for now,
|
||||
ASS will effectively use the following transform matrix
|
||||
|
||||
| scale_x 0 | | 1 fax |
|
||||
| | * | |
|
||||
| 0 scale_y | | fay 1 |
|
||||
|
||||
|
||||
| scale_x scale_x fax |
|
||||
= | |
|
||||
| scale_y fay scale_y |
|
||||
|
||||
|
||||
Let's assume that's true.
|
||||
Then given an arbitrary transform matrix M,
|
||||
with known coefficients a, b, c, d \in \R
|
||||
| a b |
|
||||
M = | |
|
||||
| c d |
|
||||
|
||||
we get:
|
||||
|
||||
I: scale_x = a
|
||||
II: scale_y = d
|
||||
III: scale_x fax = b
|
||||
IV: scale_y fay = c
|
||||
|
||||
If (a = b = 0) or (c = d = 0), then scale_x = 0
|
||||
or scale_y = 0 and all other values can be set to zero
|
||||
as the event vanishes anyway.
|
||||
|
||||
If (a = 0 and b != 0) or (c != 0 and d = 0), then
|
||||
we can't solve this as is directly. Ignore this
|
||||
case for now, we'll later describe how to adapt the solution for this.
|
||||
|
||||
If scale_x = a != 0 != d = scale_y, it follows that
|
||||
III => fax = b / scale_x
|
||||
IV => fay = c / scale_y
|
||||
|
||||
But even in this case, there's one issue:
|
||||
scale_x, scale_y may be negative,
|
||||
but ASS only allows positive scale values.
|
||||
|
||||
To remedy this we'll use 3D rotations to emulate negative scale.
|
||||
It is easy to see, that by themselves a
|
||||
rotation around x by π, is equivalent to scale_y = -1 and
|
||||
a rotation around y by π is equivalent to scale_x = -1.
|
||||
If we use \fscx and \fscy to scale by the respective absolute values
|
||||
and immediately follow this up by a “-1”-scale if needed the result
|
||||
will be equivalent to a scale by the proper value.
|
||||
In general this isn't so straightforward as ASS always applies rotations
|
||||
in the order of z, x, y, but we chose rot_z = 0, resulting in it being a
|
||||
dismissable identity operation.
|
||||
|
||||
If scale_x is negative, pass the absolute value to \fscx and add \fry180.
|
||||
If scale_y is negative, pass the absolute value to \fscy and add \frx180.
|
||||
|
||||
ASS-3D-rotation matrices:
|
||||
|
||||
| 1 0 0 |
|
||||
| |
|
||||
Rx = | 0 cos(rot_x) sin(rot_x) |
|
||||
| |
|
||||
| 0 sin(rot_x) -cos(rot_x) |
|
||||
|
||||
|
||||
| cos(rot_y) 0 sin(rot_y) |
|
||||
| |
|
||||
Ry = | 0 1 0 |
|
||||
| |
|
||||
| sin(rot_y) 0 -cos(rot_y) |
|
||||
|
||||
|
||||
| cos(rot_z) -sin(rot_z) 0 |
|
||||
| |
|
||||
Rz = | sin(rot_z) cos(rot_z) 0 | (for choice of rot_z=0 identity matrix)
|
||||
| |
|
||||
| 0 0 1 |
|
||||
|
||||
(from: https://sourceforge.net/p/guliverkli2/code/HEAD/tree/src/subtitles/RTS.cpp#l148)
|
||||
|
||||
|
||||
Using sgn_x, sgn_y \in {-1, 1} as the sign of the respective scales
|
||||
and sc_x, sc_y \in { x >= 0 | x \in \R } as the absolute scale values,
|
||||
all in all we get the following tags
|
||||
|
||||
\fry(-360*(sgn_x-1)) \frx(-360/(sgn_y-1)) \fscx(sc_x) \fscy(sc_y) \fax(fax) \fay(fay) \org(0,0)
|
||||
|
||||
which results in the ASS transform matrix:
|
||||
|
||||
|
||||
| sgn_x 0 0 | | 1 0 0 | | sc_x sc_x fax 0 |
|
||||
| | | | | |
|
||||
| 0 1 0 | * | 0 sgn_y 0 | * | sc_y fay sc_y 0 |
|
||||
| | | | | |
|
||||
| 0 0 -sgn_x | | 0 0 -sgn_y | | 0 0 1 |
|
||||
|
||||
|
||||
| sgn_x 0 0 | | sc_x sc_x fax 0 |
|
||||
| | | |
|
||||
= | 0 sgn_y 0 | * | sc_y fay sc_y 0 |
|
||||
| | | |
|
||||
| 0 0 sgn_x*sgn_y | | 0 0 1 |
|
||||
|
||||
|
||||
| sgn_x*sc_x sgn_x*sc_x fax 0 |
|
||||
| |
|
||||
= | sgn_y*sc_y fay sgn_y*sc_y 0 |
|
||||
| |
|
||||
| 0 0 sgn_x*sgn_y |
|
||||
|
||||
|
||||
using sgn_x*sc_x = scale_x and sgn_y*sc_y = scale_y
|
||||
|
||||
|
||||
| scale_x scale_x fax 0 |
|
||||
| |
|
||||
= | scale_y fay scale_y 0 |
|
||||
| |
|
||||
| 0 0 sgn_x*sgn_y |
|
||||
|
||||
|
||||
| a b 0 |
|
||||
| |
|
||||
= | c d 0 |
|
||||
| |
|
||||
| 0 0 sgn_x*sgn_y |
|
||||
|
||||
|
||||
Apart from flipping the sign of the z-coordinates when sgn_x != sgn_y
|
||||
this is exactly the matrix we wanted.
|
||||
Since 2D-glyphs and -drawings are initially placed at z=0,
|
||||
this additional sign-flip is of no concern.
|
||||
|
||||
---
|
||||
|
||||
Now coming back to the case of (a = 0 and b != 0) or (c != 0 and d = 0):
|
||||
|
||||
To be able to solve this we also need to apply a z-Rotation:
|
||||
|
||||
1) If in each column there's at least one non-zero entry or one row is all zero
|
||||
(together with case condition the latter means only b xor c is non-zero):
|
||||
Use \frz90, being a row swap with a sign flip:
|
||||
|
||||
| 0 -1 |
|
||||
\frz90 = | |
|
||||
| 1 0 |
|
||||
|
||||
So our transform-matrix equation becomes:
|
||||
|
||||
| -scale_y fay -scale_y | | a b |
|
||||
| | = | |
|
||||
| scale_x scale_x fax | | c d |
|
||||
|
||||
Which can be solved as before for signed scales.
|
||||
The additon of a z-Rotation means our "scale sign"-roations
|
||||
no longer immediately follow the actual scale.
|
||||
To compensate, use \frx for sgn_x and \fry for sgn_y
|
||||
(roles reversed from before)
|
||||
|
||||
2) Otherwise:
|
||||
(If one column is zero and the other one has only non-zero entries)
|
||||
|
||||
2.1) a = 0 = c and b ≠ 0 ≠ d
|
||||
|
||||
| scale_x*cos(rz) - scale_y*fay*sin(rz) scale_x*fax*cos(rz) - scale_y*sin(rz) | | 0 b |
|
||||
| | = | |
|
||||
| scale_x*sin(rz) + scale_y*fay*cos(rz) scale_x*fax*sin(rz) + scale_y*cos(rz) | | 0 d |
|
||||
|
||||
I: scale_x*cos(rz) - scale_y*fay*sin(rz) = 0
|
||||
II: scale_x*sin(rz) + scale_y*fay*cos(rz) = 0
|
||||
III: scale_x*fax*cos(rz) - scale_y*sin(rz) = b
|
||||
IV: scale_x*fax*sin(rz) + scale_y*cos(rz) = d
|
||||
|
||||
I² + II² ⇒ scale_x^2 = - scale_y^2 * fay^2 ⇒ scale_x = 0 and (scale_y = 0 or fay = 0)
|
||||
|
||||
III' : -scale_y*sin(rz) = b
|
||||
IV' : scale_y*cos(rz) = d
|
||||
|
||||
⇒ since b ≠ 0 ≠ d ⇒ scale_y ≠ 0 ⇒ fay = 0
|
||||
|
||||
⇒ ||scale_y|| = sqrt(b^2 + d^2)
|
||||
⇒ rz = tan⁻¹(-b/d)
|
||||
Note: The conventional tan⁻¹ definition always returns positive cosine.
|
||||
Thus we can always coose the positive solution for scale_y
|
||||
and instead add π to rot_z if d < 0
|
||||
|
||||
Since scale_y > 0 and scale_x = 0 we do not need \frx and \fry to simulate a negative scale.
|
||||
|
||||
2.2) b = 0 = d and a ≠ 0 ≠ c
|
||||
|
||||
| scale_x*cos(rz) - scale_y*fay*sin(rz) scale_x*fax*cos(rz) - scale_y*sin(rz) | | a 0 |
|
||||
| | = | |
|
||||
| scale_x*sin(rz) + scale_y*fay*cos(rz) scale_x*fax*sin(rz) + scale_y*cos(rz) | | c 0 |
|
||||
|
||||
|
||||
I: scale_x*fax*cos(rz) - scale_y*sin(rz) = 0
|
||||
II: scale_x*fax*sin(rz) + scale_y*cos(rz) = 0
|
||||
III: scale_x*cos(rz) - scale_y*fay*sin(rz) = a
|
||||
IV: scale_x*sin(rz) + scale_y*fay*cos(rz) = b
|
||||
|
||||
I² + II² ⇒ scale_y^2 = - scale_x^2 * fax^2 ⇒ scale_y = 0 and (scale_x = 0 or fax = 0)
|
||||
|
||||
III' : scale_x*cos(rz) = a
|
||||
IV' : scale_x*sin(rz) = c
|
||||
|
||||
⇒ since a ≠ 0 ≠ c ⇒ scale_x ≠ 0 ⇒ fax = 0
|
||||
|
||||
⇒ ||scale_x|| = sqrt(a^2 + c^2)
|
||||
⇒ rz = tan⁻¹(c/a)
|
||||
Note: The conventional tan⁻¹ definition always returns positive cosine.
|
||||
Thus we can always coose the positive solution for scale_x
|
||||
and instead add π to rot_z if a < 0
|
||||
|
||||
Since scale_x > 0 and scale_y = 0 we do not need \frx and \fry to simulate a negative scale.
|
||||
|
||||
In both 2.1) and 2.2) we get one dimension scaled to zero, and – if I didin't miss something –
|
||||
no contradictions in the equations. Meaning the event actually vanishes and is visually identical
|
||||
to choosing all parameters zero. If interpolations are involved having the mathematically accurate
|
||||
transform matrix might still be good though.
|
13
cimpl/Makefile
Normal file
13
cimpl/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/gmake
|
||||
|
||||
EXES := unstable stable
|
||||
|
||||
all: $(EXES)
|
||||
|
||||
$(EXES): %: %.c common.h
|
||||
gcc -O2 -ftree-vectorize -fno-trapping-math -gdwarf \
|
||||
-Wall -Wextra -Wpedantic \
|
||||
-o $@ $^ -lm
|
||||
|
||||
clean:
|
||||
rm -f $(EXES)
|
226
cimpl/common.h
Normal file
226
cimpl/common.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
#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;
|
||||
}
|
39
cimpl/test.sh
Executable file
39
cimpl/test.sh
Executable file
|
@ -0,0 +1,39 @@
|
|||
#!/bin/sh
|
||||
|
||||
if [ "$#" -ne 1 ] ; then
|
||||
echo "Usage $0 <executable>" >&2
|
||||
exit 2
|
||||
fi
|
||||
NAME="$(basename $1)"
|
||||
|
||||
cnt_fail=0
|
||||
cnt_succ=0
|
||||
|
||||
printf "" > failure_"$NAME".log
|
||||
printf "" > success_"$NAME".log
|
||||
|
||||
for sa in "" - ; do
|
||||
for sb in "" - ; do
|
||||
for sc in "" - ; do
|
||||
for sd in "" - ; do
|
||||
for a in 5 0 ; do
|
||||
for b in 11 0 ; do
|
||||
for c in 3 0 ; do
|
||||
for d in 19 0 ; do
|
||||
outp="$(./"$1" $sa$a $sb$b $sc$c $sd$d 2>/dev/null)"
|
||||
if [ "$?" -ne 0 ] ; then
|
||||
cnt_fail="$((cnt_fail+1))"
|
||||
printf '\n\n' >> failure_"$NAME".log
|
||||
printf "%s\n" "$outp" >> failure_"$NAME".log
|
||||
else
|
||||
cnt_succ="$((cnt_succ+1))"
|
||||
printf '\n\n' >> success_"$SNAME".log
|
||||
printf "%s\n" "$outp" >> success_"$NAME".log
|
||||
fi
|
||||
done ; done ; done ; done
|
||||
done ; done ; done ; done
|
||||
|
||||
printf " %3d SUCCESSES\n" "$cnt_succ"
|
||||
printf " %3d FAILURES\n" "$cnt_fail"
|
||||
printf " %3d total\n" "$((cnt_succ + cnt_fail))"
|
||||
|
125
cimpl/unstable.c
Normal file
125
cimpl/unstable.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
#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);
|
||||
}
|
Loading…
Reference in a new issue