u02: Implement transformation functions

This commit is contained in:
Simon Bruder 2023-05-06 16:37:48 +02:00
parent 837a1e5519
commit 18456541aa
3 changed files with 148 additions and 0 deletions

27
u02/include/util.h Normal file
View file

@ -0,0 +1,27 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once
#include <cstdint>
#include <tuple>
typedef uint8_t Transformation;
const Transformation TRANSFORM_MIRROR_X = 1 << 0;
const Transformation TRANSFORM_MIRROR_Y = 1 << 1;
const Transformation TRANSFORM_ROTATE_CW = 1 << 2;
const Transformation TRANSFORM_ROTATE_CCW = 1 << 3;
// Applies the provided transformation to the point, mutating it in place.
// Rotation is done before mirroring.
void transform_mut(Transformation transformation, int &x, int &y);
// Applies the provided transformation to the point,
// returning the transformed point.
// Rotation is done before mirroring.
std::pair<int, int> transform(Transformation transformation, int x, int y);
// Applies the inverse transformation to the point, mutating it in place.
// Composition of this with the transformation is the identity function.
void transform_inv_mut(Transformation transformation, int &x, int &y);
// Applies the inverse transformation to the point,
// returning the transformed point.
// Composition of this with the transformation is the identity function.
std::pair<int, int> transform_inv(Transformation transformation, int x, int y);

72
u02/src/tests.cpp Normal file
View file

@ -0,0 +1,72 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#include <algorithm>
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/generators/catch_generators_adapters.hpp>
#include <catch2/generators/catch_generators_random.hpp>
#include "util.h"
TEST_CASE("Transform Mirror") {
// elementary operations
REQUIRE(transform(TRANSFORM_MIRROR_X, 10, 20) == std::make_pair(10, -20));
REQUIRE(transform(TRANSFORM_MIRROR_Y, 10, 20) == std::make_pair(-10, 20));
// composite operations
REQUIRE(transform(TRANSFORM_MIRROR_X | TRANSFORM_MIRROR_Y, 10, 20) ==
std::make_pair(-10, -20));
}
TEST_CASE("Transform Rotate") {
REQUIRE(transform(TRANSFORM_ROTATE_CW, 10, 20) ==
std::make_pair(-20, 10)); // 4th quadrant
REQUIRE(transform(TRANSFORM_ROTATE_CW, -20, 10) ==
std::make_pair(-10, -20)); // 3rd quadrant
REQUIRE(transform(TRANSFORM_ROTATE_CW, -10, -20) ==
std::make_pair(20, -10)); // 2nd quadrant
REQUIRE(transform(TRANSFORM_ROTATE_CW, 20, -10) ==
std::make_pair(10, 20)); // 1st quadrant
REQUIRE(transform(TRANSFORM_ROTATE_CCW, 20, -10) ==
std::make_pair(-10, -20)); // 1nd quadrant
REQUIRE(transform(TRANSFORM_ROTATE_CCW, -10, -20) ==
std::make_pair(-20, 10)); // 2rd quadrant
REQUIRE(transform(TRANSFORM_ROTATE_CCW, -20, 10) ==
std::make_pair(10, 20)); // 3th quadrant
REQUIRE(transform(TRANSFORM_ROTATE_CCW, 10, 20) ==
std::make_pair(20, -10)); // 4st quadrant
}
TEST_CASE("Transform Rotate + Mirror") {
REQUIRE(transform(TRANSFORM_ROTATE_CW | TRANSFORM_MIRROR_X, 10, 20) ==
std::make_pair(-20, -10));
REQUIRE(transform(TRANSFORM_ROTATE_CW | TRANSFORM_MIRROR_Y, 10, 20) ==
std::make_pair(20, 10));
REQUIRE(
transform(TRANSFORM_ROTATE_CW | TRANSFORM_MIRROR_X | TRANSFORM_MIRROR_Y,
10, 20) == std::make_pair(20, -10));
REQUIRE(transform(TRANSFORM_ROTATE_CCW | TRANSFORM_MIRROR_X, 10, 20) ==
std::make_pair(20, 10));
REQUIRE(transform(TRANSFORM_ROTATE_CCW | TRANSFORM_MIRROR_Y, 10, 20) ==
std::make_pair(-20, -10));
REQUIRE(
transform(TRANSFORM_ROTATE_CCW | TRANSFORM_MIRROR_X | TRANSFORM_MIRROR_Y,
10, 20) == std::make_pair(-20, 10));
}
TEST_CASE("Transform = Inverse Transform ○ Transform") {
int x = GENERATE(take(10, random(-100, 100)));
int y = GENERATE(take(10, random(-100, 100)));
// this iterates over all possible transformations,
// even bogus ones (like rotating cw and ccw)
for (Transformation transformation = 0; transformation < 0b10000;
transformation++) {
int xt, yt;
std::tie(xt, yt) = transform(transformation, x, y);
int xti, yti;
std::tie(xti, yti) = transform_inv(transformation, xt, yt);
REQUIRE(x == xti);
REQUIRE(y == yti);
}
}

49
u02/src/util.cpp Normal file
View file

@ -0,0 +1,49 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "util.h"
#include <cmath>
void transform_mut(Transformation transformation, int &x, int &y) {
if ((transformation & TRANSFORM_ROTATE_CW) != 0) {
std::swap(x, y);
x = -x;
}
if ((transformation & TRANSFORM_ROTATE_CCW) != 0) {
std::swap(x, y);
y = -y;
}
if ((transformation & TRANSFORM_MIRROR_X) != 0) {
y = -y;
}
if ((transformation & TRANSFORM_MIRROR_Y) != 0) {
x = -x;
}
}
std::pair<int, int> transform(Transformation transformation, int x, int y) {
transform_mut(transformation, x, y);
return std::make_pair(x, y);
}
void transform_inv_mut(Transformation transformation, int &x, int &y) {
if ((transformation & TRANSFORM_MIRROR_Y) != 0) {
x = -x;
}
if ((transformation & TRANSFORM_MIRROR_X) != 0) {
y = -y;
}
if (transformation & TRANSFORM_ROTATE_CCW) {
// does clockwise rotation
std::swap(x, y);
x = -x;
}
if (transformation & TRANSFORM_ROTATE_CW) {
// does counterclockwise rotation
std::swap(x, y);
y = -y;
}
}
std::pair<int, int> transform_inv(Transformation transformation, int x, int y) {
transform_inv_mut(transformation, x, y);
return std::make_pair(x, y);
}