浏览代码

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 年之前
父节点
当前提交
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));