<commit_before>// This file is part of playd.
// playd is licensed under the MIT licence: see LICENSE.txt.

/**
 * @file
 * Tests for the Tokeniser class.
 */

#include "catch.hpp"
#include "../tokeniser.hpp"

SCENARIO("Tokenisers can handle complete, unquoted commands", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a nullary command") {
			auto lines = t.Feed("stop\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word is the nullary command") {
				REQUIRE(lines[0][0] == "stop");
			}
		}

		WHEN("the Tokeniser is fed a unary command") {
			auto lines = t.Feed("seek 10s\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains two words") {
				REQUIRE(lines[0].size() == 2);
			}

			THEN("the first word is the command") {
				REQUIRE(lines[0][0] == "seek");
			}

			THEN("the second word is the argument") {
				REQUIRE(lines[0][1] == "10s");
			}
		}
	}
}

SCENARIO("Tokenisers can handle single-quoted strings", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a single-quoted string with no special characters") {
			auto lines = t.Feed("'normal_string'\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the single quotes") {
				REQUIRE(lines[0][0] == "normal_string");
			}
		}

		WHEN("the Tokeniser is fed a single-quoted string with spaces") {
			auto lines = t.Feed("'not three words'\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the single quotes") {
				REQUIRE(lines[0][0] == "not three words");
			}
		}

		// Backslashes are tested in their own scenario below.
	}
}

SCENARIO("Tokenisers can handle double-quoted strings", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a double-quoted string with no special characters") {
			auto lines = t.Feed("\"normal_string\"\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the double quotes") {
				REQUIRE(lines[0][0] == "normal_string");
			}
		}

		WHEN("the Tokeniser is fed a double-quoted string with spaces") {
			auto lines = t.Feed("\"not three words\"\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the double quotes") {
				REQUIRE(lines[0][0] == "not three words");
			}
		}

		// Backslashes are tested in their own scenario below.
	}
}

SCENARIO("Tokenisers can handle mixed-quoted strings", "[tokeniser]") {
	// This is a slightly strange concept, but is based on what happens in
	// POSIX shell.

	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a word with a mixture of different quote styles") {
			auto lines = t.Feed("This' is'\\ perfectly\"\\ valid \"syntax!\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the concatenation of each") {
				REQUIRE(lines[0][0] == "This is perfectly valid syntax!");
			}
		}
	}
}

SCENARIO("Tokenisers can backslash-escape bytes", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a backslashed space in unquoted mode") {
			auto lines = t.Feed("backslashed\\ space\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the line contains the space, but no backslash") {
				REQUIRE(lines[0][0] == "backslashed space");
			}
		}

		WHEN("the Tokeniser is fed a backslashed space in double-quoted mode") {
			auto lines = t.Feed("\"backslashed\\ space\"\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the line contains the space, but no backslash or quotes") {
				REQUIRE(lines[0][0] == "backslashed space");
			}
		}

		WHEN("the Tokeniser is fed a backslashed space in single-quoted mode") {
			auto lines = t.Feed("'backslashed\\ space'\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the line contains the space AND backslash, but no quotes") {
				REQUIRE(lines[0][0] == "backslashed\\ space");
			}
		}
	}
}

// See http://universityradioyork.github.io/baps3-spec/comms/internal/protocol.html
SCENARIO("Tokeniser is compliant with the BAPS3 spec", "[tokeniser][spec]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;
		WHEN("the Tokeniser is fed E1") {
			auto lines = t.Feed("");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 0);
			}
		}
		WHEN("the Tokeniser is fed E2") {
			auto lines = t.Feed("\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 0);
			}
		}
		WHEN("the Tokeniser is fed E3") {
			auto lines = t.Feed("''\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "");
			}
		}
		WHEN("the Tokeniser is fed E4") {
			auto lines = t.Feed("\"\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "");
			}
		}
		WHEN("the Tokeniser is fed W1") {
			auto lines = t.Feed("foo bar baz\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 3);
				REQUIRE(lines[0][0] == "foo");
				REQUIRE(lines[0][1] == "bar");
				REQUIRE(lines[0][2] == "baz");
			}
		}
		WHEN("the Tokeniser is fed W2") {
			auto lines = t.Feed("foo\tbar\tbaz\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 3);
				REQUIRE(lines[0][0] == "foo");
				REQUIRE(lines[0][1] == "bar");
				REQUIRE(lines[0][2] == "baz");
			}
		}
		WHEN("the Tokeniser is fed W3") {
			auto lines = t.Feed("foo\rbar\rbaz\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 3);
				REQUIRE(lines[0][0] == "foo");
				REQUIRE(lines[0][1] == "bar");
				REQUIRE(lines[0][2] == "baz");
			}
		}
		WHEN("the Tokeniser is fed W4") {
			auto lines = t.Feed("silly windows\r\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "silly");
				REQUIRE(lines[0][1] == "windows");
			}
		}
		WHEN("the Tokeniser is fed W5") {
			auto lines = t.Feed("    abc def\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "abc");
				REQUIRE(lines[0][1] == "def");
			}
		}
		WHEN("the Tokeniser is fed W6") {
			auto lines = t.Feed("ghi jkl    \n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "ghi");
				REQUIRE(lines[0][1] == "jkl");
			}
		}
		WHEN("the Tokeniser is fed W7") {
			auto lines = t.Feed("    mno pqr    \n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "mno");
				REQUIRE(lines[0][1] == "pqr");
			}
		}
		WHEN("the Tokeniser is fed Q1") {
			auto lines = t.Feed("abc\\\ndef\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q2") {
			auto lines = t.Feed("\"abc\ndef\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q3") {
			auto lines = t.Feed("\"abc\\\ndef\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q4") {
			auto lines = t.Feed("'abc\ndef'\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q5") {
			auto lines = t.Feed("'abc\\\ndef'\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\\\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q6") {
			auto lines = t.Feed("Scare\\\" quotes\\\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "Scare\"");
				REQUIRE(lines[0][1] == "quotes\"");
			}
		}
		WHEN("the Tokeniser is fed Q7") {
			auto lines = t.Feed("I\\'m free\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "I'm");
				REQUIRE(lines[0][1] == "free");
			}
		}
		WHEN("the Tokeniser is fed Q8") {
			auto lines = t.Feed("'hello, I'\\''m an escaped single quote'\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "hello, I'm an escaped single quote");
			}
		}
		WHEN("the Tokeniser is fed Q9") {
			auto lines = t.Feed("\"hello, this is an \\\" escaped double quote\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "hello, this is an \" escaped double quote");
			}
		}
		WHEN("the Tokeniser is fed M1") {
			auto lines = t.Feed("first line\nsecond line\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 2);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "first");
				REQUIRE(lines[0][1] == "line");
				REQUIRE(lines[1].size() == 2);
				REQUIRE(lines[1][0] == "second");
				REQUIRE(lines[1][1] == "line");
			}
		}
		WHEN("the Tokeniser is fed U1") {
			auto lines = t.Feed("北野 武\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "北野");
				REQUIRE(lines[0][1] == "武");
			}
		}
		WHEN("the Tokeniser is fed X1") {
			auto lines = t.Feed("enqueue file \"C:\\\\Users\\\\Test\\\\Artist - Title.mp3\" 1\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 4);
				REQUIRE(lines[0][0] == "enqueue");
				REQUIRE(lines[0][1] == "file");
				REQUIRE(lines[0][2] == "C:\\Users\\Test\\Artist - Title.mp3");
				REQUIRE(lines[0][3] == "1");
			}
		}
	}
}
<commit_msg>Update test link.<commit_after>// This file is part of playd.
// playd is licensed under the MIT licence: see LICENSE.txt.

/**
 * @file
 * Tests for the Tokeniser class.
 */

#include "catch.hpp"
#include "../tokeniser.hpp"

SCENARIO("Tokenisers can handle complete, unquoted commands", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a nullary command") {
			auto lines = t.Feed("stop\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word is the nullary command") {
				REQUIRE(lines[0][0] == "stop");
			}
		}

		WHEN("the Tokeniser is fed a unary command") {
			auto lines = t.Feed("seek 10s\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains two words") {
				REQUIRE(lines[0].size() == 2);
			}

			THEN("the first word is the command") {
				REQUIRE(lines[0][0] == "seek");
			}

			THEN("the second word is the argument") {
				REQUIRE(lines[0][1] == "10s");
			}
		}
	}
}

SCENARIO("Tokenisers can handle single-quoted strings", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a single-quoted string with no special characters") {
			auto lines = t.Feed("'normal_string'\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the single quotes") {
				REQUIRE(lines[0][0] == "normal_string");
			}
		}

		WHEN("the Tokeniser is fed a single-quoted string with spaces") {
			auto lines = t.Feed("'not three words'\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the single quotes") {
				REQUIRE(lines[0][0] == "not three words");
			}
		}

		// Backslashes are tested in their own scenario below.
	}
}

SCENARIO("Tokenisers can handle double-quoted strings", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a double-quoted string with no special characters") {
			auto lines = t.Feed("\"normal_string\"\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the double quotes") {
				REQUIRE(lines[0][0] == "normal_string");
			}
		}

		WHEN("the Tokeniser is fed a double-quoted string with spaces") {
			auto lines = t.Feed("\"not three words\"\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the bytes enclosed in the double quotes") {
				REQUIRE(lines[0][0] == "not three words");
			}
		}

		// Backslashes are tested in their own scenario below.
	}
}

SCENARIO("Tokenisers can handle mixed-quoted strings", "[tokeniser]") {
	// This is a slightly strange concept, but is based on what happens in
	// POSIX shell.

	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a word with a mixture of different quote styles") {
			auto lines = t.Feed("This' is'\\ perfectly\"\\ valid \"syntax!\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the word contains the concatenation of each") {
				REQUIRE(lines[0][0] == "This is perfectly valid syntax!");
			}
		}
	}
}

SCENARIO("Tokenisers can backslash-escape bytes", "[tokeniser]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;

		WHEN("the Tokeniser is fed a backslashed space in unquoted mode") {
			auto lines = t.Feed("backslashed\\ space\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the line contains the space, but no backslash") {
				REQUIRE(lines[0][0] == "backslashed space");
			}
		}

		WHEN("the Tokeniser is fed a backslashed space in double-quoted mode") {
			auto lines = t.Feed("\"backslashed\\ space\"\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the line contains the space, but no backslash or quotes") {
				REQUIRE(lines[0][0] == "backslashed space");
			}
		}

		WHEN("the Tokeniser is fed a backslashed space in single-quoted mode") {
			auto lines = t.Feed("'backslashed\\ space'\n");

			THEN("one line is returned") {
				REQUIRE(lines.size() == 1);
			}

			THEN("the line contains only one word") {
				REQUIRE(lines[0].size() == 1);
			}

			THEN("the line contains the space AND backslash, but no quotes") {
				REQUIRE(lines[0][0] == "backslashed\\ space");
			}
		}
	}
}

