summaryrefslogtreecommitdiff
path: root/src/ipa/raspberrypi/data
AgeCommit message (Collapse)Author
2021-05-11meson: Replace obselete join_paths() with '/' operatorUmang Jain
Since meson v0.49.0, join_paths() is equivalent to '/' hence, drop and replace it with '/' short-hand in meson files. This commit does not introduce any functional changes. Signed-off-by: Umang Jain <umang.jain@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2021-03-14ipa: raspberrypi: Add support for imx327-based SE327M12 moduleDavid Plowman
This patch adds support for the Soho Enterprises SE327M12 module. The sensor is an imx327 which therefore uses the imx290 kernel driver and CamHelper. To use this module and camera tuning, place the following in the /boot/config.txt file: dtoverlay=imx290,clock-frequency=37125000 and then the existing imx290.json file must be over-written with se327m12.json Signed-off-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2021-03-09ipa: raspberrypi: Add support for imx290/imx327 sensorsDavid Plowman
imx290 and imx327 share the same kernel driver (imx290.c) and are therefore both recognised here as "imx290". We add the necessary CamHelper for these sensors, as well as a camera tuning file. The tuning was done with an Innomaker STARVIS IMX327LQR module. These have no IR cut filter so there is no proper colour tuning. However, you should obtain reasonable results for most modules using this sensor. Specific tunings for further modules can always be added subsequently. To use this sensor on the Raspberry Pi platform, please add dtoverlay=imx290,clock-frequency=74250000 into your /boot/config.txt file. Signed-off-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2021-01-20ipa: raspberrypi: config: Update shutter speeds for imx219/477 and ov5647Naushir Patuck
Set the maximum shutter speed for the normal exposure profile to 66ms, allowing viewfinder framerates to go down to approx. 15fps. Set the maximum shutter speed for the sport exposure profile to 33ms, limiting the minimum framerate to approx. 30fps. Add a long exposure profile to allow shutter speeds of up to 120ms. Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: David Plowman <david.plowman@raspberrypi.com> Tested-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2020-12-01src: ipa: raspberrypi: Fix initial AGC oscillation for imx219 sensorDavid Plowman
The exposure times in the exposure modes were causing AGC oscillations because the algorithm was demanding long unachievable exposure times but, without working sensor metadata, thought it was getting them when actually it was not. We fix it by making the exposure profile request only achievable exposure times, as we do for the ov5647 tuning. Signed-off-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2020-11-20src: ipa: raspberrypi: Change 'sport' exposure mode name to 'short'David Plowman
The names have to match for the setting to work. Use the libcamera terminology for consistency (even though it touches more files). Signed-off-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2020-07-03ipa: raspberrypi: Enable focus measure without recompileDavid Plowman
Previously, output of the focus measure could not be enabled without recompiling (because of the RPI_LOGGING_ENABLE macro). This uses the libcamera logging mechanism instead, so can be enabled/disabled at runtime. Signed-off-by: David Plowman <david.plowman@raspberrypi.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2020-06-25ipa: rpi: Add "focus" algorithmDavid Plowman
Adds FocusStatus to the image metadata, containing contrast measurements across the image. Optionally also prints a contrast measure to the console, to aid in manual adjustment of the lens. Note that it is not an actual auto-focus algorithm that can drive a lens! Signed-off-by: David Plowman <david.plowman@raspberrypi.com> Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2020-06-09libcamera: Add missing SPDX headers to miscellaneous small filesLaurent Pinchart
Add missing SPDX headers to miscellaneous small files. Use CC0-1.0 for meson.build, .gitignore and the small include/linux/README, and licenses matching the corresponding component for other files. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
2020-05-11libcamera: ipa: Raspberry Pi IPANaushir Patuck
Initial implementation of the Raspberry Pi (BCM2835) libcamera IPA and associated libraries. All code is licensed under the BSD-2-Clause terms. Copyright (c) 2019-2020 Raspberry Pi Trading Ltd. Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
a> 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * geometry.cpp - Geometry classes tests
 */

#include <iostream>

#include <libcamera/geometry.h>

#include "test.h"

using namespace std;
using namespace libcamera;

class GeometryTest : public Test
{
protected:
	template<typename T>
	bool compare(const T &lhs, const T &rhs,
		     bool (*op)(const T &lhs, const T &rhs),
		     const char *opName, bool expect)
	{
		bool result = op(lhs, rhs);

		if (result != expect) {
			cout << lhs.toString()
			     << opName << " "
			     << rhs.toString()
			     << "test failed" << std::endl;
			return false;
		}

		return true;
	}

