Ver código fonte

Move 2D math objects into 2D math namespace.
Add functions for line intersection and line orthogonal.
Add tests for line intersection around (0,0), including parallel lines.

Sam Jaffe 6 anos atrás
pai
commit
2fe7cf5a77

+ 1 - 1
math/include/game/math/common.hpp

@@ -11,5 +11,5 @@
 
 namespace math {
   vec2 rotate(vec2 const & center, vec2 const & point, radian r);
-  quad rotate(vec2 const & center, quad const & q, radian r);
+  dim2::quad rotate(vec2 const & center, dim2::quad const & q, radian r);
 }

+ 7 - 5
math/include/game/math/math_fwd.hpp

@@ -21,11 +21,13 @@ namespace math {
     using square_matrix = matrix<T, N, N>;
   }
   
-  struct line;
-  struct circle;
-  struct quad;
-  struct rectangle;
-  struct square;
+  namespace dim2 {
+    struct line;
+    struct circle;
+    struct quad;
+    struct rectangle;
+    struct square;
+  }
   
   struct degree;
   struct radian;

+ 18 - 9
math/include/game/math/shape.hpp

@@ -11,29 +11,38 @@
 
 #include "math_fwd.hpp"
 
-namespace math {
+namespace math { namespace dim2 {
+  using point = vec2;
+  
   struct line {
-    vec2 first, second;
+    float length() const;
+    float slope() const;
+    point first, second;
   };
   
   struct circle {
-    vec2 center;
+    point center;
     float radius;
   };
   
   struct quad {
-    vec2 ll, lr, ur, ul;
+    point ll, lr, ur, ul;
   };
   
   struct rectangle {
     operator quad() const;
-    vec2 origin, size;
+    point origin, size;
   };
-    
+  
   struct square {
     operator rectangle() const;
     operator quad() const;
-    vec2 origin;
+    point origin;
     float size;
-  };  
-}
+  };
+} }
+
+namespace math { namespace lines {
+  dim2::point intersection(dim2::line const & lhs, dim2::line const & rhs);
+  dim2::line orthogonal(dim2::line const & from, dim2::point const & to);
+} }

+ 22 - 0
math/math-test/Info.plist

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>

+ 245 - 1
math/math.xcodeproj/project.pbxproj

@@ -7,15 +7,67 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		CD1FCFD2227E194D00F9BF93 /* libmath.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CD3786181CF9F61100BE89B2 /* libmath.dylib */; };
+		CD1FCFD8227E195B00F9BF93 /* shape_test.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CD1FCFC8227E193000F9BF93 /* shape_test.cxx */; };
+		CD1FCFE9227E198100F9BF93 /* GoogleMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD1FCFE1227E197800F9BF93 /* GoogleMock.framework */; };
+		CD1FCFEC227E4C2E00F9BF93 /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3C80BA1D68902300ACC795 /* common.cpp */; };
 		CD3AC71E1D2C0AF8002B4BB0 /* shape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3AC71C1D2C0AF8002B4BB0 /* shape.cpp */; };
 		CD3C809F1D675AB100ACC795 /* angle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3C809D1D675AB100ACC795 /* angle.cpp */; };
-		CD3C80BC1D68902300ACC795 /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD3C80BA1D68902300ACC795 /* common.cpp */; };
 		CDA34D9522517967008036A7 /* matrix_helpers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CDA34D8C22517680008036A7 /* matrix_helpers.hpp */; };
 		CDA34D9622517969008036A7 /* matrix.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CDA34D8D22517680008036A7 /* matrix.hpp */; };
 		CDA34D972251796B008036A7 /* vector.hpp in Headers */ = {isa = PBXBuildFile; fileRef = CDA34D9022517689008036A7 /* vector.hpp */; };
 /* End PBXBuildFile section */
 
+/* Begin PBXContainerItemProxy section */
+		CD1FCFD3227E194D00F9BF93 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD3786101CF9F61100BE89B2 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = CD3786171CF9F61100BE89B2;
+			remoteInfo = math;
+		};
+		CD1FCFE0227E197800F9BF93 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F861A685AEA0072A469;
+			remoteInfo = GoogleMock;
+		};
+		CD1FCFE2227E197800F9BF93 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96ABD1A68600C00204102;
+			remoteInfo = gmock;
+		};
+		CD1FCFE4227E197800F9BF93 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05E96B1F1A68634900204102;
+			remoteInfo = gtest;
+		};
+		CD1FCFE6227E197800F9BF93 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 05818F901A685AEA0072A469;
+			remoteInfo = GoogleMockTests;
+		};
+		CD1FCFEA227E198400F9BF93 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */;
+			proxyType = 1;
+			remoteGlobalIDString = 05818F851A685AEA0072A469;
+			remoteInfo = GoogleMock;
+		};
+/* End PBXContainerItemProxy section */
+
 /* Begin PBXFileReference section */