// See http://universityradioyork.github.io/baps3-spec/tests/internal.html
SCENARIO("Tokeniser is compliant with the BAPS3 spec", "[tokeniser][spec]") {
	GIVEN("A fresh Tokeniser") {
		Tokeniser t;
		WHEN("the Tokeniser is fed E1") {
			auto lines = t.Feed("");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 0);
			}
		}
		WHEN("the Tokeniser is fed E2") {
			auto lines = t.Feed("\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 0);
			}
		}
		WHEN("the Tokeniser is fed E3") {
			auto lines = t.Feed("''\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "");
			}
		}
		WHEN("the Tokeniser is fed E4") {
			auto lines = t.Feed("\"\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "");
			}
		}
		WHEN("the Tokeniser is fed W1") {
			auto lines = t.Feed("foo bar baz\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 3);
				REQUIRE(lines[0][0] == "foo");
				REQUIRE(lines[0][1] == "bar");
				REQUIRE(lines[0][2] == "baz");
			}
		}
		WHEN("the Tokeniser is fed W2") {
			auto lines = t.Feed("foo\tbar\tbaz\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 3);
				REQUIRE(lines[0][0] == "foo");
				REQUIRE(lines[0][1] == "bar");
				REQUIRE(lines[0][2] == "baz");
			}
		}
		WHEN("the Tokeniser is fed W3") {
			auto lines = t.Feed("foo\rbar\rbaz\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 3);
				REQUIRE(lines[0][0] == "foo");
				REQUIRE(lines[0][1] == "bar");
				REQUIRE(lines[0][2] == "baz");
			}
		}
		WHEN("the Tokeniser is fed W4") {
			auto lines = t.Feed("silly windows\r\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "silly");
				REQUIRE(lines[0][1] == "windows");
			}
		}
		WHEN("the Tokeniser is fed W5") {
			auto lines = t.Feed("    abc def\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "abc");
				REQUIRE(lines[0][1] == "def");
			}
		}
		WHEN("the Tokeniser is fed W6") {
			auto lines = t.Feed("ghi jkl    \n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "ghi");
				REQUIRE(lines[0][1] == "jkl");
			}
		}
		WHEN("the Tokeniser is fed W7") {
			auto lines = t.Feed("    mno pqr    \n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "mno");
				REQUIRE(lines[0][1] == "pqr");
			}
		}
		WHEN("the Tokeniser is fed Q1") {
			auto lines = t.Feed("abc\\\ndef\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q2") {
			auto lines = t.Feed("\"abc\ndef\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q3") {
			auto lines = t.Feed("\"abc\\\ndef\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q4") {
			auto lines = t.Feed("'abc\ndef'\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q5") {
			auto lines = t.Feed("'abc\\\ndef'\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "abc\\\ndef");
			}
		}
		WHEN("the Tokeniser is fed Q6") {
			auto lines = t.Feed("Scare\\\" quotes\\\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "Scare\"");
				REQUIRE(lines[0][1] == "quotes\"");
			}
		}
		WHEN("the Tokeniser is fed Q7") {
			auto lines = t.Feed("I\\'m free\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "I'm");
				REQUIRE(lines[0][1] == "free");
			}
		}
		WHEN("the Tokeniser is fed Q8") {
			auto lines = t.Feed("'hello, I'\\''m an escaped single quote'\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "hello, I'm an escaped single quote");
			}
		}
		WHEN("the Tokeniser is fed Q9") {
			auto lines = t.Feed("\"hello, this is an \\\" escaped double quote\"\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 1);
				REQUIRE(lines[0][0] == "hello, this is an \" escaped double quote");
			}
		}
		WHEN("the Tokeniser is fed M1") {
			auto lines = t.Feed("first line\nsecond line\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 2);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "first");
				REQUIRE(lines[0][1] == "line");
				REQUIRE(lines[1].size() == 2);
				REQUIRE(lines[1][0] == "second");
				REQUIRE(lines[1][1] == "line");
			}
		}
		WHEN("the Tokeniser is fed U1") {
			auto lines = t.Feed("北野 武\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 2);
				REQUIRE(lines[0][0] == "北野");
				REQUIRE(lines[0][1] == "武");
			}
		}
		WHEN("the Tokeniser is fed X1") {
			auto lines = t.Feed("enqueue file \"C:\\\\Users\\\\Test\\\\Artist - Title.mp3\" 1\n");
			THEN ("the Tokeniser returns the specified result") {
				REQUIRE(lines.size() == 1);
				REQUIRE(lines[0].size() == 4);
				REQUIRE(lines[0][0] == "enqueue");
				REQUIRE(lines[0][1] == "file");
				REQUIRE(lines[0][2] == "C:\\Users\\Test\\Artist - Title.mp3");
				REQUIRE(lines[0][3] == "1");
			}
		}
	}
}
<|endoftext|>


<commit_before>/*******************************************************************************
    Taichi - Physically based Computer Graphics Library

    Copyright (c) 2016 Yuanming Hu <yuanmhu@gmail.com>

    All rights reserved. Use of this source code is governed by
    the MIT license as written in the LICENSE file.
*******************************************************************************/

#include <taichi/visual/texture.h>
#include <taichi/visual/scene_geometry.h>
#include <taichi/visualization/image_buffer.h>
#include <taichi/math/array_3d.h>
#include <taichi/math/levelset.h>
#include <taichi/math/math.h>
#include <taichi/common/asset_manager.h>

TC_NAMESPACE_BEGIN

class ConstantTexture final : public Texture {
 private:
  Vector4 val;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    val = config.get<Vector4>("value");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return val;
  }
};

TC_IMPLEMENTATION(Texture, ConstantTexture, "const");

class Array3DTexture : public Texture {
 protected:
  Array3D<Vector4> arr;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    arr = *config.get_ptr<Array3D<Vector4>>("array_ptr");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return arr.sample_relative_coord(coord);
  }
};

TC_IMPLEMENTATION(Texture, Array3DTexture, "array3d");

class ImageTexture : public Texture {
 protected:
  Array2D<Vector4> image;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    image.load_image(config.get<std::string>("filename"));
  }

  bool inside(const Vector3 &coord) const {
    return 0 <= coord.x && coord.x <= 1.0 && 0 <= coord.y && coord.y <= 1.0 &&
           0 <= coord.z && coord.z <= 1.0;
  }

  virtual Vector4 sample(const Vector3 &coord_) const override {
    Vector2 coord(coord_.x - floor(coord_.x), coord_.y - floor(coord_.y));
    if (inside(coord_))
      return image.sample_relative_coord(coord);
    else
      return Vector4(0);
  }
};

TC_IMPLEMENTATION(Texture, ImageTexture, "image");

class TextTexture : public Texture {
 protected:
  Array2D<Vector4> image;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    int width = config.get<int>("width");
    int height = config.get<int>("height");
    std::string font_file_fn = config.get<std::string>("font_file");
    std::string content = config.get<std::string>("content");
    real size = config.get<real>("size");
    int dx = config.get<int>("dx");
    int dy = config.get<int>("dy");
    image.initialize(Vector2i(width, height));
    image.write_text(font_file_fn, content, size, dx, dy);
  }

  virtual Vector4 sample(const Vector3 &coord_) const override {
    Vector2 coord(coord_.x - floor(coord_.x), coord_.y - floor(coord_.y));
    return image.sample_relative_coord(coord);
  }
};

TC_IMPLEMENTATION(Texture, TextTexture, "text");

class RectTexture : public Texture {
 protected:
  Vector3 bounds;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    bounds = config.get<Vector3>("bounds") * 0.5f;
  }

  bool inside(const Vector3 &coord) const {
    Vector3 c = coord - Vector3(0.5f);
    return std::abs(c.x) < bounds.x && std::abs(c.y) < bounds.y &&
           std::abs(c.z) < bounds.z;
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return Vector4(inside(coord) ? 1.0_f : 0.0_f);
  }
};

TC_IMPLEMENTATION(Texture, RectTexture, "rect");

class RingTexture : public Texture {
 protected:
  real inner, outer;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    inner = config.get("inner", 0.0_f) / 2.0f;
    outer = config.get("outer", 1.0_f) / 2.0f;
  }

  static bool inside(Vector2 p, Vector2 c, real r) {
    return (p.x - c.x) * (p.x - c.x) + (p.y - c.y) * (p.y - c.y) <= r * r;
  }

  virtual Vector4 sample(const Vector2 &coord) const override {
    return Vector4(inside(coord, Vector2(0.5f, 0.5f), outer) &&
                           !inside(coord, Vector2(0.5f, 0.5f), inner)
                       ? 1.0_f
                       : 0.0_f);
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return sample(Vector2(coord.x, coord.y));
  }
};

TC_IMPLEMENTATION(Texture, RingTexture, "ring");

class TaichiTexture : public Texture {
 protected:
  real scale;
  real rotation_c, rotation_s;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    scale = config.get("scale", 1.0_f);
    real rotation = config.get("rotation", 0.0_f);
    rotation_c = std::cos(rotation);
    rotation_s = std::sin(rotation);
  }

  static bool inside(Vector2 p, Vector2 c, real r) {
    return (p.x - c.x) * (p.x - c.x) + (p.y - c.y) * (p.y - c.y) <= r * r;
  }

  static bool inside_left(Vector2 p, Vector2 c, real r) {
    return inside(p, c, r) && p.x < c.x;
  }

  static bool inside_right(Vector2 p, Vector2 c, real r) {
    return inside(p, c, r) && p.x >= c.x;
  }

  bool is_white(Vector2 p_) const {
    p_ -= Vector2(0.5f);
    Vector2 p(p_.x * rotation_c + p_.y * rotation_s,
              -p_.x * rotation_s + p_.y * rotation_c);
    p += Vector2(0.5f);
    if (!inside(p, Vector2(0.50f, 0.50f), 0.5f)) {
      return true;
    }
    if (!inside(p, Vector2(0.50f, 0.50f), 0.5f * scale)) {
      return false;
    }
    p = Vector2(0.5f) + (p - Vector2(0.5f)) * (1.0_f / scale);
    if (inside(p, Vector2(0.50f, 0.25f), 0.08f)) {
      return true;
    }
    if (inside(p, Vector2(0.50f, 0.75f), 0.08f)) {
      return false;
    }
    if (inside(p, Vector2(0.50f, 0.25f), 0.25f)) {
      return false;
    }
    if (inside(p, Vector2(0.50f, 0.75f), 0.25f)) {
      return true;
    }
    if (p.x < 0.5f) {
      return true;
    } else {
      return false;
    }
  }

  virtual Vector4 sample(const Vector2 &coord) const override {
    return Vector4(is_white(coord) ? 1.0_f : 0.0_f);
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return sample(Vector2(coord.x, coord.y));
  }
};

