#define CATCH_CONFIG_MAIN
#define WINDOWS_LEAN_AND_MEAN
#include <catch.h>
#include <Gorgon/Geometry/Transform3D.h>
#include <Gorgon/Geometry/Point3D.h>
#include <Gorgon/Geometry/Point.h>
#include <Gorgon/Geometry/Size.h>
#include <Gorgon/Geometry/Bounds.h>
#include <Gorgon/Geometry/Rectangle.h>
#include <Gorgon/String.h>
#undef Rectangle
#pragma warning(disable:4305)
#pragma warning(disable:4244)
using namespace Gorgon::Geometry;
TEST_CASE( "Point constructors", "[Point]" ) {
Point p1(1.2, 2.2);
Pointf p2(1.2, 2.2);
Point p3(p2);
Pointf p4(p3);
Point p5;
Pointf p6;
Pointf p7;
Point p8=Point::FromVector(4, 0.785398f, p1); //45 degrees
Pointf p9=Pointf::FromVector(4.1, 0.785398f, p2); //45 degrees
Point p10("1, 2");
Pointf p11("1.2, 2.2");
p5=p2;
p6=p2;
p7=p1;
REQUIRE( p1.X == 1);
REQUIRE( p1.Y == 2);
REQUIRE( p2.X == Approx(1.2f) );
REQUIRE( p2.Y == Approx(2.2f) );
REQUIRE( p3.X == 1);
REQUIRE( p3.Y == 2);
REQUIRE( p4.X == Approx(1) );
REQUIRE( p4.Y == Approx(2) );
REQUIRE( p5.X == 1);
REQUIRE( p5.Y == 2);
REQUIRE( p6.X == Approx(1.2f) );
REQUIRE( p6.Y == Approx(2.2f) );
REQUIRE( p7.X == Approx(1) );
REQUIRE( p7.Y == Approx(2) );
REQUIRE( p8.X == 3);
REQUIRE( p8.Y == 4);
REQUIRE( p9.X == Approx(4.099138f) );
REQUIRE( p9.Y == Approx(5.099138f) );
REQUIRE( p10.X == 1);
REQUIRE( p10.Y == 2);
REQUIRE( p11.X == Approx(1.2f) );
REQUIRE( p11.Y == Approx(2.2f) );
}
TEST_CASE( "Point comparison", "[Point]" ) {
Point p1(1, 2);
Pointf p2(1.2f, 2.2f);
Point p3(1, 2);
Pointf p4(1.2f, 2.2f);
Point p5(3, 4);
Pointf p6(3.3f, 7.1f);
REQUIRE( p1 == p3 );
REQUIRE( p2 == p4 );
REQUIRE_FALSE( p1 == p5 );
REQUIRE_FALSE( p2 == p6 );
REQUIRE_FALSE( p1 != p3 );
REQUIRE_FALSE( p2 != p4 );
REQUIRE( p1 != p5 );
REQUIRE( p2 != p6 );
REQUIRE( p1.Compare(p1) );
REQUIRE( p1.Compare(p3) );
REQUIRE_FALSE( p1.Compare(p5) );
REQUIRE( p1 == p1 );
REQUIRE_FALSE( p1 != p1 );
REQUIRE( p2.Compare(p2) );
REQUIRE( p2.Compare(p4) );
REQUIRE_FALSE( p2.Compare(p6) );
REQUIRE( p2 == p2 );
REQUIRE_FALSE( p2 != p2 );
}
TEST_CASE( "Point arithmetic", "[Point]" ) {
Point p1(1, 2);
Pointf p2(1.2f, 2.2f);
Point p3(5, 6);
Pointf p4(5.5f, 6.8f);
Point p5;
Pointf p6;
p5=p1+p3;
REQUIRE( p5 == Point(6,8) );
p5=p1-p3;
REQUIRE( p5 == Point(-4,-4) );
p5=p1*2;
REQUIRE( p5 == Point(2,4) );
p5=p1/2;
REQUIRE( p5 == Point(0,1) );
p5=p1*1.5;
REQUIRE( p5 == Point(1,3) );
p5=p1/0.5;
REQUIRE( p5 == Point(2,4) );
p6=p2+p4;
REQUIRE( p6.X == Approx(6.7f) );
REQUIRE( p6.Y == Approx(9.0f) );
p6=p2-p4;
REQUIRE( p6.X == Approx(-4.3f) );
REQUIRE( p6.Y == Approx(-4.6f) );
p6=p2*2;
REQUIRE( p6.X == Approx(2.4f) );
REQUIRE( p6.Y == Approx(4.4f) );
p6=p2/2;
REQUIRE( p6.X == Approx(0.6f) );
REQUIRE( p6.Y == Approx(1.1f) );
p6=p2*1.5;
REQUIRE( p6.X == Approx(1.8f) );
REQUIRE( p6.Y == Approx(3.3f) );
p6=p2/0.5;
REQUIRE( p6.X == Approx(2.4f) );
REQUIRE( p6.Y == Approx(4.4f) );
p5.Move(p1.X, p1.Y);
REQUIRE( p5 == p1 );
p5+=p3;
REQUIRE( p5 == Point(6,8) );
p5=p1;
p5-=p3;
REQUIRE( p5 == Point(-4,-4) );
p5=p1;
p5*=2;
REQUIRE( p5 == Point(2,4) );
p5=p1;
p5/=2;
REQUIRE( p5 == Point(0,1) );
p5=p1;
p5*=1.5;
REQUIRE( p5 == Point(1,3) );
p5=p1;
p5/=0.5;
REQUIRE( p5 == Point(2,4) );
p6.Move(p2.X, p2.Y);
REQUIRE( p6 == p2 );
p6+=p4;
REQUIRE( p6.X == Approx(6.7f) );
REQUIRE( p6.Y == Approx(9.0f) );
p6=p2;
p6-=p4;
REQUIRE( p6.X == Approx(-4.3f) );
REQUIRE( p6.Y == Approx(-4.6f) );
p6=p2;
p6*=2;
REQUIRE( p6.X == Approx(2.4f) );
REQUIRE( p6.Y == Approx(4.4f) );
p6=p2;
p6/=2;
REQUIRE( p6.X == Approx(0.6f) );
REQUIRE( p6.Y == Approx(1.1f) );
p6=p2;
p6*=1.5;
REQUIRE( p6.X == Approx(1.8f) );
REQUIRE( p6.Y == Approx(3.3f) );
p6=p2;
p6/=0.5;
REQUIRE( p6.X == Approx(2.4f) );
REQUIRE( p6.Y == Approx(4.4f) );
p5=-p1;
REQUIRE( p5 == Point(-1,-2) );
p6=-p2;
REQUIRE( p6.X == Approx(-1.2f) );
REQUIRE( p6.Y == Approx(-2.2f) );
}
TEST_CASE( "Point geometric info", "[Point]") {
Point p1(1, 2);
Pointf p2(1.2f, 2.2f);
Point p3(5, 6);
Pointf p4(5.5f, 6.8f);
Point p5;
Pointf p6;
REQUIRE( p1.Distance() == Approx(2.236068f) );
REQUIRE( p2.Distance() == Approx(2.505992f) );
REQUIRE( p1.Distance(p3) == Approx(5.656854f) );
REQUIRE( p2.Distance(p4) == Approx(6.296824f) );
REQUIRE( p1.Angle() == Approx(1.107149f) );
REQUIRE( p2.Angle() == Approx(1.071450f) );
REQUIRE( p1.Angle(p3) == Approx(-2.356195f) );
REQUIRE( p2.Angle(p4) == Approx(-2.322499f) );
REQUIRE( p1.Slope() == Approx(2.000000f) );
REQUIRE( p2.Slope() == Approx(1.833333f) );
REQUIRE( p1.Slope(p3) == Approx(1.000000f) );
REQUIRE( p2.Slope(p4) == Approx(1.069767f) );
}
/*TEST_CASE( "Point <-> string", "[Point]" ) {
Point p1("1, 2");
Pointf p2("(1.2f, 2.2f)");
Point p3;
Pointf p4;
std::stringstream ss;
auto makestream=[&](std::string s) -> std::stringstream & {
p3 = {0,0};
p4 = {0,0};
ss.str(s);
ss.clear();
return ss;
};
auto resetstream=[&] {
p3 = {0,0};
p4 = {0,0};
ss.str("");
ss.clear();
};
makestream("1,2")>>p3;
REQUIRE( p1 == p3 );
makestream("1.2,2.2")>>p3;
REQUIRE( p1 == p3 );
makestream("-1.2,-2.2")>>p3;
REQUIRE( p1 == -p3 );
makestream("(1,2)")>>p3;
REQUIRE( p1 == p3 );
makestream("(1.2,2.2)")>>p3;
REQUIRE( p1 == p3 );
makestream("(-1.2,-2.2)")>>p3;
REQUIRE( p1 == -p3 );
makestream("1, 2")>>p3;
REQUIRE( p1 == p3 );
makestream("1.2, 2.2")>>p3;
REQUIRE( p1 == p3 );
makestream("-1.2, -2.2")>>p3;
REQUIRE( p1 == -p3 );
makestream("(1, 2)")>>p3;
REQUIRE( p1 == p3 );
makestream("(1.2, 2.2)")>>p3;
REQUIRE( p1 == p3 );
makestream("(-1.2, -2.2)")>>p3;
REQUIRE( p1 == -p3 );
makestream("1,2")>>p3;
REQUIRE( p1 == p3 );
makestream("1.2,2.2")>>p3;
REQUIRE( p1 == p3 );
makestream("-1.2,-2.2")>>p3;
REQUIRE( p1 == -p3 );
makestream("(1,2) (1.2,2.2)")>>p3>>p4;
REQUIRE( p1 == p3 );
REQUIRE( p2 == p4 );
makestream("( 1,2 ) 1.2,2.2")>>p3>>p4;
REQUIRE( p1 == p3 );
REQUIRE( p2 == p4 );
makestream("(1.2,2.2) (1.2,2.2)")>>p3>>p4;
REQUIRE( p1 == p3 );
REQUIRE( p2 == p4 );
makestream("1.2,2.2 1.2,2.2")>>p3>>p4;
REQUIRE( p1 == p3 );
REQUIRE( p2 == p4 );
makestream("(-1.2,-2.2) (-1.2,-2.2)")>>p3>>p4;
REQUIRE( p1 == -p3 );
REQUIRE( p2 == -p4 );
REQUIRE( std::string(p1) == "(1, 2)" );
//Its ok to have extra zeros at the end
REQUIRE( Gorgon::String::Replace(std::string(p2),"0","") == "(1.2, 2.2)" );
REQUIRE( std::string(-p1) == "(-1, -2)" );
resetstream();
ss<<p1;
REQUIRE( Gorgon::String::Replace(ss.str(), " ","") == "(1,2)" );
resetstream();
ss<<p2;
REQUIRE( Gorgon::String::Replace(ss.str(), " ","") == "(1.2,2.2)" );
resetstream();
ss<<p1;
makestream(ss.str())>>p3;
REQUIRE( p1 == p3 );
resetstream();
ss<<p2;
makestream(ss.str())>>p4;
REQUIRE( p2 == p4 );
REQUIRE( Gorgon::String::To<Point>("1,2") == p1 );
REQUIRE( Gorgon::String::To<Point>("1.2,2.2") == p1 );
REQUIRE( Gorgon::String::To<Pointf>("1.2,2.2") == p2 );
REQUIRE( Gorgon::String::To<Point>("(1,2)") == p1 );
REQUIRE( Gorgon::String::To<Point>("(1.2,2.2)") == p1 );
REQUIRE( Gorgon::String::To<Pointf>("(1.2,2.2)") == p2 );
REQUIRE( Gorgon::String::To<Point>("(1, 2)") == p1 );
REQUIRE( Gorgon::String::To<Point>("(1.2, 2.2)") == p1 );
REQUIRE( Gorgon::String::To<Pointf>("(1.2, 2.2)") == p2 );
REQUIRE( Point::Parse("3,5") == Point(3,5) );
REQUIRE( Point::Parse("(3,5)") == Point(3,5) );
REQUIRE( Point::Parse("(3, 5)") == Point(3,5) );
REQUIRE( Point::Parse("3.2,5.8") == Point(3,5) );
REQUIRE( Point::Parse(" 3, 5 ") == Point(3,5) );
REQUIRE_THROWS( Point::Parse("") );
REQUIRE_THROWS( Point::Parse("3,") );
REQUIRE_THROWS( Point::Parse("3,a") );
REQUIRE_THROWS( Point::Parse("7a,5e") );
REQUIRE_THROWS( Point::Parse("(3,4") );
REQUIRE_THROWS( Point::Parse("3,4)") );
}
*/
TEST_CASE( "Point geometry functions", "[Point]" ) {
Point p1(1, 2);
Pointf p2(1.2f, 2.2f);
Point p3;
Pointf p4;
Point p5{4, 2};
Pointf p6{4.3f, 5.5f};
p3=p1;
Translate(p3, 1, 2);
REQUIRE(p3 == Point(2, 4));
Translate(p3, p5);
REQUIRE(p3 == Point(6, 6));
Translate(p3, -p5);
Translate(p3, -1, -2);
REQUIRE(p3 == p1);
p4=p2;
Translate(p4, 1.2f, 2.4f);
REQUIRE(p4.X == Approx(2.4));
REQUIRE(p4.Y == Approx(4.6));
Translate(p4, p6);
REQUIRE(p4.X == Approx(6.7));
REQUIRE(p4.Y == Approx(10.1));
Translate(p4, -p6);
Translate(p4, -1.2, -2.4);
REQUIRE(p4.X == Approx(p2.X));
REQUIRE(p4.Y == Approx(p2.Y));
p3=p1;
Scale(p3, 2);
REQUIRE(p3 == Point(2, 4));
Scale(p3, 2, Point{1,6});
REQUIRE(p3 == Point(3, 2));
Scale(p3, 0.5, Point{1, 6});
REQUIRE(p3 == Point(2, 4));
Scale(p3, 0.5);
REQUIRE(p3 == Point(1, 2));
Scale(p3, 2.5);
REQUIRE(p3 == Point(2, 5));
p4=p2;
Scale(p4, 2);
REQUIRE(p4.X == Approx(2.4));
REQUIRE(p4.Y == Approx(4.4));
Scale(p4, 2.5, Pointf{0.4f, 1.4f});
REQUIRE(p4.X == Approx(5.4));
REQUIRE(p4.Y == Approx(8.9));
p3=p1;
Scale(p3, 2.0, 0.5);
REQUIRE(p3 == Point(2, 1));
Scale(p3, 2.0, 0.5, Point{2,3});
REQUIRE(p3 == Point(2, 2));
p4=p2;
Scale(p4, 2.0, 0.5);
REQUIRE(p4.X == Approx(2.4));
REQUIRE(p4.Y == Approx(1.1));
Scale(p4, 2.0, 0.5, Pointf{2.4f,3.1f});
REQUIRE(p4.X == Approx(2.4));
REQUIRE(p4.Y == Approx(2.1));
p4=p1;
Rotate(p4, 3.14159265359/2);
REQUIRE(p4.X == Approx(-2));
REQUIRE(p4.Y == Approx(1));
p4={3, 4};
Rotate(p4, 3.14159265359/2, Pointf{2,2});
REQUIRE(p4.X == Approx(0));
REQUIRE(p4.Y == Approx(3));
p4=p2;
SkewX(p4, 0.2);
REQUIRE(p4.X == Approx(p2.X+2.2*0.2));
REQUIRE(p4.Y == p2.Y);
p4=p2;
SkewY(p4, 0.2);
REQUIRE(p4.X == p2.X);
REQUIRE(p4.Y == Approx(p2.Y+1.2*0.2));
p4=p2;
SkewX(p4, 0.2, Pointf{2,2});
REQUIRE(p4.X == Approx(p2.X+0.2*0.2));
REQUIRE(p4.Y == p2.Y);
p4=p2;
SkewY(p4, 0.2, Pointf{2,2});
REQUIRE(p4.X == p2.X);
REQUIRE(p4.Y == Approx(p2.Y-0.8*0.2));
p3=p1;
ReflectY(p3);
REQUIRE(p3 == Point(-1, 2));
ReflectX(p3);
REQUIRE(p3 == Point(-1, -2));
ReflectY(p3, Point{2, 2});
REQUIRE(p3 == Point(5, -2));
ReflectX(p3, Point{2, 2});
REQUIRE(p3 == Point(5, 6));
p4=p2;
ReflectY(p4);
REQUIRE(p4.X == Approx(-1.2));
REQUIRE(p4.Y == Approx(2.2));
ReflectX(p4);
REQUIRE(p4.X == Approx(-1.2));
REQUIRE(p4.Y == Approx(-2.2));
ReflectY(p4, Pointf{2, 2});
REQUIRE(p4.X == Approx(5.2));
REQUIRE(p4.Y == Approx(-2.2));
ReflectX(p4, Pointf{2, 2});
REQUIRE(p4.X == Approx(5.2));
REQUIRE(p4.Y == Approx(6.2));
p3=p1;
VerticalMirror(p3);
REQUIRE(p3 == Point(-1, 2));
HorizontalMirror(p3);
REQUIRE(p3 == Point(-1, -2));
VerticalMirror(p3, Point{2, 2});
REQUIRE(p3 == Point(5, -2));
HorizontalMirror(p3, Point{2, 2});
REQUIRE(p3 == Point(5, 6));
p4=p2;
VerticalMirror(p4);
REQUIRE(p4.X == Approx(-1.2));
REQUIRE(p4.Y == Approx(2.2));
HorizontalMirror(p4);
REQUIRE(p4.X == Approx(-1.2));
REQUIRE(p4.Y == Approx(-2.2));
VerticalMirror(p4, Pointf{2, 2});
REQUIRE(p4.X == Approx(5.2));
REQUIRE(p4.Y == Approx(-2.2));
HorizontalMirror(p4, Pointf{2, 2});
REQUIRE(p4.X == Approx(5.2));
REQUIRE(p4.Y == Approx(6.2));
}
TEST_CASE( "Size constructors", "[Size]" ) {
Size s1(2, 5);
Size s2(4);
Size s3(2.2, 5.2);
Sizef s4(4.4);
Sizef s5(2.2, 5.2);
Size s6;
Sizef s7;
Size s8(Point(2, 5));
Sizef s9(Pointf(2.2, 5.2));
Point p1(2, 5);
Pointf p2(2.2, 5.2);
Size s10;
Sizef s11;
Size s12("2x5");
Sizef s13("2.2x5.2");
s6=s1;
s7=s5;
s10=p1;
s11=p2;
REQUIRE(s1.Width == 2);
REQUIRE(s1.Height == 5);
REQUIRE(s2.Width == 4);
REQUIRE(s2.Height == 4);
REQUIRE(s3.Width == 2);
REQUIRE(s3.Height == 5);
REQUIRE(s4.Width == Approx(4.4));
REQUIRE(s4.Height == Approx(4.4));
REQUIRE(s5.Width == Approx(2.2));
REQUIRE(s5.Height == Approx(5.2));
REQUIRE(s6.Width == 2);
REQUIRE(s6.Height == 5);
REQUIRE(s7.Width == Approx(2.2));
REQUIRE(s7.Height == Approx(5.2));
REQUIRE(s8.Width == 2);
REQUIRE(s8.Height == 5);
REQUIRE(s9.Width == Approx(2.2));
REQUIRE(s9.Height == Approx(5.2));
REQUIRE(s10.Width == 2);
REQUIRE(s10.Height == 5);
REQUIRE(s11.Width == Approx(2.2));
REQUIRE(s11.Height == Approx(5.2));
REQUIRE(s12.Width == 2);
REQUIRE(s12.Height == 5);
REQUIRE(s13.Width == Approx(2.2));
REQUIRE(s13.Height == Approx(5.2));
//REQUIRE( ((basic_Point<int>)s1) == Point(2, 5) );
//REQUIRE( (Pointf)s2 == Pointf(4, 4) );
}
TEST_CASE( "Size comparison", "[Size]" ) {
Size s1(1, 2);
Sizef s2(1.2f, 2.2f);
Size s3(1, 2);
Sizef s4(1.2f, 2.2f);
Size s5(3, 4);
Sizef s6(3.3f, 7.1f);
REQUIRE( s1 == s3 );
REQUIRE( s2 == s4 );
REQUIRE_FALSE( s1 == s5 );
REQUIRE_FALSE( s2 == s6 );
REQUIRE_FALSE( s1 != s3 );
REQUIRE_FALSE( s2 != s4 );
REQUIRE( s1 != s5 );
REQUIRE( s2 != s6 );
REQUIRE( s1 == s1 );
REQUIRE_FALSE( s1 != s1 );
REQUIRE( s2 == s2 );
REQUIRE_FALSE( s2 != s2 );
}
TEST_CASE( "Size arithmetic", "[Size]" ) {
Size s1(1, 2);
Sizef s2(1.2f, 2.2f);
Size s3(5, 6);
Sizef s4(5.5f, 6.8f);
Size s5;
Sizef s6;
s5=s1+s3;
REQUIRE( s5 == Size(6,8) );
s5=s1-s3;
REQUIRE( s5 == Size(-4,-4) );
s5=s1*2;
REQUIRE( s5 == Size(2,4) );
s5=s1/2;
REQUIRE( s5 == Size(0,1) );
s5=s1*1.5;
REQUIRE( s5 == Size(1,3) );
s5=s1/0.5;
REQUIRE( s5 == Size(2,4) );
s6=s2+s4;
REQUIRE( s6.Width == Approx(6.7f) );
REQUIRE( s6.Height == Approx(9.0f) );
s6=s2-s4;
REQUIRE( s6.Width == Approx(-4.3f) );
REQUIRE( s6.Height == Approx(-4.6f) );
s6=s2*2;
REQUIRE( s6.Width == Approx(2.4f) );
REQUIRE( s6.Height == Approx(4.4f) );
s6=s2/2;
REQUIRE( s6.Width == Approx(0.6f) );
REQUIRE( s6.Height == Approx(1.1f) );
s6=s2*1.5;
REQUIRE( s6.Width == Approx(1.8f) );
REQUIRE( s6.Height == Approx(3.3f) );
s6=s2/0.5;
REQUIRE( s6.Width == Approx(2.4f) );
REQUIRE( s6.Height == Approx(4.4f) );
s5=s1;
s5-=s3;
REQUIRE( s5 == Size(-4,-4) );
//REQUIRE_FALSE( s5.IsValid() );
s5=s1;
s5*=2;
REQUIRE( s5 == Size(2,4) );
//REQUIRE( s5.IsValid() );
s5=s1;
s5/=2;
REQUIRE( s5 == Size(0,1) );
s5=s1;
s5*=1.5;
REQUIRE( s5 == Size(1,3) );
s5=s1;
s5/=0.5;
REQUIRE( s5 == Size(2,4) );
s6=s2;
s6-=s4;
REQUIRE( s6.Width == Approx(-4.3f) );
REQUIRE( s6.Height == Approx(-4.6f) );
s6=s2;
s6*=2;
REQUIRE( s6.Width == Approx(2.4f) );
REQUIRE( s6.Height == Approx(4.4f) );
s6=s2;
s6/=2;
REQUIRE( s6.Width == Approx(0.6f) );
REQUIRE( s6.Height == Approx(1.1f) );
s6=s2;
s6*=1.5;
REQUIRE( s6.Width == Approx(1.8f) );
REQUIRE( s6.Height == Approx(3.3f) );
s6=s2;
s6/=0.5;
REQUIRE( s6.Width == Approx(2.4f) );
REQUIRE( s6.Height == Approx(4.4f) );
}
TEST_CASE( "Size geometric info", "[Size]" ) {
Size s1(1, 2);
Sizef s2(1.2f, 2.2f);
Size s3(5, 6);
Sizef s4(5.5f, 6.8f);
REQUIRE( s1.Area() == 2 );
REQUIRE( s2.Area() == Approx(2.64) );
REQUIRE( s3.Cells() == 30 );
REQUIRE( s4.Cells() == 30 );
}
TEST_CASE( "Size <-> string", "[Size]" ) {
Size s1("1,2");
Sizef s2("1.2fx2.2f");
Size s3;
Sizef s4;
std::stringstream ss;
auto makestream=[&](std::string s) -> std::stringstream & {
s3 = {0,0};
s4 = {0,0};
ss.str(s);
ss.clear();
return ss;
};
auto resetstream=[&] {
s3 = {0,0};
s4 = {0,0};
ss.str("");
ss.clear();
};
makestream("1x2")>>s3;
REQUIRE( s1 == s3 );
makestream("1.2x2.2")>>s3;
REQUIRE( s1 == s3 );
makestream("-1.2x-2.2")>>s3;
REQUIRE( s1 == s3*-1 );
makestream("1x 2")>>s3;
REQUIRE( s1 == s3 );
makestream("1.2 x2.2")>>s3;
REQUIRE( s1 == s3 );
makestream("-1.2 x -2.2")>>s3;
REQUIRE( s1 == s3*-1 );
makestream("1 x2")>>s3;
REQUIRE( s1 == s3 );
makestream("1.2 x 2.2")>>s3;
REQUIRE( s1 == s3 );
makestream("-1.2x-2.2")>>s3;
REQUIRE( s1 == s3*-1 );
makestream("1x2 1.2x2.2")>>s3>>s4;
REQUIRE( s1 == s3 );
REQUIRE( s2 == s4 );
makestream("-1.2x-2.2 -1.2x-2.2")>>s3>>s4;
REQUIRE( s1 == s3*-1 );
REQUIRE( s2 == s4*-1 );
REQUIRE( std::string(s1) == "1x2" );
//Its ok to have extra zeros at the end
REQUIRE( Gorgon::String::Replace(std::string(s2),"0","") == "1.2x2.2" );
REQUIRE( std::string(s1*-1) == "-1x-2" );
resetstream();
ss<<s1;
REQUIRE( Gorgon::String::Replace(ss.str(), " ","") == "1x2" );
resetstream();
ss<<s2;
REQUIRE( Gorgon::String::Replace(ss.str(), " ","") == "1.2x2.2" );
resetstream();
ss<<s1;
makestream(ss.str())>>s3;
REQUIRE( s1 == s3 );
resetstream();
ss<<s2;
makestream(ss.str())>>s4;
REQUIRE( s2 == s4 );
REQUIRE( Gorgon::String::To<Size>("1x2") == s1 );
REQUIRE( Gorgon::String::To<Size>("1.2x2.2") == s1 );
REQUIRE( Gorgon::String::To<Sizef>("1.2x2.2") == s2 );
REQUIRE( Gorgon::String::To<Size>("1 x2") == s1 );
REQUIRE( Gorgon::String::To<Size>("1.2x 2.2") == s1 );
REQUIRE( Gorgon::String::To<Sizef>("1.2 x 2.2") == s2 );
REQUIRE( Size::Parse("3x5") == Size(3,5) );
REQUIRE( Size::Parse("3 x5") == Size(3,5) );
REQUIRE( Size::Parse("3x 5") == Size(3,5) );
REQUIRE( Size::Parse("3.2x5.8") == Size(3,5) );
REQUIRE( Size::Parse(" 3x 5 ") == Size(3,5) );
REQUIRE_THROWS( Size::Parse("") );
REQUIRE_THROWS( Size::Parse("3x") );
REQUIRE_THROWS( Size::Parse("3xa") );
REQUIRE_THROWS( Size::Parse("7ax5e") );
REQUIRE_THROWS( Size::Parse("3,4") );
REQUIRE_THROWS( Size::Parse("3,4)") );
REQUIRE_THROWS( Size::Parse("(3,4)") );
}
TEST_CASE( "Size point interaction", "[Size][Point]" ) {
Point p1(10,20);
Size s1(2,5);
Pointf p2(1.2, 2.2);
Sizef s2(2.2, 5.2);
Pointf p3;
Point p4;
REQUIRE( (p1*s1) == Point(20, 100) );
REQUIRE( (p1/s1) == Point(5, 4) );
REQUIRE( (p1*s2) == Pointf(22, 104) );
p3=(p1/s2);
REQUIRE( p3.X == Approx(4.5454) );
REQUIRE( p3.Y == Approx(3.8461) );
p3=(p2*s1);
REQUIRE( p3.X == Approx(2.4) );
REQUIRE( p3.Y == Approx(11) );
p3=(p2/s1);
REQUIRE( p3.X == Approx(0.6) );
REQUIRE( p3.Y == Approx(0.44) );
p3=(p2*s2);
REQUIRE( p3.X == Approx(2.64) );
REQUIRE( p3.Y == Approx(11.44) );
p3=(p2/s2);
REQUIRE( p3.X == Approx(0.54545) );
REQUIRE( p3.Y == Approx(0.42308) );
}
/*p4=p1;
Scale(p4, s1);
REQUIRE( p4 == Point(20, 100) );
p4=p1;
Scale(p4, s2);
REQUIRE( p4 == Point(22, 103) || p4 == Point(22, 104) );
p3=p2;
Scale(p3, s1);
REQUIRE( p3.X == Approx(2.4) );
REQUIRE( p3.Y == Approx(11) );
p3=p2;
Scale(p3, s2);
REQUIRE( p3.X == Approx(2.64) );
REQUIRE( p3.Y == Approx(11.44) );
}
TEST_CASE( "Size geometric functions", "[Size]" ) {
Size s1(1, 2);
Sizef s2(1.2f, 2.2f);
Scale(s1, 2);
REQUIRE( s1 == Size(2, 4) );
Scale(s1, 0.25);
REQUIRE( s1 == Size(0, 1) );
Scale(s2, 2);
REQUIRE( s2.Width == Approx(2.4) );
REQUIRE( s2.Height == Approx(4.4) );
Scale(s2, 0.25);
REQUIRE( s2.Width == Approx(0.6) );
REQUIRE( s2.Height == Approx(1.1) );
}
TEST_CASE( "Point3D") {
Point3D p1(1, 2, 3);
Point3D p2;
auto similar = [](Point3D p1, Point3D p2) {
return fabs(p1.X - p2.X) < 0.00001 && fabs(p1.Y - p2.Y) < 0.00001 && fabs(p1.Z - p2.Z) < 0.00001;
};
REQUIRE(p1.X == 1);
REQUIRE(p1.Y == 2);
REQUIRE(p1.Z == 3);
p2.X = 4;
p2.Y = 5;
p2.Z = 6;
REQUIRE(similar(p1 * 3, {3.f, 6.f, 9.f}));
REQUIRE(similar(p1 / 2, {.5f, 1.f, 1.5f}));
REQUIRE(similar(p1 + p2, {5.f, 7.f, 9.f}));
REQUIRE(similar(p1 - p2, {-3.f, -3.f, -3.f}));
REQUIRE(Approx(p1 * p2) == 32);
REQUIRE(similar(p1.CrossProduct(p2), {-3.f, 6.f, -3.f}));
REQUIRE(similar(p1.Normalize(), p1 / 3.741657));
REQUIRE(Approx(p1.Distance()) == 3.741657);
REQUIRE(Approx(p1.ManhattanDistance()) == 6);
}
TEST_CASE( "Transform3D") {
auto similar = [](Transform3D t1, Transform3D t2) {
for(int i=0; i<16; i++) {
if(fabs(t1.Data()[i] - t2.Data()[i]) > 0.00001)
return false;
}
return true;
};
auto similarp = [](Point3D p1, Point3D p2) {
return fabs(p1.X - p2.X) < 0.00001 && fabs(p1.Y - p2.Y) < 0.00001 && fabs(p1.Z - p2.Z) < 0.00001;
};
Transform3D t1, t2;
Point3D p1(1, 2, 3);
//check if identity is loaded
for(int i=0; i<4; i++) {
for(int j=0; j<4; j++) {
if(i == j)
REQUIRE(t1(i, j) == 1);
else
REQUIRE(t1(i, j) == 0);
}
}
REQUIRE(similarp(t1 * p1, p1));
t1.Translate({1, 2, 3});
t2(0, 3) = 1;
t2(1, 3) = 2;
t2(2, 3) = 3;
REQUIRE(similar(t1, t2));
glutil::MatrixStack m;
m.SetIdentity();
m.Translate(1, 2, 3);
m.Rotate({0,0,1}, Gorgon::PI/2);
m.Translate(1, 2, 3);
for(int i=0; i<4; i++) {
for(int j=0; j<4; j++) {
std::cout<<std::fixed<<std::setprecision(1)<<std::setw(5)<<m.Top().operator[](j)[i]<<" ";
}
std::cout<<std::endl;
}
glm::vec4 v(3, 3, 3, 1);
v = m.Top() * v;
std::cout<<v.x<<" "<<v.y<<" "<<v.z<<std::endl;
t2 = {{0,-1,0,1}, {1,0,0,2},{0,0,1,3},{0,0,0,1}};
t1.Rotate(0, 0, Gorgon::PI/2);
REQUIRE(similar(t1, t2));
t2 = {};
t2(0, 3) = 1;
t2(1, 3) = 2;
t2(2, 3) = 3;
t1 *= t2;
t2 = {{0,-1,0,-1}, {1,0,0,3},{0,0,1,6},{0,0,0,1}};
REQUIRE(similar(t1, t2));
t2 = {{1, 1, 1, 0}, {0,0,0,0},{0,0,0,0},{0,0,0,1}};
t2.Transpose();
REQUIRE(similar(t2, {{1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {0,0,0,1}}));
p1 = {3, 3, 3};
p1 = t1 * p1;
REQUIRE(similarp(p1, {-4, 6, 9}));
t1 = {};
t1.Scale(1, 2, 3);
p1 = {3, 3, 3};
p1 = t1 * p1;
REQUIRE(similarp(p1, {3, 6, 9}));
}
TEST_CASE( "Bounds constructors", "[Bounds]" ) {
Bounds b1(1.2, 2.2);
Boundsf b2(1.2, 2.2);
Bounds b3(b2); Boundsf b4(b3);
Bounds b5;
Boundsf b6;
Boundsf b7;
Bounds b8("1, 2");
Boundsf b9("1.2, 2.2");
}
*/