+		CD1FCFC8227E193000F9BF93 /* shape_test.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = shape_test.cxx; sourceTree = "<group>"; };
+		CD1FCFCD227E194D00F9BF93 /* math-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "math-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
+		CD1FCFD1227E194D00F9BF93 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GoogleMock.xcodeproj; path = "../../gmock-xcode-master/GoogleMock.xcodeproj"; sourceTree = "<group>"; };
 		CD3786181CF9F61100BE89B2 /* libmath.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libmath.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		CD3AC71C1D2C0AF8002B4BB0 /* shape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shape.cpp; sourceTree = "<group>"; };
 		CD3C809D1D675AB100ACC795 /* angle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = angle.cpp; sourceTree = "<group>"; };
@@ -27,6 +79,15 @@
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
+		CD1FCFCA227E194D00F9BF93 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD1FCFE9227E198100F9BF93 /* GoogleMock.framework in Frameworks */,
+				CD1FCFD2227E194D00F9BF93 /* libmath.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		CD3786151CF9F61100BE89B2 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
@@ -37,14 +98,43 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		CD1FCFCE227E194D00F9BF93 /* math-test */ = {
+			isa = PBXGroup;
+			children = (
+				CD1FCFD1227E194D00F9BF93 /* Info.plist */,
+			);
+			path = "math-test";
+			sourceTree = "<group>";
+		};
+		CD1FCFDA227E197800F9BF93 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				CD1FCFE1227E197800F9BF93 /* GoogleMock.framework */,
+				CD1FCFE3227E197800F9BF93 /* gmock.framework */,
+				CD1FCFE5227E197800F9BF93 /* gtest.framework */,
+				CD1FCFE7227E197800F9BF93 /* GoogleMockTests.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		CD1FCFE8227E198100F9BF93 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
 		CD37860F1CF9F61100BE89B2 = {
 			isa = PBXGroup;
 			children = (
+				CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */,
 				CDA34D89225175CB008036A7 /* game */,
 				CDA34D8A22517670008036A7 /* include */,
 				CD3C80791D66440200ACC795 /* test */,
 				CD3786321CFA304800BE89B2 /* src */,
+				CD1FCFCE227E194D00F9BF93 /* math-test */,
 				CD3786191CF9F61100BE89B2 /* Products */,
+				CD1FCFE8227E198100F9BF93 /* Frameworks */,
 			);
 			sourceTree = "<group>";
 		};