TC_IMPLEMENTATION(Texture, TaichiTexture, "taichi");

class CheckerboardTexture : public Texture {
 protected:
  real repeat_u, repeat_v, repeat_w;
  std::shared_ptr<Texture> tex1, tex2;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    tex1 = AssetManager::get_asset<Texture>(config.get<int>("tex1"));
    tex2 = AssetManager::get_asset<Texture>(config.get<int>("tex2"));
    repeat_u = config.get<real>("repeat_u");
    repeat_v = config.get<real>("repeat_v");
    repeat_w = config.get("repeat_w", 1.0_f);
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    int p = (int)floor(coord.x * repeat_u), q = (int)floor(coord.y * repeat_v),
        r = (int)floor(coord.z * repeat_w);
    return ((p + q + r) % 2 == 0 ? tex1 : tex2)->sample(coord);
  }
};

TC_IMPLEMENTATION(Texture, CheckerboardTexture, "checkerboard");

class UVTexture : public Texture {
 protected:
  real coeff_u, coeff_v;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    coeff_u = config.get<real>("coeff_u");
    coeff_v = config.get<real>("coeff_v");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return Vector4(coeff_u * coord.x + coeff_v * coord.y);
  }
};

TC_IMPLEMENTATION(Texture, UVTexture, "uv");

class SphereTexture : public Texture {
 protected:
  Vector3 center;
  real radius;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    center = config.get<Vector3>("center");
    radius = config.get<real>("radius");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return Vector4(real(bool(length(coord - center) < radius)));
  }
};

TC_IMPLEMENTATION(Texture, SphereTexture, "sphere");

class SlicedTexture : public Texture {
 protected:
  Vector4 base;
  Vector4 increment;
  Vector4 steps;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    steps = config.get<Vector4>("steps");
    base = config.get<Vector4>("base");
    increment = config.get<Vector4>("increment");
  }

  virtual Vector4 sample(const Vector3 &coord_) const override {
    Vector4 coord(coord_, 0.0_f);
    return base + (coord * steps).floor() * increment;
  }
};

TC_IMPLEMENTATION(Texture, SlicedTexture, "sliced");

class MeshTexture : public Texture {
 protected:
  Array3D<real> arr;
  Vector3i resolution;

 public:
  // parameter name for mesh path is 'filename'
  void initialize(const Config &config) override {
    Texture::initialize(config);
    Mesh mesh;
    mesh.initialize(config);
    Scene scene;
    Vector3 scale = config.get("scale", Vector3(1));
    Vector3 translate = config.get("translate", Vector3(0));
    bool adaptive = config.get("adaptive", true);
    auto mesh_p = std::make_shared<Mesh>(mesh);
    Matrix4 trans(1);
    trans = matrix4_scale(&trans, scale);
    trans = matrix4_translate(&trans, translate);
    mesh_p->transform = trans;
    scene.add_mesh(mesh_p);
    scene.finalize_geometry();
    auto ray_intersection = create_instance<RayIntersection>("embree");
    std::shared_ptr<SceneGeometry> scene_geometry(
        new SceneGeometry(std::make_shared<Scene>(scene), ray_intersection));
    BoundingBox bb = mesh.get_bounding_box();
    // calc offset and delta_x to keep the mesh in the center of texture
    resolution = config.get<Vector3i>("resolution");
    arr = Array3D<real>(resolution);
    real delta_x = 0;
    Vector3i offset;
    for (int i = 0; i < 3; ++i)
      delta_x = std::max(
          delta_x,
          (bb.upper_boundary[i] - bb.lower_boundary[i]) / resolution[i]);
    for (int i = 0; i < 3; ++i)
      offset[i] = int(resolution[i] -
                      (bb.upper_boundary[i] - bb.lower_boundary[i]) / delta_x) /
                  2;
    if (!adaptive) {
      offset = Vector3i(0);
      delta_x = 1.0_f / resolution[0];
      bb.lower_boundary = Vector3(0);
    }
    // cast ray for each i, j
    for (int i = 0; i < resolution.x; ++i) {
      for (int j = 0; j < resolution.y; ++j) {
        real x = (i - offset.x) * delta_x + bb.lower_boundary.x;
        real y = (j - offset.y) * delta_x + bb.lower_boundary.y;
        real z = (0 - offset.z) * delta_x + bb.lower_boundary.z;
        real base_z = z - eps;
        int k = 0;
        bool inside = false;
        while (k < resolution.z) {
          int next_k;
          Ray ray(Vector3(x, y, z), Vector3(0, 0, 1));
          scene_geometry->query(ray);
          if (ray.dist == Ray::DIST_INFINITE) {
            next_k = resolution.z;
            inside = false;
          } else {
            z += ray.dist;
            next_k = std::min(int((z - base_z) / delta_x), resolution.z);
          }
          while (k < next_k) {
            arr.set(i, j, k, inside ? 1 : 0);
            ++k;
          }
          inside = !inside;
        }
      }
    }
  }

  bool inside(const Vector3 &coord) const {
    return 0 < coord.x && coord.x < 1.f && 0 < coord.y && coord.y < 1.f &&
           0 < coord.z && coord.z < 1.f;
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    if (inside(coord)) {
      return Vector4(real(arr.sample_relative_coord(coord)));
    } else
      return Vector4(0);
  }
};

TC_IMPLEMENTATION(Texture, MeshTexture, "mesh")

class LevelSet3DTexture : public Texture {
 protected:
  std::shared_ptr<LevelSet3D> levelset;
  Vector2 bounds;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    levelset = AssetManager::get_asset<LevelSet3D>(config.get<int>("levelset"));
    bounds = config.get<Vector2>("bounds");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    real value = levelset->sample_relative_coord(coord);
    return (bounds.x < value && value < bounds.y) ? Vector4(1) : Vector4(0);
  }
};

TC_IMPLEMENTATION(Texture, LevelSet3DTexture, "levelset3d")

TC_NAMESPACE_END
<commit_msg>fix pd sampling in mesh<commit_after>/*******************************************************************************
    Taichi - Physically based Computer Graphics Library

    Copyright (c) 2016 Yuanming Hu <yuanmhu@gmail.com>

    All rights reserved. Use of this source code is governed by
    the MIT license as written in the LICENSE file.
*******************************************************************************/

#include <taichi/visual/texture.h>
#include <taichi/visual/scene_geometry.h>
#include <taichi/visualization/image_buffer.h>
#include <taichi/math/array_3d.h>
#include <taichi/math/levelset.h>
#include <taichi/math/math.h>
#include <taichi/common/asset_manager.h>

TC_NAMESPACE_BEGIN

class ConstantTexture final : public Texture {
 private:
  Vector4 val;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    val = config.get<Vector4>("value");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return val;
  }
};

TC_IMPLEMENTATION(Texture, ConstantTexture, "const");

class Array3DTexture : public Texture {
 protected:
  Array3D<Vector4> arr;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    arr = *config.get_ptr<Array3D<Vector4>>("array_ptr");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return arr.sample_relative_coord(coord);
  }
};

TC_IMPLEMENTATION(Texture, Array3DTexture, "array3d");

class ImageTexture : public Texture {
 protected:
  Array2D<Vector4> image;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    image.load_image(config.get<std::string>("filename"));
  }

  bool inside(const Vector3 &coord) const {
    return 0 <= coord.x && coord.x <= 1.0 && 0 <= coord.y && coord.y <= 1.0 &&
           0 <= coord.z && coord.z <= 1.0;
  }

  virtual Vector4 sample(const Vector3 &coord_) const override {
    Vector2 coord(coord_.x - floor(coord_.x), coord_.y - floor(coord_.y));
    if (inside(coord_))
      return image.sample_relative_coord(coord);
    else
      return Vector4(0);
  }
};

TC_IMPLEMENTATION(Texture, ImageTexture, "image");

class TextTexture : public Texture {
 protected:
  Array2D<Vector4> image;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    int width = config.get<int>("width");
    int height = config.get<int>("height");
    std::string font_file_fn = config.get<std::string>("font_file");
    std::string content = config.get<std::string>("content");
    real size = config.get<real>("size");
    int dx = config.get<int>("dx");
    int dy = config.get<int>("dy");
    image.initialize(Vector2i(width, height));
    image.write_text(font_file_fn, content, size, dx, dy);
  }

  virtual Vector4 sample(const Vector3 &coord_) const override {
    Vector2 coord(coord_.x - floor(coord_.x), coord_.y - floor(coord_.y));
    return image.sample_relative_coord(coord);
  }
};

TC_IMPLEMENTATION(Texture, TextTexture, "text");

class RectTexture : public Texture {
 protected:
  Vector3 bounds;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    bounds = config.get<Vector3>("bounds") * 0.5f;
  }

  bool inside(const Vector3 &coord) const {
    Vector3 c = coord - Vector3(0.5f);
    return std::abs(c.x) < bounds.x && std::abs(c.y) < bounds.y &&
           std::abs(c.z) < bounds.z;
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return Vector4(inside(coord) ? 1.0_f : 0.0_f);
  }
};

TC_IMPLEMENTATION(Texture, RectTexture, "rect");

class RingTexture : public Texture {
 protected:
  real inner, outer;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    inner = config.get("inner", 0.0_f) / 2.0f;
    outer = config.get("outer", 1.0_f) / 2.0f;
  }

  static bool inside(Vector2 p, Vector2 c, real r) {
    return (p.x - c.x) * (p.x - c.x) + (p.y - c.y) * (p.y - c.y) <= r * r;
  }

  virtual Vector4 sample(const Vector2 &coord) const override {
    return Vector4(inside(coord, Vector2(0.5f, 0.5f), outer) &&
                           !inside(coord, Vector2(0.5f, 0.5f), inner)
                       ? 1.0_f
                       : 0.0_f);
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return sample(Vector2(coord.x, coord.y));
  }
};

TC_IMPLEMENTATION(Texture, RingTexture, "ring");

