blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

commit ff0286325a3dd1f4fe7e29e78341b9bd63e1725c
parent e650c912ba86c84cdad466674a0ca0c4ebadef9c
Author: Mattias Andrée <maandree@kth.se>
Date:   Fri, 14 Jul 2017 21:15:32 +0200

blind-matrix-{rotate,shear}: add -d

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
Mman/blind-matrix-rotate.1 | 14+++++++++++++-
Mman/blind-matrix-shear.1 | 5++++-
Msrc/blind-matrix-rotate.c | 22++++++++++++++++++----
Msrc/blind-matrix-shear.c | 13+++++++++----
Msrc/video-math.h | 46++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 90 insertions(+), 10 deletions(-)

diff --git a/man/blind-matrix-rotate.1 b/man/blind-matrix-rotate.1 @@ -3,7 +3,7 @@ blind-matrix-rotate - Create an affine 2D-transformation matrix for rotation .SH SYNOPSIS .B blind-matrix-rotate -[-c] +[-cd] .SH DESCRIPTION .B blind-matrix-rotate creates an affine 2D-transformation matrix for @@ -28,9 +28,21 @@ Create different matrices for each channel. Use values from each channel in stdin to create matrices whose values are stored in the same channels in stdout. +.TP +.B -d +Input angles in degrees rather than radians. .SH NOTES The image is rotated anti-clockwise if the Y-axis grows upwards rather than downwards. +.P +Due to truncation error, when rotating a multiple +of 90 degrees, it is preferable to use +.B -d +with lets +.B blind-matrix-rotate +eliminate the error. If this is not done, +.BR blind-invert-matrix (1) +may return odd results. .SH SEE ALSO .BR blind (7), .BR blind-from-text (1), diff --git a/man/blind-matrix-shear.1 b/man/blind-matrix-shear.1 @@ -3,7 +3,7 @@ blind-matrix-shear - Create an affine 2D-transformation matrix for shearing .SH SYNOPSIS .B blind-matrix-shear -[-ac] +[-a [-d]] [-c] .SH DESCRIPTION .B blind-matrix-shear creates an affine 2D-transformation matrix for @@ -37,6 +37,9 @@ Create different matrices for each channel. Use values from each channel in stdin to create matrices whose values are stored in the same channels in stdout. +.TP +.B -d +Input angles in degrees rather than radians. .SH NOTES The description assumes the Y-axis grows downwards. .P diff --git a/src/blind-matrix-rotate.c b/src/blind-matrix-rotate.c @@ -1,9 +1,10 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -USAGE("[-c]") +USAGE("[-cd]") static int per_channel = 0; +static int in_degrees = 0; #define PROCESS(TYPE)\ do {\ @@ -19,15 +20,25 @@ static int per_channel = 0; }\ \ while (eread_frame(stream, buf)) {\ - if (per_channel) {\ + if (per_channel && in_degrees) {\ + for (i = 0; i < 4; i++) {\ + matrix[4][i] = matrix[0][i] = degcos(buf[i]);\ + matrix[3][i] = -(matrix[1][i] = degsin(buf[i]));\ + }\ + } else if (per_channel) {\ for (i = 0; i < 4; i++) {\ matrix[4][i] = matrix[0][i] = cos(buf[i]);\ matrix[3][i] = -(matrix[1][i] = sin(buf[i]));\ }\ } else {\ buf[1] *= buf[3];\ - matrix[4][0] = matrix[0][0] = cos(buf[1]);\ - matrix[3][0] = -(matrix[1][0] = sin(buf[1]));\ + if (in_degrees) {\ + matrix[4][0] = matrix[0][0] = degcos(buf[1]);\ + matrix[3][0] = -(matrix[1][0] = degsin(buf[1]));\ + } else {\ + matrix[4][0] = matrix[0][0] = cos(buf[1]);\ + matrix[3][0] = -(matrix[1][0] = sin(buf[1]));\ + }\ matrix[0][3] = matrix[0][2] = matrix[0][1] = matrix[0][0];\ matrix[1][3] = matrix[1][2] = matrix[1][1] = matrix[1][0];\ matrix[3][3] = matrix[3][2] = matrix[3][1] = matrix[3][0];\ @@ -50,6 +61,9 @@ main(int argc, char *argv[]) case 'c': per_channel = 1; break; + case 'd': + in_degrees = 1; + break; default: usage(); } ARGEND; diff --git a/src/blind-matrix-shear.c b/src/blind-matrix-shear.c @@ -1,16 +1,18 @@ /* See LICENSE file for copyright and license details. */ #include "common.h" -USAGE("[-ac]") +USAGE("[-a [-d]][c]") static int by_angle = 0; static int per_channel = 0; +static int in_degrees = 0; #define PROCESS(TYPE)\ do {\ typedef TYPE pixel_t[4];\ pixel_t matrix[9];\ pixel_t buf[2];\ + TYPE conv = in_degrees ? (TYPE)(M_PI / 180.) : 1;\ int i;\ \ for (i = 0; i < 4; i++) {\ @@ -22,8 +24,8 @@ static int per_channel = 0; while (eread_frame(stream, buf)) {\ if (by_angle) {\ for (i = !per_channel; i < (per_channel ? 4 : 2); i++) {\ - buf[0][i] = tan(buf[0][i]);\ - buf[1][i] = tan(buf[1][i]);\ + buf[0][i] = tan(buf[0][i] * conv);\ + buf[1][i] = tan(buf[1][i] * conv);\ }\ }\ if (per_channel) {\ @@ -55,11 +57,14 @@ main(int argc, char *argv[]) case 'c': per_channel = 1; break; + case 'd': + in_degrees = 1; + break; default: usage(); } ARGEND; - if (argc) + if (argc || (in_degrees && !by_angle)) usage(); eopen_stream(&stream, NULL); diff --git a/src/video-math.h b/src/video-math.h @@ -31,6 +31,50 @@ posmodf(float a, float b) return x < 0 ? x + b : x; } +static inline double +degsin(double u) +{ + if (!fmod(u, 90)) { + int64_t v = u; + v = ((v / 90) % 4 + 4) % 4; + return ((double[]){0, 1, 0, -1})[v]; + } + return sin(u * (M_PI / 180.0)); +} + +static inline float +degsinf(float u) +{ + if (!fmodf(u, 90)) { + int64_t v = u; + v = ((v / 90) % 4 + 4) % 4; + return ((float[]){0, 1, 0, -1})[v]; + } + return sin(u * (float)(M_PI / 180.0)); +} + +static inline double +degcos(double u) +{ + if (!fmod(u, 90)) { + int64_t v = u; + v = ((v / 90) % 4 + 4) % 4; + return ((double[]){1, 0, -1, 0})[v]; + } + return cos(u * (M_PI / 180.0)); +} + +static inline float +degcosf(float u) +{ + if (!fmodf(u, 90)) { + int64_t v = u; + v = ((v / 90) % 4 + 4) % 4; + return ((float[]){1, 0, -1, 0})[v]; + } + return cos(u * (float)(M_PI / 180.0)); +} + #define GENERIC(TYPE, FUNC, ...)\ TYPE: FUNC(__VA_ARGS__),\ TYPE *: FUNC(__VA_ARGS__),\ @@ -73,6 +117,8 @@ posmodf(float a, float b) #define sin(...) MATH_GENERIC_1(sin, __VA_ARGS__) #define tan(...) MATH_GENERIC_1(tan, __VA_ARGS__) #define atan2(...) MATH_GENERIC_N(atan2, __VA_ARGS__) +#define degcos(...) MATH_GENERIC_1(degcos, __VA_ARGS__) +#define degsin(...) MATH_GENERIC_1(degsin, __VA_ARGS__) #define srgb_encode(...) BLIND_GENERIC_1(srgb_encode, __VA_ARGS__) #define srgb_decode(...) BLIND_GENERIC_1(srgb_decode, __VA_ARGS__)