@@ -52,6 +142,7 @@
 			isa = PBXGroup;
 			children = (
 				CD3786181CF9F61100BE89B2 /* libmath.dylib */,
+				CD1FCFCD227E194D00F9BF93 /* math-test.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -69,6 +160,7 @@
 		CD3C80791D66440200ACC795 /* test */ = {
 			isa = PBXGroup;
 			children = (
+				CD1FCFC8227E193000F9BF93 /* shape_test.cxx */,
 			);
 			path = test;
 			sourceTree = "<group>";
@@ -99,6 +191,25 @@
 /* End PBXHeadersBuildPhase section */
 
 /* Begin PBXNativeTarget section */
+		CD1FCFCC227E194D00F9BF93 /* math-test */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CD1FCFD5227E194D00F9BF93 /* Build configuration list for PBXNativeTarget "math-test" */;
+			buildPhases = (
+				CD1FCFC9227E194D00F9BF93 /* Sources */,
+				CD1FCFCA227E194D00F9BF93 /* Frameworks */,
+				CD1FCFCB227E194D00F9BF93 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				CD1FCFEB227E198400F9BF93 /* PBXTargetDependency */,
+				CD1FCFD4227E194D00F9BF93 /* PBXTargetDependency */,
+			);
+			name = "math-test";
+			productName = "math-test";
+			productReference = CD1FCFCD227E194D00F9BF93 /* math-test.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
 		CD3786171CF9F61100BE89B2 /* math */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = CD3786231CF9F61100BE89B2 /* Build configuration list for PBXNativeTarget "math" */;
@@ -123,9 +234,14 @@
 		CD3786101CF9F61100BE89B2 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
+				LastSwiftUpdateCheck = 1010;
 				LastUpgradeCheck = 1010;
 				ORGANIZATIONNAME = "Sam Jaffe";
 				TargetAttributes = {
+					CD1FCFCC227E194D00F9BF93 = {
+						CreatedOnToolsVersion = 10.1;
+						ProvisioningStyle = Automatic;
+					};
 					CD3786171CF9F61100BE89B2 = {
 						CreatedOnToolsVersion = 7.2.1;
 					};
@@ -141,13 +257,61 @@
 			mainGroup = CD37860F1CF9F61100BE89B2;
 			productRefGroup = CD3786191CF9F61100BE89B2 /* Products */;
 			projectDirPath = "";
+			projectReferences = (
+				{
+					ProductGroup = CD1FCFDA227E197800F9BF93 /* Products */;
+					ProjectRef = CD1FCFD9227E197800F9BF93 /* GoogleMock.xcodeproj */;
+				},
+			);
 			projectRoot = "";
 			targets = (
 				CD3786171CF9F61100BE89B2 /* math */,
+				CD1FCFCC227E194D00F9BF93 /* math-test */,
 			);
 		};
 /* End PBXProject section */
 
+/* Begin PBXReferenceProxy section */
+		CD1FCFE1227E197800F9BF93 /* GoogleMock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = GoogleMock.framework;
+			remoteRef = CD1FCFE0227E197800F9BF93 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CD1FCFE3227E197800F9BF93 /* gmock.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gmock.framework;
+			remoteRef = CD1FCFE2227E197800F9BF93 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CD1FCFE5227E197800F9BF93 /* gtest.framework */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.framework;
+			path = gtest.framework;
+			remoteRef = CD1FCFE4227E197800F9BF93 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		CD1FCFE7227E197800F9BF93 /* GoogleMockTests.xctest */ = {
+			isa = PBXReferenceProxy;
+			fileType = wrapper.cfbundle;
+			path = GoogleMockTests.xctest;
+			remoteRef = CD1FCFE6227E197800F9BF93 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+/* End PBXReferenceProxy section */
+
+/* Begin PBXResourcesBuildPhase section */
+		CD1FCFCB227E194D00F9BF93 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
 /* Begin PBXShellScriptBuildPhase section */
 		CD6F73E822517BDA0081ED74 /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
@@ -169,6 +333,14 @@
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
+		CD1FCFC9227E194D00F9BF93 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CD1FCFD8227E195B00F9BF93 /* shape_test.cxx in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		CD3786141CF9F61100BE89B2 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -181,7 +353,70 @@
 		};
 /* End PBXSourcesBuildPhase section */
 
+/* Begin PBXTargetDependency section */
+		CD1FCFD4227E194D00F9BF93 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = CD3786171CF9F61100BE89B2 /* math */;
+			targetProxy = CD1FCFD3227E194D00F9BF93 /* PBXContainerItemProxy */;
+		};
+		CD1FCFEB227E198400F9BF93 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			name = GoogleMock;
+			targetProxy = CD1FCFEA227E198400F9BF93 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
 /* Begin XCBuildConfiguration section */
+		CD1FCFD6227E194D00F9BF93 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				INFOPLIST_FILE = "math-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+				MTL_FAST_MATH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.math-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 4.2;
+			};
+			name = Debug;
+		};
+		CD1FCFD7227E194D00F9BF93 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				INFOPLIST_FILE = "math-test/Info.plist";
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 10.13;
+				MTL_FAST_MATH = YES;
+				PRODUCT_BUNDLE_IDENTIFIER = "leumasjaffe.math-test";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+				SWIFT_VERSION = 4.2;
+			};
+			name = Release;
+		};
 		CD3786211CF9F61100BE89B2 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