class TaichiTexture : public Texture {
 protected:
  real scale;
  real rotation_c, rotation_s;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    scale = config.get("scale", 1.0_f);
    real rotation = config.get("rotation", 0.0_f);
    rotation_c = std::cos(rotation);
    rotation_s = std::sin(rotation);
  }

  static bool inside(Vector2 p, Vector2 c, real r) {
    return (p.x - c.x) * (p.x - c.x) + (p.y - c.y) * (p.y - c.y) <= r * r;
  }

  static bool inside_left(Vector2 p, Vector2 c, real r) {
    return inside(p, c, r) && p.x < c.x;
  }

  static bool inside_right(Vector2 p, Vector2 c, real r) {
    return inside(p, c, r) && p.x >= c.x;
  }

  bool is_white(Vector2 p_) const {
    p_ -= Vector2(0.5f);
    Vector2 p(p_.x * rotation_c + p_.y * rotation_s,
              -p_.x * rotation_s + p_.y * rotation_c);
    p += Vector2(0.5f);
    if (!inside(p, Vector2(0.50f, 0.50f), 0.5f)) {
      return true;
    }
    if (!inside(p, Vector2(0.50f, 0.50f), 0.5f * scale)) {
      return false;
    }
    p = Vector2(0.5f) + (p - Vector2(0.5f)) * (1.0_f / scale);
    if (inside(p, Vector2(0.50f, 0.25f), 0.08f)) {
      return true;
    }
    if (inside(p, Vector2(0.50f, 0.75f), 0.08f)) {
      return false;
    }
    if (inside(p, Vector2(0.50f, 0.25f), 0.25f)) {
      return false;
    }
    if (inside(p, Vector2(0.50f, 0.75f), 0.25f)) {
      return true;
    }
    if (p.x < 0.5f) {
      return true;
    } else {
      return false;
    }
  }

  virtual Vector4 sample(const Vector2 &coord) const override {
    return Vector4(is_white(coord) ? 1.0_f : 0.0_f);
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return sample(Vector2(coord.x, coord.y));
  }
};

TC_IMPLEMENTATION(Texture, TaichiTexture, "taichi");

class CheckerboardTexture : public Texture {
 protected:
  real repeat_u, repeat_v, repeat_w;
  std::shared_ptr<Texture> tex1, tex2;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    tex1 = AssetManager::get_asset<Texture>(config.get<int>("tex1"));
    tex2 = AssetManager::get_asset<Texture>(config.get<int>("tex2"));
    repeat_u = config.get<real>("repeat_u");
    repeat_v = config.get<real>("repeat_v");
    repeat_w = config.get("repeat_w", 1.0_f);
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    int p = (int)floor(coord.x * repeat_u), q = (int)floor(coord.y * repeat_v),
        r = (int)floor(coord.z * repeat_w);
    return ((p + q + r) % 2 == 0 ? tex1 : tex2)->sample(coord);
  }
};

TC_IMPLEMENTATION(Texture, CheckerboardTexture, "checkerboard");

class UVTexture : public Texture {
 protected:
  real coeff_u, coeff_v;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    coeff_u = config.get<real>("coeff_u");
    coeff_v = config.get<real>("coeff_v");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return Vector4(coeff_u * coord.x + coeff_v * coord.y);
  }
};

TC_IMPLEMENTATION(Texture, UVTexture, "uv");

class SphereTexture : public Texture {
 protected:
  Vector3 center;
  real radius;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    center = config.get<Vector3>("center");
    radius = config.get<real>("radius");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    return Vector4(real(bool(length(coord - center) < radius)));
  }
};

TC_IMPLEMENTATION(Texture, SphereTexture, "sphere");

class SlicedTexture : public Texture {
 protected:
  Vector4 base;
  Vector4 increment;
  Vector4 steps;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    steps = config.get<Vector4>("steps");
    base = config.get<Vector4>("base");
    increment = config.get<Vector4>("increment");
  }

  virtual Vector4 sample(const Vector3 &coord_) const override {
    Vector4 coord(coord_, 0.0_f);
    return base + (coord * steps).floor() * increment;
  }
};

TC_IMPLEMENTATION(Texture, SlicedTexture, "sliced");

class FastMeshTexture : public Texture {
 protected:
  Array3D<real> arr;
  Vector3i resolution;

 public:
  // parameter name for mesh path is 'filename'
  void initialize(const Config &config) override {
    Texture::initialize(config);
    Mesh mesh;
    mesh.initialize(config);
    Scene scene;
    Vector3 scale = config.get("scale", Vector3(1));
    Vector3 translate = config.get("translate", Vector3(0));
    bool adaptive = config.get("adaptive", true);
    auto mesh_p = std::make_shared<Mesh>(mesh);
    Matrix4 trans(1);
    trans = matrix4_scale(&trans, scale);
    trans = matrix4_translate(&trans, translate);
    mesh_p->transform = trans;
    scene.add_mesh(mesh_p);
    scene.finalize_geometry();
    auto ray_intersection = create_instance<RayIntersection>("embree");
    std::shared_ptr<SceneGeometry> scene_geometry(
        new SceneGeometry(std::make_shared<Scene>(scene), ray_intersection));
    BoundingBox bb = mesh.get_bounding_box();
    // calc offset and delta_x to keep the mesh in the center of texture
    resolution = config.get<Vector3i>("resolution");
    arr = Array3D<real>(resolution);
    real delta_x = 0;
    Vector3i offset;
    for (int i = 0; i < 3; ++i)
      delta_x = std::max(
          delta_x,
          (bb.upper_boundary[i] - bb.lower_boundary[i]) / resolution[i]);
    for (int i = 0; i < 3; ++i)
      offset[i] = int(resolution[i] -
                      (bb.upper_boundary[i] - bb.lower_boundary[i]) / delta_x) /
                  2;
    if (!adaptive) {
      offset = Vector3i(0);
      delta_x = 1.0_f / resolution[0];
      bb.lower_boundary = Vector3(0);
    }
    // cast ray for each i, j
    for (int i = 0; i < resolution.x; ++i) {
      for (int j = 0; j < resolution.y; ++j) {
        real x = (i - offset.x) * delta_x + bb.lower_boundary.x;
        real y = (j - offset.y) * delta_x + bb.lower_boundary.y;
        real z = (0 - offset.z) * delta_x + bb.lower_boundary.z;
        real base_z = z - eps;
        int k = 0;
        bool inside = false;
        while (k < resolution.z) {
          int next_k;
          Ray ray(Vector3(x, y, z), Vector3(0, 0, 1));
          scene_geometry->query(ray);
          if (ray.dist == Ray::DIST_INFINITE) {
            next_k = resolution.z;
            inside = false;
          } else {
            z += ray.dist;
            next_k = std::min(int((z - base_z) / delta_x), resolution.z);
          }
          while (k < next_k) {
            arr.set(i, j, k, inside ? 1 : 0);
            ++k;
          }
          inside = !inside;
        }
      }
    }
  }

  bool inside(const Vector3 &coord) const {
    return 0 < coord.x && coord.x < 1.f && 0 < coord.y && coord.y < 1.f &&
           0 < coord.z && coord.z < 1.f;
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    if (inside(coord)) {
      return Vector4(real(arr.sample_relative_coord(coord)));
    } else
      return Vector4(0);
  }
};

TC_IMPLEMENTATION(Texture, FastMeshTexture, "fast_mesh")

class MeshTexture : public Texture {
protected:
    std::shared_ptr<SceneGeometry> scene_geometry;
    Vector3 offset;

public:
    // parameter name for mesh path is 'filename'
    void initialize(const Config &config) override {
        Texture::initialize(config);
        Mesh mesh;
        mesh.initialize(config);
        Scene scene;
        Vector3 scale = config.get("scale", Vector3(1));
        Vector3 translate = config.get("translate", Vector3(0));
        auto mesh_p = std::make_shared<Mesh>(mesh);
        Matrix4 trans(1);
        trans = matrix4_scale(&trans, scale);
        trans = matrix4_translate(&trans, translate);
        mesh_p->transform = trans;
        scene.add_mesh(mesh_p);
        scene.finalize_geometry();
        auto ray_intersection = create_instance<RayIntersection>("embree");
        scene_geometry = std::make_shared<SceneGeometry>(std::make_shared<Scene>(scene), ray_intersection);
        if (config.get("adaptive", true)) {
            BoundingBox bb = mesh.get_bounding_box();
            offset = (bb.lower_boundary + bb.upper_boundary) / 2.0_f - Vector3(0.5_f);
        } else {
            offset = Vector3(0.0_f);
        }
    }

    virtual Vector4 sample(const Vector3 &coord) const override {
        real x = coord.x + offset.x;
        real y = coord.y + offset.y;
        real z = coord.z + offset.z;
        bool inside = false;
        while (true) {
            Ray ray(Vector3(x, y, z), Vector3(0, 0, 1));
            scene_geometry->query(ray);
            if (ray.dist == Ray::DIST_INFINITE) {
                break;
            } else {
                z += ray.dist;
                inside = !inside;
            }
        }
        return Vector4(inside ? 1.0_f : 0.0_f);
    }
};

TC_IMPLEMENTATION(Texture, MeshTexture, "mesh")

class LevelSet3DTexture : public Texture {
 protected:
  std::shared_ptr<LevelSet3D> levelset;
  Vector2 bounds;

 public:
  void initialize(const Config &config) override {
    Texture::initialize(config);
    levelset = AssetManager::get_asset<LevelSet3D>(config.get<int>("levelset"));
    bounds = config.get<Vector2>("bounds");
  }

  virtual Vector4 sample(const Vector3 &coord) const override {
    real value = levelset->sample_relative_coord(coord);
    return (bounds.x < value && value < bounds.y) ? Vector4(1) : Vector4(0);
  }
};

TC_IMPLEMENTATION(Texture, LevelSet3DTexture, "levelset3d")

TC_NAMESPACE_END
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2013] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef TIGHTDB_VERSION_HPP
#define TIGHTDB_VERSION_HPP

#include <string>
#include <sstream>

#define TIGHTDB_VER_MAJOR 0
#define TIGHTDB_VER_MINOR 84
#define TIGHTDB_VER_PATCH 1

namespace tightdb {

enum Feature {
    feature_Debug,
    feature_Replication
};

class Version {
public:
    static int get_major() { return TIGHTDB_VER_MAJOR; }
    static int get_minor() { return TIGHTDB_VER_MINOR; }
    static int get_patch() { return TIGHTDB_VER_PATCH; }
    static std::string get_version();
    static bool is_at_least(int major, int minor, int patch);
    static bool has_feature(Feature feature);
};

} // namespace tightdb

