Util: Add some basic geometry math

This commit is contained in:
Vicki Pfau 2023-02-20 22:59:23 -08:00
parent bd6edce5cf
commit efbc4a49ce
4 changed files with 256 additions and 2 deletions

View File

@ -13,10 +13,13 @@ CXX_GUARD_START
struct Rectangle {
int x;
int y;
unsigned width;
unsigned height;
int width;
int height;
};
void RectangleUnion(struct Rectangle* dst, const struct Rectangle* add);
void RectangleCenter(const struct Rectangle* ref, struct Rectangle* rect);
CXX_GUARD_END
#endif

View File

@ -16,6 +16,7 @@ set(SOURCE_FILES
convolve.c
elf-read.c
export.c
geometry.c
patch.c
patch-fast.c
patch-ips.c
@ -33,6 +34,7 @@ set(GUI_FILES
gui/menu.c)
set(TEST_FILES
test/geometry.c
test/sfo.c
test/string-parser.c
test/string-utf8.c

36
src/util/geometry.c Normal file
View File

@ -0,0 +1,36 @@
/* Copyright (c) 2013-2023 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <mgba-util/geometry.h>
void RectangleUnion(struct Rectangle* dst, const struct Rectangle* add) {
int x0 = dst->x;
int y0 = dst->y;
int x1 = dst->x + dst->width;
int y1 = dst->y + dst->height;
if (add->x < x0) {
x0 = add->x;
}
if (add->y < y0) {
y0 = add->y;
}
if (add->x + add->width > x1) {
x1 = add->x + add->width;
}
if (add->y + add->height > y1) {
y1 = add->y + add->height;
}
dst->x = x0;
dst->y = y0;
dst->width = x1 - x0;
dst->height = y1 - y0;
}
void RectangleCenter(const struct Rectangle* ref, struct Rectangle* rect) {
rect->x = ref->x + (ref->width - rect->width) / 2;
rect->y = ref->y + (ref->height - rect->height) / 2;
}

213
src/util/test/geometry.c Normal file
View File

@ -0,0 +1,213 @@
/* Copyright (c) 2013-2023 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "util/test/suite.h"
#include <mgba-util/geometry.h>
M_TEST_DEFINE(unionRectOrigin) {
struct Rectangle a = {
.x = 0,
.y = 0,
.width = 1,
.height = 1
};
struct Rectangle b = {
.x = 1,
.y = 1,
.width = 1,
.height = 1
};
RectangleUnion(&a, &b);
assert_int_equal(a.x, 0);
assert_int_equal(a.y, 0);
assert_int_equal(a.width, 2);
assert_int_equal(a.height, 2);
}
M_TEST_DEFINE(unionRectOriginSwapped) {
struct Rectangle a = {
.x = 1,
.y = 1,
.width = 1,
.height = 1
};
struct Rectangle b = {
.x = 0,
.y = 0,
.width = 1,
.height = 1
};
RectangleUnion(&a, &b);
assert_int_equal(a.x, 0);
assert_int_equal(a.y, 0);
assert_int_equal(a.width, 2);
assert_int_equal(a.height, 2);
}
M_TEST_DEFINE(unionRectNonOrigin) {
struct Rectangle a = {
.x = 1,
.y = 1,
.width = 1,
.height = 1
};
struct Rectangle b = {
.x = 2,
.y = 2,
.width = 1,
.height = 1
};
RectangleUnion(&a, &b);
assert_int_equal(a.x, 1);
assert_int_equal(a.y, 1);
assert_int_equal(a.width, 2);
assert_int_equal(a.height, 2);
}
M_TEST_DEFINE(unionRectOverlapping) {
struct Rectangle a = {
.x = 0,
.y = 0,
.width = 2,
.height = 2
};
struct Rectangle b = {
.x = 1,
.y = 1,
.width = 2,
.height = 2
};
RectangleUnion(&a, &b);
assert_int_equal(a.x, 0);
assert_int_equal(a.y, 0);
assert_int_equal(a.width, 3);
assert_int_equal(a.height, 3);
}
M_TEST_DEFINE(unionRectSubRect) {
struct Rectangle a = {
.x = 0,
.y = 0,
.width = 3,
.height = 3
};
struct Rectangle b = {
.x = 1,
.y = 1,
.width = 1,
.height = 1
};
RectangleUnion(&a, &b);
assert_int_equal(a.x, 0);
assert_int_equal(a.y, 0);
assert_int_equal(a.width, 3);
assert_int_equal(a.height, 3);
}
M_TEST_DEFINE(unionRectNegativeOrigin) {
struct Rectangle a = {
.x = -1,
.y = -1,
.width = 1,
.height = 1
};
struct Rectangle b = {
.x = 0,
.y = 0,
.width = 1,
.height = 1
};
RectangleUnion(&a, &b);
assert_int_equal(a.x, -1);
assert_int_equal(a.y, -1);
assert_int_equal(a.width, 2);
assert_int_equal(a.height, 2);
}
M_TEST_DEFINE(centerRectBasic) {
struct Rectangle ref = {
.x = 0,
.y = 0,
.width = 4,
.height = 4
};
struct Rectangle a = {
.x = 0,
.y = 0,
.width = 2,
.height = 2
};
RectangleCenter(&ref, &a);
assert_int_equal(a.x, 1);
assert_int_equal(a.y, 1);
}
M_TEST_DEFINE(centerRectRoundDown) {
struct Rectangle ref = {
.x = 0,
.y = 0,
.width = 4,
.height = 4
};
struct Rectangle a = {
.x = 0,
.y = 0,
.width = 1,
.height = 1
};
RectangleCenter(&ref, &a);
assert_int_equal(a.x, 1);
assert_int_equal(a.y, 1);
}
M_TEST_DEFINE(centerRectRoundDown2) {
struct Rectangle ref = {
.x = 0,
.y = 0,
.width = 4,
.height = 4
};
struct Rectangle a = {
.x = 0,
.y = 0,
.width = 3,
.height = 2
};
RectangleCenter(&ref, &a);
assert_int_equal(a.x, 0);
assert_int_equal(a.y, 1);
}
M_TEST_DEFINE(centerRectOffset) {
struct Rectangle ref = {
.x = 1,
.y = 1,
.width = 4,
.height = 4
};
struct Rectangle a = {
.x = 0,
.y = 0,
.width = 2,
.height = 2
};
RectangleCenter(&ref, &a);
assert_int_equal(a.x, 2);
assert_int_equal(a.y, 2);
}
M_TEST_SUITE_DEFINE(Geometry,
cmocka_unit_test(unionRectOrigin),
cmocka_unit_test(unionRectOriginSwapped),
cmocka_unit_test(unionRectNonOrigin),
cmocka_unit_test(unionRectOverlapping),
cmocka_unit_test(unionRectSubRect),
cmocka_unit_test(unionRectNegativeOrigin),
cmocka_unit_test(centerRectBasic),
cmocka_unit_test(centerRectRoundDown),
cmocka_unit_test(centerRectRoundDown2),
cmocka_unit_test(centerRectOffset),
)