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