#endif // TIGHTDB_VERSION_HPP
<commit_msg>Update version.hpp<commit_after>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2013] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/
#ifndef TIGHTDB_VERSION_HPP
#define TIGHTDB_VERSION_HPP

#include <string>
#include <sstream>

#define TIGHTDB_VER_MAJOR 0
#define TIGHTDB_VER_MINOR 84
#define TIGHTDB_VER_PATCH 0

namespace tightdb {

enum Feature {
    feature_Debug,
    feature_Replication
};

class Version {
public:
    static int get_major() { return TIGHTDB_VER_MAJOR; }
    static int get_minor() { return TIGHTDB_VER_MINOR; }
    static int get_patch() { return TIGHTDB_VER_PATCH; }
    static std::string get_version();
    static bool is_at_least(int major, int minor, int patch);
    static bool has_feature(Feature feature);
};

} // namespace tightdb

#endif // TIGHTDB_VERSION_HPP
<|endoftext|>


<commit_before>//
// File:   csg_nemat.cc
// Author: ruehle
//
// Created on March 6, 2008, 4:35 PM
//

#include <math.h>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <cgengine.h>
#include <libversion.h>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <tools/cubicspline.h>
#include <gsl/gsl_linalg.h>

#define _DEBUG

namespace ub = boost::numeric::ublas;
using namespace std;

class CGForceMatching
    : public CGObserver
{
public:
    void BeginCG(Topology *top, Topology *top_atom)
    {
     n = SplineBond.GenerateGrid ( 0.08, 0.25, 0.1 ); // n - number of points
     n -= 1; // n - number of splines

     N = top->BeadCount();
     L = 0;

        cout << "hey, someone wants to coarse grain\n";

        _A.resize(n-1, 2*(n+1), false); // to do: does it initialize _A with zeros?
        _b.resize(n-1, false);
        _A.clear();
        _b.clear();

        for (int i = 0; i < n-1; ++i) {
            _A(i,i) = SplineBond.A_prime(i, 0);
            _A(i, i+1) = SplineBond.B_prime(i,0) - SplineBond.A_prime(i,1);
            _A(i, i+2) = -SplineBond.B_prime(i,1);

            _A(i, n+1 + i) = SplineBond.C_prime(i,0);
            _A(i, n+1 + i+1) = SplineBond.D_prime(i,0) - SplineBond.C_prime(i,1);
            _A(i, n+1 + i+2) = -SplineBond.D_prime(i,1);

        }
    }

    void EndCG() {
        // Solving linear equations system

    //    double *pointer_m = new double [_b.size() * 2*(n+1)];
    //    double *pointer_b = new double [_b.size()];

        double* pointer_m = & _A(0,0);
        double* pointer_b = & _b(0);

#ifdef _DEBUG

        cout << _b.size() << " " << 2*(n+1) << endl;
        for(int i_line = 0; i_line < _b.size(); i_line++ ) {
            for(int j_col = 0; j_col < 2*(n+1); j_col++) {
//                cout << _A(i_line, j_col) << " ";
//                pointer_m[ i_line * 2*(n+1) + j_col ] = _A(i_line, j_col);
                cout << pointer_m[ i_line * 2*(n+1) + j_col ] << "\n";
            }
//            cout << "\n";
        }

        cout << _b.size() << endl;
        for(int i_line = 0; i_line < _b.size(); i_line++ ) {
//            cout << _b(i_line) << "\n";
//            pointer_b[ i_line ] = _b(i_line);
            cout << pointer_b[ i_line ] << endl;
        }

#endif

        gsl_matrix_view m
            = gsl_matrix_view_array (pointer_m, _b.size(), 2*(n+1));

        gsl_vector_view b
            = gsl_vector_view_array (pointer_b, _b.size());

        gsl_vector *x = gsl_vector_alloc (2*(n+1));

        gsl_vector *tau = gsl_vector_alloc (2*(n+1));

        gsl_vector *residual = gsl_vector_alloc (_b.size());

        gsl_linalg_QR_decomp (&m.matrix, tau);

        gsl_linalg_QR_lssolve (&m.matrix, tau, &b.vector, x, residual);

        /*

    gsl_matrix_view m
      = gsl_matrix_view_array (_A, lin_dim, col_dim);

    gsl_vector_view b
      = gsl_vector_view_array (_b, lin_dim);

    gsl_vector *x = gsl_vector_alloc (col_dim);

    gsl_vector *tau = gsl_vector_alloc (col_dim);

    gsl_vector *residual = gsl_vector_alloc (lin_dim);

    gsl_linalg_QR_decomp (&m.matrix, tau);

    gsl_linalg_QR_lssolve (&m.matrix, tau, &b.vector, x, residual);

         */

        //output of the results
        _x.resize(2*(n+1), false);
        _x.clear();

        cout << "write out results\n";
        for (int i =0 ; i < 2*(n+1); i++) {
            cout << "x[" << i <<"] = " << gsl_vector_get(x, i) << "\n";
            _x(i) = gsl_vector_get(x, i);
        }

        SplineBond.GetResult(& _x);
        SplineBond.PrintOutResult();

        gsl_vector_free (x);
        gsl_vector_free (tau);
        gsl_vector_free (residual);

    };

    void EvalConfiguration(Configuration *conf, Configuration *conf_atom = 0) {
 //       cout << "yea, new configuration!\n";
        _A.resize(n-1 + 3*N*(L+1), 2*(n+1), true); // resize matrix
        _b.resize(n-1 + 3*N*(L+1), true);

        // here we have to set zero values to the new matrix elements - stupid thing
        for(int i_line = n-1 + 3*N*L; i_line < n-1 + 3*N*(L+1); i_line++ ) {
            for(int j_col = 0; j_col < 2*(n+1); j_col++) {
                _A(i_line, j_col) = 0;
            }
        }

#ifdef _DEBUG
      //  cout << "random matrix value: " << _A(n-1 + 3*N*L + 2*N, 2) << endl;
#endif

        InteractionContainer &ic = conf->getTopology()->getBondedInteractions();
        InteractionContainer::iterator ia;

        // loop for the matrix:
        for(ia=ic.begin(); ia != ic.end(); ++ia) {
            if ((*ia)->BeadCount() == 2 ) {

               int i1 = (*ia)->getBeadId(0);
               int i2 = (*ia)->getBeadId(1);
               double r = (*ia)->EvaluateVar(*conf);
               int i = SplineBond.getInterval(r);

               vec  n_ij = (*ia)->Grad(*conf, 0);

#ifdef _DEBUG
      //         cout << r << " " << -(conf->getF(i1) * n_ij) << endl;
#endif

                  _A(n-1 + 3*N*L+i1,i) = SplineBond.A(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i1, i) = SplineBond.A(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i1, i) = SplineBond.A(r)*n_ij.z();

                  _A(n-1 + 3*N*L+i1, i+1) = SplineBond.B(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i1, i+1) = SplineBond.B(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i1, i+1) = SplineBond.B(r)*n_ij.z();

                  _A(n-1 + 3*N*L+i1, n+i+1) = SplineBond.C(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i1, n+i+1) = SplineBond.C(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i1, n+i+1) = SplineBond.C(r)*n_ij.z();

                  _A(n-1 + 3*N*L+i1, n+1+i+1) = SplineBond.D(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i1, n+1+i+1) = SplineBond.D(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i1, n+1+i+1) = SplineBond.D(r)*n_ij.z();

              n_ij = (*ia)->Grad(*conf, 1);

                  _A(n-1 + 3*N*L+i2,i) = SplineBond.A(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i2, i) = SplineBond.A(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i2, i) = SplineBond.A(r)*n_ij.z();

                  _A(n-1 + 3*N*L+i2, i+1) = SplineBond.B(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i2, i+1) = SplineBond.B(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i2, i+1) = SplineBond.B(r)*n_ij.z();

                  _A(n-1 + 3*N*L+i2, n+i+1) = SplineBond.C(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i2, n+i+1) = SplineBond.C(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i2, n+i+1) = SplineBond.C(r)*n_ij.z();

                  _A(n-1 + 3*N*L+i2, n+1+i+1) = SplineBond.D(r)*n_ij.x();
                  _A(n-1 + 3*N*L+N+i2, n+1+i+1) = SplineBond.D(r)*n_ij.y();
                  _A(n-1 + 3*N*L+2*N+i2, n+1+i+1) = SplineBond.D(r)*n_ij.z();

             }
//            cout << name << ": " << ((*ia)->EvaluateVar(*conf)) << endl;

        }

        // loop for the forces vector:
        if ( conf->HasF() ) {
            vec Force(0., 0., 0.);
            for (int iatom = 0; iatom < N; ++iatom) {
                     Force = conf->getF(iatom);
                    _b(n-1 + 3*N*L + iatom) = Force.x();
                    _b(n-1 + 3*N*L + N+iatom) = Force.y();
                    _b(n-1 + 3*N*L + 2*N+iatom) = Force.z();
            }
        }
        else {
            cout << "ERROR: No forces in configuration!\n" ;
        }
        L+=1; // update the frame counter

    }

protected:
    // _A*_x = _b

  ub::matrix<double> _A;
  ub::vector<double> _b; // F_ref
  ub::vector<double> _x; //
    // _A(i, j) = 10;
    // _A.resize(n, m, true);
  int L; // counter for frames
  int N; //number of cg_beads
  int n; //number of splines
  CubicSpline SplineBond;
};

int main(int argc, char** argv)
{
    // we have one observer, this analyzes neamtic order
    CGForceMatching fmatch;
    // The CGEngine does the work
    CGEngine cg_engine;

    // add our observer that it gets called to analyze frames
    cg_engine.AddObserver((CGObserver*)&fmatch);

    // initialize the readers/writers,
    // this will be combined in an initialize function later
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();

    // lets read in some program options
    namespace po = boost::program_options;

    // Declare the supported options.
    po::options_description desc("Allowed options");

    // let cg_engine add some program options
    cg_engine.AddProgramOptions(desc);

    // now read in the command line
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    // does the user want help?
    if (vm.count("help")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR << "\n\n";
        cout << desc << endl;
        return 0;
    }
    // or asks for the program version?
    if (vm.count("version")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR  << "\n";
        return 0;
    }

    // try to run the cg process, go through the frames, etc...
    try {
        cg_engine.Run(desc, vm);
    }
    // did an error occour?
    catch(string error) {
        cerr << "An error occoured!" << endl << error << endl;
    }
    return 0;
}