@@ -310,6 +545,15 @@
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+		CD1FCFD5227E194D00F9BF93 /* Build configuration list for PBXNativeTarget "math-test" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CD1FCFD6227E194D00F9BF93 /* Debug */,
+				CD1FCFD7227E194D00F9BF93 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 		CD3786131CF9F61100BE89B2 /* Build configuration list for PBXProject "math" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (

+ 67 - 0
math/math.xcodeproj/xcshareddata/xcschemes/math-test.xcscheme

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1010"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      codeCoverageEnabled = "YES"
+      onlyGenerateCoverageForSpecifiedTargets = "YES"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <CodeCoverageTargets>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "CD3786171CF9F61100BE89B2"
+            BuildableName = "libmath.dylib"
+            BlueprintName = "math"
+            ReferencedContainer = "container:math.xcodeproj">
+         </BuildableReference>
+      </CodeCoverageTargets>
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "CD1FCFCC227E194D00F9BF93"
+               BuildableName = "math-test.xctest"
+               BlueprintName = "math-test"
+               ReferencedContainer = "container:math.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>

+ 1 - 1
math/src/common.cpp

@@ -21,7 +21,7 @@ namespace math {
     }};
   }
   
-  quad rotate(vec2 const & c, quad const & q, radian r) {
+  dim2::quad rotate(vec2 const & c, dim2::quad const & q, radian r) {
     return {
       rotate(c, q.ll, r),
       rotate(c, q.lr, r),

+ 36 - 7
math/src/shape.cpp

@@ -7,14 +7,23 @@
 
 #include "game/math/shape.hpp"
 
-namespace math {
+#include <iostream>
+
+namespace math { namespace dim2 {
+  float line::length() const {
+    return (second - first).magnitude();
+  }
+  
+  float line::slope() const {
+    return (second[1] - first[1]) / (second[0] - first[0]);
+  }
   
   rectangle::operator quad() const {
     return {
       origin,
-      origin + vec2{{size.x(), 0.0}},
+      origin + point{{size.x(), 0.0}},
       origin + size,
-      origin + vec2{{0.0, size.y()}}
+      origin + point{{0.0, size.y()}}
     };
   }
 
@@ -25,10 +34,30 @@ namespace math {
   square::operator quad() const {
     return {
       origin,
-      origin + vec2{{size, 0.0 }},
-      origin + vec2{{size, size}},
-      origin + vec2{{ 0.0, size}}
+      origin + point{{size, 0.0 }},
+      origin + point{{size, size}},
+      origin + point{{ 0.0, size}}
     };
   }
+} }
+
+namespace math { namespace lines {
+  inline dim2::point intersection(float b1, float s1, float b2, float s2) {
+    float const x = (b1 + b2) / (s1 - s2);
+    return {{x, b1 + x * s1}};
+  }
+
+  inline dim2::point intersection(dim2::point p1, float s1, dim2::point p2,
+                                  float s2) {
+    return intersection(p1[1] - s1 * p1[0], s1, p2[1] - s2 * p2[0], s2);
+  }
   
-}
+  dim2::point intersection(dim2::line const & lhs, dim2::line const & rhs) {
+    return intersection(lhs.first, lhs.slope(), rhs.first, rhs.slope());
+  }
+
+  dim2::line orthogonal(dim2::line const & from, dim2::point const & to) {
+    float const slope = from.slope();
+    return {to, intersection(from.first, slope, to, -1/slope)};
+  }
+} }

+ 47 - 0
math/test/shape_test.cxx

@@ -0,0 +1,47 @@
+//
+//  shape_test.cxx
+//  math
+//
+//  Created by Sam Jaffe on 5/4/19.
+//  Copyright © 2019 Sam Jaffe. All rights reserved.
+//
+
+#include <gmock/gmock.h>
+
+#include "game/math/shape.hpp"
+
+namespace math { namespace vector {
+  std::ostream & operator<<(std::ostream & os, math::vec2 const & p) {
+    return os << '[' << p[0] << ',' << p[1] << ']';
+  }
+} }
+namespace math { namespace dim2 {
+  std::ostream & operator<<(std::ostream & os, line const & l) {
+    return os << '[' << l.first << ',' << l.second << ']';
+  }
+} }
+
+struct FromOriginTest : testing::TestWithParam<math::dim2::line> {};
+
+TEST_P(FromOriginTest, IntersectsAtOrigin) {
+  math::dim2::line l1 = { GetParam().first, {{0, 0}} };
+  math::dim2::line l2 = { {{0, 0}}, GetParam().second };
+  
+  EXPECT_THAT(math::lines::intersection(l1, l2),
+              testing::Eq(math::dim2::point{{0, 0}}));
+}
+
+std::vector<math::dim2::line> const point_pairs{
+  {{{1, 1}}, {{0, 0}}},
+  {{{1, 1}}, {{1, 0}}},
+  {{{1, 1}}, {{0, 1}}},
+  {{{1, 1}}, {{1, 1}}},
+  {{{1, 1}}, {{2, 1}}},
+  {{{2, 3}}, {{1, 2}}},
+  {{{1, 1}}, {{-1,  0}}},
+  {{{1, 1}}, {{ 0, -1}}},
+  {{{1, 1}}, {{-1, -1}}},
+};
+
+INSTANTIATE_TEST_CASE_P(LineIntersection, FromOriginTest,
+                        testing::ValuesIn(point_pairs));