├── Curve Interpolation.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── Curve Interpolation.xccheckout └── xcuserdata │ └── johnfisher.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── Curve Interpolation.xcscheme │ └── xcschememanagement.plist ├── Curve Interpolation ├── CGPointExtension.h ├── CGPointExtension.m ├── CRVINTERAppDelegate.h ├── CRVINTERAppDelegate.m ├── CRVINTERGraphicsView.h ├── CRVINTERGraphicsView.m ├── CRVINTERViewController.h ├── CRVINTERViewController.m ├── Curve Interpolation-Info.plist ├── Curve Interpolation-Prefix.pch ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── Main.storyboard ├── UIBezierPath+Interpolation.h ├── UIBezierPath+Interpolation.m ├── en.lproj │ └── InfoPlist.strings └── main.m ├── Curve InterpolationTests ├── Curve InterpolationTests-Info.plist ├── Curve_InterpolationTests.m └── en.lproj │ └── InfoPlist.strings ├── LICENSE.md └── README.md /Curve Interpolation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8868F9D6190C1CE500F5332C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8868F9D5190C1CE500F5332C /* Foundation.framework */; }; 11 | 8868F9D8190C1CE500F5332C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8868F9D7190C1CE500F5332C /* CoreGraphics.framework */; }; 12 | 8868F9DA190C1CE500F5332C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8868F9D9190C1CE500F5332C /* UIKit.framework */; }; 13 | 8868F9E0190C1CE500F5332C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8868F9DE190C1CE500F5332C /* InfoPlist.strings */; }; 14 | 8868F9E2190C1CE500F5332C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8868F9E1190C1CE500F5332C /* main.m */; }; 15 | 8868F9E6190C1CE500F5332C /* CRVINTERAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8868F9E5190C1CE500F5332C /* CRVINTERAppDelegate.m */; }; 16 | 8868F9E8190C1CE500F5332C /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8868F9E7190C1CE500F5332C /* Images.xcassets */; }; 17 | 8868F9EF190C1CE500F5332C /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8868F9EE190C1CE500F5332C /* XCTest.framework */; }; 18 | 8868F9F0190C1CE500F5332C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8868F9D5190C1CE500F5332C /* Foundation.framework */; }; 19 | 8868F9F1190C1CE500F5332C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8868F9D9190C1CE500F5332C /* UIKit.framework */; }; 20 | 8868F9F9190C1CE500F5332C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8868F9F7190C1CE500F5332C /* InfoPlist.strings */; }; 21 | 8868F9FB190C1CE500F5332C /* Curve_InterpolationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8868F9FA190C1CE500F5332C /* Curve_InterpolationTests.m */; }; 22 | 8868FA05190C1D1300F5332C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8868FA04190C1D1300F5332C /* Main.storyboard */; }; 23 | 88B642AB190C22FF00B6B5F3 /* CRVINTERGraphicsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B642AA190C22FF00B6B5F3 /* CRVINTERGraphicsView.m */; }; 24 | 88B642B2190C23CF00B6B5F3 /* CGPointExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B642AD190C23CF00B6B5F3 /* CGPointExtension.m */; }; 25 | 88B642B7190C240200B6B5F3 /* UIBezierPath+Interpolation.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B642B6190C240200B6B5F3 /* UIBezierPath+Interpolation.m */; }; 26 | 88B642BA190C2A2900B6B5F3 /* CRVINTERViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 88B642B9190C2A2900B6B5F3 /* CRVINTERViewController.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 8868F9F2190C1CE500F5332C /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 8868F9CA190C1CE500F5332C /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 8868F9D1190C1CE500F5332C; 35 | remoteInfo = "Curve Interpolation"; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 8868F9D2190C1CE500F5332C /* Curve Interpolation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Curve Interpolation.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 8868F9D5190C1CE500F5332C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 42 | 8868F9D7190C1CE500F5332C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 43 | 8868F9D9190C1CE500F5332C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 44 | 8868F9DD190C1CE500F5332C /* Curve Interpolation-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Curve Interpolation-Info.plist"; sourceTree = ""; }; 45 | 8868F9DF190C1CE500F5332C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 46 | 8868F9E1190C1CE500F5332C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 47 | 8868F9E3190C1CE500F5332C /* Curve Interpolation-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Curve Interpolation-Prefix.pch"; sourceTree = ""; }; 48 | 8868F9E4190C1CE500F5332C /* CRVINTERAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CRVINTERAppDelegate.h; sourceTree = ""; }; 49 | 8868F9E5190C1CE500F5332C /* CRVINTERAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CRVINTERAppDelegate.m; sourceTree = ""; }; 50 | 8868F9E7190C1CE500F5332C /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 51 | 8868F9ED190C1CE500F5332C /* Curve InterpolationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Curve InterpolationTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 8868F9EE190C1CE500F5332C /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 53 | 8868F9F6190C1CE500F5332C /* Curve InterpolationTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Curve InterpolationTests-Info.plist"; sourceTree = ""; }; 54 | 8868F9F8190C1CE500F5332C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 55 | 8868F9FA190C1CE500F5332C /* Curve_InterpolationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Curve_InterpolationTests.m; sourceTree = ""; }; 56 | 8868FA04190C1D1300F5332C /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 57 | 88B642A9190C22FF00B6B5F3 /* CRVINTERGraphicsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRVINTERGraphicsView.h; sourceTree = ""; }; 58 | 88B642AA190C22FF00B6B5F3 /* CRVINTERGraphicsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CRVINTERGraphicsView.m; sourceTree = ""; }; 59 | 88B642AC190C23CF00B6B5F3 /* CGPointExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CGPointExtension.h; sourceTree = ""; }; 60 | 88B642AD190C23CF00B6B5F3 /* CGPointExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CGPointExtension.m; sourceTree = ""; }; 61 | 88B642B5190C240200B6B5F3 /* UIBezierPath+Interpolation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIBezierPath+Interpolation.h"; sourceTree = ""; }; 62 | 88B642B6190C240200B6B5F3 /* UIBezierPath+Interpolation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIBezierPath+Interpolation.m"; sourceTree = ""; }; 63 | 88B642B8190C2A2900B6B5F3 /* CRVINTERViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRVINTERViewController.h; sourceTree = ""; }; 64 | 88B642B9190C2A2900B6B5F3 /* CRVINTERViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CRVINTERViewController.m; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | 8868F9CF190C1CE500F5332C /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | 8868F9D8190C1CE500F5332C /* CoreGraphics.framework in Frameworks */, 73 | 8868F9DA190C1CE500F5332C /* UIKit.framework in Frameworks */, 74 | 8868F9D6190C1CE500F5332C /* Foundation.framework in Frameworks */, 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | 8868F9EA190C1CE500F5332C /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | 8868F9EF190C1CE500F5332C /* XCTest.framework in Frameworks */, 83 | 8868F9F1190C1CE500F5332C /* UIKit.framework in Frameworks */, 84 | 8868F9F0190C1CE500F5332C /* Foundation.framework in Frameworks */, 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | /* End PBXFrameworksBuildPhase section */ 89 | 90 | /* Begin PBXGroup section */ 91 | 8868F9C9190C1CE500F5332C = { 92 | isa = PBXGroup; 93 | children = ( 94 | 8868F9DB190C1CE500F5332C /* Curve Interpolation */, 95 | 8868F9F4190C1CE500F5332C /* Curve InterpolationTests */, 96 | 8868F9D4190C1CE500F5332C /* Frameworks */, 97 | 8868F9D3190C1CE500F5332C /* Products */, 98 | ); 99 | sourceTree = ""; 100 | }; 101 | 8868F9D3190C1CE500F5332C /* Products */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 8868F9D2190C1CE500F5332C /* Curve Interpolation.app */, 105 | 8868F9ED190C1CE500F5332C /* Curve InterpolationTests.xctest */, 106 | ); 107 | name = Products; 108 | sourceTree = ""; 109 | }; 110 | 8868F9D4190C1CE500F5332C /* Frameworks */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 8868F9D5190C1CE500F5332C /* Foundation.framework */, 114 | 8868F9D7190C1CE500F5332C /* CoreGraphics.framework */, 115 | 8868F9D9190C1CE500F5332C /* UIKit.framework */, 116 | 8868F9EE190C1CE500F5332C /* XCTest.framework */, 117 | ); 118 | name = Frameworks; 119 | sourceTree = ""; 120 | }; 121 | 8868F9DB190C1CE500F5332C /* Curve Interpolation */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 88B642AC190C23CF00B6B5F3 /* CGPointExtension.h */, 125 | 88B642AD190C23CF00B6B5F3 /* CGPointExtension.m */, 126 | 8868F9E4190C1CE500F5332C /* CRVINTERAppDelegate.h */, 127 | 8868F9E5190C1CE500F5332C /* CRVINTERAppDelegate.m */, 128 | 88B642A9190C22FF00B6B5F3 /* CRVINTERGraphicsView.h */, 129 | 88B642AA190C22FF00B6B5F3 /* CRVINTERGraphicsView.m */, 130 | 88B642B5190C240200B6B5F3 /* UIBezierPath+Interpolation.h */, 131 | 88B642B6190C240200B6B5F3 /* UIBezierPath+Interpolation.m */, 132 | 88B642B8190C2A2900B6B5F3 /* CRVINTERViewController.h */, 133 | 88B642B9190C2A2900B6B5F3 /* CRVINTERViewController.m */, 134 | 8868F9E7190C1CE500F5332C /* Images.xcassets */, 135 | 8868F9DC190C1CE500F5332C /* Supporting Files */, 136 | 8868FA04190C1D1300F5332C /* Main.storyboard */, 137 | ); 138 | path = "Curve Interpolation"; 139 | sourceTree = ""; 140 | }; 141 | 8868F9DC190C1CE500F5332C /* Supporting Files */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 8868F9DD190C1CE500F5332C /* Curve Interpolation-Info.plist */, 145 | 8868F9DE190C1CE500F5332C /* InfoPlist.strings */, 146 | 8868F9E1190C1CE500F5332C /* main.m */, 147 | 8868F9E3190C1CE500F5332C /* Curve Interpolation-Prefix.pch */, 148 | ); 149 | name = "Supporting Files"; 150 | sourceTree = ""; 151 | }; 152 | 8868F9F4190C1CE500F5332C /* Curve InterpolationTests */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 8868F9FA190C1CE500F5332C /* Curve_InterpolationTests.m */, 156 | 8868F9F5190C1CE500F5332C /* Supporting Files */, 157 | ); 158 | path = "Curve InterpolationTests"; 159 | sourceTree = ""; 160 | }; 161 | 8868F9F5190C1CE500F5332C /* Supporting Files */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 8868F9F6190C1CE500F5332C /* Curve InterpolationTests-Info.plist */, 165 | 8868F9F7190C1CE500F5332C /* InfoPlist.strings */, 166 | ); 167 | name = "Supporting Files"; 168 | sourceTree = ""; 169 | }; 170 | /* End PBXGroup section */ 171 | 172 | /* Begin PBXNativeTarget section */ 173 | 8868F9D1190C1CE500F5332C /* Curve Interpolation */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = 8868F9FE190C1CE500F5332C /* Build configuration list for PBXNativeTarget "Curve Interpolation" */; 176 | buildPhases = ( 177 | 8868F9CE190C1CE500F5332C /* Sources */, 178 | 8868F9CF190C1CE500F5332C /* Frameworks */, 179 | 8868F9D0190C1CE500F5332C /* Resources */, 180 | ); 181 | buildRules = ( 182 | ); 183 | dependencies = ( 184 | ); 185 | name = "Curve Interpolation"; 186 | productName = "Curve Interpolation"; 187 | productReference = 8868F9D2190C1CE500F5332C /* Curve Interpolation.app */; 188 | productType = "com.apple.product-type.application"; 189 | }; 190 | 8868F9EC190C1CE500F5332C /* Curve InterpolationTests */ = { 191 | isa = PBXNativeTarget; 192 | buildConfigurationList = 8868FA01190C1CE500F5332C /* Build configuration list for PBXNativeTarget "Curve InterpolationTests" */; 193 | buildPhases = ( 194 | 8868F9E9190C1CE500F5332C /* Sources */, 195 | 8868F9EA190C1CE500F5332C /* Frameworks */, 196 | 8868F9EB190C1CE500F5332C /* Resources */, 197 | ); 198 | buildRules = ( 199 | ); 200 | dependencies = ( 201 | 8868F9F3190C1CE500F5332C /* PBXTargetDependency */, 202 | ); 203 | name = "Curve InterpolationTests"; 204 | productName = "Curve InterpolationTests"; 205 | productReference = 8868F9ED190C1CE500F5332C /* Curve InterpolationTests.xctest */; 206 | productType = "com.apple.product-type.bundle.unit-test"; 207 | }; 208 | /* End PBXNativeTarget section */ 209 | 210 | /* Begin PBXProject section */ 211 | 8868F9CA190C1CE500F5332C /* Project object */ = { 212 | isa = PBXProject; 213 | attributes = { 214 | CLASSPREFIX = CRVINTER; 215 | LastUpgradeCheck = 0510; 216 | ORGANIZATIONNAME = "John Fisher"; 217 | TargetAttributes = { 218 | 8868F9EC190C1CE500F5332C = { 219 | TestTargetID = 8868F9D1190C1CE500F5332C; 220 | }; 221 | }; 222 | }; 223 | buildConfigurationList = 8868F9CD190C1CE500F5332C /* Build configuration list for PBXProject "Curve Interpolation" */; 224 | compatibilityVersion = "Xcode 3.2"; 225 | developmentRegion = English; 226 | hasScannedForEncodings = 0; 227 | knownRegions = ( 228 | en, 229 | ); 230 | mainGroup = 8868F9C9190C1CE500F5332C; 231 | productRefGroup = 8868F9D3190C1CE500F5332C /* Products */; 232 | projectDirPath = ""; 233 | projectRoot = ""; 234 | targets = ( 235 | 8868F9D1190C1CE500F5332C /* Curve Interpolation */, 236 | 8868F9EC190C1CE500F5332C /* Curve InterpolationTests */, 237 | ); 238 | }; 239 | /* End PBXProject section */ 240 | 241 | /* Begin PBXResourcesBuildPhase section */ 242 | 8868F9D0190C1CE500F5332C /* Resources */ = { 243 | isa = PBXResourcesBuildPhase; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | 8868F9E0190C1CE500F5332C /* InfoPlist.strings in Resources */, 247 | 8868F9E8190C1CE500F5332C /* Images.xcassets in Resources */, 248 | 8868FA05190C1D1300F5332C /* Main.storyboard in Resources */, 249 | ); 250 | runOnlyForDeploymentPostprocessing = 0; 251 | }; 252 | 8868F9EB190C1CE500F5332C /* Resources */ = { 253 | isa = PBXResourcesBuildPhase; 254 | buildActionMask = 2147483647; 255 | files = ( 256 | 8868F9F9190C1CE500F5332C /* InfoPlist.strings in Resources */, 257 | ); 258 | runOnlyForDeploymentPostprocessing = 0; 259 | }; 260 | /* End PBXResourcesBuildPhase section */ 261 | 262 | /* Begin PBXSourcesBuildPhase section */ 263 | 8868F9CE190C1CE500F5332C /* Sources */ = { 264 | isa = PBXSourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | 88B642AB190C22FF00B6B5F3 /* CRVINTERGraphicsView.m in Sources */, 268 | 88B642BA190C2A2900B6B5F3 /* CRVINTERViewController.m in Sources */, 269 | 88B642B7190C240200B6B5F3 /* UIBezierPath+Interpolation.m in Sources */, 270 | 8868F9E2190C1CE500F5332C /* main.m in Sources */, 271 | 88B642B2190C23CF00B6B5F3 /* CGPointExtension.m in Sources */, 272 | 8868F9E6190C1CE500F5332C /* CRVINTERAppDelegate.m in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | 8868F9E9190C1CE500F5332C /* Sources */ = { 277 | isa = PBXSourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | 8868F9FB190C1CE500F5332C /* Curve_InterpolationTests.m in Sources */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | /* End PBXSourcesBuildPhase section */ 285 | 286 | /* Begin PBXTargetDependency section */ 287 | 8868F9F3190C1CE500F5332C /* PBXTargetDependency */ = { 288 | isa = PBXTargetDependency; 289 | target = 8868F9D1190C1CE500F5332C /* Curve Interpolation */; 290 | targetProxy = 8868F9F2190C1CE500F5332C /* PBXContainerItemProxy */; 291 | }; 292 | /* End PBXTargetDependency section */ 293 | 294 | /* Begin PBXVariantGroup section */ 295 | 8868F9DE190C1CE500F5332C /* InfoPlist.strings */ = { 296 | isa = PBXVariantGroup; 297 | children = ( 298 | 8868F9DF190C1CE500F5332C /* en */, 299 | ); 300 | name = InfoPlist.strings; 301 | sourceTree = ""; 302 | }; 303 | 8868F9F7190C1CE500F5332C /* InfoPlist.strings */ = { 304 | isa = PBXVariantGroup; 305 | children = ( 306 | 8868F9F8190C1CE500F5332C /* en */, 307 | ); 308 | name = InfoPlist.strings; 309 | sourceTree = ""; 310 | }; 311 | /* End PBXVariantGroup section */ 312 | 313 | /* Begin XCBuildConfiguration section */ 314 | 8868F9FC190C1CE500F5332C /* Debug */ = { 315 | isa = XCBuildConfiguration; 316 | buildSettings = { 317 | ALWAYS_SEARCH_USER_PATHS = NO; 318 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 319 | CLANG_CXX_LIBRARY = "libc++"; 320 | CLANG_ENABLE_MODULES = YES; 321 | CLANG_ENABLE_OBJC_ARC = YES; 322 | CLANG_WARN_BOOL_CONVERSION = YES; 323 | CLANG_WARN_CONSTANT_CONVERSION = YES; 324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 325 | CLANG_WARN_EMPTY_BODY = YES; 326 | CLANG_WARN_ENUM_CONVERSION = YES; 327 | CLANG_WARN_INT_CONVERSION = YES; 328 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | GCC_C_LANGUAGE_STANDARD = gnu99; 333 | GCC_DYNAMIC_NO_PIC = NO; 334 | GCC_OPTIMIZATION_LEVEL = 0; 335 | GCC_PREPROCESSOR_DEFINITIONS = ( 336 | "DEBUG=1", 337 | "$(inherited)", 338 | ); 339 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 340 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 341 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 342 | GCC_WARN_UNDECLARED_SELECTOR = YES; 343 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 344 | GCC_WARN_UNUSED_FUNCTION = YES; 345 | GCC_WARN_UNUSED_VARIABLE = YES; 346 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 347 | ONLY_ACTIVE_ARCH = YES; 348 | SDKROOT = iphoneos; 349 | }; 350 | name = Debug; 351 | }; 352 | 8868F9FD190C1CE500F5332C /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | ALWAYS_SEARCH_USER_PATHS = NO; 356 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 357 | CLANG_CXX_LIBRARY = "libc++"; 358 | CLANG_ENABLE_MODULES = YES; 359 | CLANG_ENABLE_OBJC_ARC = YES; 360 | CLANG_WARN_BOOL_CONVERSION = YES; 361 | CLANG_WARN_CONSTANT_CONVERSION = YES; 362 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 363 | CLANG_WARN_EMPTY_BODY = YES; 364 | CLANG_WARN_ENUM_CONVERSION = YES; 365 | CLANG_WARN_INT_CONVERSION = YES; 366 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 368 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 369 | COPY_PHASE_STRIP = YES; 370 | ENABLE_NS_ASSERTIONS = NO; 371 | GCC_C_LANGUAGE_STANDARD = gnu99; 372 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 373 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 374 | GCC_WARN_UNDECLARED_SELECTOR = YES; 375 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 376 | GCC_WARN_UNUSED_FUNCTION = YES; 377 | GCC_WARN_UNUSED_VARIABLE = YES; 378 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 379 | SDKROOT = iphoneos; 380 | VALIDATE_PRODUCT = YES; 381 | }; 382 | name = Release; 383 | }; 384 | 8868F9FF190C1CE500F5332C /* Debug */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 388 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 389 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 390 | GCC_PREFIX_HEADER = "Curve Interpolation/Curve Interpolation-Prefix.pch"; 391 | INFOPLIST_FILE = "Curve Interpolation/Curve Interpolation-Info.plist"; 392 | PRODUCT_NAME = "$(TARGET_NAME)"; 393 | WRAPPER_EXTENSION = app; 394 | }; 395 | name = Debug; 396 | }; 397 | 8868FA00190C1CE500F5332C /* Release */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 402 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 403 | GCC_PREFIX_HEADER = "Curve Interpolation/Curve Interpolation-Prefix.pch"; 404 | INFOPLIST_FILE = "Curve Interpolation/Curve Interpolation-Info.plist"; 405 | PRODUCT_NAME = "$(TARGET_NAME)"; 406 | WRAPPER_EXTENSION = app; 407 | }; 408 | name = Release; 409 | }; 410 | 8868FA02190C1CE500F5332C /* Debug */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Curve Interpolation.app/Curve Interpolation"; 414 | FRAMEWORK_SEARCH_PATHS = ( 415 | "$(SDKROOT)/Developer/Library/Frameworks", 416 | "$(inherited)", 417 | "$(DEVELOPER_FRAMEWORKS_DIR)", 418 | ); 419 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 420 | GCC_PREFIX_HEADER = "Curve Interpolation/Curve Interpolation-Prefix.pch"; 421 | GCC_PREPROCESSOR_DEFINITIONS = ( 422 | "DEBUG=1", 423 | "$(inherited)", 424 | ); 425 | INFOPLIST_FILE = "Curve InterpolationTests/Curve InterpolationTests-Info.plist"; 426 | PRODUCT_NAME = "$(TARGET_NAME)"; 427 | TEST_HOST = "$(BUNDLE_LOADER)"; 428 | WRAPPER_EXTENSION = xctest; 429 | }; 430 | name = Debug; 431 | }; 432 | 8868FA03190C1CE500F5332C /* Release */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Curve Interpolation.app/Curve Interpolation"; 436 | FRAMEWORK_SEARCH_PATHS = ( 437 | "$(SDKROOT)/Developer/Library/Frameworks", 438 | "$(inherited)", 439 | "$(DEVELOPER_FRAMEWORKS_DIR)", 440 | ); 441 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 442 | GCC_PREFIX_HEADER = "Curve Interpolation/Curve Interpolation-Prefix.pch"; 443 | INFOPLIST_FILE = "Curve InterpolationTests/Curve InterpolationTests-Info.plist"; 444 | PRODUCT_NAME = "$(TARGET_NAME)"; 445 | TEST_HOST = "$(BUNDLE_LOADER)"; 446 | WRAPPER_EXTENSION = xctest; 447 | }; 448 | name = Release; 449 | }; 450 | /* End XCBuildConfiguration section */ 451 | 452 | /* Begin XCConfigurationList section */ 453 | 8868F9CD190C1CE500F5332C /* Build configuration list for PBXProject "Curve Interpolation" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | 8868F9FC190C1CE500F5332C /* Debug */, 457 | 8868F9FD190C1CE500F5332C /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | 8868F9FE190C1CE500F5332C /* Build configuration list for PBXNativeTarget "Curve Interpolation" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | 8868F9FF190C1CE500F5332C /* Debug */, 466 | 8868FA00190C1CE500F5332C /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | 8868FA01190C1CE500F5332C /* Build configuration list for PBXNativeTarget "Curve InterpolationTests" */ = { 472 | isa = XCConfigurationList; 473 | buildConfigurations = ( 474 | 8868FA02190C1CE500F5332C /* Debug */, 475 | 8868FA03190C1CE500F5332C /* Release */, 476 | ); 477 | defaultConfigurationIsVisible = 0; 478 | defaultConfigurationName = Release; 479 | }; 480 | /* End XCConfigurationList section */ 481 | }; 482 | rootObject = 8868F9CA190C1CE500F5332C /* Project object */; 483 | } 484 | -------------------------------------------------------------------------------- /Curve Interpolation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Curve Interpolation.xcodeproj/project.xcworkspace/xcshareddata/Curve Interpolation.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 38F13CF3-011E-47C2-9BD0-0956F17D49C1 9 | IDESourceControlProjectName 10 | Curve Interpolation 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | B26FE351-4204-4EB6-BE11-94DC848A735A 14 | ssh://github.com/jnfisher/ios-curve-interpolation.git 15 | 16 | IDESourceControlProjectPath 17 | Curve Interpolation.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | B26FE351-4204-4EB6-BE11-94DC848A735A 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | ssh://github.com/jnfisher/ios-curve-interpolation.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | B26FE351-4204-4EB6-BE11-94DC848A735A 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | B26FE351-4204-4EB6-BE11-94DC848A735A 36 | IDESourceControlWCCName 37 | Curve Interpolation 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Curve Interpolation.xcodeproj/xcuserdata/johnfisher.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Curve Interpolation.xcodeproj/xcuserdata/johnfisher.xcuserdatad/xcschemes/Curve Interpolation.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Curve Interpolation.xcodeproj/xcuserdata/johnfisher.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Curve Interpolation.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 8868F9D1190C1CE500F5332C 16 | 17 | primary 18 | 19 | 20 | 8868F9EC190C1CE500F5332C 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Curve Interpolation/CGPointExtension.h: -------------------------------------------------------------------------------- 1 | /* cocos2d for iPhone 2 | * http://www.cocos2d-iphone.org 3 | * 4 | * Copyright (c) 2007 Scott Lembcke 5 | * 6 | * Copyright (c) 2010 Lam Pham 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | 27 | /* 28 | * Some of the functions were based on Chipmunk's cpVect.h. 29 | */ 30 | 31 | /** 32 | @file 33 | CGPoint extensions based on Chipmunk's cpVect file. 34 | These extensions work both with CGPoint and cpVect. 35 | 36 | The "ccp" prefix means: "CoCos2d Point" 37 | 38 | Examples: 39 | - ccpAdd( ccp(1,1), ccp(2,2) ); // preferred cocos2d way 40 | - ccpAdd( CGPointMake(1,1), CGPointMake(2,2) ); // also ok but more verbose 41 | 42 | - cpvadd( cpv(1,1), cpv(2,2) ); // way of the chipmunk 43 | - ccpAdd( cpv(1,1), cpv(2,2) ); // mixing chipmunk and cocos2d (avoid) 44 | - cpvadd( CGPointMake(1,1), CGPointMake(2,2) ); // mixing chipmunk and CG (avoid) 45 | */ 46 | 47 | #import 48 | #import 49 | #import 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | /** Helper macro that creates a CGPoint 56 | @return CGPoint 57 | */ 58 | static inline CGPoint ccp( CGFloat x, CGFloat y ) 59 | { 60 | return CGPointMake(x, y); 61 | } 62 | 63 | /** Returns opposite of point. 64 | @return CGPoint 65 | */ 66 | static inline CGPoint 67 | ccpNeg(const CGPoint v) 68 | { 69 | return ccp(-v.x, -v.y); 70 | } 71 | 72 | /** Calculates sum of two points. 73 | @return CGPoint 74 | */ 75 | static inline CGPoint 76 | ccpAdd(const CGPoint v1, const CGPoint v2) 77 | { 78 | return ccp(v1.x + v2.x, v1.y + v2.y); 79 | } 80 | 81 | /** Calculates difference of two points. 82 | @return CGPoint 83 | */ 84 | static inline CGPoint 85 | ccpSub(const CGPoint v1, const CGPoint v2) 86 | { 87 | return ccp(v1.x - v2.x, v1.y - v2.y); 88 | } 89 | 90 | /** Returns point multiplied by given factor. 91 | @return CGPoint 92 | */ 93 | static inline CGPoint 94 | ccpMult(const CGPoint v, const CGFloat s) 95 | { 96 | return ccp(v.x*s, v.y*s); 97 | } 98 | 99 | /** Calculates midpoint between two points. 100 | @return CGPoint 101 | */ 102 | static inline CGPoint 103 | ccpMidpoint(const CGPoint v1, const CGPoint v2) 104 | { 105 | return ccpMult(ccpAdd(v1, v2), 0.5f); 106 | } 107 | 108 | /** Calculates dot product of two points. 109 | @return CGFloat 110 | */ 111 | static inline CGFloat 112 | ccpDot(const CGPoint v1, const CGPoint v2) 113 | { 114 | return v1.x*v2.x + v1.y*v2.y; 115 | } 116 | 117 | /** Calculates cross product of two points. 118 | @return CGFloat 119 | */ 120 | static inline CGFloat 121 | ccpCross(const CGPoint v1, const CGPoint v2) 122 | { 123 | return v1.x*v2.y - v1.y*v2.x; 124 | } 125 | 126 | /** Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0 127 | @return CGPoint 128 | */ 129 | static inline CGPoint 130 | ccpPerp(const CGPoint v) 131 | { 132 | return ccp(-v.y, v.x); 133 | } 134 | 135 | /** Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0 136 | @return CGPoint 137 | */ 138 | static inline CGPoint 139 | ccpRPerp(const CGPoint v) 140 | { 141 | return ccp(v.y, -v.x); 142 | } 143 | 144 | /** Calculates the projection of v1 over v2. 145 | @return CGPoint 146 | */ 147 | static inline CGPoint 148 | ccpProject(const CGPoint v1, const CGPoint v2) 149 | { 150 | return ccpMult(v2, ccpDot(v1, v2)/ccpDot(v2, v2)); 151 | } 152 | 153 | /** Rotates two points. 154 | @return CGPoint 155 | */ 156 | static inline CGPoint 157 | ccpRotate(const CGPoint v1, const CGPoint v2) 158 | { 159 | return ccp(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x); 160 | } 161 | 162 | /** Unrotates two points. 163 | @return CGPoint 164 | */ 165 | static inline CGPoint 166 | ccpUnrotate(const CGPoint v1, const CGPoint v2) 167 | { 168 | return ccp(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y); 169 | } 170 | 171 | /** Calculates the square length of a CGPoint (not calling sqrt() ) 172 | @return CGFloat 173 | */ 174 | static inline CGFloat 175 | ccpLengthSQ(const CGPoint v) 176 | { 177 | return ccpDot(v, v); 178 | } 179 | 180 | /** Calculates the square distance between two points (not calling sqrt() ) 181 | @return CGFloat 182 | */ 183 | static inline CGFloat 184 | ccpDistanceSQ(const CGPoint p1, const CGPoint p2) 185 | { 186 | return ccpLengthSQ(ccpSub(p1, p2)); 187 | } 188 | 189 | /** Calculates distance between point an origin 190 | @return CGFloat 191 | */ 192 | CGFloat ccpLength(const CGPoint v); 193 | 194 | /** Calculates the distance between two points 195 | @return CGFloat 196 | */ 197 | CGFloat ccpDistance(const CGPoint v1, const CGPoint v2); 198 | 199 | /** Returns point multiplied to a length of 1. 200 | @return CGPoint 201 | */ 202 | CGPoint ccpNormalize(const CGPoint v); 203 | 204 | /** Converts radians to a normalized vector. 205 | @return CGPoint 206 | */ 207 | CGPoint ccpForAngle(const CGFloat a); 208 | 209 | /** Converts a vector to radians. 210 | @return CGFloat 211 | */ 212 | CGFloat ccpToAngle(const CGPoint v); 213 | 214 | 215 | /** Clamp a value between from and to. 216 | */ 217 | float clampf(float value, float min_inclusive, float max_inclusive); 218 | 219 | /** Clamp a point between from and to. 220 | */ 221 | CGPoint ccpClamp(CGPoint p, CGPoint from, CGPoint to); 222 | 223 | /** Quickly convert CGSize to a CGPoint 224 | */ 225 | CGPoint ccpFromSize(CGSize s); 226 | 227 | /** Run a math operation function on each point component 228 | * absf, fllorf, ceilf, roundf 229 | * any function that has the signature: float func(float); 230 | * For example: let's try to take the floor of x,y 231 | * ccpCompOp(p,floorf); 232 | */ 233 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)); 234 | 235 | /** Linear Interpolation between two points a and b 236 | @returns 237 | alpha == 0 ? a 238 | alpha == 1 ? b 239 | otherwise a value between a..b 240 | */ 241 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha); 242 | 243 | 244 | /** @returns if points have fuzzy equality which means equal with some degree of variance. 245 | */ 246 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float variance); 247 | 248 | 249 | /** Multiplies a nd b components, a.x*b.x, a.y*b.y 250 | @returns a component-wise multiplication 251 | */ 252 | CGPoint ccpCompMult(CGPoint a, CGPoint b); 253 | 254 | /** @returns the signed angle in radians between two vector directions 255 | */ 256 | float ccpAngleSigned(CGPoint a, CGPoint b); 257 | 258 | /** @returns the angle in radians between two vector directions 259 | */ 260 | float ccpAngle(CGPoint a, CGPoint b); 261 | 262 | /** Rotates a point counter clockwise by the angle around a pivot 263 | @param v is the point to rotate 264 | @param pivot is the pivot, naturally 265 | @param angle is the angle of rotation cw in radians 266 | @returns the rotated point 267 | */ 268 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle); 269 | 270 | /** A general line-line intersection test 271 | @param p1 272 | is the startpoint for the first line P1 = (p1 - p2) 273 | @param p2 274 | is the endpoint for the first line P1 = (p1 - p2) 275 | @param p3 276 | is the startpoint for the second line P2 = (p3 - p4) 277 | @param p4 278 | is the endpoint for the second line P2 = (p3 - p4) 279 | @param s 280 | is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)) 281 | @param t 282 | is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)) 283 | @return bool 284 | indicating successful intersection of a line 285 | note that to truly test intersection for segments we have to make 286 | sure that s & t lie within [0..1] and for rays, make sure s & t > 0 287 | the hit point is p3 + t * (p4 - p3); 288 | the hit point also is p1 + s * (p2 - p1); 289 | */ 290 | BOOL ccpLineIntersect(CGPoint p1, CGPoint p2, 291 | CGPoint p3, CGPoint p4, 292 | float *s, float *t); 293 | 294 | /* 295 | ccpSegmentIntersect returns YES if Segment A-B intersects with segment C-D 296 | */ 297 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D); 298 | 299 | /* 300 | ccpIntersectPoint returns the intersection point of line A-B, C-D 301 | */ 302 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D); 303 | 304 | #ifdef __cplusplus 305 | } 306 | #endif 307 | -------------------------------------------------------------------------------- /Curve Interpolation/CGPointExtension.m: -------------------------------------------------------------------------------- 1 | /* cocos2d for iPhone 2 | * http://www.cocos2d-iphone.org 3 | * 4 | * Copyright (c) 2007 Scott Lembcke 5 | * 6 | * Copyright (c) 2010 Lam Pham 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | * SOFTWARE. 25 | */ 26 | 27 | #include "stdio.h" 28 | #include "math.h" 29 | #include "CGPointExtension.h" 30 | 31 | #define kCGPointEpsilon FLT_EPSILON 32 | 33 | CGFloat 34 | ccpLength(const CGPoint v) 35 | { 36 | return sqrtf(ccpLengthSQ(v)); 37 | } 38 | 39 | CGFloat 40 | ccpDistance(const CGPoint v1, const CGPoint v2) 41 | { 42 | return ccpLength(ccpSub(v1, v2)); 43 | } 44 | 45 | CGPoint 46 | ccpNormalize(const CGPoint v) 47 | { 48 | return ccpMult(v, 1.0f/ccpLength(v)); 49 | } 50 | 51 | CGPoint 52 | ccpForAngle(const CGFloat a) 53 | { 54 | return ccp(cosf(a), sinf(a)); 55 | } 56 | 57 | CGFloat 58 | ccpToAngle(const CGPoint v) 59 | { 60 | return atan2f(v.y, v.x); 61 | } 62 | 63 | CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha) 64 | { 65 | return ccpAdd(ccpMult(a, 1.f - alpha), ccpMult(b, alpha)); 66 | } 67 | 68 | float clampf(float value, float min_inclusive, float max_inclusive) 69 | { 70 | if (min_inclusive > max_inclusive) { 71 | float tmp=min_inclusive; 72 | min_inclusive = max_inclusive; 73 | max_inclusive = tmp; 74 | } 75 | return value < min_inclusive ? min_inclusive : value < max_inclusive? value : max_inclusive; 76 | } 77 | 78 | CGPoint ccpClamp(CGPoint p, CGPoint min_inclusive, CGPoint max_inclusive) 79 | { 80 | return ccp(clampf(p.x,min_inclusive.x,max_inclusive.x), clampf(p.y, min_inclusive.y, max_inclusive.y)); 81 | } 82 | 83 | CGPoint ccpFromSize(CGSize s) 84 | { 85 | return ccp(s.width, s.height); 86 | } 87 | 88 | CGPoint ccpCompOp(CGPoint p, float (*opFunc)(float)) 89 | { 90 | return ccp(opFunc(p.x), opFunc(p.y)); 91 | } 92 | 93 | BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float var) 94 | { 95 | if(a.x - var <= b.x && b.x <= a.x + var) 96 | if(a.y - var <= b.y && b.y <= a.y + var) 97 | return true; 98 | return false; 99 | } 100 | 101 | CGPoint ccpCompMult(CGPoint a, CGPoint b) 102 | { 103 | return ccp(a.x * b.x, a.y * b.y); 104 | } 105 | 106 | float ccpAngleSigned(CGPoint a, CGPoint b) 107 | { 108 | CGPoint a2 = ccpNormalize(a); 109 | CGPoint b2 = ccpNormalize(b); 110 | float angle = atan2f(a2.x * b2.y - a2.y * b2.x, ccpDot(a2, b2)); 111 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; 112 | return angle; 113 | } 114 | 115 | CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle) 116 | { 117 | CGPoint r = ccpSub(v, pivot); 118 | float cosa = cosf(angle), sina = sinf(angle); 119 | float t = r.x; 120 | r.x = t*cosa - r.y*sina + pivot.x; 121 | r.y = t*sina + r.y*cosa + pivot.y; 122 | return r; 123 | } 124 | 125 | 126 | BOOL ccpSegmentIntersect(CGPoint A, CGPoint B, CGPoint C, CGPoint D) 127 | { 128 | float S, T; 129 | 130 | if( ccpLineIntersect(A, B, C, D, &S, &T ) 131 | && (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f) ) 132 | return YES; 133 | 134 | return NO; 135 | } 136 | 137 | CGPoint ccpIntersectPoint(CGPoint A, CGPoint B, CGPoint C, CGPoint D) 138 | { 139 | float S, T; 140 | 141 | if( ccpLineIntersect(A, B, C, D, &S, &T) ) { 142 | // Point of intersection 143 | CGPoint P; 144 | P.x = A.x + S * (B.x - A.x); 145 | P.y = A.y + S * (B.y - A.y); 146 | return P; 147 | } 148 | 149 | return CGPointZero; 150 | } 151 | 152 | BOOL ccpLineIntersect(CGPoint A, CGPoint B, 153 | CGPoint C, CGPoint D, 154 | float *S, float *T) 155 | { 156 | // FAIL: Line undefined 157 | if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) return NO; 158 | 159 | const float BAx = B.x - A.x; 160 | const float BAy = B.y - A.y; 161 | const float DCx = D.x - C.x; 162 | const float DCy = D.y - C.y; 163 | const float ACx = A.x - C.x; 164 | const float ACy = A.y - C.y; 165 | 166 | const float denom = DCy*BAx - DCx*BAy; 167 | 168 | *S = DCx*ACy - DCy*ACx; 169 | *T = BAx*ACy - BAy*ACx; 170 | 171 | if (denom == 0) { 172 | if (*S == 0 || *T == 0) { 173 | // Lines incident 174 | return YES; 175 | } 176 | // Lines parallel and not incident 177 | return NO; 178 | } 179 | 180 | *S = *S / denom; 181 | *T = *T / denom; 182 | 183 | // Point of intersection 184 | // CGPoint P; 185 | // P.x = A.x + *S * (B.x - A.x); 186 | // P.y = A.y + *S * (B.y - A.y); 187 | 188 | return YES; 189 | } 190 | 191 | float ccpAngle(CGPoint a, CGPoint b) 192 | { 193 | float angle = acosf(ccpDot(ccpNormalize(a), ccpNormalize(b))); 194 | if( fabs(angle) < kCGPointEpsilon ) return 0.f; 195 | return angle; 196 | } 197 | -------------------------------------------------------------------------------- /Curve Interpolation/CRVINTERAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRVINTERAppDelegate.h 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CRVINTERAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Curve Interpolation/CRVINTERAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRVINTERAppDelegate.m 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import "CRVINTERAppDelegate.h" 10 | 11 | @implementation CRVINTERAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | return YES; 16 | } 17 | 18 | - (void)applicationWillResignActive:(UIApplication *)application 19 | { 20 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 21 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 22 | } 23 | 24 | - (void)applicationDidEnterBackground:(UIApplication *)application 25 | { 26 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 27 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 28 | } 29 | 30 | - (void)applicationWillEnterForeground:(UIApplication *)application 31 | { 32 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 33 | } 34 | 35 | - (void)applicationDidBecomeActive:(UIApplication *)application 36 | { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | - (void)applicationWillTerminate:(UIApplication *)application 41 | { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Curve Interpolation/CRVINTERGraphicsView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRVINTERGraphicsView.h 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CRVINTERGraphicsView : UIView 12 | @property (strong, nonatomic) NSMutableArray *interpolationPoints; 13 | 14 | - (void) setIsClosed:(BOOL)closed; 15 | - (void) setAlpha:(float)alpha; 16 | - (void) setUseHermite:(BOOL)useHermite; 17 | @end 18 | -------------------------------------------------------------------------------- /Curve Interpolation/CRVINTERGraphicsView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRVINTERGraphicsView.m 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import "CRVINTERGraphicsView.h" 10 | #import "UIBezierPath+Interpolation.h" 11 | 12 | @interface CRVINTERGraphicsView() { 13 | BOOL _closed; 14 | float _alpha; 15 | BOOL _useHermite; 16 | } 17 | 18 | @end 19 | 20 | @implementation CRVINTERGraphicsView 21 | 22 | - (id)initWithFrame:(CGRect)frame { 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | _closed = NO; 26 | _alpha = 0.5; 27 | _useHermite = NO; 28 | self.interpolationPoints = [NSMutableArray new]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)drawRect:(CGRect)rect { 34 | // Dashed line drawing 35 | UIBezierPath *dashedConnectors; 36 | for (int ii=0; ii < [self.interpolationPoints count]; ++ii) { 37 | NSValue *pv = self.interpolationPoints[ii]; 38 | CGPoint point; 39 | [pv getValue:&point]; 40 | 41 | if ([self.interpolationPoints count] > 1) { 42 | if (ii == 0) { 43 | dashedConnectors = [UIBezierPath new]; 44 | [dashedConnectors moveToPoint:point]; 45 | } 46 | else { 47 | [dashedConnectors addLineToPoint:point]; 48 | } 49 | } 50 | } 51 | 52 | if (_closed) 53 | [dashedConnectors closePath]; 54 | 55 | CGFloat dashedConnectorsPattern[] = {3, 3, 3, 3}; 56 | dashedConnectors.lineWidth = 0.5; 57 | [[UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:1.0] setStroke]; 58 | [dashedConnectors setLineDash: dashedConnectorsPattern count: 4 phase: 0]; 59 | [dashedConnectors stroke]; 60 | 61 | // Interpolation points drawing 62 | for (NSValue *pv in self.interpolationPoints) { 63 | CGPoint point; 64 | [pv getValue:&point]; 65 | 66 | UIBezierPath *pointPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(point.x-2, point.y-2, 4, 4)]; 67 | [[UIColor redColor] setFill]; 68 | [pointPath fill]; 69 | } 70 | 71 | // Curve drawing 72 | UIBezierPath *path; 73 | if (_useHermite) { 74 | path = [UIBezierPath interpolateCGPointsWithHermite:self.interpolationPoints closed:_closed]; 75 | } 76 | else { 77 | path = [UIBezierPath interpolateCGPointsWithCatmullRom:self.interpolationPoints closed:_closed alpha:_alpha]; 78 | } 79 | 80 | if (path) { 81 | [[UIColor blackColor] setStroke]; 82 | path.lineWidth = 1.0; 83 | [path stroke]; 84 | } 85 | } 86 | 87 | - (void) setIsClosed:(BOOL)closed { 88 | _closed = closed; 89 | } 90 | 91 | - (void) setAlpha:(float)alpha { 92 | _alpha = alpha; 93 | } 94 | 95 | - (void) setUseHermite:(BOOL)useHermite { 96 | _useHermite = useHermite; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Curve Interpolation/CRVINTERViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRVINTERViewController.h 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CRVINTERViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Curve Interpolation/CRVINTERViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRVINTERViewController.m 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import "CRVINTERViewController.h" 10 | #import "CRVINTERGraphicsView.h" 11 | 12 | @interface CRVINTERViewController () { 13 | float controlHeightForCatmull; 14 | float controlHeightForHermite; 15 | } 16 | @property (strong, nonatomic) IBOutlet UISegmentedControl *hermiteCatmull; 17 | @property (strong, nonatomic) IBOutlet UISlider *alphaSlider; 18 | @property (strong, nonatomic) IBOutlet UISwitch *closedSwitch; 19 | @property (strong, nonatomic) IBOutlet CRVINTERGraphicsView *graphicsView; 20 | @property (strong, nonatomic) IBOutlet UILabel *alphaLabel; 21 | @property (strong, nonatomic) IBOutlet UIButton *clearButton; 22 | @property (strong, nonatomic) IBOutlet UILabel *alphaTitle; 23 | 24 | @property UITapGestureRecognizer *gestureRecognizer; 25 | @property (strong, nonatomic) IBOutlet UILabel *noPointsHelperLabel; 26 | 27 | - (IBAction)clearDataPoints:(UIButton *)sender; 28 | - (IBAction)alphaChanged:(UISlider *)sender; 29 | - (IBAction)hermiteCatmullChanged:(UISegmentedControl *)sender; 30 | - (IBAction)closeChanged:(UISwitch *)sender; 31 | 32 | @end 33 | 34 | @implementation CRVINTERViewController 35 | 36 | - (void)updateGraphicsView { 37 | self.alphaLabel.text = [NSString stringWithFormat:@"%.2f", self.alphaSlider.value]; 38 | [self.graphicsView setIsClosed:self.closedSwitch.on]; 39 | [self.graphicsView setAlpha:self.alphaSlider.value]; 40 | [self.graphicsView setUseHermite:(self.hermiteCatmull.selectedSegmentIndex == 0)]; 41 | [self.graphicsView setNeedsDisplay]; 42 | } 43 | 44 | - (void)animateHelpText:(float)toAlpha { 45 | float startAlpha = (toAlpha == 0.0 ? 1.0 : 0.0); 46 | if (self.noPointsHelperLabel.alpha == startAlpha) { 47 | [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseIn 48 | animations:^{ self.noPointsHelperLabel.alpha = toAlpha;} 49 | completion:nil]; 50 | } 51 | } 52 | 53 | - (void)viewDidLoad 54 | { 55 | [super viewDidLoad]; 56 | 57 | self.clearButton.layer.cornerRadius = 4; 58 | self.clearButton.clipsToBounds = YES; 59 | self.closedSwitch.onTintColor = [UIColor colorWithRed:0 green:122.0/255.0f blue:1.0 alpha:1.0]; 60 | self.closedSwitch.tintColor = [UIColor colorWithRed:180.0/255.0f green:180.0/255.0f blue:180.0/255.0f alpha:1.0]; 61 | 62 | self.gestureRecognizer = [[UITapGestureRecognizer alloc] 63 | initWithTarget:self 64 | action:@selector(tapped:)]; 65 | self.gestureRecognizer.delegate = self; 66 | self.gestureRecognizer.numberOfTapsRequired = 1; 67 | self.gestureRecognizer.numberOfTouchesRequired = 1; 68 | [self.graphicsView addGestureRecognizer:self.gestureRecognizer]; 69 | 70 | self.alphaLabel.hidden = YES; 71 | self.alphaTitle.hidden = YES; 72 | self.alphaSlider.hidden = YES; 73 | 74 | [self clearDataPoints:nil]; 75 | [self updateGraphicsView]; 76 | } 77 | 78 | - (IBAction)clearDataPoints:(UIButton *)sender { 79 | [self animateHelpText:1.0]; 80 | self.graphicsView.interpolationPoints = [NSMutableArray new]; 81 | [self updateGraphicsView]; 82 | } 83 | 84 | - (IBAction)alphaChanged:(UISlider *)sender { 85 | [self updateGraphicsView]; 86 | } 87 | 88 | - (IBAction)hermiteCatmullChanged:(UISegmentedControl *)sender { 89 | BOOL isHermite = (self.hermiteCatmull.selectedSegmentIndex == 0); 90 | self.alphaLabel.hidden = isHermite; 91 | self.alphaTitle.hidden = isHermite; 92 | self.alphaSlider.hidden = isHermite; 93 | 94 | [self updateGraphicsView]; 95 | } 96 | 97 | - (IBAction)closeChanged:(UISwitch *)sender { 98 | [self updateGraphicsView]; 99 | } 100 | 101 | -(void)tapped:(UITapGestureRecognizer *)gesture { 102 | [self animateHelpText:0.0]; 103 | CGPoint touchedPt = [gesture locationOfTouch:0 inView:self.graphicsView]; 104 | const char *encoding = @encode(CGPoint); 105 | [self.graphicsView.interpolationPoints addObject:[NSValue valueWithBytes:&touchedPt objCType:encoding]]; 106 | [self updateGraphicsView]; 107 | } 108 | @end 109 | -------------------------------------------------------------------------------- /Curve Interpolation/Curve Interpolation-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.JohnFisher.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Curve Interpolation/Curve Interpolation-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /Curve Interpolation/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Curve Interpolation/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Curve Interpolation/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 89 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /Curve Interpolation/UIBezierPath+Interpolation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIBezierPath+Interpolation.h 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIBezierPath (Interpolation) 12 | 13 | // pointsAsNSValues must be NSValue objects containing CGPoints. 14 | // 15 | // ex: 16 | // const char *encoding = @encode(CGPoint); 17 | // NSValue *pointAsValue = [NSValue valueWithBytes:&cgPoint objCType:encoding]; 18 | 19 | // 0.0 <= alpha <= 1.0 20 | +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha; 21 | +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues closed:(BOOL)closed; 22 | @end 23 | -------------------------------------------------------------------------------- /Curve Interpolation/UIBezierPath+Interpolation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIBezierPath+Interpolation.m 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import "UIBezierPath+Interpolation.h" 10 | #import "CGPointExtension.h" 11 | 12 | #define kEPSILON 1.0e-5 13 | 14 | @implementation UIBezierPath (Interpolation) 15 | 16 | +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha { 17 | if ([pointsAsNSValues count] < 4) 18 | return nil; 19 | 20 | NSInteger endIndex = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-2); 21 | NSAssert(alpha >= 0.0 && alpha <= 1.0, @"alpha value is between 0.0 and 1.0, inclusive"); 22 | 23 | UIBezierPath *path = [UIBezierPath bezierPath]; 24 | NSInteger startIndex = (closed ? 0 : 1); 25 | for (NSInteger ii=startIndex; ii < endIndex; ++ii) { 26 | CGPoint p0, p1, p2, p3; 27 | NSInteger nextii = (ii+1)%[pointsAsNSValues count]; 28 | NSInteger nextnextii = (nextii+1)%[pointsAsNSValues count]; 29 | NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1); 30 | 31 | [pointsAsNSValues[ii] getValue:&p1]; 32 | [pointsAsNSValues[previi] getValue:&p0]; 33 | [pointsAsNSValues[nextii] getValue:&p2]; 34 | [pointsAsNSValues[nextnextii] getValue:&p3]; 35 | 36 | CGFloat d1 = ccpLength(ccpSub(p1, p0)); 37 | CGFloat d2 = ccpLength(ccpSub(p2, p1)); 38 | CGFloat d3 = ccpLength(ccpSub(p3, p2)); 39 | 40 | CGPoint b1, b2; 41 | if (fabs(d1) < kEPSILON) { 42 | b1 = p1; 43 | } 44 | else { 45 | b1 = ccpMult(p2, powf(d1, 2*alpha)); 46 | b1 = ccpSub(b1, ccpMult(p0, powf(d2, 2*alpha))); 47 | b1 = ccpAdd(b1, ccpMult(p1,(2*powf(d1, 2*alpha) + 3*powf(d1, alpha)*powf(d2, alpha) + powf(d2, 2*alpha)))); 48 | b1 = ccpMult(b1, 1.0 / (3*powf(d1, alpha)*(powf(d1, alpha)+powf(d2, alpha)))); 49 | } 50 | 51 | if (fabs(d3) < kEPSILON) { 52 | b2 = p2; 53 | } 54 | else { 55 | b2 = ccpMult(p1, powf(d3, 2*alpha)); 56 | b2 = ccpSub(b2, ccpMult(p3, powf(d2, 2*alpha))); 57 | b2 = ccpAdd(b2, ccpMult(p2,(2*powf(d3, 2*alpha) + 3*powf(d3, alpha)*powf(d2, alpha) + powf(d2, 2*alpha)))); 58 | b2 = ccpMult(b2, 1.0 / (3*powf(d3, alpha)*(powf(d3, alpha)+powf(d2, alpha)))); 59 | } 60 | 61 | if (ii==startIndex) 62 | [path moveToPoint:p1]; 63 | 64 | [path addCurveToPoint:p2 controlPoint1:b1 controlPoint2:b2]; 65 | } 66 | 67 | if (closed) 68 | [path closePath]; 69 | 70 | return path; 71 | } 72 | 73 | +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues closed:(BOOL)closed { 74 | if ([pointsAsNSValues count] < 2) 75 | return nil; 76 | 77 | NSInteger nCurves = (closed ? [pointsAsNSValues count] : [pointsAsNSValues count]-1); 78 | 79 | UIBezierPath *path = [UIBezierPath bezierPath]; 80 | for (NSInteger ii=0; ii < nCurves; ++ii) { 81 | NSValue *value = pointsAsNSValues[ii]; 82 | 83 | CGPoint curPt, prevPt, nextPt, endPt; 84 | [value getValue:&curPt]; 85 | if (ii==0) 86 | [path moveToPoint:curPt]; 87 | 88 | NSInteger nextii = (ii+1)%[pointsAsNSValues count]; 89 | NSInteger previi = (ii-1 < 0 ? [pointsAsNSValues count]-1 : ii-1); 90 | 91 | [pointsAsNSValues[previi] getValue:&prevPt]; 92 | [pointsAsNSValues[nextii] getValue:&nextPt]; 93 | endPt = nextPt; 94 | 95 | CGFloat mx, my; 96 | if (closed || ii > 0) { 97 | mx = (nextPt.x - curPt.x)*0.5 + (curPt.x - prevPt.x)*0.5; 98 | my = (nextPt.y - curPt.y)*0.5 + (curPt.y - prevPt.y)*0.5; 99 | } 100 | else { 101 | mx = (nextPt.x - curPt.x)*0.5; 102 | my = (nextPt.y - curPt.y)*0.5; 103 | } 104 | 105 | CGPoint ctrlPt1; 106 | ctrlPt1.x = curPt.x + mx / 3.0; 107 | ctrlPt1.y = curPt.y + my / 3.0; 108 | 109 | [pointsAsNSValues[nextii] getValue:&curPt]; 110 | 111 | nextii = (nextii+1)%[pointsAsNSValues count]; 112 | previi = ii; 113 | 114 | [pointsAsNSValues[previi] getValue:&prevPt]; 115 | [pointsAsNSValues[nextii] getValue:&nextPt]; 116 | 117 | if (closed || ii < nCurves-1) { 118 | mx = (nextPt.x - curPt.x)*0.5 + (curPt.x - prevPt.x)*0.5; 119 | my = (nextPt.y - curPt.y)*0.5 + (curPt.y - prevPt.y)*0.5; 120 | } 121 | else { 122 | mx = (curPt.x - prevPt.x)*0.5; 123 | my = (curPt.y - prevPt.y)*0.5; 124 | } 125 | 126 | CGPoint ctrlPt2; 127 | ctrlPt2.x = curPt.x - mx / 3.0; 128 | ctrlPt2.y = curPt.y - my / 3.0; 129 | 130 | [path addCurveToPoint:endPt controlPoint1:ctrlPt1 controlPoint2:ctrlPt2]; 131 | } 132 | 133 | if (closed) 134 | [path closePath]; 135 | 136 | return path; 137 | } 138 | 139 | 140 | @end 141 | -------------------------------------------------------------------------------- /Curve Interpolation/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Curve Interpolation/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Curve Interpolation 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CRVINTERAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([CRVINTERAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Curve InterpolationTests/Curve InterpolationTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.JohnFisher.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Curve InterpolationTests/Curve_InterpolationTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Curve_InterpolationTests.m 3 | // Curve InterpolationTests 4 | // 5 | // Created by John Fisher on 4/26/14. 6 | // Copyright (c) 2014 John Fisher. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Curve_InterpolationTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Curve_InterpolationTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Curve InterpolationTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) {{{year}}} {{{fullname}}} 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Synopsis 2 | iOS Curve Interpolation consists of two main components: 3 | - A category on UIBezierCurvePath, UIBezierCurvePath+Interpolation. 4 | - A small iOS app that demonstrates the categories use. 5 | 6 | ## Example 7 | ```C 8 | #include "UIBezierCurvePath+Interpolation.h" 9 | 10 | const char *encoding = @encode(CGPoint); 11 | 12 | NSMutableArray *array = [NSMutableArray new]; 13 | 14 | // Add 4 CGPoints as NSValue 15 | [array addObject:[NSValue valueWithBytes:&CGPointMake(0.0, 0.0) objCType:encoding]; 16 | [array addObject:[NSValue valueWithBytes:&CGPointMake(0.0, 1.0) objCType:encoding]; 17 | [array addObject:[NSValue valueWithBytes:&CGPointMake(1.0, 1.0) objCType:encoding]; 18 | [array addObject:[NSValue valueWithBytes:&CGPointMake(1.0, 0.0) objCType:encoding]; 19 | 20 | UIBezierPath *path = [interpolateCGPointsWithCatmullRom:array closed:NO alpha:0.5]; 21 | // Use the path 22 | ``` 23 | 24 | ## Motivation 25 | To add an easy-to-use category for curve interpolation onto UIBezierPath. Also to provide a small iOS app for demonstrating/testing the interpolation inputs (Hermite vs. Catmull-Rom, alpha value effects, and open/closed option). 26 | 27 | ## Installation 28 | Clone the repo, open the Xcode project in Xcode 5+. 29 | 30 | The UIBezierPath+Interpolation.h/.m is standalone, provided you also include CGPointExtension.h/.m (which are also included in the Xcode project). 31 | 32 | ## API Reference 33 | ```C 34 | // pointsAsNSValues must be NSValue objects containing CGPoints. 35 | // 36 | // ex: 37 | // const char *encoding = @encode(CGPoint); 38 | // NSValue *pointAsValue = [NSValue valueWithBytes:&cgPoint objCType:encoding]; 39 | 40 | // 0.0 <= alpha <= 1.0 41 | +(UIBezierPath *)interpolateCGPointsWithCatmullRom:(NSArray *)pointsAsNSValues closed:(BOOL)closed alpha:(float)alpha; 42 | +(UIBezierPath *)interpolateCGPointsWithHermite:(NSArray *)pointsAsNSValues closed:(BOOL)closed; 43 | ``` 44 | --------------------------------------------------------------------------------