<commit_msg>csgfmatch.cc last version<commit_after>//
// File:   csg_nemat.cc
// Author: ruehle
//
// Created on March 6, 2008, 4:35 PM
//

#include <math.h>
#include <boost/tokenizer.hpp>
#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <cgengine.h>
#include <libversion.h>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix_sparse.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <tools/cubicspline.h>
#include <gsl/gsl_linalg.h>
#include <stdio.h>

//#define _DEBUG

namespace ub = boost::numeric::ublas;
using namespace std;

class CGForceMatching
    : public CGObserver
{
public:
    void BeginCG(Topology *top, Topology *top_atom)
    {
        n = SplineBond.GenerateGrid ( 0.06, 0.21, 0.01 ); // n - number of points
        n -= 1; // n - number of splines

        N = top->BeadCount();
        L = 0;

        cout << "hey, someone wants to coarse grain\n";

        _A.resize(n+1, 2*(n+1), false); // to do: does it initialize _A with zeros?
        _b.resize(n+1, false);
        _A.clear();
        _b.clear();

        // smoothing conditions for first derivatives:
        // internal points
        for (int i = 0; i < n-1; ++i) {
            _A(i,i) = SplineBond.A_prime(i, 0);
            _A(i, i+1) = SplineBond.B_prime(i,0) - SplineBond.A_prime(i,1);
            _A(i, i+2) = -SplineBond.B_prime(i,1);

            _A(i, n+1 + i) = SplineBond.C_prime(i,0);
            _A(i, n+1 + i+1) = SplineBond.D_prime(i,0) - SplineBond.C_prime(i,1);
            _A(i, n+1 + i+2) = -SplineBond.D_prime(i,1);

        }
        // smoothing conditions for first derivatives:
        // external points
        _A(n-1, n+1 ) = 1.0;
        _A(n, 2*(n+1) - 1) = 1.0;
    }

    void EndCG() {
        // Solving linear equations system

        // libgsl has problems with solving overdetermined systems by means of
        // QR decomposition if the system doesn't have the full rank.
        // MATLAB can handle this problem easily.

        double* pointer_m = & _A(0,0);
        double* pointer_b = & _b(0);

#ifdef _DEBUG
        // this ifdef writes _A and _b with their dimensions to myfile.bin in binary format
        // this file can be used later to check the solution, e.g. with MATLAB
        // it also prints _A and _b to stdout.

        int lin_dim = _b.size();
        int col_dim = 2*(n+1);

        FILE * pFile;
        pFile = fopen ( "myfile.bin" , "wb" );
        fwrite(&lin_dim, sizeof(int), 1, pFile);
        fwrite(&col_dim, sizeof(int), 1, pFile);
        fwrite (pointer_m , sizeof(double) , 2*(n+1)*_b.size() , pFile );
        fwrite (pointer_b, sizeof(double), _b.size(), pFile);
        fclose (pFile);

        cout << _b.size() << " " << 2*(n+1) << endl;
        for(int i_line = 0; i_line < _b.size(); i_line++ ) {
            for(int j_col = 0; j_col < 2*(n+1); j_col++) {
                cout << pointer_m[ i_line * 2*(n+1) + j_col ] << "\n";
            }

        }

        cout << _b.size() << endl;
        for(int i_line = 0; i_line < _b.size(); i_line++ ) {
            cout << pointer_b[ i_line ] << endl;
        }

#endif

        gsl_matrix_view m
            = gsl_matrix_view_array (pointer_m, _b.size(), 2*(n+1));

        gsl_vector_view b
            = gsl_vector_view_array (pointer_b, _b.size());

        gsl_vector *x = gsl_vector_alloc (2*(n+1));
        gsl_vector *tau = gsl_vector_alloc (2*(n+1));
        gsl_vector *residual = gsl_vector_alloc (_b.size());

        gsl_linalg_QR_decomp (&m.matrix, tau);

#ifdef _DEBUG
        // prints TAU which is used by libgsl to stdout

        cout << "TAU ";
        for (int loop = 0; loop < 2*(n+1); loop++) {
             cout << gsl_vector_get(tau, loop) << " ";
        }
        cout << endl;
#endif

        gsl_linalg_QR_lssolve (&m.matrix, tau, &b.vector, x, residual);

#ifdef _DEBUG
        // prints RESIDUAL which is used by libgsl to stdout
        cout << "RESIDUAL \n";
        for (int loop = 0; loop < _b.size(); loop++) {
             cout << gsl_vector_get(residual, loop) << endl;
        }
#endif

        //output of the results
        _x.resize(2*(n+1), false);
        _x.clear();

        cout << "write out results\n";
        for (int i =0 ; i < 2*(n+1); i++) {
            cout << "x[" << i <<"] = " << gsl_vector_get(x, i) << "\n";
            _x(i) = gsl_vector_get(x, i);
        }

        cout << "r  " << "F(r)  " << endl;

        SplineBond.GetResult(& _x);
        SplineBond.PrintOutResult();

        gsl_vector_free (x);
        gsl_vector_free (tau);
        gsl_vector_free (residual);

    };

    void EvalConfiguration(Configuration *conf, Configuration *conf_atom = 0) {
 //       cout << "yea, new configuration!\n";
        _A.resize(n+1 + 3*N*(L+1), 2*(n+1), true); // resize matrix _A
        _b.resize(n+1 + 3*N*(L+1), true);          // resize vector _b

        // here we have to set zero values to the new matrix elements - stupid thing
        for(int i_line = n+1 + 3*N*L; i_line < n+1 + 3*N*(L+1); i_line++ ) {
            for(int j_col = 0; j_col < 2*(n+1); j_col++) {
                _A(i_line, j_col) = 0;
            }
        }

        InteractionContainer &ic = conf->getTopology()->getBondedInteractions();
        InteractionContainer::iterator ia;

        // loop for the matrix:
        for(ia=ic.begin(); ia != ic.end(); ++ia) {
            if ((*ia)->BeadCount() == 2 ) {

               int i1 = (*ia)->getBeadId(0);
               int i2 = (*ia)->getBeadId(1);
               double r = (*ia)->EvaluateVar(*conf);
               int i = SplineBond.getInterval(r);

               vec  n_ij = (*ia)->Grad(*conf, 0);

#ifdef _DEBUG
               // this can be used to get reference F(r) dependence
               cout << r << "   " << -abs(conf->getF(i1) ) << endl;
#endif

                  _A(n+1 + 3*N*L+i1,i) = SplineBond.A(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i1, i) = SplineBond.A(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i1, i) = SplineBond.A(r)*n_ij.z();

                  _A(n+1 + 3*N*L+i1, i+1) = SplineBond.B(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i1, i+1) = SplineBond.B(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i1, i+1) = SplineBond.B(r)*n_ij.z();

                  _A(n+1 + 3*N*L+i1, n+i+1) = SplineBond.C(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i1, n+i+1) = SplineBond.C(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i1, n+i+1) = SplineBond.C(r)*n_ij.z();

                  _A(n+1 + 3*N*L+i1, n+1+i+1) = SplineBond.D(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i1, n+1+i+1) = SplineBond.D(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i1, n+1+i+1) = SplineBond.D(r)*n_ij.z();

              n_ij = (*ia)->Grad(*conf, 1);

                  _A(n+1 + 3*N*L+i2,i) = SplineBond.A(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i2, i) = SplineBond.A(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i2, i) = SplineBond.A(r)*n_ij.z();

                  _A(n+1 + 3*N*L+i2, i+1) = SplineBond.B(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i2, i+1) = SplineBond.B(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i2, i+1) = SplineBond.B(r)*n_ij.z();

                  _A(n+1 + 3*N*L+i2, n+i+1) = SplineBond.C(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i2, n+i+1) = SplineBond.C(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i2, n+i+1) = SplineBond.C(r)*n_ij.z();

                  _A(n+1 + 3*N*L+i2, n+1+i+1) = SplineBond.D(r)*n_ij.x();
                  _A(n+1 + 3*N*L+N+i2, n+1+i+1) = SplineBond.D(r)*n_ij.y();
                  _A(n+1 + 3*N*L+2*N+i2, n+1+i+1) = SplineBond.D(r)*n_ij.z();

             }

        }

        // loop for the forces vector:
        if ( conf->HasF() ) {
            vec Force(0., 0., 0.);
            for (int iatom = 0; iatom < N; ++iatom) {
                     Force = conf->getF(iatom);
                    _b(n+1 + 3*N*L + iatom) = Force.x();
                    _b(n+1 + 3*N*L + N+iatom) = Force.y();
                    _b(n+1 + 3*N*L + 2*N+iatom) = Force.z();
            }
        }
        else {
            cout << "ERROR: No forces in configuration!\n" ;
        }
        L+=1; // update the frame counter

    }

protected:
    // _A*_x = _b

  ub::matrix<double> _A;
  ub::vector<double> _b; // F_ref
  ub::vector<double> _x; //
    // _A(i, j) = 10;
    // _A.resize(n, m, true);
  int L; // counter for frames
  int N; //number of cg_beads
  int n; //number of splines
  CubicSpline SplineBond;
};

int main(int argc, char** argv)
{
    // we have one observer, this analyzes neamtic order
    CGForceMatching fmatch;
    // The CGEngine does the work
    CGEngine cg_engine;

    // add our observer that it gets called to analyze frames
    cg_engine.AddObserver((CGObserver*)&fmatch);

    // initialize the readers/writers,
    // this will be combined in an initialize function later
    TrajectoryWriter::RegisterPlugins();
    TrajectoryReader::RegisterPlugins();
    TopologyReader::RegisterPlugins();

    // lets read in some program options
    namespace po = boost::program_options;

    // Declare the supported options.
    po::options_description desc("Allowed options");

    // let cg_engine add some program options
    cg_engine.AddProgramOptions(desc);

    // now read in the command line
    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, desc), vm);
    po::notify(vm);

    // does the user want help?
    if (vm.count("help")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR << "\n\n";
        cout << desc << endl;
        return 0;
    }
    // or asks for the program version?
    if (vm.count("version")) {
        cout << "csg_fmatch, lib version " << LIB_VERSION_STR  << "\n";
        return 0;
    }

    // try to run the cg process, go through the frames, etc...
    try {
        cg_engine.Run(desc, vm);
    }
    // did an error occour?
    catch(string error) {
        cerr << "An error occoured!" << endl << error << endl;
    }
    return 0;
}

<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkTestingMacros.h"
#include <mitkTestingConfig.h>
#include <mitkTestFixture.h>