	int run()
	{
		/*
		 * Point tests
		 */

		/* Equality */
		if (!compare(Point(50, 100), Point(50, 100), &operator==, "==", true))
			return TestFail;

		if (!compare(Point(-50, 100), Point(-50, 100), &operator==, "==", true))
			return TestFail;

		if (!compare(Point(50, -100), Point(50, -100), &operator==, "==", true))
			return TestFail;

		if (!compare(Point(-50, -100), Point(-50, -100), &operator==, "==", true))
			return TestFail;

		/* Inequality */
		if (!compare(Point(50, 100), Point(50, 100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(-50, 100), Point(-50, 100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(50, -100), Point(50, -100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(-50, -100), Point(-50, -100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Point(-50, 100), Point(50, 100), &operator!=, "!=", true))
			return TestFail;

		if (!compare(Point(50, -100), Point(50, 100), &operator!=, "!=", true))
			return TestFail;

		if (!compare(Point(-50, -100), Point(50, 100), &operator!=, "!=", true))
			return TestFail;

		/* Negation */
		if (Point(50, 100) != -Point(-50, -100) ||
		    Point(50, 100) == -Point(50, -100) ||
		    Point(50, 100) == -Point(-50, 100)) {
			cout << "Point negation test failed" << endl;
			return TestFail;
		}

		/* Default constructor */
		if (Point() != Point(0, 0)) {
			cout << "Default constructor test failed" << endl;
			return TestFail;
		}

		/*
		 * Size tests
		 */

		if (!Size().isNull() || !Size(0, 0).isNull()) {
			cout << "Null size incorrectly reported as not null" << endl;
			return TestFail;
		}

		if (Size(0, 100).isNull() || Size(100, 0).isNull() || Size(100, 100).isNull()) {
			cout << "Non-null size incorrectly reported as null" << endl;
			return TestFail;
		}

		/* Test alignDownTo(), alignUpTo(), boundTo() and expandTo() */
		Size s(50, 50);

		s.alignDownTo(16, 16);
		if (s != Size(48, 48)) {
			cout << "Size::alignDownTo() test failed" << endl;
			return TestFail;
		}

		s.alignUpTo(32, 32);
		if (s != Size(64, 64)) {
			cout << "Size::alignUpTo() test failed" << endl;
			return TestFail;
		}

		s.boundTo({ 40, 40 });
		if (s != Size(40, 40)) {
			cout << "Size::boundTo() test failed" << endl;
			return TestFail;
		}

		s.expandTo({ 50, 50 });
		if (s != Size(50, 50)) {
			cout << "Size::expandTo() test failed" << endl;
			return TestFail;
		}

		s.alignDownTo(16, 16).alignUpTo(32, 32)
		 .boundTo({ 40, 80 }).expandTo({ 16, 80 });
		if (s != Size(40, 80)) {
			cout << "Size chained in-place modifiers test failed" << endl;
			return TestFail;
		}

		/* Test alignedDownTo(), alignedUpTo(), boundedTo() and expandedTo() */
		if (Size(0, 0).alignedDownTo(16, 8) != Size(0, 0) ||
		    Size(1, 1).alignedDownTo(16, 8) != Size(0, 0) ||
		    Size(16, 8).alignedDownTo(16, 8) != Size(16, 8)) {
			cout << "Size::alignedDownTo() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).alignedUpTo(16, 8) != Size(0, 0) ||
		    Size(1, 1).alignedUpTo(16, 8) != Size(16, 8) ||
		    Size(16, 8).alignedUpTo(16, 8) != Size(16, 8)) {
			cout << "Size::alignedUpTo() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).boundedTo({ 100, 100 }) != Size(0, 0) ||
		    Size(200, 50).boundedTo({ 100, 100 }) != Size(100, 50) ||
		    Size(50, 200).boundedTo({ 100, 100 }) != Size(50, 100)) {
			cout << "Size::boundedTo() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).expandedTo({ 100, 100 }) != Size(100, 100) ||
		    Size(200, 50).expandedTo({ 100, 100 }) != Size(200, 100) ||
		    Size(50, 200).expandedTo({ 100, 100 }) != Size(100, 200)) {
			cout << "Size::expandedTo() test failed" << endl;
			return TestFail;
		}

		/* Aspect ratio tests */
		if (Size(0, 0).boundedToAspectRatio(Size(4, 3)) != Size(0, 0) ||
		    Size(1920, 1440).boundedToAspectRatio(Size(16, 9)) != Size(1920, 1080) ||
		    Size(1920, 1440).boundedToAspectRatio(Size(65536, 36864)) != Size(1920, 1080) ||
		    Size(1440, 1920).boundedToAspectRatio(Size(9, 16)) != Size(1080, 1920) ||
		    Size(1920, 1080).boundedToAspectRatio(Size(4, 3)) != Size(1440, 1080) ||
		    Size(1920, 1080).boundedToAspectRatio(Size(65536, 49152)) != Size(1440, 1080) ||
		    Size(1024, 1024).boundedToAspectRatio(Size(1, 1)) != Size(1024, 1024) ||
		    Size(1920, 1080).boundedToAspectRatio(Size(16, 9)) != Size(1920, 1080) ||
		    Size(200, 100).boundedToAspectRatio(Size(16, 9)) != Size(177, 100) ||
		    Size(300, 200).boundedToAspectRatio(Size(16, 9)) != Size(300, 168)) {
			cout << "Size::boundedToAspectRatio() test failed" << endl;
			return TestFail;
		}

		if (Size(0, 0).expandedToAspectRatio(Size(4, 3)) != Size(0, 0) ||
		    Size(1920, 1440).expandedToAspectRatio(Size(16, 9)) != Size(2560, 1440) ||
		    Size(1920, 1440).expandedToAspectRatio(Size(65536, 36864)) != Size(2560, 1440) ||
		    Size(1440, 1920).expandedToAspectRatio(Size(9, 16)) != Size(1440, 2560) ||
		    Size(1920, 1080).expandedToAspectRatio(Size(4, 3)) != Size(1920, 1440) ||
		    Size(1920, 1080).expandedToAspectRatio(Size(65536, 49152)) != Size(1920, 1440) ||
		    Size(1024, 1024).expandedToAspectRatio(Size(1, 1)) != Size(1024, 1024) ||
		    Size(1920, 1080).expandedToAspectRatio(Size(16, 9)) != Size(1920, 1080) ||
		    Size(200, 100).expandedToAspectRatio(Size(16, 9)) != Size(200, 112) ||
		    Size(300, 200).expandedToAspectRatio(Size(16, 9)) != Size(355, 200)) {
			cout << "Size::expandedToAspectRatio() test failed" << endl;
			return TestFail;
		}

		/* Size::centeredTo() tests */
		if (Size(0, 0).centeredTo(Point(50, 100)) != Rectangle(50, 100, 0, 0) ||
		    Size(0, 0).centeredTo(Point(-50, -100)) != Rectangle(-50, -100, 0, 0) ||
		    Size(100, 200).centeredTo(Point(50, 100)) != Rectangle(0, 0, 100, 200) ||
		    Size(100, 200).centeredTo(Point(-50, -100)) != Rectangle(-100, -200, 100, 200) ||
		    Size(101, 201).centeredTo(Point(-50, -100)) != Rectangle(-100, -200, 101, 201) ||
		    Size(101, 201).centeredTo(Point(-51, -101)) != Rectangle(-101, -201, 101, 201)) {
			cout << "Size::centeredTo() test failed" << endl;
			return TestFail;
		}

		/* Scale a size by a float */
		if (Size(1000, 2000) * 2.0 != Size(2000, 4000) ||
		    Size(300, 100) * 0.5 != Size(150, 50) ||
		    Size(1, 2) * 1.6 != Size(1, 3)) {
			cout << "Size::operator*() failed" << endl;
			return TestFail;
		}

		if (Size(1000, 2000) / 2.0 != Size(500, 1000) ||
		    Size(300, 100) / 0.5 != Size(600, 200) ||
		    Size(1000, 2000) / 3.0 != Size(333, 666)) {
			cout << "Size::operator*() failed" << endl;
			return TestFail;
		}

		s = Size(300, 100);
		s *= 0.3333;
		if (s != Size(99, 33)) {
			cout << "Size::operator*() test failed" << endl;
			return TestFail;
		}

		s = Size(300, 100);
		s /= 3;
		if (s != Size(100, 33)) {
			cout << "Size::operator*() test failed" << endl;
			return TestFail;
		}

		/* Test Size equality and inequality. */
		if (!compare(Size(100, 100), Size(100, 100), &operator==, "==", true))
			return TestFail;
		if (!compare(Size(100, 100), Size(100, 100), &operator!=, "!=", false))
			return TestFail;

		if (!compare(Size(100, 100), Size(200, 100), &operator==, "==", false))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 100), &operator!=, "!=", true))
			return TestFail;

		if (!compare(Size(100, 100), Size(100, 200), &operator==, "==", false))
			return TestFail;
		if (!compare(Size(100, 100), Size(100, 200), &operator!=, "!=", true))
			return TestFail;

		/* Test Size ordering based on combined with and height. */
		if (!compare(Size(100, 100), Size(200, 200), &operator<, "<", true))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 200), &operator<=, "<=", true))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 200), &operator>, ">", false))
			return TestFail;
		if (!compare(Size(100, 100), Size(200, 200), &operator>=, ">=", false))
			return TestFail;

		if (!compare(Size(200, 200), Size(100, 100), &operator<, "<", false))
			return TestFail;
		if (!compare(Size(200, 200), Size(100, 100), &operator<=, "<=", false))
			return TestFail;
		if (!compare(Size(200, 200), Size(100, 100), &operator>, ">", true))
			return TestFail;
		if (!compare(Size(200, 200), Size(100, 100), &operator>=, ">=", true))
			return TestFail;

		/* Test Size ordering based on area (with overlapping sizes). */
		if (!compare(Size(200, 100), Size(100, 400), &operator<, "<", true))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 400), &operator<=, "<=", true))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 400), &operator>, ">", false))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 400), &operator>=, ">=", false))
			return TestFail;

		if (!compare(Size(100, 400), Size(200, 100), &operator<, "<", false))
			return TestFail;
		if (!compare(Size(100, 400), Size(200, 100), &operator<=, "<=", false))
			return TestFail;
		if (!compare(Size(100, 400), Size(200, 100), &operator>, ">", true))
			return TestFail;
		if (!compare(Size(100, 400), Size(200, 100), &operator>=, ">=", true))
			return TestFail;

		/* Test Size ordering based on width (with identical areas). */
		if (!compare(Size(100, 200), Size(200, 100), &operator<, "<", true))
			return TestFail;
		if (!compare(Size(100, 200), Size(200, 100), &operator<=, "<=", true))
			return TestFail;
		if (!compare(Size(100, 200), Size(200, 100), &operator>, ">", false))
			return TestFail;
		if (!compare(Size(100, 200), Size(200, 100), &operator>=, ">=", false))
			return TestFail;

		if (!compare(Size(200, 100), Size(100, 200), &operator<, "<", false))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 200), &operator<=, "<=", false))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 200), &operator>, ">", true))
			return TestFail;
		if (!compare(Size(200, 100), Size(100, 200), &operator>=, ">=", true))
			return TestFail;

		/*
		 * Rectangle tests
		 */

		/* Test Rectangle::isNull(). */
		if (!Rectangle(0, 0, 0, 0).isNull() ||
		    !Rectangle(1, 1, 0, 0).isNull()) {
			cout << "Null rectangle incorrectly reported as not null" << endl;
			return TestFail;
		}

		if (Rectangle(0, 0, 0, 1).isNull() ||
		    Rectangle(0, 0, 1, 0).isNull() ||
		    Rectangle(0, 0, 1, 1).isNull()) {
			cout << "Non-null rectangle incorrectly reported as null" << endl;
			return TestFail;
		}

		/* Rectangle::size(), Rectangle::topLeft() and Rectangle::center() tests */
		if (Rectangle(-1, -2, 3, 4).size() != Size(3, 4) ||
		    Rectangle(0, 0, 100000, 200000).size() != Size(100000, 200000)) {
			cout << "Rectangle::size() test failed" << endl;
			return TestFail;
		}

		if (Rectangle(1, 2, 3, 4).topLeft() != Point(1, 2) ||
		    Rectangle(-1, -2, 3, 4).topLeft() != Point(-1, -2)) {
			cout << "Rectangle::topLeft() test failed" << endl;
			return TestFail;
		}

		if (Rectangle(0, 0, 300, 400).center() != Point(150, 200) ||
		    Rectangle(-1000, -2000, 300, 400).center() != Point(-850, -1800) ||
		    Rectangle(10, 20, 301, 401).center() != Point(160, 220) ||
		    Rectangle(11, 21, 301, 401).center() != Point(161, 221) ||
		    Rectangle(-1011, -2021, 301, 401).center() != Point(-861, -1821)) {
			cout << "Rectangle::center() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::boundedTo() (intersection function) */
		if (Rectangle(0, 0, 1000, 2000).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(0, 0, 1000, 2000) ||
		    Rectangle(-500, -1000, 1000, 2000).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(0, 0, 500, 1000) ||
		    Rectangle(500, 1000, 1000, 2000).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(500, 1000, 500, 1000) ||
		    Rectangle(300, 400, 50, 100).boundedTo(Rectangle(0, 0, 1000, 2000)) !=
			    Rectangle(300, 400, 50, 100) ||
		    Rectangle(0, 0, 1000, 2000).boundedTo(Rectangle(300, 400, 50, 100)) !=
			    Rectangle(300, 400, 50, 100) ||
		    Rectangle(0, 0, 100, 100).boundedTo(Rectangle(50, 100, 100, 100)) !=
			    Rectangle(50, 100, 50, 0) ||
		    Rectangle(0, 0, 100, 100).boundedTo(Rectangle(100, 50, 100, 100)) !=
			    Rectangle(100, 50, 0, 50) ||
		    Rectangle(-10, -20, 10, 20).boundedTo(Rectangle(10, 20, 100, 100)) !=
			    Rectangle(10, 20, 0, 0)) {
			cout << "Rectangle::boundedTo() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::enclosedIn() tests */
		if (Rectangle(10, 20, 300, 400).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(10, 20, 300, 400) ||
		    Rectangle(-100, -200, 3000, 4000).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(-10, -20, 1300, 1400) ||
		    Rectangle(-100, -200, 300, 400).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(-10, -20, 300, 400) ||
		    Rectangle(5100, 6200, 300, 400).enclosedIn(Rectangle(-10, -20, 1300, 1400)) !=
			    Rectangle(990, 980, 300, 400) ||
		    Rectangle(100, -300, 150, 200).enclosedIn(Rectangle(50, 0, 200, 300)) !=
			    Rectangle(100, 0, 150, 200) ||
		    Rectangle(100, -300, 150, 1200).enclosedIn(Rectangle(50, 0, 200, 300)) !=
			    Rectangle(100, 0, 150, 300) ||
		    Rectangle(-300, 100, 200, 150).enclosedIn(Rectangle(0, 50, 300, 200)) !=
			    Rectangle(0, 100, 200, 150) ||
		    Rectangle(-300, 100, 1200, 150).enclosedIn(Rectangle(0, 50, 300, 200)) !=
			    Rectangle(0, 100, 300, 150)) {
			cout << "Rectangle::enclosedIn() test failed" << endl;
			return TestFail;
		}

		/* Rectange::scaledBy() tests */
		if (Rectangle(10, 20, 300, 400).scaledBy(Size(0, 0), Size(1, 1)) !=
			    Rectangle(0, 0, 0, 0) ||
		    Rectangle(10, -20, 300, 400).scaledBy(Size(32768, 65536), Size(32768, 32768)) !=
			    Rectangle(10, -40, 300, 800) ||
		    Rectangle(-30000, 10000, 20000, 20000).scaledBy(Size(7, 7), Size(7, 7)) !=
			    Rectangle(-30000, 10000, 20000, 20000) ||
		    Rectangle(-20, -30, 320, 240).scaledBy(Size(1280, 960), Size(640, 480)) !=
			    Rectangle(-40, -60, 640, 480) ||
		    Rectangle(1, 1, 2026, 1510).scaledBy(Size(4056, 3024), Size(2028, 1512)) !=
			    Rectangle(2, 2, 4052, 3020)) {
			cout << "Rectangle::scaledBy() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::translatedBy() tests */
		if (Rectangle(10, -20, 300, 400).translatedBy(Point(-30, 40)) !=
			    Rectangle(-20, 20, 300, 400) ||
		    Rectangle(-10, 20, 400, 300).translatedBy(Point(50, -60)) !=
			    Rectangle(40, -40, 400, 300)) {
			cout << "Rectangle::translatedBy() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::scaleBy() tests */
		Rectangle r(-20, -30, 320, 240);
		r.scaleBy(Size(1280, 960), Size(640, 480));
		if (r != Rectangle(-40, -60, 640, 480)) {
			cout << "Rectangle::scaleBy() test failed" << endl;
			return TestFail;
		}

		r = Rectangle(1, 1, 2026, 1510);
		r.scaleBy(Size(4056, 3024), Size(2028, 1512));
		if (r != Rectangle(2, 2, 4052, 3020)) {
			cout << "Rectangle::scaleBy() test failed" << endl;
			return TestFail;
		}

		/* Rectangle::translateBy() tests */
		r = Rectangle(10, -20, 300, 400);
		r.translateBy(Point(-30, 40));
		if (r != Rectangle(-20, 20, 300, 400)) {
			cout << "Rectangle::translateBy() test failed" << endl;
			return TestFail;
		}

		r = Rectangle(-10, 20, 400, 300);
		r.translateBy(Point(50, -60));
		if (r != Rectangle(40, -40, 400, 300)) {
			cout << "Rectangle::translateBy() test failed" << endl;
			return TestFail;
		}

		return TestPass;
	}
};

TEST_REGISTER(GeometryTest)