#include <mitkIOUtil.h>
#include <mitkInteractionTestHelper.h>
#include <mitkPointSet.h>
#include <mitkPointSetDataInteractor.h>

class mitkPointSetDataInteractorTestSuite : public mitk::TestFixture
{

  CPPUNIT_TEST_SUITE(mitkPointSetDataInteractorTestSuite);
  MITK_TEST(AddPointInteraction);
  CPPUNIT_TEST_SUITE_END();

private:
  mitk::DataNode::Pointer m_TestPointSetNode;
  mitk::PointSetDataInteractor::Pointer m_DataInteractor;
  mitk::PointSet::Pointer m_TestPointSet;

public:

  void setUp()
  {
    //Create DataNode as a container for our PointSet to be tested
    m_TestPointSetNode = mitk::DataNode::New();

    // Create PointSetData Interactor
    m_DataInteractor = mitk::PointSetDataInteractor::New();
    // Load the according state machine for regular point set interaction
    m_DataInteractor->LoadStateMachine("PointSet.xml");
    // Set the configuration file that defines the triggers for the transitions
    m_DataInteractor->SetEventConfig("PointSetConfig.xml");

    //Create new PointSet which will receive the interaction input
    m_TestPointSet = mitk::PointSet::New();
    m_TestPointSetNode->SetData(m_TestPointSet);
    // set the DataNode (which already is added to the DataStorage)
    m_DataInteractor->SetDataNode(m_TestPointSetNode);
  }

  void tearDown()
  {
    //destroy all objects
    m_TestPointSetNode = NULL;
    m_TestPointSet = NULL;
    m_DataInteractor = NULL;
  }

  void AddPointInteraction()
  {
    //Path to the reference PointSet
    std::string referencePointSetPath = GetTestDataFilePath("InteractionTestData/ReferenceData/PointSetDataInteractor_add_points_in_2D_ref.mps");

    //Path to the interaction xml file
    std::string interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/PointSetDataInteractor_add_points_in_2D.xml");

    //Create test helper to initialize all necessary objects for interaction
    mitk::InteractionTestHelper interactionTestHelper(interactionXmlPath);

    //Add our test node to the DataStorage of our test helper
    interactionTestHelper.AddNodeToStorage(m_TestPointSetNode);

    //Start Interaction
    interactionTestHelper.PlaybackInteraction();

    //Load the reference PointSet
    mitk::PointSet::Pointer referencePointSet = mitk::IOUtil::LoadPointSet(referencePointSetPath);

    //Compare reference with the result of the interaction
    MITK_ASSERT_EQUAL(m_TestPointSet, referencePointSet, "");
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkPointSetDataInteractor)
<commit_msg>Added point deletion PointSetDataInteractorTest.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkTestingMacros.h"
#include <mitkTestingConfig.h>
#include <mitkTestFixture.h>

#include <mitkIOUtil.h>
#include <mitkInteractionTestHelper.h>
#include <mitkPointSet.h>
#include <mitkPointSetDataInteractor.h>

class mitkPointSetDataInteractorTestSuite : public mitk::TestFixture
{

  CPPUNIT_TEST_SUITE(mitkPointSetDataInteractorTestSuite);
  MITK_TEST(AddPointInteraction);
  MITK_TEST(DeletePointInteraction);
  CPPUNIT_TEST_SUITE_END();

private:
  mitk::DataNode::Pointer m_TestPointSetNode;
  mitk::PointSetDataInteractor::Pointer m_DataInteractor;
  mitk::PointSet::Pointer m_TestPointSet;

public:

  void setUp()
  {
    //Create DataNode as a container for our PointSet to be tested
    m_TestPointSetNode = mitk::DataNode::New();

    // Create PointSetData Interactor
    m_DataInteractor = mitk::PointSetDataInteractor::New();
    // Load the according state machine for regular point set interaction
    m_DataInteractor->LoadStateMachine("PointSet.xml");
    // Set the configuration file that defines the triggers for the transitions
    m_DataInteractor->SetEventConfig("PointSetConfig.xml");

    //Create new PointSet which will receive the interaction input
    m_TestPointSet = mitk::PointSet::New();
    m_TestPointSetNode->SetData(m_TestPointSet);
    // set the DataNode (which already is added to the DataStorage)
    m_DataInteractor->SetDataNode(m_TestPointSetNode);
  }

  void tearDown()
  {
    //destroy all objects
    m_TestPointSetNode = NULL;
    m_TestPointSet = NULL;
    m_DataInteractor = NULL;
  }

  void AddPointInteraction()
  {
    //Path to the reference PointSet
    std::string referencePointSetPath = GetTestDataFilePath("InteractionTestData/ReferenceData/PointSetDataInteractor_add_points_in_2D_ref.mps");

    //Path to the interaction xml file
    std::string interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/PointSetDataInteractor_add_points_in_2D.xml");

    //Create test helper to initialize all necessary objects for interaction
    mitk::InteractionTestHelper interactionTestHelper(interactionXmlPath);

    //Add our test node to the DataStorage of our test helper
    interactionTestHelper.AddNodeToStorage(m_TestPointSetNode);

    //Start Interaction
    interactionTestHelper.PlaybackInteraction();

    //Load the reference PointSet
    mitk::PointSet::Pointer referencePointSet = mitk::IOUtil::LoadPointSet(referencePointSetPath);

    //Compare reference with the result of the interaction
    MITK_ASSERT_EQUAL(m_TestPointSet, referencePointSet, "");
  }

  void PlayInteraction( std::string &xmlFile )
  {
    mitk::InteractionTestHelper interactionTestHelper( xmlFile );
    interactionTestHelper.AddNodeToStorage( m_TestPointSetNode );
    interactionTestHelper.PlaybackInteraction();
  }

  void EvaluateState( std::string &refPsFile, mitk::PointSet::Pointer ps, int selected )
  {
    mitk::PointSet::Pointer refPs = mitk::IOUtil::LoadPointSet( refPsFile );

    MITK_ASSERT_EQUAL(ps, refPs, "");

    MITK_TEST_CONDITION_REQUIRED(ps->GetNumberOfSelected() == 1, "One selected point." );
    MITK_TEST_CONDITION_REQUIRED(ps->GetSelectInfo( selected ) , "Testing if point is selected." );
  }

  void DeletePointInteraction()
  {
    //Path to the reference PointSet
    std::string referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet.mps");
    mitk::PointSet::Pointer ps = mitk::IOUtil::LoadPointSet( referencePointSetPath );
    m_TestPointSetNode->SetData( ps );

    std::string interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel1_0.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet1.mps");
    PlayInteraction( interactionXmlPath );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel3_1.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet2.mps");
    PlayInteraction( interactionXmlPath );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel4_2.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet3.mps");
    PlayInteraction( interactionXmlPath );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel8_3.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet4.mps");
    PlayInteraction( interactionXmlPath );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel2_4.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet5.mps");
    PlayInteraction( interactionXmlPath );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel6_5.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet6.mps");
    PlayInteraction( interactionXmlPath );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel7_6.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet7.mps");
    PlayInteraction( interactionXmlPath );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel5_7.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet1.mps");
    PlayInteraction( interactionXmlPath );

    MITK_TEST_CONDITION_REQUIRED(ps->GetPointSet()->GetNumberOfPoints() == 0, "Empty point set check.");
    MITK_TEST_CONDITION_REQUIRED(ps->GetNumberOfSelected() == 0, "No selected points." );
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkPointSetDataInteractor)
<|endoftext|>


<commit_before>/*Copyright 2011 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include <QtCore/QString>
#include <QtTest/QtTest>
#include "BinarySearchTree.h"
#include <iostream>
GUTIL_USING_CORE_NAMESPACE(DataObjects);
using namespace std;

class BST_TestTest :
        public QObject
{
    Q_OBJECT

public:
    BST_TestTest();

private Q_SLOTS:
    void test_basic_function();

    void test_compare();

    void test_insertions();
    void test_deletions();

private:
    static void show_depth_first_tree(const BinarySearchTree<int> &);

    static void show_breadth_first_tree(const BinarySearchTree<int> &);
    static QString get_btf_string(const BST_NodeIterator<int> &iter);

    // You can feed in your own manual breadth-first description to test if
    //  the tree looks like you expect
    static bool tree_matches(const BinarySearchTree<int> &, const QString &);

    static int backwards_compare(const int &, const int &);
};

BST_TestTest::BST_TestTest()
{
    qsrand(QDateTime::currentDateTime().time().msec());
}

void BST_TestTest::test_basic_function()
{
    BinarySearchTree<int> bst;
    for(int i(1); i < 10; i++)
    {
        bst.Add(i);
        //cout<<"Step "<<i<<": ";
        //show_breadth_first_tree(bst);
    }
    show_depth_first_tree(bst);
    show_breadth_first_tree(bst);

    // Verify that the numbers are sorted
    vector<int> df( bst.ExportDepthFirst() );
    QVERIFY(df.size() == 9);
    for(int i(0); i < df.size(); i++)
        QVERIFY(df.at(i) == i + 1);

    bst.Clear();

    for(int i(9); i >= 1; i--)
        bst.Add(i);
    show_depth_first_tree(bst);
    show_breadth_first_tree(bst);

    // Verify that the numbers are sorted
    df = bst.ExportDepthFirst();
    QVERIFY(df.size() == 9);
    for(int i(0); i < df.size(); i++)
        QVERIFY(df.at(i) == i + 1);

    bst.Clear();

    // Add random numbers
    for(int i(0); i < 20; i++)
    {
        int new_num(qrand() % 1000);
        while(bst.HasItem(new_num)) new_num = qrand() % 100;
        bst.Add(new_num);
    }

    show_depth_first_tree(bst);
}

int BST_TestTest::backwards_compare(const int &lhs, const int &rhs)
{
    if(lhs < rhs)
        return 1;
    else if(rhs < lhs)
        return -1;
    return 0;
}

void BST_TestTest::test_compare()
{
    BinarySearchTree<int> backwards_tree(&BST_TestTest::backwards_compare);
    for(int i(1); i < 10; i++)
        backwards_tree.Add(i);

    show_depth_first_tree(backwards_tree);
    show_breadth_first_tree(backwards_tree);

    // Verify that it sorted the numbers backwards
    vector<int> df( backwards_tree.ExportDepthFirst() );
    QVERIFY(df.size() == 9);
    for(int i(0); i < df.size(); i++)
        QVERIFY(df.at(i) == 9 - i);
}

void BST_TestTest::show_depth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"DF: ";
    vector<int> sorted_values(t.ExportDepthFirst());
    for(int i(0); i < (int)sorted_values.size(); i++)
        cout<<sorted_values[i]<<" ";
    cout<<endl;
}

void BST_TestTest::show_breadth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"BF: ";
    cout<<get_btf_string(t.Root()).toStdString();
    cout<<endl;
}

QString BST_TestTest::get_btf_string(const BST_NodeIterator<int> &i)
{
    QString ret;
    BST_NodeIterator<int> iter(i);

    ret.append(QString("(%1, ").arg(iter.Value()));
    if(iter.CanDescendLeft())
    {
        iter.DescendLeft();
        ret.append(get_btf_string(iter));
        iter.Ascend();
    }
    ret.append(", ");
    if(iter.CanDescendRight())
    {
        iter.DescendRight();
        ret.append(get_btf_string(iter));
        iter.Ascend();
    }
    ret.append(")");

    return ret;
}

bool BST_TestTest::tree_matches(const BinarySearchTree<int> &t, const QString &s)
{
    bool ret = get_btf_string(t.Root()) == s;
    if(!ret)
    {
        cout<< get_btf_string(t.Root()).toStdString() <<"\tNot equal to:"<<endl<<s.toStdString()<<endl;
    }
    return ret;
}

void BST_TestTest::test_insertions()
{
    // Test the 4 cases of rebalancing:  LL, RR, LR, RL
    BinarySearchTree<int> bst;

    // This tests the RR condition twice (Rotate left)
    bst.Add(5);
    bst.Add(10);
    bst.Add(15);
    bst.Add(20);
    bst.Add(25);
    QVERIFY(tree_matches(bst, "(10, (5, , ), (20, (15, , ), (25, , )))"));

    // Then LL (Rotate Right)
    bst.Add(2);
    bst.Add(1);
    QVERIFY(tree_matches(bst, "(10, (2, (1, , ), (5, , )), (20, (15, , ), (25, , )))"));

    // Then RL
    bst.Clear();
    bst.Add(5);
    bst.Add(10);
    bst.Add(9);
    QVERIFY(tree_matches(bst, "(9, (5, , ), (10, , ))"));

    // Then LR
    bst.Clear();
    bst.Add(5);
    bst.Add(3);
    bst.Add(4);
    QVERIFY(tree_matches(bst, "(4, (3, , ), (5, , ))"));
}

void BST_TestTest::test_deletions()
{

}

QTEST_APPLESS_MAIN(BST_TestTest);

#include "tst_bst_testtest.moc"
<commit_msg>Added tests for pointer trees; it still works!<commit_after>/*Copyright 2011 George Karagoulis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/

#include <QtCore/QString>
#include <QtTest/QtTest>
#include "BinarySearchTree.h"
#include <iostream>
GUTIL_USING_CORE_NAMESPACE(DataObjects);
using namespace std;

class BST_TestTest :
        public QObject
{
    Q_OBJECT

public:
    BST_TestTest();

private Q_SLOTS:
    void test_basic_function();

    void test_compare();

    void test_insertions();
    void test_deletions();

    void test_pointers();

private:
    static void show_depth_first_tree(const BinarySearchTree<int> &);

    static void show_breadth_first_tree(const BinarySearchTree<int> &);
    static void show_breadth_first_pointerTree(const BinarySearchTree<int *> &);

    static QString get_bft_string(const BST_NodeIterator<int> &iter);
    static QString get_bft_pointer_string(const BST_NodeIterator<int *> &);

    // You can feed in your own manual breadth-first description to test if
    //  the tree looks like you expect
    static bool tree_matches(const BinarySearchTree<int> &, const QString &);
    static bool tree_matches(const BinarySearchTree<int *> &, const QString &);

    static int backwards_compare(const int &, const int &);

    static int pointer_compare(int* const &, int* const &);
};

BST_TestTest::BST_TestTest()
{
    qsrand(QDateTime::currentDateTime().time().msec());
}

void BST_TestTest::test_basic_function()
{
    BinarySearchTree<int> bst;
    for(int i(1); i < 10; i++)
    {
        bst.Add(i);
        //cout<<"Step "<<i<<": ";
        //show_breadth_first_tree(bst);
    }
    show_depth_first_tree(bst);
    show_breadth_first_tree(bst);

    // Verify that the numbers are sorted
    vector<int> df( bst.ExportDepthFirst() );
    QVERIFY(df.size() == 9);
    for(int i(0); i < df.size(); i++)
        QVERIFY(df.at(i) == i + 1);

    bst.Clear();

    for(int i(9); i >= 1; i--)
        bst.Add(i);
    show_depth_first_tree(bst);
    show_breadth_first_tree(bst);

    // Verify that the numbers are sorted
    df = bst.ExportDepthFirst();
    QVERIFY(df.size() == 9);
    for(int i(0); i < df.size(); i++)
        QVERIFY(df.at(i) == i + 1);

    bst.Clear();

    // Add random numbers
    for(int i(0); i < 20; i++)
    {
        int new_num(qrand() % 1000);
        while(bst.HasItem(new_num)) new_num = qrand() % 100;
        bst.Add(new_num);
    }

    show_depth_first_tree(bst);
}

int BST_TestTest::backwards_compare(const int &lhs, const int &rhs)
{
    if(lhs < rhs)
        return 1;
    else if(rhs < lhs)
        return -1;
    return 0;
}

void BST_TestTest::test_compare()
{
    BinarySearchTree<int> backwards_tree(&BST_TestTest::backwards_compare);
    for(int i(1); i < 10; i++)
        backwards_tree.Add(i);

    show_depth_first_tree(backwards_tree);
    show_breadth_first_tree(backwards_tree);

    // Verify that it sorted the numbers backwards
    vector<int> df( backwards_tree.ExportDepthFirst() );
    QVERIFY(df.size() == 9);
    for(int i(0); i < df.size(); i++)
        QVERIFY(df.at(i) == 9 - i);
}

void BST_TestTest::show_depth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"DF: ";
    vector<int> sorted_values(t.ExportDepthFirst());
    for(int i(0); i < (int)sorted_values.size(); i++)
        cout<<sorted_values[i]<<" ";
    cout<<endl;
}

void BST_TestTest::show_breadth_first_tree(const BinarySearchTree<int> &t)
{
    cout<<"BF: ";
    cout<<get_bft_string(t.Root()).toStdString();
    cout<<endl;
}

void BST_TestTest::show_breadth_first_pointerTree(const BinarySearchTree<int *> &t)
{
    cout<<"BF: ";
    cout<<get_bft_pointer_string(t.Root()).toStdString();
    cout<<endl;
}

QString BST_TestTest::get_bft_string(const BST_NodeIterator<int> &i)
{
    QString ret;
    BST_NodeIterator<int> iter(i);

    ret.append(QString("(%1, ").arg(iter.Value()));
    if(iter.CanDescendLeft())
    {
        iter.DescendLeft();
        ret.append(get_bft_string(iter));
        iter.Ascend();
    }
    ret.append(", ");
    if(iter.CanDescendRight())
    {
        iter.DescendRight();
        ret.append(get_bft_string(iter));
        iter.Ascend();
    }
    ret.append(")");

    return ret;
}

QString BST_TestTest::get_bft_pointer_string(const BST_NodeIterator<int *> &i)
{
    QString ret;
    BST_NodeIterator<int *> iter(i);

    ret.append(QString("(%1, ").arg(*iter.Value()));
    if(iter.CanDescendLeft())
    {
        iter.DescendLeft();
        ret.append(get_bft_pointer_string(iter));
        iter.Ascend();
    }
    ret.append(", ");
    if(iter.CanDescendRight())
    {
        iter.DescendRight();
        ret.append(get_bft_pointer_string(iter));
        iter.Ascend();
    }
    ret.append(")");

    return ret;
}

bool BST_TestTest::tree_matches(const BinarySearchTree<int *> &t, const QString &s)
{
    bool ret = get_bft_pointer_string(t.Root()) == s;
    if(!ret)
    {
        cout<< get_bft_pointer_string(t.Root()).toStdString() <<"\tNot equal to:"<<endl<<s.toStdString()<<endl;
    }
    return ret;
}

bool BST_TestTest::tree_matches(const BinarySearchTree<int> &t, const QString &s)
{
    bool ret = get_bft_string(t.Root()) == s;
    if(!ret)
    {
        cout<< get_bft_string(t.Root()).toStdString() <<"\tNot equal to:"<<endl<<s.toStdString()<<endl;
    }
    return ret;
}

void BST_TestTest::test_insertions()
{
    // Test the 4 cases of rebalancing:  LL, RR, LR, RL
    BinarySearchTree<int> bst;

    // This tests the RR condition twice (Rotate left)
    bst.Add(5);
    bst.Add(10);
    bst.Add(15);
    bst.Add(20);
    bst.Add(25);
    QVERIFY(tree_matches(bst, "(10, (5, , ), (20, (15, , ), (25, , )))"));

    // Then LL (Rotate Right)
    bst.Add(2);
    bst.Add(1);
    QVERIFY(tree_matches(bst, "(10, (2, (1, , ), (5, , )), (20, (15, , ), (25, , )))"));

    // Then RL
    bst.Clear();
    bst.Add(5);
    bst.Add(10);
    bst.Add(9);
    QVERIFY(tree_matches(bst, "(9, (5, , ), (10, , ))"));

    // Then LR
    bst.Clear();
    bst.Add(5);
    bst.Add(3);
    bst.Add(4);
    QVERIFY(tree_matches(bst, "(4, (3, , ), (5, , ))"));
}

void BST_TestTest::test_deletions()
{

}

int BST_TestTest::pointer_compare(int* const &lhs, int* const &rhs)
{
    if(*lhs < *rhs)
        return -1;
    else if(*rhs < *lhs)
        return 1;
    return 0;
}

void BST_TestTest::test_pointers()
{
    BinarySearchTree<int *> pointer_tree(&BST_TestTest::pointer_compare);
    int a(1), b(2), c(3);
    pointer_tree.Add(&a);
    pointer_tree.Add(&b);
    pointer_tree.Add(&c);

    show_breadth_first_pointerTree(pointer_tree);
    QVERIFY(tree_matches(pointer_tree, "(2, (1, , ), (3, , ))"));

    // Update the data pointed to and see if the tree data was also updated.
    a = 500;
    QVERIFY(tree_matches(pointer_tree, "(2, (500, , ), (3, , ))"));
    show_breadth_first_pointerTree(pointer_tree);
}

QTEST_APPLESS_MAIN(BST_TestTest);

#include "tst_bst_testtest.moc"
<|endoftext|>