git.iko.soy/metal-metaballs
on 038568f help sign in
.gitignore+1−6
since splitsnapshots
unifiedsplit
@@ -1,8 +1,3 @@
1.DS*
1.DS*
2PixelImage.xcodeproj/xcuserdata/*
2PixelImage.xcodeproj/xcuserdata/*
3−PixelImage.xcodeproj/project.xcworkspace/xcuserdata/*
3+PixelImage.xcodeproj/project.xcworkspace/xcuserdata/*
4−PixelImage.xcworkspace/xcuserdata/*
5−
6−Pods/*
7−
8−
.tailor.ymldeleted−14
@@ -1,14 +0,0 @@
1−
2−
3−# Tailor will check for violations to all rules except for the following ones
4−except:
5− - constant-k-prefix
6− - function-whitespace
7− - leading-whitespace
8−
9−# include:
10−# - Source # Inspect all Swift files under "Source/"
11−exclude:
12− - Pods # Ignore Swift files under "Pods/"
13− - PixelImage/SwiftSugar/SwiftSequences
14−
Examples/Animation.gifdeleted

Binary file not shown.

PixelImage.xcodeproj/project.pbxproj+147−125
@@ -12,25 +12,45 @@
12 2426868D1C63B72A00D62456 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2426868B1C63B72A00D62456 /* Main.storyboard */; };
12 2426868D1C63B72A00D62456 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2426868B1C63B72A00D62456 /* Main.storyboard */; };
13 2426868F1C63B72A00D62456 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2426868E1C63B72A00D62456 /* Assets.xcassets */; };
13 2426868F1C63B72A00D62456 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2426868E1C63B72A00D62456 /* Assets.xcassets */; };
14 242686921C63B72A00D62456 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 242686901C63B72A00D62456 /* LaunchScreen.storyboard */; };
14 242686921C63B72A00D62456 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 242686901C63B72A00D62456 /* LaunchScreen.storyboard */; };
15− 2461651B1C6DA4F400A913C8 /* Interpolation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461651A1C6DA4F400A913C8 /* Interpolation.swift */; };
16− 246B0F831C70635D00A71D05 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 246B0F821C70635D00A71D05 /* UIColor.swift */; };
17− 249CF84C1C6D113C008B0C78 /* Matrix.swift in Sources */ = {isa = PBXBuildFile; fileRef = 249CF84B1C6D113C008B0C78 /* Matrix.swift */; };
18 24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */; };
15 24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */; };
16+ 24E1E7D91C67C9C900ECF1C4 /* MetaballRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7D81C67C9C900ECF1C4 /* MetaballRenderer.swift */; };
17+ 24E1E7DB1C67CA3600ECF1C4 /* ImageMetaballRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7DA1C67CA3600ECF1C4 /* ImageMetaballRenderer.swift */; };
19 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */; };
18 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */; };
20 24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E31C67D39300ECF1C4 /* MetalKit.framework */; };
19 24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E1E7E31C67D39300ECF1C4 /* MetalKit.framework */; };
21 24E1E7EB1C67D70300ECF1C4 /* MetalMetaballRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */; };
20 24E1E7EB1C67D70300ECF1C4 /* MetalMetaballRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */; };
22 24E1E7F01C67D74300ECF1C4 /* Metal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */; };
21 24E1E7F01C67D74300ECF1C4 /* Metal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */; };
23 24E1E7F11C67D74300ECF1C4 /* shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7EF1C67D74300ECF1C4 /* shaders.metal */; };
22 24E1E7F11C67D74300ECF1C4 /* shaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 24E1E7EF1C67D74300ECF1C4 /* shaders.metal */; };
24− 24ED21CD1C6C2397009C40FC /* MetaballDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */; };
23+ 24FFA86B1C6BA038005ACD60 /* ApproximationOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84C1C6BA038005ACD60 /* ApproximationOperator.swift */; };
25− 24FC38341C7F931E0085C04A /* Metaball.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FC38331C7F931E0085C04A /* Metaball.swift */; };
24+ 24FFA86C1C6BA038005ACD60 /* Collections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84D1C6BA038005ACD60 /* Collections.swift */; };
26− 24FC38361C7F9ABE0085C04A /* Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FC38351C7F9ABE0085C04A /* Dispatch.swift */; };
25+ 24FFA86D1C6BA038005ACD60 /* ComparatorChains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84E1C6BA038005ACD60 /* ComparatorChains.swift */; };
26+ 24FFA86E1C6BA038005ACD60 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA84F1C6BA038005ACD60 /* Dictionary.swift */; };
27+ 24FFA86F1C6BA038005ACD60 /* NSNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8511C6BA038005ACD60 /* NSNumber.swift */; };
27 24FFA8701C6BA038005ACD60 /* Numeric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8521C6BA038005ACD60 /* Numeric.swift */; };
28 24FFA8701C6BA038005ACD60 /* Numeric.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8521C6BA038005ACD60 /* Numeric.swift */; };
28 24FFA8711C6BA038005ACD60 /* PowerOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8531C6BA038005ACD60 /* PowerOperator.swift */; };
29 24FFA8711C6BA038005ACD60 /* PowerOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8531C6BA038005ACD60 /* PowerOperator.swift */; };
29− 400CECBA73C835B415805169 /* Pods_PixelImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D10DBF530542A19EEF699A /* Pods_PixelImage.framework */; };
30+ 24FFA8721C6BA038005ACD60 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8541C6BA038005ACD60 /* Sequence.swift */; };
31+ 24FFA8731C6BA038005ACD60 /* Memoize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8561C6BA038005ACD60 /* Memoize.swift */; };
32+ 24FFA8741C6BA038005ACD60 /* SignOperator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8571C6BA038005ACD60 /* SignOperator.swift */; };
33+ 24FFA8751C6BA038005ACD60 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8581C6BA038005ACD60 /* String.swift */; };
34+ 24FFA8761C6BA038005ACD60 /* Categorise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85A1C6BA038005ACD60 /* Categorise.swift */; };
35+ 24FFA8771C6BA038005ACD60 /* ChunkWindowSplit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85B1C6BA038005ACD60 /* ChunkWindowSplit.swift */; };
36+ 24FFA8781C6BA038005ACD60 /* Combinations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85C1C6BA038005ACD60 /* Combinations.swift */; };
37+ 24FFA8791C6BA038005ACD60 /* Cycle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85D1C6BA038005ACD60 /* Cycle.swift */; };
38+ 24FFA87A1C6BA038005ACD60 /* Enumerate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85E1C6BA038005ACD60 /* Enumerate.swift */; };
39+ 24FFA87B1C6BA038005ACD60 /* Finding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA85F1C6BA038005ACD60 /* Finding.swift */; };
40+ 24FFA87C1C6BA038005ACD60 /* FlatMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8601C6BA038005ACD60 /* FlatMap.swift */; };
41+ 24FFA87D1C6BA038005ACD60 /* Hopping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8611C6BA038005ACD60 /* Hopping.swift */; };
42+ 24FFA87E1C6BA038005ACD60 /* Interpose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8621C6BA038005ACD60 /* Interpose.swift */; };
43+ 24FFA87F1C6BA038005ACD60 /* Iterate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8631C6BA038005ACD60 /* Iterate.swift */; };
44+ 24FFA8801C6BA038005ACD60 /* NestedSequences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8641C6BA038005ACD60 /* NestedSequences.swift */; };
45+ 24FFA8811C6BA038005ACD60 /* Permutations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8651C6BA038005ACD60 /* Permutations.swift */; };
46+ 24FFA8821C6BA038005ACD60 /* ScanReduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8661C6BA038005ACD60 /* ScanReduce.swift */; };
47+ 24FFA8831C6BA038005ACD60 /* Slicing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8671C6BA038005ACD60 /* Slicing.swift */; };
48+ 24FFA8841C6BA038005ACD60 /* TakeDrop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */; };
49+ 24FFA8851C6BA038005ACD60 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA8691C6BA038005ACD60 /* Zip.swift */; };
50+ 24FFA8861C6BA038005ACD60 /* TestCommons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */; };
30/* End PBXBuildFile section */
51/* End PBXBuildFile section */
31
52
32/* Begin PBXFileReference section */
53/* Begin PBXFileReference section */
33− 0C9CE70F7D2C2896912B7B14 /* Pods-PixelImage.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.release.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.release.xcconfig"; sourceTree = "<group>"; };
34 242686841C63B72A00D62456 /* PixelImage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PixelImage.app; sourceTree = BUILT_PRODUCTS_DIR; };
54 242686841C63B72A00D62456 /* PixelImage.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PixelImage.app; sourceTree = BUILT_PRODUCTS_DIR; };
35 242686871C63B72A00D62456 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
55 242686871C63B72A00D62456 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
36 242686891C63B72A00D62456 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
56 242686891C63B72A00D62456 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
@@ -38,22 +58,42 @@
38 2426868E1C63B72A00D62456 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
58 2426868E1C63B72A00D62456 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
39 242686911C63B72A00D62456 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
59 242686911C63B72A00D62456 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
40 242686931C63B72A00D62456 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
60 242686931C63B72A00D62456 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
41− 2461651A1C6DA4F400A913C8 /* Interpolation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Interpolation.swift; path = PixelImage/Interpolation.swift; sourceTree = SOURCE_ROOT; };
42− 246B0F821C70635D00A71D05 /* UIColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = "<group>"; };
43− 249CF84B1C6D113C008B0C78 /* Matrix.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Matrix.swift; sourceTree = "<group>"; };
44 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIKit.swift; sourceTree = "<group>"; };
61 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIKit.swift; sourceTree = "<group>"; };
62+ 24E1E7D81C67C9C900ECF1C4 /* MetaballRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetaballRenderer.swift; sourceTree = "<group>"; };
63+ 24E1E7DA1C67CA3600ECF1C4 /* ImageMetaballRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageMetaballRenderer.swift; sourceTree = "<group>"; };
45 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
64 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
46 24E1E7E31C67D39300ECF1C4 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
65 24E1E7E31C67D39300ECF1C4 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
47 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetalMetaballRenderer.swift; sourceTree = "<group>"; };
66 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetalMetaballRenderer.swift; sourceTree = "<group>"; };
48 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metal.swift; sourceTree = "<group>"; };
67 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metal.swift; sourceTree = "<group>"; };
49 24E1E7EF1C67D74300ECF1C4 /* shaders.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = shaders.metal; sourceTree = "<group>"; };
68 24E1E7EF1C67D74300ECF1C4 /* shaders.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = shaders.metal; sourceTree = "<group>"; };
69+ 24FFA84C1C6BA038005ACD60 /* ApproximationOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApproximationOperator.swift; sourceTree = "<group>"; };
70+ 24FFA84D1C6BA038005ACD60 /* Collections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Collections.swift; sourceTree = "<group>"; };
50− 24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetaballDataSource.swift; sourceTree = "<group>"; };
71+ 24FFA84E1C6BA038005ACD60 /* ComparatorChains.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComparatorChains.swift; sourceTree = "<group>"; };
51− 24FC38331C7F931E0085C04A /* Metaball.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metaball.swift; sourceTree = "<group>"; };
72+ 24FFA84F1C6BA038005ACD60 /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
52− 24FC38351C7F9ABE0085C04A /* Dispatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dispatch.swift; sourceTree = "<group>"; };
73+ 24FFA8511C6BA038005ACD60 /* NSNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSNumber.swift; sourceTree = "<group>"; };
53− 24FFA8521C6BA038005ACD60 /* Numeric.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Numeric.swift; path = SwiftSugar/Numeric.swift; sourceTree = "<group>"; };
74+ 24FFA8521C6BA038005ACD60 /* Numeric.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Numeric.swift; sourceTree = "<group>"; };
54− 24FFA8531C6BA038005ACD60 /* PowerOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PowerOperator.swift; path = SwiftSugar/PowerOperator.swift; sourceTree = "<group>"; };
75+ 24FFA8531C6BA038005ACD60 /* PowerOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PowerOperator.swift; sourceTree = "<group>"; };
55− 6659D12A5984961F335BDF69 /* Pods-PixelImage.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PixelImage.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage.debug.xcconfig"; sourceTree = "<group>"; };
76+ 24FFA8541C6BA038005ACD60 /* Sequence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sequence.swift; sourceTree = "<group>"; };
56− 93D10DBF530542A19EEF699A /* Pods_PixelImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PixelImage.framework; sourceTree = BUILT_PRODUCTS_DIR; };
77+ 24FFA8561C6BA038005ACD60 /* Memoize.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Memoize.swift; sourceTree = "<group>"; };
78+ 24FFA8571C6BA038005ACD60 /* SignOperator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignOperator.swift; sourceTree = "<group>"; };
79+ 24FFA8581C6BA038005ACD60 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
80+ 24FFA85A1C6BA038005ACD60 /* Categorise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Categorise.swift; sourceTree = "<group>"; };
81+ 24FFA85B1C6BA038005ACD60 /* ChunkWindowSplit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChunkWindowSplit.swift; sourceTree = "<group>"; };
82+ 24FFA85C1C6BA038005ACD60 /* Combinations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Combinations.swift; sourceTree = "<group>"; };
83+ 24FFA85D1C6BA038005ACD60 /* Cycle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cycle.swift; sourceTree = "<group>"; };
84+ 24FFA85E1C6BA038005ACD60 /* Enumerate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Enumerate.swift; sourceTree = "<group>"; };
85+ 24FFA85F1C6BA038005ACD60 /* Finding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Finding.swift; sourceTree = "<group>"; };
86+ 24FFA8601C6BA038005ACD60 /* FlatMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlatMap.swift; sourceTree = "<group>"; };
87+ 24FFA8611C6BA038005ACD60 /* Hopping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Hopping.swift; sourceTree = "<group>"; };
88+ 24FFA8621C6BA038005ACD60 /* Interpose.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Interpose.swift; sourceTree = "<group>"; };
89+ 24FFA8631C6BA038005ACD60 /* Iterate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Iterate.swift; sourceTree = "<group>"; };
90+ 24FFA8641C6BA038005ACD60 /* NestedSequences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NestedSequences.swift; sourceTree = "<group>"; };
91+ 24FFA8651C6BA038005ACD60 /* Permutations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Permutations.swift; sourceTree = "<group>"; };
92+ 24FFA8661C6BA038005ACD60 /* ScanReduce.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanReduce.swift; sourceTree = "<group>"; };
93+ 24FFA8671C6BA038005ACD60 /* Slicing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Slicing.swift; sourceTree = "<group>"; };
94+ 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TakeDrop.swift; sourceTree = "<group>"; };
95+ 24FFA8691C6BA038005ACD60 /* Zip.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Zip.swift; sourceTree = "<group>"; };
96+ 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestCommons.swift; sourceTree = "<group>"; };
57/* End PBXFileReference section */
97/* End PBXFileReference section */
58
98
59/* Begin PBXFrameworksBuildPhase section */
99/* Begin PBXFrameworksBuildPhase section */
@@ -63,22 +103,12 @@
63 files = (
103 files = (
64 24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */,
104 24E1E7E41C67D39300ECF1C4 /* MetalKit.framework in Frameworks */,
65 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */,
105 24E1E7E21C67D37F00ECF1C4 /* Metal.framework in Frameworks */,
66− 400CECBA73C835B415805169 /* Pods_PixelImage.framework in Frameworks */,
67 );
106 );
68 runOnlyForDeploymentPostprocessing = 0;
107 runOnlyForDeploymentPostprocessing = 0;
69 };
108 };
70/* End PBXFrameworksBuildPhase section */
109/* End PBXFrameworksBuildPhase section */
71
110
72/* Begin PBXGroup section */
111/* Begin PBXGroup section */
73− 0C205AE1A1A55E89EFAEE593 /* Pods */ = {
74− isa = PBXGroup;
75− children = (
76− 6659D12A5984961F335BDF69 /* Pods-PixelImage.debug.xcconfig */,
77− 0C9CE70F7D2C2896912B7B14 /* Pods-PixelImage.release.xcconfig */,
78− );
79− name = Pods;
80− sourceTree = "<group>";
81− };
82 2426867B1C63B72A00D62456 = {
112 2426867B1C63B72A00D62456 = {
83 isa = PBXGroup;
113 isa = PBXGroup;
84 children = (
114 children = (
@@ -86,8 +116,6 @@
86 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */,
116 24E1E7E11C67D37F00ECF1C4 /* Metal.framework */,
87 242686861C63B72A00D62456 /* PixelImage */,
117 242686861C63B72A00D62456 /* PixelImage */,
88 242686851C63B72A00D62456 /* Products */,
118 242686851C63B72A00D62456 /* Products */,
89− 0C205AE1A1A55E89EFAEE593 /* Pods */,
90− 8C02F866C2C0C9A954BB9375 /* Frameworks */,
91 );
119 );
92 sourceTree = "<group>";
120 sourceTree = "<group>";
93 };
121 };
@@ -102,20 +130,15 @@
102 242686861C63B72A00D62456 /* PixelImage */ = {
130 242686861C63B72A00D62456 /* PixelImage */ = {
103 isa = PBXGroup;
131 isa = PBXGroup;
104 children = (
132 children = (
105− 2461651A1C6DA4F400A913C8 /* Interpolation.swift */,
133+ 24FFA84B1C6BA038005ACD60 /* SwiftSugar */,
106− 24FFA8521C6BA038005ACD60 /* Numeric.swift */,
107− 24FFA8531C6BA038005ACD60 /* PowerOperator.swift */,
108 242686871C63B72A00D62456 /* AppDelegate.swift */,
134 242686871C63B72A00D62456 /* AppDelegate.swift */,
109− 24FC38351C7F9ABE0085C04A /* Dispatch.swift */,
135+ 242686891C63B72A00D62456 /* ViewController.swift */,
110 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */,
136 24E1E7D61C67C8B200ECF1C4 /* UIKit.swift */,
111− 246B0F821C70635D00A71D05 /* UIColor.swift */,
137+ 24E1E7D81C67C9C900ECF1C4 /* MetaballRenderer.swift */,
112− 24FC38331C7F931E0085C04A /* Metaball.swift */,
138+ 24E1E7DA1C67CA3600ECF1C4 /* ImageMetaballRenderer.swift */,
113− 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */,
114− 249CF84B1C6D113C008B0C78 /* Matrix.swift */,
115− 24ED21CC1C6C2397009C40FC /* MetaballDataSource.swift */,
116 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */,
139 24E1E7EA1C67D70300ECF1C4 /* MetalMetaballRenderer.swift */,
140+ 24E1E7EE1C67D74300ECF1C4 /* Metal.swift */,
117 24E1E7EF1C67D74300ECF1C4 /* shaders.metal */,
141 24E1E7EF1C67D74300ECF1C4 /* shaders.metal */,
118− 242686891C63B72A00D62456 /* ViewController.swift */,
119 2426868B1C63B72A00D62456 /* Main.storyboard */,
142 2426868B1C63B72A00D62456 /* Main.storyboard */,
120 2426868E1C63B72A00D62456 /* Assets.xcassets */,
143 2426868E1C63B72A00D62456 /* Assets.xcassets */,
121 242686901C63B72A00D62456 /* LaunchScreen.storyboard */,
144 242686901C63B72A00D62456 /* LaunchScreen.storyboard */,
@@ -124,12 +147,63 @@
124 path = PixelImage;
147 path = PixelImage;
125 sourceTree = "<group>";
148 sourceTree = "<group>";
126 };
149 };
127− 8C02F866C2C0C9A954BB9375 /* Frameworks */ = {
150+ 24FFA84B1C6BA038005ACD60 /* SwiftSugar */ = {
128 isa = PBXGroup;
151 isa = PBXGroup;
129 children = (
152 children = (
130− 93D10DBF530542A19EEF699A /* Pods_PixelImage.framework */,
153+ 24FFA84C1C6BA038005ACD60 /* ApproximationOperator.swift */,
154+ 24FFA84D1C6BA038005ACD60 /* Collections.swift */,
155+ 24FFA84E1C6BA038005ACD60 /* ComparatorChains.swift */,
156+ 24FFA84F1C6BA038005ACD60 /* Dictionary.swift */,
157+ 24FFA8501C6BA038005ACD60 /* Foundation */,
158+ 24FFA8521C6BA038005ACD60 /* Numeric.swift */,
159+ 24FFA8531C6BA038005ACD60 /* PowerOperator.swift */,
160+ 24FFA8541C6BA038005ACD60 /* Sequence.swift */,
161+ 24FFA8551C6BA038005ACD60 /* Sequences */,
162+ 24FFA8571C6BA038005ACD60 /* SignOperator.swift */,
163+ 24FFA8581C6BA038005ACD60 /* String.swift */,
164+ 24FFA8591C6BA038005ACD60 /* SwiftSequences */,
165+ 24FFA86A1C6BA038005ACD60 /* TestCommons.swift */,
131 );
166 );
132− name = Frameworks;
167+ path = SwiftSugar;
168+ sourceTree = "<group>";
169+ };
170+ 24FFA8501C6BA038005ACD60 /* Foundation */ = {
171+ isa = PBXGroup;
172+ children = (
173+ 24FFA8511C6BA038005ACD60 /* NSNumber.swift */,
174+ );
175+ path = Foundation;
176+ sourceTree = "<group>";
177+ };
178+ 24FFA8551C6BA038005ACD60 /* Sequences */ = {
179+ isa = PBXGroup;
180+ children = (
181+ 24FFA8561C6BA038005ACD60 /* Memoize.swift */,
182+ );
183+ path = Sequences;
184+ sourceTree = "<group>";
185+ };
186+ 24FFA8591C6BA038005ACD60 /* SwiftSequences */ = {
187+ isa = PBXGroup;
188+ children = (
189+ 24FFA85A1C6BA038005ACD60 /* Categorise.swift */,
190+ 24FFA85B1C6BA038005ACD60 /* ChunkWindowSplit.swift */,
191+ 24FFA85C1C6BA038005ACD60 /* Combinations.swift */,
192+ 24FFA85D1C6BA038005ACD60 /* Cycle.swift */,
193+ 24FFA85E1C6BA038005ACD60 /* Enumerate.swift */,
194+ 24FFA85F1C6BA038005ACD60 /* Finding.swift */,
195+ 24FFA8601C6BA038005ACD60 /* FlatMap.swift */,
196+ 24FFA8611C6BA038005ACD60 /* Hopping.swift */,
197+ 24FFA8621C6BA038005ACD60 /* Interpose.swift */,
198+ 24FFA8631C6BA038005ACD60 /* Iterate.swift */,
199+ 24FFA8641C6BA038005ACD60 /* NestedSequences.swift */,
200+ 24FFA8651C6BA038005ACD60 /* Permutations.swift */,
201+ 24FFA8661C6BA038005ACD60 /* ScanReduce.swift */,
202+ 24FFA8671C6BA038005ACD60 /* Slicing.swift */,
203+ 24FFA8681C6BA038005ACD60 /* TakeDrop.swift */,
204+ 24FFA8691C6BA038005ACD60 /* Zip.swift */,
205+ );
206+ path = SwiftSequences;
133 sourceTree = "<group>";
207 sourceTree = "<group>";
134 };
208 };
135/* End PBXGroup section */
209/* End PBXGroup section */
@@ -139,11 +213,9 @@
139 isa = PBXNativeTarget;
213 isa = PBXNativeTarget;
140 buildConfigurationList = 242686961C63B72A00D62456 /* Build configuration list for PBXNativeTarget "PixelImage" */;
214 buildConfigurationList = 242686961C63B72A00D62456 /* Build configuration list for PBXNativeTarget "PixelImage" */;
141 buildPhases = (
215 buildPhases = (
142− 041D2472535A642E23154A31 /* [CP] Check Pods Manifest.lock */,
143 242686801C63B72A00D62456 /* Sources */,
216 242686801C63B72A00D62456 /* Sources */,
144 242686811C63B72A00D62456 /* Frameworks */,
217 242686811C63B72A00D62456 /* Frameworks */,
145 242686821C63B72A00D62456 /* Resources */,
218 242686821C63B72A00D62456 /* Resources */,
146− 3CA888DC160972BAEB74EC52 /* [CP] Embed Pods Frameworks */,
147 );
219 );
148 buildRules = (
220 buildRules = (
149 );
221 );
@@ -161,13 +233,12 @@
161 isa = PBXProject;
233 isa = PBXProject;
162 attributes = {
234 attributes = {
163 LastSwiftUpdateCheck = 0720;
235 LastSwiftUpdateCheck = 0720;
164− LastUpgradeCheck = 1020;
236+ LastUpgradeCheck = 0720;
165 ORGANIZATIONNAME = "Vinicius Vendramini";
237 ORGANIZATIONNAME = "Vinicius Vendramini";
166 TargetAttributes = {
238 TargetAttributes = {
167 242686831C63B72A00D62456 = {
239 242686831C63B72A00D62456 = {
168 CreatedOnToolsVersion = 7.2;
240 CreatedOnToolsVersion = 7.2;
169− DevelopmentTeam = 8J63JZYYHZ;
241+ DevelopmentTeam = HHT774898M;
170− LastSwiftMigration = 1020;
171 };
242 };
172 };
243 };
173 };
244 };
@@ -176,7 +247,6 @@
176 developmentRegion = English;
247 developmentRegion = English;
177 hasScannedForEncodings = 0;
248 hasScannedForEncodings = 0;
178 knownRegions = (
249 knownRegions = (
179− English,
180 en,
250 en,
181 Base,
251 Base,
182 );
252 );
@@ -203,64 +273,47 @@
203 };
273 };
204/* End PBXResourcesBuildPhase section */
274/* End PBXResourcesBuildPhase section */
205
275
206−/* Begin PBXShellScriptBuildPhase section */
207− 041D2472535A642E23154A31 /* [CP] Check Pods Manifest.lock */ = {
208− isa = PBXShellScriptBuildPhase;
209− buildActionMask = 2147483647;
210− files = (
211− );
212− inputPaths = (
213− "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
214− "${PODS_ROOT}/Manifest.lock",
215− );
216− name = "[CP] Check Pods Manifest.lock";
217− outputPaths = (
218− "$(DERIVED_FILE_DIR)/Pods-PixelImage-checkManifestLockResult.txt",
219− );
220− runOnlyForDeploymentPostprocessing = 0;
221− shellPath = /bin/sh;
222− shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
223− showEnvVarsInLog = 0;
224− };
225− 3CA888DC160972BAEB74EC52 /* [CP] Embed Pods Frameworks */ = {
226− isa = PBXShellScriptBuildPhase;
227− buildActionMask = 2147483647;
228− files = (
229− );
230− inputPaths = (
231− "${SRCROOT}/Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage-frameworks.sh",
232− "${BUILT_PRODUCTS_DIR}/ChameleonFramework/ChameleonFramework.framework",
233− );
234− name = "[CP] Embed Pods Frameworks";
235− outputPaths = (
236− "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ChameleonFramework.framework",
237− );
238− runOnlyForDeploymentPostprocessing = 0;
239− shellPath = /bin/sh;
240− shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PixelImage/Pods-PixelImage-frameworks.sh\"\n";
241− showEnvVarsInLog = 0;
242− };
243−/* End PBXShellScriptBuildPhase section */
244−
245/* Begin PBXSourcesBuildPhase section */
276/* Begin PBXSourcesBuildPhase section */
246 242686801C63B72A00D62456 /* Sources */ = {
277 242686801C63B72A00D62456 /* Sources */ = {
247 isa = PBXSourcesBuildPhase;
278 isa = PBXSourcesBuildPhase;
248 buildActionMask = 2147483647;
279 buildActionMask = 2147483647;
249 files = (
280 files = (
281+ 24FFA87B1C6BA038005ACD60 /* Finding.swift in Sources */,
282+ 24FFA8751C6BA038005ACD60 /* String.swift in Sources */,
283+ 24FFA8781C6BA038005ACD60 /* Combinations.swift in Sources */,
284+ 24FFA87E1C6BA038005ACD60 /* Interpose.swift in Sources */,
250 2426868A1C63B72A00D62456 /* ViewController.swift in Sources */,
285 2426868A1C63B72A00D62456 /* ViewController.swift in Sources */,
251− 2461651B1C6DA4F400A913C8 /* Interpolation.swift in Sources */,
286+ 24FFA8841C6BA038005ACD60 /* TakeDrop.swift in Sources */,
252− 24FC38341C7F931E0085C04A /* Metaball.swift in Sources */,
287+ 24FFA8771C6BA038005ACD60 /* ChunkWindowSplit.swift in Sources */,
253− 24ED21CD1C6C2397009C40FC /* MetaballDataSource.swift in Sources */,
288+ 24FFA86F1C6BA038005ACD60 /* NSNumber.swift in Sources */,
254− 24FC38361C7F9ABE0085C04A /* Dispatch.swift in Sources */,
289+ 24FFA8861C6BA038005ACD60 /* TestCommons.swift in Sources */,
290+ 24FFA8741C6BA038005ACD60 /* SignOperator.swift in Sources */,
291+ 24FFA8821C6BA038005ACD60 /* ScanReduce.swift in Sources */,
292+ 24FFA8831C6BA038005ACD60 /* Slicing.swift in Sources */,
293+ 24FFA8721C6BA038005ACD60 /* Sequence.swift in Sources */,
294+ 24FFA87F1C6BA038005ACD60 /* Iterate.swift in Sources */,
295+ 24FFA8761C6BA038005ACD60 /* Categorise.swift in Sources */,
296+ 24FFA86D1C6BA038005ACD60 /* ComparatorChains.swift in Sources */,
255 24FFA8711C6BA038005ACD60 /* PowerOperator.swift in Sources */,
297 24FFA8711C6BA038005ACD60 /* PowerOperator.swift in Sources */,
298+ 24E1E7D91C67C9C900ECF1C4 /* MetaballRenderer.swift in Sources */,
256 24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */,
299 24E1E7D71C67C8B200ECF1C4 /* UIKit.swift in Sources */,
257− 249CF84C1C6D113C008B0C78 /* Matrix.swift in Sources */,
300+ 24FFA8851C6BA038005ACD60 /* Zip.swift in Sources */,
301+ 24FFA8791C6BA038005ACD60 /* Cycle.swift in Sources */,
258 24E1E7F11C67D74300ECF1C4 /* shaders.metal in Sources */,
302 24E1E7F11C67D74300ECF1C4 /* shaders.metal in Sources */,
303+ 24FFA86E1C6BA038005ACD60 /* Dictionary.swift in Sources */,
304+ 24FFA87D1C6BA038005ACD60 /* Hopping.swift in Sources */,
259 24E1E7EB1C67D70300ECF1C4 /* MetalMetaballRenderer.swift in Sources */,
305 24E1E7EB1C67D70300ECF1C4 /* MetalMetaballRenderer.swift in Sources */,
260− 246B0F831C70635D00A71D05 /* UIColor.swift in Sources */,
306+ 24FFA87A1C6BA038005ACD60 /* Enumerate.swift in Sources */,
307+ 24E1E7DB1C67CA3600ECF1C4 /* ImageMetaballRenderer.swift in Sources */,
261 242686881C63B72A00D62456 /* AppDelegate.swift in Sources */,
308 242686881C63B72A00D62456 /* AppDelegate.swift in Sources */,
262 24E1E7F01C67D74300ECF1C4 /* Metal.swift in Sources */,
309 24E1E7F01C67D74300ECF1C4 /* Metal.swift in Sources */,
310+ 24FFA87C1C6BA038005ACD60 /* FlatMap.swift in Sources */,
263 24FFA8701C6BA038005ACD60 /* Numeric.swift in Sources */,
311 24FFA8701C6BA038005ACD60 /* Numeric.swift in Sources */,
312+ 24FFA8811C6BA038005ACD60 /* Permutations.swift in Sources */,
313+ 24FFA86B1C6BA038005ACD60 /* ApproximationOperator.swift in Sources */,
314+ 24FFA8801C6BA038005ACD60 /* NestedSequences.swift in Sources */,
315+ 24FFA8731C6BA038005ACD60 /* Memoize.swift in Sources */,
316+ 24FFA86C1C6BA038005ACD60 /* Collections.swift in Sources */,
264 );
317 );
265 runOnlyForDeploymentPostprocessing = 0;
318 runOnlyForDeploymentPostprocessing = 0;
266 };
319 };
@@ -290,28 +343,17 @@
290 isa = XCBuildConfiguration;
343 isa = XCBuildConfiguration;
291 buildSettings = {
344 buildSettings = {
292 ALWAYS_SEARCH_USER_PATHS = NO;
345 ALWAYS_SEARCH_USER_PATHS = NO;
293− CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
294 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
346 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
295 CLANG_CXX_LIBRARY = "libc++";
347 CLANG_CXX_LIBRARY = "libc++";
296 CLANG_ENABLE_MODULES = YES;
348 CLANG_ENABLE_MODULES = YES;
297 CLANG_ENABLE_OBJC_ARC = YES;
349 CLANG_ENABLE_OBJC_ARC = YES;
298− CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
299 CLANG_WARN_BOOL_CONVERSION = YES;
350 CLANG_WARN_BOOL_CONVERSION = YES;
300− CLANG_WARN_COMMA = YES;
301 CLANG_WARN_CONSTANT_CONVERSION = YES;
351 CLANG_WARN_CONSTANT_CONVERSION = YES;
302− CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
303 CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
352 CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
304 CLANG_WARN_EMPTY_BODY = YES;
353 CLANG_WARN_EMPTY_BODY = YES;
305 CLANG_WARN_ENUM_CONVERSION = YES;
354 CLANG_WARN_ENUM_CONVERSION = YES;
306− CLANG_WARN_INFINITE_RECURSION = YES;
307 CLANG_WARN_INT_CONVERSION = YES;
355 CLANG_WARN_INT_CONVERSION = YES;
308− CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
309− CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
310− CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
311 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
356 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
312− CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
313− CLANG_WARN_STRICT_PROTOTYPES = YES;
314− CLANG_WARN_SUSPICIOUS_MOVE = YES;
315 CLANG_WARN_UNREACHABLE_CODE = YES;
357 CLANG_WARN_UNREACHABLE_CODE = YES;
316 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
358 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
317 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
359 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -338,7 +380,6 @@
338 ONLY_ACTIVE_ARCH = YES;
380 ONLY_ACTIVE_ARCH = YES;
339 SDKROOT = iphoneos;
381 SDKROOT = iphoneos;
340 SWIFT_OPTIMIZATION_LEVEL = "-Onone";
382 SWIFT_OPTIMIZATION_LEVEL = "-Onone";
341− SWIFT_SWIFT3_OBJC_INFERENCE = Off;
342 TARGETED_DEVICE_FAMILY = "1,2";
383 TARGETED_DEVICE_FAMILY = "1,2";
343 };
384 };
344 name = Debug;
385 name = Debug;
@@ -347,28 +388,17 @@
347 isa = XCBuildConfiguration;
388 isa = XCBuildConfiguration;
348 buildSettings = {
389 buildSettings = {
349 ALWAYS_SEARCH_USER_PATHS = NO;
390 ALWAYS_SEARCH_USER_PATHS = NO;
350− CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
351 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
391 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
352 CLANG_CXX_LIBRARY = "libc++";
392 CLANG_CXX_LIBRARY = "libc++";
353 CLANG_ENABLE_MODULES = YES;
393 CLANG_ENABLE_MODULES = YES;
354 CLANG_ENABLE_OBJC_ARC = YES;
394 CLANG_ENABLE_OBJC_ARC = YES;
355− CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
356 CLANG_WARN_BOOL_CONVERSION = YES;
395 CLANG_WARN_BOOL_CONVERSION = YES;
357− CLANG_WARN_COMMA = YES;
358 CLANG_WARN_CONSTANT_CONVERSION = YES;
396 CLANG_WARN_CONSTANT_CONVERSION = YES;
359− CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
360 CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
397 CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
361 CLANG_WARN_EMPTY_BODY = YES;
398 CLANG_WARN_EMPTY_BODY = YES;
362 CLANG_WARN_ENUM_CONVERSION = YES;
399 CLANG_WARN_ENUM_CONVERSION = YES;
363− CLANG_WARN_INFINITE_RECURSION = YES;
364 CLANG_WARN_INT_CONVERSION = YES;
400 CLANG_WARN_INT_CONVERSION = YES;
365− CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
366− CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
367− CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
368 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
401 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
369− CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
370− CLANG_WARN_STRICT_PROTOTYPES = YES;
371− CLANG_WARN_SUSPICIOUS_MOVE = YES;
372 CLANG_WARN_UNREACHABLE_CODE = YES;
402 CLANG_WARN_UNREACHABLE_CODE = YES;
373 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
403 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
374 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
404 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -387,8 +417,6 @@
387 IPHONEOS_DEPLOYMENT_TARGET = 9.2;
417 IPHONEOS_DEPLOYMENT_TARGET = 9.2;
388 MTL_ENABLE_DEBUG_INFO = NO;
418 MTL_ENABLE_DEBUG_INFO = NO;
389 SDKROOT = iphoneos;
419 SDKROOT = iphoneos;
390− SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
391− SWIFT_SWIFT3_OBJC_INFERENCE = Off;
392 TARGETED_DEVICE_FAMILY = "1,2";
420 TARGETED_DEVICE_FAMILY = "1,2";
393 VALIDATE_PRODUCT = YES;
421 VALIDATE_PRODUCT = YES;
394 };
422 };
@@ -396,29 +424,23 @@
396 };
424 };
397 242686971C63B72A00D62456 /* Debug */ = {
425 242686971C63B72A00D62456 /* Debug */ = {
398 isa = XCBuildConfiguration;
426 isa = XCBuildConfiguration;
399− baseConfigurationReference = 6659D12A5984961F335BDF69 /* Pods-PixelImage.debug.xcconfig */;
400 buildSettings = {
427 buildSettings = {
401 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
428 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
402− DEVELOPMENT_TEAM = 8J63JZYYHZ;
403 INFOPLIST_FILE = PixelImage/Info.plist;
429 INFOPLIST_FILE = PixelImage/Info.plist;
404 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
430 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
405 PRODUCT_BUNDLE_IDENTIFIER = vinivendra.PixelImage;
431 PRODUCT_BUNDLE_IDENTIFIER = vinivendra.PixelImage;
406 PRODUCT_NAME = "$(TARGET_NAME)";
432 PRODUCT_NAME = "$(TARGET_NAME)";
407− SWIFT_VERSION = 5.0;
408 };
433 };
409 name = Debug;
434 name = Debug;
410 };
435 };
411 242686981C63B72A00D62456 /* Release */ = {
436 242686981C63B72A00D62456 /* Release */ = {
412 isa = XCBuildConfiguration;
437 isa = XCBuildConfiguration;
413− baseConfigurationReference = 0C9CE70F7D2C2896912B7B14 /* Pods-PixelImage.release.xcconfig */;
414 buildSettings = {
438 buildSettings = {
415 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
439 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
416− DEVELOPMENT_TEAM = 8J63JZYYHZ;
417 INFOPLIST_FILE = PixelImage/Info.plist;
440 INFOPLIST_FILE = PixelImage/Info.plist;
418 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
441 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
419 PRODUCT_BUNDLE_IDENTIFIER = vinivendra.PixelImage;
442 PRODUCT_BUNDLE_IDENTIFIER = vinivendra.PixelImage;
420 PRODUCT_NAME = "$(TARGET_NAME)";
443 PRODUCT_NAME = "$(TARGET_NAME)";
421− SWIFT_VERSION = 5.0;
422 };
444 };
423 name = Release;
445 name = Release;
424 };
446 };
PixelImage.xcodeproj/xcuserdata/vini.xcuserdatad/xcschemes/PixelImage.xcscheme+1−1
@@ -1,6 +1,6 @@
1<?xml version="1.0" encoding="UTF-8"?>
1<?xml version="1.0" encoding="UTF-8"?>
2<Scheme
2<Scheme
3− LastUpgradeVersion = "0830"
3+ LastUpgradeVersion = "0720"
4 version = "1.3">
4 version = "1.3">
5 <BuildAction
5 <BuildAction
6 parallelizeBuildables = "YES"
6 parallelizeBuildables = "YES"
PixelImage.xcworkspace/contents.xcworkspacedatadeleted−10
@@ -1,10 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<Workspace
3− version = "1.0">
4− <FileRef
5− location = "group:PixelImage.xcodeproj">
6− </FileRef>
7− <FileRef
8− location = "group:Pods/Pods.xcodeproj">
9− </FileRef>
10−</Workspace>
PixelImage.xcworkspace/xcuserdata/vini.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistdeleted−5
@@ -1,5 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8"?>
2−<Bucket
3− type = "0"
4− version = "2.0">
5−</Bucket>
PixelImage/AppDelegate.swift+10−6
@@ -13,30 +13,34 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
13
13
14 var window: UIWindow?
14 var window: UIWindow?
15
15
16+
16− func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
17 // Override point for customization after application launch.
18 // Override point for customization after application launch.
18 return true
19 return true
19 }
20 }
20
21
21− func applicationWillResignActive(_ application: UIApplication) {
22+ func applicationWillResignActive(application: UIApplication) {
22 // 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.
23 // 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.
23 // 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.
24 // 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.
24 }
25 }
25
26
26− func applicationDidEnterBackground(_ application: UIApplication) {
27+ func applicationDidEnterBackground(application: UIApplication) {
27 // 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.
28 // 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.
28 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
29 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
29 }
30 }
30
31
31− func applicationWillEnterForeground(_ application: UIApplication) {
32+ func applicationWillEnterForeground(application: UIApplication) {
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 // 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 }
34
35
35− func applicationDidBecomeActive(_ application: UIApplication) {
36+ func applicationDidBecomeActive(application: UIApplication) {
36 // 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.
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.
37 }
38 }
38
39
39− func applicationWillTerminate(_ application: UIApplication) {
40+ func applicationWillTerminate(application: UIApplication) {
40 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
41 // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
41 }
42 }
43+
44+
42}
45}
46+
PixelImage/Dispatch.swiftdeleted−10
@@ -1,10 +0,0 @@
1−
2−import Dispatch
3−
4−func delay(_ duration: Float = 1, block: @escaping () -> ()) {
5− DispatchQueue.main.asyncAfter(
6− deadline: DispatchTime.now() +
7− Double(duration * Float(NSEC_PER_SEC)) /
8− Double(NSEC_PER_SEC),
9− execute: block)
10−}
PixelImage/ImageMetaballRenderer.swiftnew file+109
@@ -0,0 +1,109 @@
1+
2+import UIKit
3+
4+class ImageMetaballRenderer: MetaballRenderer {
5+ typealias TargetView = UIImageView
6+
7+ let targetView = TargetView()
8+
9+ let dataSource: MetaballDataSource
10+
11+ required init(dataSource: MetaballDataSource) {
12+ self.dataSource = dataSource
13+ }
14+
15+ func updateTargetView() {
16+ let width = Int(targetView.width)
17+ let height = Int(targetView.height)
18+ let metaballs = dataSource.metaballs
19+
20+ let bytesPerPixel = 4;
21+ let bytesPerRow = bytesPerPixel * width;
22+ let bitsPerComponent = 8;
23+
24+ var matrix = PixelMatrix(width: width, height: height)
25+ for i in 0..<width {
26+ for j in 0..<height {
27+ let pixelPosition = CGPoint(x: i, y: j)
28+
29+ var sum: CGFloat = 0
30+
31+ for combo in metaballs.combos() {
32+ let metaball1 = combo[0].middle
33+ let metaball2 = combo[1].middle
34+
35+ let metaball1Vector = metaball1 - pixelPosition
36+ let metaball2Vector = metaball2 - pixelPosition
37+
38+ let direction1 = metaball1Vector.normalized
39+ let direction2 = metaball2Vector.normalized
40+
41+ let cos = direction1 * direction2
42+
43+ let value1 = 255000 / (metaball1Vector * metaball1Vector + 1)
44+ let value2 = 255000 / (metaball2Vector * metaball2Vector + 1)
45+
46+ let v = gradient(value1 + value2)
47+ let link = ((1 - cos) * 0.5) ^ 50
48+
49+ let weightedLink = 128 * CGFloat(link)
50+ let weightedValue = 0.6 * CGFloat(v)
51+
52+ sum += weightedValue + weightedLink
53+ }
54+
55+ let result = threshold(sum)
56+
57+ matrix.set(x: i, y: j, r:0, g:result/2, b:result)
58+ }
59+ }
60+
61+ let buffer: UnsafeMutablePointer<Void> = UnsafeMutablePointer(matrix.pixels)
62+
63+ let colorSpace = CGColorSpaceCreateDeviceRGB()
64+ let context = CGBitmapContextCreate(buffer, width, height, bitsPerComponent, bytesPerRow, colorSpace, CGImageAlphaInfo.PremultipliedLast.rawValue | CGBitmapInfo.ByteOrder32Big.rawValue);
65+
66+ let cgImage = CGBitmapContextCreateImage(context)
67+ let image = UIImage(CGImage: cgImage!)
68+ targetView.image = image
69+ }
70+}
71+
72+struct PixelMatrix {
73+ var pixels: [UInt8]
74+
75+ let width: Int
76+ let height: Int
77+
78+ init(width: Int, height: Int) {
79+ self.width = width
80+ self.height = height
81+ pixels = [UInt8](count: (4 * width * height), repeatedValue: 255)
82+ }
83+
84+ mutating func set(x x: Int, y: Int, r: UInt8, g: UInt8, b: UInt8) {
85+ let index = 4 * (y * width + x)
86+ pixels[index ] = r
87+ pixels[index + 1] = g
88+ pixels[index + 2] = b
89+ }
90+
91+ mutating func set(x x: Int, y: Int, white: UInt8) {
92+ let index = 4 * (y * width + x)
93+ pixels[index ] = white
94+ pixels[index + 1] = white
95+ pixels[index + 2] = white
96+ }
97+}
98+
99+func threshold(value: CGFloat) -> UInt8 {
100+ return value < 128 ? 0 : 255
101+}
102+
103+func gradient(value: CGFloat) -> UInt8 {
104+ return UInt8(min(max(value, 0), CGFloat(255)))
105+}
106+
107+func thresholdf(value value: CGFloat, cap: CGFloat = 0.5) -> CGFloat {
108+ return value < cap ? 0 : 1.0
109+}
PixelImage/Interpolation.swiftdeleted−67
@@ -1,67 +0,0 @@
1−
2−import Darwin
3−
4−func interpolateCubeEaseIn<T: Numeric>(_ linear: T) -> T {
5− return linear ^ 3
6−}
7−
8−func interpolateSquareEaseIn<T: Numeric>(_ linear: T) -> T {
9− return linear ^ 2
10−}
11−
12−func interpolateSquareEaseOut<T: Numeric>(_ linear: T) -> T {
13− return 1 - (1 - linear) * (1 - linear)
14−}
15−
16−func interpolateSmooth<T: Numeric>(_ linear: T) -> T {
17− let cube = (linear) * (linear) * (linear)
18− return (cube * ((linear) * ((linear) * 6 - 15) + 10))
19−}
20−
21−func createStringKeyframes(_ bounces: Int = 2, elasticity: Double = 1.1, bounceSpeed: Double) -> [(time: Double, position: Double)] {
22− // Setup keyframes
23− var keyFrames: [(time: Double, position: Double)] = [(1, 1)]
24−
25− let overreach = elasticity - 1
26−
27− var currentBounceTime: Double = overreach / (bounceSpeed ^ Double(bounces))
28− var bounceDirection = Double((bounces % 2) * 2 - 1)
29− var bounceReach = overreach / (2 ^ Double(bounces - 1))
30− var currentBouncePosition: Double = 1.0 + bounceDirection * bounceReach
31−
32− keyFrames.append((1.0 - currentBounceTime, currentBouncePosition))
33−
34− for i in (1..<bounces).reversed() {
35− currentBounceTime += overreach / (bounceSpeed ^ Double(i + 1))
36− currentBounceTime += overreach / (bounceSpeed ^ Double(i))
37− bounceDirection = Double((i % 2) * 2 - 1)
38− bounceReach = overreach / (2 ^ Double(i - 1))
39− currentBouncePosition = 1.0 + bounceDirection * bounceReach
40−
41− keyFrames.append((1.0 - currentBounceTime, currentBouncePosition))
42− }
43−
44− keyFrames.append((0, 0))
45−
46− var reversed = [(time: Double, position: Double)]()
47− for keyFrame in keyFrames.reversed() {
48− reversed.append(keyFrame)
49− }
50−
51− return reversed
52−}
53−
54−func interpolateSpring<T: Numeric>(_ linear: T, bounces: Int = 2, elasticity: Double = 1.1, bounceSpeed: Double = 1.0) -> T {
55− let keyFrames: [(time: Double, position: Double)]
56− keyFrames = createStringKeyframes(bounces, elasticity: elasticity, bounceSpeed: bounceSpeed)
57−
58− let x = linear.toDouble
59−
60− let startFrame = keyFrames.filter { $0.time < x }.last ?? (0, 0)
61− let endFrame = keyFrames.filter { $0.time > x }.first ?? (1, 1)
62− let adjustedX = (x - startFrame.time) / (endFrame.time - startFrame.time)
63− let interpolatedX = interpolateSmooth(adjustedX)
64− let position = startFrame.position + interpolatedX * (endFrame.position - startFrame.position)
65−
66− return T.fromDouble(position)
67−}
PixelImage/Matrix.swiftdeleted−72
@@ -1,72 +0,0 @@
1−import UIKit
2−
3−class Graph<T> {
4− var adjacencyMatrix: Matrix
5− var vertices: [T]
6−
7− var size: Int {
8− get {
9− return vertices.count
10− }
11− }
12−
13− init(vertices: [T]) {
14− let size = vertices.count
15−
16− self.vertices = vertices
17− self.adjacencyMatrix = Matrix(size: size)
18− }
19−
20− func addEdge(_ i: Int, _ j: Int) {
21− adjacencyMatrix.set(i, j)
22− adjacencyMatrix.set(j, i)
23− }
24−
25− func removeEdge(_ i: Int, _ j: Int) {
26− adjacencyMatrix.reset(i, j)
27− adjacencyMatrix.reset(j, i)
28− }
29−
30−}
31−
32−struct Matrix: CustomStringConvertible {
33− var buffer: [Float]
34−
35− let size: Int
36−
37− init(size: Int) {
38− buffer = [Float](repeating: 0.0, count: size * size)
39− self.size = size
40− }
41−
42− func get(_ i: Int, j: Int) -> Float {
43− return buffer[index(i, j)]
44− }
45−
46− mutating func set(_ i: Int, _ j: Int, value: Float = 1.0) {
47− buffer[index(i, j)] = value
48− }
49−
50− mutating func reset(_ i: Int, _ j: Int) {
51− buffer[index(i, j)] = 0.0
52− }
53−
54− fileprivate func index(_ i: Int, _ j: Int) -> Int {
55− return j * size + i
56− }
57−
58− var description: String {
59− get {
60− var result = ""
61− for (index, value) in buffer.enumerated() {
62− result = result + "\(value)"
63− if index % size == size - 1 {
64− result = result + "\n"
65− } else {
66− result = result + " "
67− }
68− }
69− return result
70− }
71− }
72−}
PixelImage/Metaball.swiftdeleted−67
@@ -1,67 +0,0 @@
1−
2−import UIKit
3−
4−class Metaball: UIView {
5−
6− var color: UIColor
7−
8− init(position: CGPoint,
9− color: UIColor = UIColor(randomFlatColorOf: .light)) {
10− self.color = color
11− super.init(frame: CGRect.zero)
12−
13− size = CGSize(50)
14− middle = position
15− }
16−
17− required init?(coder aDecoder: NSCoder) {
18− self.color = UIColor(randomFlatColorOf: .light)
19− super.init(coder: aDecoder)
20− }
21−}
22−
23−class EdgeAnimationParameters {
24− let startDate: Date
25− let duration: Float
26− let fadeIn: Bool
27− let i: Int
28− let j: Int
29−
30− func unpack() -> (startDate: Date, duration: Float, fadeIn: Bool,
31− i: Int, j: Int)
32− {
33− return (startDate, duration, fadeIn, i, j)
34− }
35−
36− init(startDate: Date, duration: Float, fadeIn: Bool, i: Int, j: Int) {
37− self.startDate = startDate
38− self.duration = duration
39− self.fadeIn = fadeIn
40− self.i = i
41− self.j = j
42− }
43−}
44−
45−class VertexAnimationParameters {
46− let startDate: Date
47− let duration: Float
48− let origin: CGPoint
49− let destination: CGPoint
50− let metaball: Metaball
51−
52− func unpack() -> (startDate: Date, duration: Float, origin: CGPoint,
53− destination: CGPoint, metaball: Metaball)
54− {
55− return (startDate, duration, origin, destination, metaball)
56− }
57−
58− init(startDate: Date, duration: Float, origin: CGPoint,
59− destination: CGPoint, metaball: Metaball)
60− {
61− self.startDate = startDate
62− self.duration = duration
63− self.origin = origin
64− self.destination = destination
65− self.metaball = metaball
66− }
67−}
PixelImage/MetaballDataSource.swiftdeleted−14
@@ -1,14 +0,0 @@
1−import Metal
2−
3−protocol MetaballDataSource {
4− var metaballGraph: Graph<Metaball>! { get }
5−}
6−
7−extension MetaballDataSource {
8− var metaballs: [Metaball]! {
9− get {
10− return metaballGraph.vertices
11− }
12− }
13−
14−}
PixelImage/MetaballRenderer.swiftnew file+16
@@ -0,0 +1,16 @@
1+
2+import UIKit
3+
4+protocol MetaballDataSource {
5+ var metaballs: [Metaball] { get }
6+}
7+
8+protocol MetaballRenderer {
9+ typealias TargetView: UIView
10+
11+ var targetView: TargetView { get }
12+
13+ init(dataSource: MetaballDataSource)
14+
15+ func updateTargetView()
16+}
PixelImage/Metal.swift+2−32
@@ -1,5 +1,4 @@
1import Metal
1import Metal
2−import UIKit
3
2
4class MTLContext {
3class MTLContext {
5 let device: MTLDevice
4 let device: MTLDevice
@@ -8,36 +7,7 @@ class MTLContext {
8
7
9 init(device: MTLDevice = MTLCreateSystemDefaultDevice()!) {
8 init(device: MTLDevice = MTLCreateSystemDefaultDevice()!) {
10 self.device = device
9 self.device = device
11− self.library = device.makeDefaultLibrary()!
10+ self.library = device.newDefaultLibrary()!
12− self.commandQueue = device.makeCommandQueue()!
11+ self.commandQueue = device.newCommandQueue()
13− }
14−}
15−
16−class MTLComputeContext {
17− var texture: MTLTexture
18− var imageBuffer: UnsafeMutableRawPointer
19−
20− init(size: CGSize, texture: MTLTexture) {
21− let width = Int(size.width)
22− let height = Int(size.height)
23− let imageByteCount = width * height * 4
24− imageBuffer = malloc(imageByteCount)
25−
26− self.texture = texture
27− }
28−
29− func updateToSize(_ size: CGSize, texture: MTLTexture) {
30− free(imageBuffer)
31−
32− let width = Int(size.width)
33− let height = Int(size.height)
34− let imageByteCount = width * height * 4
35− imageBuffer = malloc(imageByteCount)
36−
37− self.texture = texture
38− }
39−
40− deinit {
41− free(imageBuffer)
42 }
12 }
43}
13}
PixelImage/MetalMetaballRenderer.swift+105−165
@@ -1,232 +1,172 @@
1+// TODO: Make shader ignore metaballs that are outside a certain area of tolerance (eg ±100 from borders)
2+
3+// TODO: Metaballs from texture to buffer
4+// TODO: Use async dispatch to free up main queue
5+// TODO: Refactor update into 2 calls: metalRendering() and textureToImage()
6+// TODO: Use two textures/images to alternate the 2 calls (like OpenGL double buffers)
7+
8+// TODO: Make graphics have edges only according to graph (instead of being a complete graph)
9+
10+// TODO: Interpolate metaball colors
11+// TODO: Use metaballs as mask: apply strong blur inside, weak blur outside
12+// TODO: Add antialiasing
13+
1import Metal
14import Metal
2import UIKit
15import UIKit
3−import ChameleonFramework
4
16
5−@objc class MetalMetaballRenderer: NSObject {
17+class MetalMetaballRenderer: MetaballRenderer {
6
18
7 typealias TargetView = UIImageView
19 typealias TargetView = UIImageView
8
20
9− let targetView: TargetView
21+ let targetView = TargetView()
22+ var previousFrame = CGRect.zero
10
23
11 let context = MTLContext()
24 let context = MTLContext()
12− var activeComputeContext: MTLComputeContext
25+ var renderingTexture: MTLTexture!
13− var idleComputeContext: MTLComputeContext
26+ var imageBuffer: UnsafeMutablePointer<Void>!
14
27
15 let dataSource: MetaballDataSource
28 let dataSource: MetaballDataSource
16
29
17− let semaphore = DispatchSemaphore(value: 2)
18−
19− enum RendererState {
20− case idle
21− case running
22− case ending
23− }
24−
25− var state: RendererState = .idle {
26− willSet {
27− if state == .idle {
28− if newValue == .running {
29− updateTargetView()
30− }
31− }
32− }
33− }
34−
35− required init(dataSource: MetaballDataSource, frame: CGRect) {
30+ required init(dataSource: MetaballDataSource) {
36 self.dataSource = dataSource
31 self.dataSource = dataSource
37−
38− targetView = TargetView(frame: frame)
39−
40− let width = Int(frame.width)
41− let height = Int(frame.height)
42− let textureDescriptor =
43− MTLTextureDescriptor.texture2DDescriptor(
44− pixelFormat: .bgra8Unorm,
45− width: width,
46− height: height,
47− mipmapped: false)
48− textureDescriptor.usage = .shaderWrite
49−
50− let texture1 =
51− context.device.makeTexture(descriptor: textureDescriptor)
52− activeComputeContext = MTLComputeContext(size: targetView.size,
53− texture: texture1!)
54− let texture2 =
55− context.device.makeTexture(descriptor: textureDescriptor)
56− idleComputeContext = MTLComputeContext(size: targetView.size,
57− texture: texture2!)
58 }
32 }
59
33
60− internal func updateTargetView() {
34+ func updateTargetView() {
61− let timeout = DispatchTime.now() + Double(1000000000) / Double(NSEC_PER_SEC)
35+ let metaballs = dataSource.metaballs
62− _ = semaphore.wait(timeout: timeout)
63−
64− state = .ending
65
36
66− DispatchQueue.main.async { () -> Void in
37+ if previousFrame != targetView.frame {
67− let computeContext = self.activeComputeContext
38+ previousFrame = targetView.frame
68− swap(&self.activeComputeContext, &self.idleComputeContext)
39+ updateFrame()
69−
70− // Render graphics to metal texture
71− self.renderToContext(computeContext)
72−
73− if self.state != .running {
74− self.state = .idle
75− } else {
76− self.updateTargetView()
77− }
78−
79− // Transform metal texture into image
80− let uiimage = self.createImageFromContext(computeContext)
81−
82− self.semaphore.signal()
83−
84− DispatchQueue.main.async { () -> Void in
85− // Send image to view
86− self.targetView.image = uiimage
87− }
88 }
40 }
89− }
90
41
91− internal func renderToContext(_ computeContext: MTLComputeContext) {
92 let width = Int(targetView.width)
42 let width = Int(targetView.width)
93 let height = Int(targetView.height)
43 let height = Int(targetView.height)
94
44
45+ if renderingTexture == nil {
46+ let textureDescriptor =
47+ MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.BGRA8Unorm, width: width, height: height, mipmapped: false)
48+
49+ renderingTexture = context.device.newTextureWithDescriptor(textureDescriptor)
50+ }
51+
95 let kernelFunction: MTLFunction?
52 let kernelFunction: MTLFunction?
96 let pipeline: MTLComputePipelineState
53 let pipeline: MTLComputePipelineState
97 do {
54 do {
98 // Get long-lived objects
55 // Get long-lived objects
99− kernelFunction =
100− context.library.makeFunction(name: "drawMetaballs")
56+ kernelFunction = context.library.newFunctionWithName("drawMetaballs")
101− pipeline = try context.device.makeComputePipelineState(
57+ pipeline = try context.device.newComputePipelineStateWithFunction(kernelFunction!)
102− function: kernelFunction!)
103
58
104 // Configure info for computing
59 // Configure info for computing
105 let threadGroupCounts = MTLSizeMake(8, 8, 1)
60 let threadGroupCounts = MTLSizeMake(8, 8, 1)
106 let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
61 let threadGroups = MTLSizeMake(width / threadGroupCounts.width,
107− height / threadGroupCounts.height,
62+ height / threadGroupCounts.height, 1)
108− 1)
63+
64+ // Create up-to-date metaball buffer
65+ let metaballInfoTexture = metaballTexture(metaballs)
109
66
110 // Send commands to metal and render
67 // Send commands to metal and render
111− let commandBuffer = context.commandQueue.makeCommandBuffer()
68+ let commandBuffer = context.commandQueue.commandBuffer()
112−
69+
113− let commandEncoder = commandBuffer!.makeComputeCommandEncoder()
70+ let commandEncoder = commandBuffer.computeCommandEncoder()
114− commandEncoder!.setComputePipelineState(pipeline)
71+ commandEncoder.setComputePipelineState(pipeline)
115− commandEncoder!.setTexture(computeContext.texture, index: 0)
72+ commandEncoder.setTexture(renderingTexture, atIndex: 0)
116− let metaballInfoBuffer = metaballBuffer()
73+ commandEncoder.setTexture(metaballInfoTexture, atIndex: 1)
117− commandEncoder!.setBuffer(metaballInfoBuffer, offset: 0, index: 0)
118− let edgesBuffer = metaballEdgesBuffer()
119− commandEncoder!.setBuffer(edgesBuffer, offset: 0, index: 1)
120− commandEncoder!.dispatchThreadgroups(threadGroups,
74+ commandEncoder.dispatchThreadgroups(threadGroups,
121 threadsPerThreadgroup: threadGroupCounts)
75 threadsPerThreadgroup: threadGroupCounts)
122− commandEncoder!.endEncoding()
76+ commandEncoder.endEncoding()
77+
78+ commandBuffer.commit()
79+ commandBuffer.waitUntilCompleted()
123
80
124− commandBuffer!.commit()
125− commandBuffer!.waitUntilCompleted()
126 } catch _ {
81 } catch _ {
127− assertionFailure()
82+ print("Error!")
128 }
83 }
129− }
130
84
131− internal func createImageFromContext(_ computeContext: MTLComputeContext)
85+ // Transform new metal texture into image
132− -> UIImage
86+ targetView.image = image(texture: renderingTexture)
133− {
87+ }
134− let texture = computeContext.texture
135
88
89+ func image(texture texture: MTLTexture) -> UIImage {
136 // Get image info
90 // Get image info
137− let imageSize = CGSize(width: CGFloat(texture.width),
91+ let imageSize = CGSizeMake(CGFloat(texture.width),
138− height: CGFloat(texture.height))
92+ CGFloat(texture.height))
139 let width = Int(imageSize.width)
93 let width = Int(imageSize.width)
140 let height = Int(imageSize.height)
94 let height = Int(imageSize.height)
141 let imageByteCount = width * height * 4
95 let imageByteCount = width * height * 4
142 let bytesPerRow = width * 4
96 let bytesPerRow = width * 4
143 let region = MTLRegionMake2D(0, 0, width, height)
97 let region = MTLRegionMake2D(0, 0, width, height)
144
98
99+ // Allocate the buffer if needed
100+ if imageBuffer == nil {
101+ imageBuffer = malloc(imageByteCount)
102+ }
103+
145 // Transfer texture info into image buffer
104 // Transfer texture info into image buffer
146− texture.getBytes(computeContext.imageBuffer,
147− bytesPerRow: bytesPerRow,
105+ texture.getBytes(imageBuffer, bytesPerRow: bytesPerRow,
148− from: region,
149− mipmapLevel: 0)
106+ fromRegion: region, mipmapLevel: 0)
150
107
151 // Get info for UIImage
108 // Get info for UIImage
152− let provider = CGDataProvider(dataInfo: nil,
109+ let provider = CGDataProviderCreateWithData(nil, imageBuffer,
153− data: computeContext.imageBuffer,
154− size: imageByteCount) {
110+ imageByteCount, nil)
155− (_, _, _) in }
156− let bitsPerComponent = 8
111+ let bitsPerComponent = 8
157 let bitsperPixel = 32
112 let bitsperPixel = 32
158 let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
113 let colorSpaceRef = CGColorSpaceCreateDeviceRGB()
159− let bitmapInfoRaw = CGImageAlphaInfo.premultipliedLast.rawValue |
160− CGBitmapInfo.byteOrder32Big.rawValue
161− let bitmapInfo = CGBitmapInfo(rawValue: bitmapInfoRaw)
114+ let bitmapInfo = CGBitmapInfo(rawValue:
115+ CGImageAlphaInfo.PremultipliedLast.rawValue |
116+ CGBitmapInfo.ByteOrder32Big.rawValue)
162− let renderingIntent = CGColorRenderingIntent.defaultIntent
117+ let renderingIntent = CGColorRenderingIntent.RenderingIntentDefault
163
118
164 // Create UIImage from image buffer
119 // Create UIImage from image buffer
165− let imageRef = CGImage(width: width, height: height,
120+ let imageRef = CGImageCreate(width, height,
166− bitsPerComponent: bitsPerComponent,
121+ bitsPerComponent, bitsperPixel, bytesPerRow,
167− bitsPerPixel: bitsperPixel,
168− bytesPerRow: bytesPerRow,
169− space: colorSpaceRef,
122+ colorSpaceRef, bitmapInfo, provider,
170− bitmapInfo: bitmapInfo,
171− provider: provider!,
172− decode: nil, shouldInterpolate: false,
173− intent: renderingIntent)
123+ nil, false, renderingIntent)
174− let image = UIImage(cgImage: imageRef!, scale: 0.0, orientation: .up)
124+ let image = UIImage(CGImage: imageRef!, scale: 0.0,
125+ orientation: UIImageOrientation.Up)
175
126
176 return image
127 return image
177 }
128 }
178
129
179− internal func metaballEdgesBuffer() -> MTLBuffer {
130+ func metaballTexture(metaballs: [Metaball]) -> MTLTexture {
180− let floats = dataSource.metaballGraph.adjacencyMatrix.buffer
181−
182− let bufferLength = floats.count * MemoryLayout<Float>.size
183− let device = context.device
184− let buffer = device.makeBuffer(bytes: floats,
185− length: bufferLength,
186− options: MTLResourceOptions())
187−
188− return buffer!
189− }
190−
191− internal func metaballBuffer() -> MTLBuffer {
192 // Create Float array for buffer
131 // Create Float array for buffer
193 // Exclude metaballs far from the view's bounds
132 // Exclude metaballs far from the view's bounds
194 let border: CGFloat = 100
133 let border: CGFloat = 100
195− let metaballs = self.dataSource.metaballs!
196−
197− var floats = [Float](repeating: 0, count: 5)
198− floats = metaballs.reduce(floats) {
199− (array, metaball) -> [Float] in
134+ var floats: [Float] = metaballs.reduce([Float(0)]) { (var array, metaball) -> [Float] in
200− var array = array
201−
202 let x = CGFloat(metaball.midX)
135 let x = CGFloat(metaball.midX)
203 let y = CGFloat(metaball.midY)
136 let y = CGFloat(metaball.midY)
204− if -border < x,
205− x < targetView.width + border,
137+ if -border < x ≤ targetView.width + border &&
206− -border < y,
207− y < targetView.height + border {
138+ -border < y ≤ targetView.height + border {
208− array.append(Float(x))
139+ array.append(Float(x))
209− array.append(Float(y))
140+ array.append(Float(y))
210−
211− let color = metaball.color
212− let components = color.components
213− array.append(Float(components.red))
214− array.append(Float(components.green))
215− array.append(Float(components.blue))
216 }
141 }
217 return array
142 return array
218 }
143 }
219−
220 // Add array size to start of array so metal knows how far to go
144 // Add array size to start of array so metal knows how far to go
221− floats[0] = Float(floats.count) / 5
145+ floats[0] = Float(floats.count) / 2
222
146
223− // Create buffer
147+ // Create texture
224− let bufferLength = floats.count * MemoryLayout<Float>.size
148+ let size = floats.count
225− let device = context.device
149+ let textureDescriptor =
226− let buffer = device.makeBuffer(bytes: floats,
150+ MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(
227− length: bufferLength,
151+ .R32Float, width: size, height: 1, mipmapped: false)
228− options: MTLResourceOptions())
152+ let texture = context.device.newTextureWithDescriptor(textureDescriptor)
153+
154+ // Copy array info into texture
155+ let region = MTLRegionMake2D(0, 0, size, 1)
156+ texture.replaceRegion(region, mipmapLevel: 0, withBytes: floats,
157+ bytesPerRow: sizeof(Float) * size)
158+
159+ return texture
160+ }
161+
162+ func updateFrame() {
163+ if imageBuffer != nil {
164+ free(imageBuffer)
165+ }
166+ imageBuffer = nil
167+ }
229
168
230− return buffer!
169+ deinit {
170+ free(imageBuffer)
231 }
171 }
232}
172}
PixelImage/SwiftSugar/ApproximationOperator.swiftnew file+12
@@ -0,0 +1,12 @@
1+import Darwin
2+
3+infix operator ==~ { associativity right precedence 130 }
4+
5+func ==~ (left: DoubleValuable, right: DoubleValuable) -> Bool {
6+ let leftDouble = left.toDouble
7+ let rightDouble = right.toDouble
8+ let epsilon = abs(leftDouble/10000)
9+
10+ return (leftDouble <= rightDouble + epsilon) &&
11+ (leftDouble >= rightDouble - epsilon)
12+}
PixelImage/SwiftSugar/Collections.swiftnew file+6
@@ -0,0 +1,6 @@
1+func iterate<C, R>(collection: C, block: (String?, Any) -> R) {
2+ let mirror = Mirror(reflecting: collection)
3+ for child in mirror.children {
4+ block(child.0, child.1)
5+ }
6+}
PixelImage/SwiftSugar/ComparatorChains.swiftnew file+57
@@ -0,0 +1,57 @@
1+let doubleMax: Double = 1E+37
2+let doubleMin: Double = -1E+37
3+let floatMax: Float = 1E+37
4+let floatMin: Float = -1E+37
5+let int32Max: Int = 0x7fffffff
6+let int32Min: Int = -0x7fffffff - 1
7+
8+infix operator ≤ { associativity right precedence 131 }
9+
10+func ≤ <T: Numeric>
11+ (left: T, right: T) -> T {
12+
13+ if left < right {
14+ return left
15+ } else {
16+ return -0x7fffffff
17+ }
18+}
19+
20+//
21+infix operator ≤= { associativity right precedence 131 }
22+
23+func ≤= <T: Numeric>
24+ (left: T, right: T) -> T {
25+
26+ if left <= right {
27+ return left
28+ } else {
29+ return -0x7fffffff
30+ }
31+}
32+
33+//
34+infix operator ≥ { associativity right precedence 131 }
35+
36+func ≥ <T: Numeric>
37+ (left: T, right: T) -> T {
38+
39+ if left > right {
40+ return left
41+ } else {
42+ return 0x7fffffff
43+ }
44+}
45+
46+//
47+infix operator ≥= { associativity right precedence 131 }
48+
49+func ≥= <T: Numeric>
50+ (left: T, right: T) -> T {
51+
52+ if left >= right {
53+ return left
54+ } else {
55+ return 0x7fffffff
56+ }
57+}
PixelImage/SwiftSugar/Dictionary.swiftnew file+12
@@ -0,0 +1,12 @@
1+extension Dictionary {
2+ subscript(keys: [Key]) -> [Value] {
3+ get {
4+ return keys.unwrappedMap({ self[$0] })
5+ }
6+ set (values) {
7+ for (key, value) in zip(keys, values) {
8+ self[key] = value
9+ }
10+ }
11+ }
12+}
PixelImage/SwiftSugar/Foundation/NSNumber.swiftnew file+11
@@ -0,0 +1,11 @@
1+import Foundation
2+
3+extension NSNumber: DoubleValuable {
4+ var toDouble: Double {
5+ get { return self.doubleValue }
6+ }
7+
8+ static func fromDouble(double: Double) -> Self {
9+ return self.init(double: double)
10+ }
11+}
PixelImage/SwiftSugar/Numeric.swift+29−22
@@ -1,55 +1,62 @@
1protocol DoubleValuable {
1protocol DoubleValuable {
2 var toDouble: Double { get }
2 var toDouble: Double { get }
3
3
4− static func fromDouble(_ double: Double) -> Self
4+ static func fromDouble(double: Double) -> Self
5}
5}
6
6
7−protocol Numeric: DoubleValuable, Comparable,
7+postfix operator ++ { }
8− ExpressibleByIntegerLiteral {
9
8
10− static func / (lhs: Self, rhs: Self) -> Self
9+protocol Incrementable {
11− static func - (lhs: Self, rhs: Self) -> Self
10+ postfix func ++ (inout _: Self) -> Self
12− static func + (lhs: Self, rhs: Self) -> Self
13− static func * (lhs: Self, rhs: Self) -> Self
14}
11}
15
12
13+protocol Numeric: DoubleValuable, Incrementable, Comparable,
14+ IntegerLiteralConvertible {
15+
16+ @warn_unused_result func / (lhs: Self, rhs: Self) -> Self
17+ @warn_unused_result func - (lhs: Self, rhs: Self) -> Self
18+ @warn_unused_result func + (lhs: Self, rhs: Self) -> Self
19+ @warn_unused_result func * (lhs: Self, rhs: Self) -> Self
20+ postfix func ++ (inout _: Self) -> Self
21+}
22+
16−protocol FastNumeric: Numeric {}
23+protocol FastNumeric: Numeric { }
17
24
18extension Double: FastNumeric {
25extension Double: FastNumeric {
19 var toDouble: Double {
26 var toDouble: Double {
20− get {
21− return self
27+ get { return self }
22− }
23 }
28 }
24
29
25− static func fromDouble(_ double: Double) -> Double {
30+ static func fromDouble(double: Double) -> Double {
26 return double
31 return double
27 }
32 }
28−
29}
33}
30
34
31extension Float: FastNumeric {
35extension Float: FastNumeric {
32 var toDouble: Double {
36 var toDouble: Double {
33− get {
34− return Double(self)
37+ get { return Double(self) }
35− }
36 }
38 }
37
39
38− static func fromDouble(_ double: Double) -> Float {
40+ static func fromDouble(double: Double) -> Float {
39 return Float(double)
41 return Float(double)
40 }
42 }
41−
42}
43}
43
44
44extension Int: FastNumeric {
45extension Int: FastNumeric {
45 var toDouble: Double {
46 var toDouble: Double {
46− get {
47− return Double(self)
47+ get { return Double(self) }
48− }
49 }
48 }
50
49
51− static func fromDouble(_ double: Double) -> Int {
50+ static func fromDouble(double: Double) -> Int {
52 return Int(double)
51 return Int(double)
53 }
52 }
53+}
54
54
55+//
56+extension Int {
57+ func times(@noescape block: () throws -> ()) rethrows {
58+ for _ in 1...self {
59+ try block()
60+ }
61+ }
55}
62}
PixelImage/SwiftSugar/PowerOperator.swift+2−8
@@ -1,14 +1,8 @@
1import Darwin
1import Darwin
2
2
3−precedencegroup PowerPrecedence {
4− higherThan: MultiplicationPrecedence
5− associativity: right
3+infix operator ^ { associativity right precedence 131 }
6−}
7−
8−//
9−infix operator ^: PowerPrecedence
10
4
11−func ^ <T: DoubleValuable>(left: T, right: T) -> T {
5+func ^<T: DoubleValuable>(left: T, right: T) -> T {
12 return T.fromDouble(pow(left.toDouble, right.toDouble))
6 return T.fromDouble(pow(left.toDouble, right.toDouble))
13}
7}
14
8
PixelImage/SwiftSugar/Sequence.swiftnew file+16
@@ -0,0 +1,16 @@
1+extension SequenceType {
2+ func unwrappedMap<T>
3+ (@noescape transform: (Self.Generator.Element) throws -> T?) rethrows
4+ -> [T] {
5+ return try self.reduce( [T]() ) {
6+ (var accumulator: [T], element: Self.Generator.Element) -> [T] in
7+
8+ let transformed = try transform(element)
9+ if let unwrapped = transformed {
10+ accumulator.append(unwrapped)
11+ }
12+
13+ return accumulator
14+ }
15+ }
16+}
PixelImage/SwiftSugar/Sequences/Memoize.swiftnew file+162
@@ -0,0 +1,162 @@
1+protocol MemoizedSequence: LazySequenceType {
2+ typealias IndexType: Hashable
3+ typealias ReturnType
4+
5+ init(first: IndexType,
6+ incrementer: ((inout IndexType) -> Void),
7+ memoizedFunction: (IndexType -> ReturnType))
8+}
9+
10+
11+struct HashMemoizedSequence <IndexType: Hashable, ReturnType>:
12+MemoizedSequence {
13+
14+ let memoizedFunction: (IndexType -> ReturnType)
15+ let increment: ((inout IndexType) -> Void)
16+ let firstIndex: IndexType
17+
18+ var index: IndexType
19+
20+ init(first: IndexType,
21+ incrementer: ((inout IndexType) -> Void),
22+ memoizedFunction: (IndexType -> ReturnType)) {
23+
24+ self.firstIndex = first
25+
26+ self.index = first
27+ self.increment = incrementer
28+ self.memoizedFunction = memoizedFunction
29+ }
30+
31+ init(first: IndexType,
32+ incrementer: ((inout IndexType) -> Void),
33+ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
34+ let memoizedFunction = memoize(closure)
35+
36+ self.init(first: first, incrementer: incrementer,
37+ memoizedFunction: memoizedFunction)
38+ }
39+
40+ init(first: IndexType,
41+ incrementer: ((inout IndexType) -> Void),
42+ function: (IndexType -> ReturnType)) {
43+
44+ let memoizedFunction = memoize(function)
45+
46+ self.init(first: first, incrementer: incrementer,
47+ memoizedFunction: memoizedFunction)
48+ }
49+}
50+
51+extension HashMemoizedSequence: GeneratorType {
52+ mutating func next() -> ReturnType? {
53+ let result = memoizedFunction(index)
54+ increment(&index)
55+ return result
56+ }
57+}
58+
59+extension HashMemoizedSequence: LazySequenceType {
60+ func generate() -> HashMemoizedSequence {
61+ return self
62+ }
63+}
64+
65+extension HashMemoizedSequence where ReturnType: Comparable {
66+ @warn_unused_result
67+ func contains(element: ReturnType) -> Bool {
68+ var index = firstIndex
69+
70+ while true {
71+ let value = memoizedFunction(index)
72+
73+ if value == element {
74+ return true
75+ } else if value > element {
76+ return false
77+ }
78+
79+ increment(&index)
80+ }
81+ }
82+}
83+
84+extension HashMemoizedSequence where IndexType: Incrementable {
85+ init(first: IndexType,
86+ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
87+ self.firstIndex = first
88+ self.index = first
89+ self.increment = { (inout index: IndexType) in
90+ index++
91+ }
92+ self.memoizedFunction = memoize(closure)
93+ }
94+
95+ init(first: IndexType,
96+ function: (IndexType -> ReturnType)) {
97+ self.firstIndex = first
98+ self.index = first
99+ self.increment = { (inout index: IndexType) in
100+ index++
101+ }
102+ self.memoizedFunction = memoize(function)
103+ }
104+}
105+
106+extension HashMemoizedSequence where IndexType: Incrementable,
107+ IndexType: IntegerLiteralConvertible {
108+ init(_ closure: ((IndexType -> ReturnType, IndexType) -> ReturnType)) {
109+ self.firstIndex = 1
110+ self.index = 1
111+ self.increment = { (inout index: IndexType) in
112+ index++
113+ }
114+ self.memoizedFunction = memoize(closure)
115+ }
116+
117+ init(_ function: (IndexType -> ReturnType)) {
118+ self.firstIndex = 1
119+ self.index = 1
120+ self.increment = { (inout index: IndexType) in
121+ index++
122+ }
123+ self.memoizedFunction = memoize(function)
124+ }
125+}
126+
127+func memoize <H: Hashable, R> (closure: ((H -> R, H) -> R) ) -> (H -> R) {
128+
129+ var table = [H : R]()
130+
131+ var auxiliaryFunction: (H -> R)!
132+ auxiliaryFunction = { index in
133+ if let result = table[index] {
134+ return result
135+ }
136+
137+ let result = closure(auxiliaryFunction, index)
138+ table[index] = result
139+
140+ return result
141+ }
142+
143+ return auxiliaryFunction
144+}
145+
146+func memoize <H: Hashable, R> (function: (H -> R) ) -> (H -> R) {
147+
148+ var table = [H : R]()
149+
150+ let result: (H -> R) = { index in
151+ if let result = table[index] {
152+ return result
153+ }
154+
155+ let result = function(index)
156+ table[index] = result
157+
158+ return result
159+ }
160+
161+ return result
162+}
PixelImage/SwiftSugar/SignOperator.swiftnew file+13
@@ -0,0 +1,13 @@
1+
2+prefix operator ± { }
3+
4+prefix func ± <T: Numeric> (number: T) -> T {
5+
6+ if number > 0 {
7+ return 1
8+ } else if number == 0 {
9+ return 0
10+ } else {
11+ return -1
12+ }
13+}
PixelImage/SwiftSugar/String.swiftnew file+9
@@ -0,0 +1,9 @@
1+extension String: DoubleValuable {
2+ var toDouble: Double {
3+ get { return Double(self) ?? Double(0) }
4+ }
5+
6+ static func fromDouble(double: Double) -> String {
7+ return "\(double)"
8+ }
9+}
PixelImage/SwiftSugar/SwiftSequences/Categorise.swiftnew file+211
@@ -0,0 +1,211 @@
1+// MARK: - Eager
2+
3+// MARK: Categorise
4+
5+public extension SequenceType {
6+
7+ /**
8+ Categorises elements of `self` into a dictionary, with the keys
9+ given by `keyFunc`
10+ ```swift
11+ struct Person : CustomStringConvertible {
12+ let name: String
13+ let age : Int
14+ init(_ name: String, _ age: Int) {
15+ self.name = name
16+ self.age = age
17+ }
18+ var description: String { return name }
19+ }
20+
21+ let people = [
22+ Person("Jo", 20),
23+ Person("An", 20),
24+ Person("Cthulu", 4000)
25+ ]
26+
27+ people.categorise { p in p.age }
28+
29+ //[20: [Jo, An], 4000: [Cthulu]]
30+ ```
31+ */
32+ @warn_unused_result
33+ func categorise<U : Hashable>(@noescape keyFunc: Generator.Element throws -> U)
34+ rethrows -> [U:[Generator.Element]] {
35+ var dict: [U:[Generator.Element]] = [:]
36+ for el in self {
37+ let key = try keyFunc(el)
38+ if case nil = dict[key]?.append(el) { dict[key] = [el] }
39+ }
40+ return dict
41+ }
42+}
43+
44+public extension SequenceType where Generator.Element : Hashable {
45+
46+ // MARK: Frequencies
47+
48+ /**
49+ Returns a dictionary where the keys are the elements of self, and
50+ the values are their respective frequencies
51+ ```swift
52+ [0, 3, 0, 1, 1, 3, 2, 3, 1, 0].freqs()
53+ // [2: 1, 0: 3, 3: 3, 1: 3]
54+ ```
55+ */
56+ @warn_unused_result
57+ func freqs() -> [Generator.Element:Int] {
58+ var freqs: [Generator.Element:Int] = [:]
59+ for el in self { freqs[el] = freqs[el]?.successor() ?? 1 }
60+ return freqs
61+ }
62+
63+ // MARK: Uniques
64+
65+ /**
66+ Returns an array of the elements of `self`, in order, with
67+ duplicates removed
68+ ```swift
69+ [3, 1, 2, 3, 2, 1, 1, 2, 3, 3].uniques()
70+ // [3, 1, 2]
71+ ```
72+ */
73+ @warn_unused_result
74+ public func uniques() -> [Generator.Element] {
75+ var prevs: Set<Generator.Element> = []
76+ var uniqs: [Generator.Element] = []
77+ for el in self where !prevs.contains(el) {
78+ prevs.insert(el)
79+ uniqs.append(el)
80+ }
81+ return uniqs
82+ }
83+
84+ /// Returns the element which occurs most frequently in `self`
85+ @warn_unused_result
86+ public func mostFrequent() -> Generator.Element? {
87+ var g = generate()
88+ guard let b = g.next() else { return nil }
89+ var be = b
90+ var bn = 1
91+ var freqs: [Generator.Element:Int] = [:]
92+ for e in self {
93+ let n = (freqs[e] ?? 0) + 1
94+ if n > bn { (be,bn) = (e,n) }
95+ freqs[e] = n
96+ }
97+ return be
98+ }
99+}
100+
101+// MARK: - Lazy
102+
103+// MARK: Uniques
104+/// :nodoc:
105+public struct UniquesGen<G : GeneratorType where G.Element : Hashable> : GeneratorType {
106+
107+ private var prevs: Set<G.Element>
108+ private var g: G
109+ /// :nodoc:
110+ public mutating func next() -> G.Element? {
111+ while let next = g.next() {
112+ if !prevs.contains(next) {
113+ prevs.insert(next)
114+ return next
115+ }
116+ }
117+ return nil
118+ }
119+}
120+/// :nodoc:
121+public struct UniquesSeq<
122+ S : SequenceType where
123+ S.Generator.Element : Hashable
124+ > : LazySequenceType {
125+ private let seq: S
126+ /// :nodoc:
127+ public func generate() -> UniquesGen<S.Generator> {
128+ return UniquesGen(prevs: [], g: seq.generate())
129+ }
130+}
131+
132+public extension LazySequenceType where Generator.Element : Hashable {
133+
134+ /// returns a `LazySequence` of the elements of `self`, in order, with
135+ /// duplicates removed
136+ @warn_unused_result
137+ func uniques() -> UniquesSeq<Self> {
138+ return UniquesSeq(seq: self)
139+ }
140+}
141+
142+// MARK: Grouping
143+
144+/// :nodoc:
145+
146+public struct GroupByGen<G : GeneratorType> : GeneratorType {
147+
148+ private var genr: G
149+ private var last: G.Element?
150+ private let isEq: (G.Element, G.Element) -> Bool
151+ /// :nodoc:
152+ mutating public func next() -> [G.Element]? {
153+ guard let head = last else { return nil }
154+ var group = [head]
155+ last = nil
156+ while let next = genr.next() {
157+ guard isEq(group.last!, next) else {
158+ last = next
159+ return group
160+ }
161+ group.append(next)
162+ }
163+ return group
164+ }
165+ private init(g : G, isEquivalent: (G.Element, G.Element) -> Bool) {
166+ genr = g
167+ last = genr.next()
168+ isEq = isEquivalent
169+ }
170+}
171+
172+/// :nodoc:
173+
174+public struct GroupBySeq<S : SequenceType> : LazySequenceType {
175+ private let seq: S
176+ private let isEquivalent: (S.Generator.Element, S.Generator.Element) -> Bool
177+ /// :nodoc:
178+ public func generate() -> GroupByGen<S.Generator> {
179+ return GroupByGen(g: seq.generate(), isEquivalent: isEquivalent)
180+ }
181+}
182+
183+public extension LazySequenceType where Generator.Element : Equatable {
184+
185+ /// Returns a lazy sequence of self, chunked into arrays of adjacent equal values
186+ /// ```swift
187+ /// [1, 2, 2, 3, 1, 1, 3, 4, 2].lazy.group()
188+ ///
189+ /// [1], [2, 2], [3], [1, 1], [3], [4], [2]
190+ /// ```
191+ @warn_unused_result
192+ func group() -> GroupBySeq<Self> {
193+ return GroupBySeq(seq: self, isEquivalent: ==)
194+ }
195+}
196+
197+public extension LazySequenceType {
198+
199+ /// Returns a lazy sequence of self, chunked into arrays of adjacent equal values
200+ /// - Parameter isEquivalent: a function that returns true if its two parameters are equal
201+ /// ```swift
202+ /// [1, 3, 5, 20, 22, 18, 6, 7].lazy.groupBy { (a,b) in abs(a - b) < 5 }
203+ ///
204+ /// [1, 3, 5], [20, 22, 18], [6, 7]
205+ /// ```
206+ @warn_unused_result
207+ func group(isEquivalent: (Generator.Element, Generator.Element) -> Bool)
208+ -> GroupBySeq<Self> {
209+ return GroupBySeq(seq: self, isEquivalent: isEquivalent)
210+ }
211+}
PixelImage/SwiftSugar/SwiftSequences/ChunkWindowSplit.swiftnew file+146
@@ -0,0 +1,146 @@
1+// MARK: - Eager
2+
3+// MARK: Chunk
4+
5+public extension CollectionType {
6+
7+ /// Returns an array of arrays of n non-overlapping elements of self
8+ /// - Parameter n: The size of the chunk
9+ /// - Precondition: `n > 0`
10+ /// - SeeAlso: `func window(n: Int) -> [[Self.Generator.Element]]`
11+ /// ```swift
12+ /// [1, 2, 3, 4, 5].chunk(2)
13+ ///
14+ /// [[1, 2], [3, 4], [5]]
15+ /// ```
16+ @warn_unused_result
17+ public func chunk(n: Index.Distance) -> [SubSequence] {
18+ var res: [SubSequence] = []
19+ var i = startIndex
20+ var j: Index
21+ while i != endIndex {
22+ j = i.advancedBy(n, limit: endIndex)
23+ res.append(self[i..<j])
24+ i = j
25+ }
26+ return res
27+ }
28+}
29+
30+// MARK: Window
31+
32+public extension CollectionType {
33+
34+ /// Returns an array of arrays of n overlapping elements of self
35+ /// - Parameter n: The size of the window
36+ /// - SeeAlso: `func chunk(n: Int) -> [[Self.Generator.Element]]`
37+ /// ```swift
38+ /// [1, 2, 3, 4].window(2)
39+ ///
40+ /// [[1, 2], [2, 3], [3, 4]]
41+ /// ```
42+ @warn_unused_result
43+ func window(n: Index.Distance) -> [SubSequence] {
44+ var ret: [SubSequence] = []
45+ ret.reserveCapacity(underestimateCount() - numericCast(n))
46+ var i = startIndex
47+ var j = i.advancedBy(n, limit: endIndex)
48+ while true {
49+ ret.append(self[i..<j])
50+ i = i.successor()
51+ if j == endIndex { return ret }
52+ j = j.successor()
53+ }
54+ }
55+}
56+
57+// MARK: - Lazy
58+
59+// MARK: Chunk
60+/// :nodoc:
61+public struct ChunkGen<C: CollectionType> : GeneratorType {
62+
63+ private var c: C
64+ private let n: C.Index.Distance
65+ private var i: C.Index
66+
67+ public mutating func next() -> C.SubSequence? {
68+ if i == c.endIndex { return nil }
69+ let j = i.advancedBy(n, limit: c.endIndex)
70+ defer { i = j }
71+ return c[i..<j]
72+ }
73+}
74+/// :nodoc:
75+public struct ChunkSeq<C: CollectionType> : LazySequenceType {
76+
77+ private let c: C
78+ private let n: C.Index.Distance
79+ /// :nodoc:
80+ public func generate() -> ChunkGen<C> {
81+ return ChunkGen(c: c, n: n, i: c.startIndex)
82+ }
83+}
84+
85+public extension LazyCollectionType {
86+
87+ /// Returns lazily-generated arrays of n non-overlapping elements of self
88+ /// - Parameter n: The size of the chunk
89+ /// - SeeAlso: `func window(n: Int) -> WindowSeq<Self>`
90+ /// ```swift
91+ /// lazy([1, 2, 3, 4, 5]).chunk(2)
92+ ///
93+ /// [1, 2], [3, 4], [5]
94+ /// ```
95+ @warn_unused_result
96+ func chunk(n: Index.Distance) -> ChunkSeq<Self> {
97+ return ChunkSeq(c: self, n: n)
98+ }
99+}
100+
101+// MARK: Window
102+/// :nodoc:
103+public struct WindowGen<C: CollectionType> : GeneratorType {
104+
105+ private let c: C
106+ private var i, j: C.Index
107+ private var s: Bool
108+ /// :nodoc:
109+ mutating public func next() -> C.SubSequence? {
110+ if s { return nil }
111+ if j == c.endIndex {
112+ s = true
113+ return c[i..<j]
114+ }
115+ defer { (i,j) = (i.successor(),j.successor()) }
116+ return c[i..<j]
117+ }
118+}
119+
120+/// :nodoc:
121+
122+public struct WindowSeq<C: CollectionType> : LazySequenceType {
123+
124+ private let c: C
125+ private let n: C.Index.Distance
126+ /// :nodoc:
127+ public func generate() -> WindowGen<C> {
128+ return WindowGen(c: c, i: c.startIndex, j: c.startIndex.advancedBy(n, limit: c.endIndex), s: false)
129+ }
130+}
131+
132+public extension LazyCollectionType {
133+
134+ /// Returns lazily-generated arrays of n overlapping elements of self
135+ /// - Parameter n: The size of the window
136+ /// - SeeAlso: `func chunk(n: Int) -> ChunkSeq<Self>`
137+ /// ```swift
138+ /// lazy([1, 2, 3, 4]).window(2)
139+ ///
140+ /// [1, 2], [2, 3], [3, 4]
141+ /// ```
142+ @warn_unused_result
143+ func window(n: Index.Distance) -> WindowSeq<Self> {
144+ return WindowSeq(c: self, n: n)
145+ }
146+}
PixelImage/SwiftSugar/SwiftSequences/Combinations.swiftnew file+114
@@ -0,0 +1,114 @@
1+/// :nodoc:
2+public struct ComboGen<SubElement> : GeneratorType {
3+
4+ private let coll: [SubElement]
5+ private var curr: [SubElement]
6+ private var inds: [Int]
7+ /// :nodoc:
8+ mutating public func next() -> [SubElement]? {
9+ for (max, curInd) in zip(coll.indices.reverse(), inds.indices.reverse())
10+ where max != inds[curInd] {
11+ curr[curInd] = coll[++inds[curInd]]
12+ for j in inds.indices.suffixFrom(curInd+1) {
13+ inds[j] = inds[j-1].successor()
14+ curr[j] = coll[inds[j]]
15+ }
16+ return curr
17+ }
18+ return nil
19+ }
20+}
21+/// :nodoc:
22+public struct ComboSeq<Element> : LazySequenceType {
23+
24+ private let start: [Element]
25+ private let col : [Element]
26+ private let inds : [Int]
27+ /// :nodoc:
28+ public func generate() -> ComboGen<Element> {
29+ return ComboGen<Element>(coll: col, curr: start, inds: inds)
30+ }
31+
32+ internal init(n: Int, col: [Element]) {
33+ self.col = col
34+ start = Array(col.prefixUpTo(n))
35+ var inds = Array(col.indices.prefixUpTo(n))
36+ if !inds.isEmpty { --inds[n.predecessor()] }
37+ self.inds = inds
38+ }
39+}
40+/// :nodoc:
41+public struct ComboRepGen<Element> : GeneratorType {
42+
43+ private let coll: [Element]
44+ private var curr: [Element]
45+ private var inds: [Int]
46+ private let max : Int
47+ /// :nodoc:
48+ mutating public func next() -> [Element]? {
49+ for curInd in inds.indices.reverse() where max != inds[curInd] {
50+ curr[curInd] = coll[++inds[curInd]]
51+ for j in (curInd+1)..<inds.count {
52+ inds[j] = inds[j-1]
53+ curr[j] = coll[inds[j]]
54+ }
55+ return curr
56+ }
57+ return nil
58+ }
59+}
60+/// :nodoc:
61+public struct ComboRepSeq<Element> : LazySequenceType {
62+
63+ private let start: [Element]
64+ private let inds : [Int]
65+ private let col : [Element]
66+ private let max : Int
67+ /// :nodoc:
68+ public func generate() -> ComboRepGen<Element> {
69+ return ComboRepGen(coll: col, curr: start, inds: inds, max: max)
70+ }
71+
72+ internal init(n: Int, col: [Element]) {
73+ self.col = col
74+ start = col.first.map { x in Array(count: n, repeatedValue: x) } ?? []
75+ var inds = Array(count: n, repeatedValue: col.startIndex)
76+ if !inds.isEmpty { --inds[n-1] }
77+ self.inds = inds
78+ max = col.endIndex.predecessor()
79+ }
80+}
81+
82+
83+extension SequenceType {
84+ /**
85+ Returns the combinations without repetition of length `n` of `self`
86+ */
87+ @warn_unused_result
88+ public func combos(n: Int = 2) -> [[Generator.Element]] {
89+ return Array(ComboSeq(n: n, col: Array(self)))
90+ }
91+ /**
92+ Returns the combinations with repetition of length `n` of `self`
93+ */
94+ @warn_unused_result
95+ public func combosWithRep(n: Int) -> [[Generator.Element]] {
96+ return Array(ComboRepSeq(n: n, col: Array(self)))
97+ }
98+ /**
99+ Returns the combinations without repetition of length `n` of `self`, generated lazily
100+ and on-demand
101+ */
102+ @warn_unused_result
103+ public func lazyCombos(n: Int) -> ComboSeq<Generator.Element> {
104+ return ComboSeq(n: n, col: Array(self))
105+ }
106+ /**
107+ Returns the combinations with repetition of length `n` of `self`, generated lazily and
108+ on-demand
109+ */
110+ @warn_unused_result
111+ public func lazyCombosWithRep(n: Int) -> ComboRepSeq<Generator.Element> {
112+ return ComboRepSeq(n: n, col: Array(self))
113+ }
114+}
PixelImage/SwiftSugar/SwiftSequences/Cycle.swiftnew file+86
@@ -0,0 +1,86 @@
1+// MARK: - Eager
2+
3+// MARK: Cycle n
4+
5+public extension CollectionType {
6+
7+ /// Returns an array of n cycles of self.
8+ /// ```swift
9+ /// [1, 2, 3].cycle(2)
10+ ///
11+ /// [1, 2, 3, 1, 2, 3]
12+ /// ```
13+ @warn_unused_result
14+ func cycle(n: Int) -> [Generator.Element] {
15+ var cycled: [Generator.Element] = []
16+ cycled.reserveCapacity(underestimateCount() * n)
17+ for _ in 0..<n {
18+ cycled.appendContentsOf(self)
19+ }
20+ return cycled
21+ }
22+}
23+
24+// MARK: - Lazy
25+
26+// MARK: Cycle n
27+/// :nodoc:
28+public struct CycleNGen<C: CollectionType> : GeneratorType, LazySequenceType {
29+
30+ private let inner: C
31+ private var innerGen: C.Generator
32+ private var n: Int
33+ /// :nodoc:
34+ public mutating func next() -> C.Generator.Element? {
35+ while true {
36+ if let next = innerGen.next() { return next }
37+ n -= 1
38+ if n > 0 { innerGen = inner.generate() }
39+ else { return nil }
40+ }
41+ }
42+}
43+
44+public extension LazySequenceType where Self : CollectionType {
45+
46+ /// Returns a generator of n cycles of self.
47+ /// ```swift
48+ /// [1, 2, 3].lazy.cycle(2)
49+ ///
50+ /// 1, 2, 3, 1, 2, 3
51+ /// ```
52+ @warn_unused_result
53+ func cycle(n: Int) -> CycleNGen<Self> {
54+ return CycleNGen(inner: self, innerGen: generate(), n: n)
55+ }
56+}
57+
58+// MARK: Cycle infinite
59+/// :nodoc:
60+public struct CycleGen<C: CollectionType> : GeneratorType, LazySequenceType {
61+
62+ private let inner: C
63+ private var innerGen: C.Generator
64+ /// :nodoc:
65+ public mutating func next() -> C.Generator.Element? {
66+ for ;;innerGen = inner.generate() {
67+ if let next = innerGen.next() {
68+ return next
69+ }
70+ }
71+ }
72+}
73+
74+public extension CollectionType {
75+
76+ /// Returns an infinite generator of cycles of self.
77+ /// ```swift
78+ /// [1, 2, 3].cycle()
79+ ///
80+ /// 1, 2, 3, 1, 2, 3, 1...
81+ /// ```
82+ @warn_unused_result
83+ func cycle() -> CycleGen<Self> {
84+ return CycleGen(inner: self, innerGen: generate())
85+ }
86+}
PixelImage/SwiftSugar/SwiftSequences/Enumerate.swiftnew file+33
@@ -0,0 +1,33 @@
1+/// :nodoc:
2+public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {
3+
4+ private let base: Base
5+ private var i: Base.Index
6+ /// :nodoc:
7+ public mutating func next() -> (Base.Index, Base.Generator.Element)? {
8+ return i == base.endIndex ? nil : (i, base[i++])
9+ }
10+}
11+/// :nodoc:
12+public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {
13+
14+ private let col: Base
15+ /// :nodoc:
16+ public func generate() -> SpecEnumerateGen<Base> {
17+ return SpecEnumerateGen(base: col, i: col.startIndex)
18+ }
19+}
20+
21+public extension CollectionType {
22+
23+ /// Returns a lazy generator of tuples `(i, e)` where `i` is successive indices of self,
24+ /// and `e` is the respective elements. Effectively the same as `.enumerate()`, but the
25+ /// indices returned are `Self.Index`s, rather than `Int`s
26+ /// - SeeAlso: `enumerate()`
27+ @warn_unused_result
28+ func specEnumerate() -> SpecEnumerateSeq<Self> {
29+ return SpecEnumerateSeq(col: self)
30+ }
31+}
32+
33+
PixelImage/SwiftSugar/SwiftSequences/Finding.swiftnew file+80
@@ -0,0 +1,80 @@
1+prefix operator ! {}
2+public prefix func !<A>(f: A -> Bool) -> A -> Bool {
3+ return { x in !f(x) }
4+}
5+
6+public extension SequenceType {
7+
8+ /// Returns the first element in self that satisfies a predicate, or nil if it doesn't
9+ /// exist
10+ @warn_unused_result
11+ func first(@noescape thatSatisfies: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
12+ for el in self where try thatSatisfies(el) { return el }
13+ return nil
14+ }
15+
16+ /// Returns the number of elements in `self` that satisfy `predicate`
17+ @warn_unused_result
18+ func count(@noescape predicate: Generator.Element throws -> Bool) rethrows -> Int {
19+ var i = 0
20+ for el in self where try predicate(el) { i += 1 }
21+ return i
22+ }
23+
24+ /// Returns true iff every element in `self` satisfies `predicate`
25+ @warn_unused_result
26+ func all(@noescape predicate: Generator.Element throws -> Bool) rethrows -> Bool {
27+ for x in self { guard try predicate(x) else { return false } }
28+ return true
29+ }
30+}
31+
32+public extension CollectionType where Index : BidirectionalIndexType {
33+
34+
35+ /// Returns the last element in self that satisfies a predicate, or nil if it doesn't
36+ /// exist
37+ @warn_unused_result
38+ func last(@noescape predicate: Generator.Element throws -> Bool) rethrows -> Generator.Element? {
39+ for el in reverse() {
40+ if try predicate(el) {
41+ return el
42+ }
43+ }
44+ return nil
45+ }
46+
47+ /**
48+ Returns the index of the final element in `self` which satisfies
49+ `isElement`, or `nil` if it doesn't exist.
50+ */
51+ @warn_unused_result
52+ func lastIndexOf(@noescape isElement: Generator.Element throws -> Bool) rethrows -> Index? {
53+ for i in indices.reverse() where try isElement(self[i]) {
54+ return i
55+ }
56+ return nil
57+ }
58+}
59+
60+extension CollectionType {
61+ /**
62+ Returns the indices of elements of `self` that satisfy the predicate `isElement`
63+ */
64+ @warn_unused_result
65+ func indicesOf(@noescape isElement: Generator.Element throws -> Bool) rethrows -> [Index] {
66+ return try indices.filter { i in try isElement(self[i]) }
67+ }
68+}
69+
70+public extension SequenceType {
71+ @warn_unused_result
72+ func partition(@noescape predicate: Generator.Element throws -> Bool) rethrows -> ([Generator.Element], [Generator.Element]) {
73+ var t,f: [Generator.Element]
74+ (t,f) = ([],[])
75+ for e in self {
76+ if try predicate(e) { t.append(e) } else { f.append(e) }
77+ }
78+ return (t,f)
79+ }
80+}
PixelImage/SwiftSugar/SwiftSequences/FlatMap.swiftnew file+23
@@ -0,0 +1,23 @@
1+extension LazySequenceType {
2+
3+ @warn_unused_result
4+ public func flatMap<T>(transform: Elements.Generator.Element -> T?)
5+ -> LazyMapSequence<LazyFilterSequence<LazyMapSequence<Elements, T?>>, T> {
6+ return self
7+ .map(transform)
8+ .filter { opt in opt != nil }
9+ .map { notNil in notNil! }
10+ }
11+}
12+
13+extension LazyCollectionType {
14+
15+ @warn_unused_result
16+ public func flatMap<T>(transform: Elements.Generator.Element -> T?)
17+ -> LazyMapCollection<LazyFilterCollection<LazyMapCollection<Elements, T?>>, T> {
18+ return self
19+ .map(transform)
20+ .filter { opt in opt != nil }
21+ .map { notNil in notNil! }
22+ }
23+}
PixelImage/SwiftSugar/SwiftSequences/Hopping.swiftnew file+78
@@ -0,0 +1,78 @@
1+public struct RandomAccessHopCollection<
2+ Base: CollectionType where
3+ Base.Index : RandomAccessIndexType,
4+ Base.Index.Distance : ForwardIndexType
5+ >: CollectionType {
6+
7+ private let base: Base
8+ private let by : Base.Index.Stride
9+ private let fac : Base.Index.Distance
10+
11+ public let startIndex: Base.Index.Distance
12+ public let endIndex: Base.Index.Distance
13+
14+ public typealias SubSequence = RandomAccessHopCollection<Base>
15+
16+ public subscript(i: Base.Index.Distance) -> Base.Generator.Element {
17+ return base[base.startIndex.advancedBy(fac * i)]
18+ }
19+
20+ public func generate() -> IndexingGenerator<RandomAccessHopCollection<Base>> {
21+ return IndexingGenerator(self)
22+ }
23+
24+ private init(_ b: Base, _ by: Base.Index.Stride) {
25+ base = b
26+ self.by = by
27+ fac = base.startIndex.distanceTo(base.startIndex.advancedBy(by))
28+ if base.isEmpty { endIndex = 0 }
29+ else { endIndex = (base.startIndex.distanceTo(base.endIndex.predecessor()) / fac).successor() }
30+ startIndex = 0
31+ }
32+
33+ private init(_ b: Base, _ by: Base.Index.Stride, from: Base.Index.Distance, to: Base.Index.Distance) {
34+ base = b
35+ self.by = by
36+ fac = base.startIndex.distanceTo(base.startIndex.advancedBy(by))
37+ startIndex = from
38+ endIndex = to
39+ }
40+
41+ public subscript(r: Range<Base.Index.Distance>) -> RandomAccessHopCollection<Base> {
42+ return RandomAccessHopCollection(base, by, from: r.startIndex, to: r.endIndex)
43+ }
44+}
45+
46+extension CollectionType where Index: RandomAccessIndexType, Index.Distance: ForwardIndexType {
47+ public subscript(by by: Index.Stride) -> RandomAccessHopCollection<Self> {
48+ return RandomAccessHopCollection(self, by)
49+ }
50+}
51+
52+extension RandomAccessHopCollection: CustomStringConvertible, CustomDebugStringConvertible {
53+ public var debugDescription: String {
54+ return Array(self).debugDescription
55+ }
56+ public var description: String {
57+ return String(Array(self))
58+ }
59+}
60+
61+public extension CollectionType where
62+ SubSequence: CollectionType,
63+ Index == SubSequence.Index,
64+ SubSequence.Index: RandomAccessIndexType,
65+ SubSequence.Index.Distance: ForwardIndexType {
66+ subscript(r: Range<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
67+ return self[r][by: by]
68+ }
69+ subscript(r: OpenEndedRange<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
70+ return suffixFrom(r.val)[by: by]
71+ }
72+ subscript(r: OpenStartedRangeTo<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
73+ return prefixUpTo(r.val)[by: by]
74+ }
75+ subscript(r: OpenStartedRangeThrough<Index>, by by: Index.Stride) -> RandomAccessHopCollection<SubSequence> {
76+ return prefixThrough(r.val)[by: by]
77+ }
78+}
PixelImage/SwiftSugar/SwiftSequences/Interpose.swiftnew file+366
@@ -0,0 +1,366 @@
1+// MARK: - Eager
2+
3+// MARK: Interpose with single element
4+
5+public extension SequenceType {
6+
7+ /// Returns an array that alternates between successive elements of self and element
8+ /// ```swift
9+ /// [1, 2, 3].interpose(10)
10+ ///
11+ /// [1, 10, 2, 10, 3]
12+ /// ```
13+ @warn_unused_result
14+ func interpose(element: Generator.Element) -> [Generator.Element] {
15+ var g = generate()
16+
17+ return g.next().map {
18+ var ret = [$0]
19+ while let next = g.next() {
20+ ret.append(element)
21+ ret.append(next)
22+ }
23+ return ret
24+ } ?? []
25+ }
26+
27+ /// Returns an array that alternates between n successive elements of self and element
28+ /// ```swift
29+ /// [1, 2, 3, 4, 5].interpose(10, n: 2)
30+ ///
31+ /// [1, 2, 10, 3, 4, 10, 5]
32+ /// ```
33+ @warn_unused_result
34+ func interpose(element: Generator.Element, n: Int) -> [Generator.Element] {
35+
36+ var ret: [Generator.Element] = []
37+ var g = generate()
38+ var i = n + 1
39+
40+ while let next = g.next() {
41+ if --i == 0 {
42+ ret.append(element)
43+ i = n
44+ }
45+ ret.append(next)
46+ }
47+ return ret
48+ }
49+}
50+
51+// MARK: Interpose with collection
52+
53+public extension SequenceType {
54+
55+ /// Returns an array that alternates between successive elements of self and elements of
56+ /// a colletion
57+ /// ```swift
58+ /// [1, 2, 3].interpose([10, 20])
59+ ///
60+ /// [1, 10, 20, 2, 10, 20, 3]
61+ /// ```
62+ @warn_unused_result
63+ func interpose<C : CollectionType where C.Generator.Element == Generator.Element>
64+ (col: C) -> [Generator.Element] {
65+ var g = generate()
66+ return g.next().map {
67+ var ret = [$0]
68+ while let next = g.next() {
69+ ret.appendContentsOf(col)
70+ ret.append(next)
71+ }
72+ return ret
73+ } ?? []
74+ }
75+
76+ /// Returns an array that alternates between n successive elements of self and elements
77+ /// of a colletion
78+ /// ```swift
79+ /// [1, 2, 3, 4, 5].interpose([10, 20], n: 2)
80+ ///
81+ /// [1, 2, 10, 20, 3, 4, 10, 20, 5]
82+ /// ```
83+
84+ func interpose<C : CollectionType where C.Generator.Element == Generator.Element>
85+ (col: C, n: Int) -> [Generator.Element] {
86+ var g = generate()
87+ return g.next().map {
88+ var i = n
89+ var ret = [$0]
90+ while let next = g.next() {
91+ if --i == 0 {
92+ ret.appendContentsOf(col)
93+ i = n
94+ }
95+ ret.append(next)
96+ }
97+ return ret
98+ } ?? []
99+ }
100+}
101+
102+// MARK: Interdigitate
103+
104+/// Returns an array of two sequences interdigitated
105+/// ```swift
106+/// interdig([1, 2, 3], [10, 20, 30])
107+///
108+/// [1, 10, 2, 20, 3, 30]
109+/// ```
110+@warn_unused_result
111+public func interdig<
112+ S0 : SequenceType, S1 : SequenceType where
113+ S0.Generator.Element == S1.Generator.Element
114+ >(s0: S0, _ s1: S1) -> [S0.Generator.Element] {
115+
116+ var ret: [S0.Generator.Element] = []
117+
118+ var (g0, g1) = (s0.generate(), s1.generate())
119+
120+ while let e0 = g0.next(), e1 = g1.next() {
121+ ret.append(e0)
122+ ret.append(e1)
123+ }
124+
125+ return ret
126+}
127+
128+/// Returns an array of two sequences interdigitated, with the respective length of each
129+/// interdigitation specified
130+/// - Parameter s0Len: The length of the first sequence's interdigitations
131+/// - Parameter s1Len: The length of the second sequence's interdigitations
132+/// ```swift
133+/// interdig([1, 2, 3, 4, 5], [10, 20, 30, 40, 50, 60], s0Len: 2, s1Len: 3)
134+///
135+/// [1, 2, 10, 20, 30, 3, 4, 40, 50, 60, 5]
136+/// ```
137+@warn_unused_result
138+public func interdig<
139+ S0 : SequenceType, S1 : SequenceType where
140+ S0.Generator.Element == S1.Generator.Element
141+ >(s0: S0, _ s1: S1, s0Len: Int, s1Len: Int) -> [S0.Generator.Element] {
142+
143+ var ret: [S0.Generator.Element] = []
144+
145+ var (g0, g1) = (s0.generate(), s1.generate())
146+
147+ for ;; {
148+ for _ in 0..<s0Len {
149+ if let next = g0.next() {
150+ ret.append(next)
151+ } else {
152+ return ret
153+ }
154+ }
155+ for _ in 0..<s1Len {
156+ if let next = g1.next() {
157+ ret.append(next)
158+ } else {
159+ return ret
160+ }
161+ }
162+ }
163+}
164+
165+// MARK: - Lazy
166+
167+// MARK: Interpose with single element
168+/// :nodoc:
169+public struct InterposeElGen<G : GeneratorType> : GeneratorType {
170+
171+ private let n: Int
172+ private var count: Int
173+ private var g: G
174+ private let element: G.Element
175+ /// :nodoc:
176+ public mutating func next() -> G.Element? {
177+ return --count < 0 ? {count = n; return element}() : g.next()
178+ }
179+}
180+/// :nodoc:
181+public struct InterposeElSeq<S : SequenceType> : LazySequenceType {
182+
183+ private let element: InterposeElGen<S.Generator>.Element
184+ private let n: Int
185+ private let seq: S
186+ /// :nodoc:
187+ public func generate() -> InterposeElGen<S.Generator> {
188+ return InterposeElGen(n: n, count: n, g: seq.generate(), element: element)
189+ }
190+}
191+
192+public extension LazySequenceType {
193+
194+ /// Returns a lazy sequence that alternates between successive elements of self and an
195+ /// element
196+ /// ```swift
197+ /// [1, 2, 3].lazy.interpose(10)
198+ ///
199+ /// 1, 10, 2, 10, 3, 10
200+ /// ```
201+ @warn_unused_result
202+ func interpose(element: Generator.Element) -> InterposeElSeq<Self> {
203+ return InterposeElSeq(element: element, n: 1, seq: self)
204+ }
205+
206+ /// Returns a lazy sequence that alternates between n successive elements of self and an
207+ /// element
208+ /// ```swift
209+ /// [1, 2, 3, 4, 5].lazy.interpose(10, n: 2)
210+ ///
211+ /// 1, 2, 10, 3, 4, 10, 5
212+ /// ```
213+ @warn_unused_result
214+ func interpose(element: Generator.Element, n: Int) -> InterposeElSeq<Self> {
215+ return InterposeElSeq(element: element, n: n, seq: self)
216+ }
217+}
218+
219+// MARK: Interpose with collection
220+/// :nodoc:
221+public struct InterposeColGen<
222+ G : GeneratorType,
223+ C: CollectionType where
224+ G.Element == C.Generator.Element
225+ > : GeneratorType {
226+
227+ private let col: C
228+ private var g: G
229+ private let n: Int
230+ private var count: Int
231+ private var colG: C.Generator
232+ /// :nodoc:
233+ public mutating func next() -> G.Element? {
234+ return --count <= 0 ? {
235+ colG.next() ?? {
236+ count = n
237+ colG = col.generate()
238+ return g.next()
239+ }()}() : g.next()
240+ }
241+}
242+/// :nodoc:
243+public struct InterposeColSeq<
244+ S : SequenceType,
245+ C: CollectionType where
246+ S.Generator.Element == C.Generator.Element
247+ > : LazySequenceType {
248+
249+ private let col: C
250+ private let n: Int
251+ private let seq: S
252+ /// :nodoc:
253+ public func generate() -> InterposeColGen<S.Generator, C> {
254+ return InterposeColGen(col: col, g: seq.generate(), n: n, count: n + 1, colG: col.generate())
255+ }
256+}
257+
258+public extension LazySequenceType {
259+
260+ /// Returns a lazy sequence that alternates between successive elements of self and
261+ /// elements of a colletion
262+ /// ```swift
263+ /// [1, 2, 3].lazy.interpose([10, 20])
264+ ///
265+ /// 1, 10, 20, 2, 10, 20, 3, 10, 20
266+ /// ```
267+ @warn_unused_result
268+ func interpose<
269+ C: CollectionType where
270+ C.Generator.Element == Generator.Element
271+ >(elements: C) -> InterposeColSeq<Self, C> {
272+ return InterposeColSeq(col: elements, n: 1, seq: self)
273+ }
274+
275+ /// Returns a lazy sequence that alternates between n successive elements of self and
276+ /// elements of a colletion
277+ /// ```swift
278+ /// [1, 2, 3, 4, 5].lazy.interpose([10, 20], n: 2)
279+ ///
280+ /// 1, 2, 10, 20, 3, 4, 10, 20, 5
281+ /// ```
282+ @warn_unused_result
283+ func interpose<
284+ C: CollectionType where
285+ C.Generator.Element == Generator.Element
286+ >(elements: C, n: Int) -> InterposeColSeq<Self, C> {
287+ return InterposeColSeq(col: elements, n: n, seq: self)
288+ }
289+}
290+
291+// MARK: Interdigitate
292+/// :nodoc:
293+public struct InterDigGen<
294+ G0 : GeneratorType,
295+ G1 : GeneratorType where
296+ G0.Element == G1.Element
297+ > : GeneratorType {
298+
299+ private var g0: G0
300+ private var g1: G1
301+
302+ private let aN: Int
303+ private let bN: Int
304+
305+ private var count: Int
306+ /// :nodoc:
307+ public mutating func next() -> G0.Element? {
308+ for (--count;;count = aN) {
309+ if count >= bN { return count < 0 ? g1.next() : g0.next() }
310+ }
311+ }
312+}
313+/// :nodoc:
314+public struct InterDigSeq<
315+ S0 : LazySequenceType,
316+ S1 : LazySequenceType where
317+ S0.Generator.Element == S1.Generator.Element
318+ > : LazySequenceType {
319+
320+ private let s0: S0
321+ private let s1: S1
322+
323+ private let aN: Int
324+ private let bN: Int
325+ /// :nodoc:
326+ public func generate() -> InterDigGen<S0.Generator, S1.Generator> {
327+ return InterDigGen(
328+ g0: s0.generate(),
329+ g1: s1.generate(),
330+ aN: aN - 1,
331+ bN: -bN,
332+ count: aN
333+ )
334+ }
335+}
336+
337+/// Returns a lazy sequence of two sequences interdigitated
338+/// ```swift
339+/// interdig([1, 2, 3].lazy, [10, 20, 30].lazy)
340+///
341+/// 1, 10, 2, 20, 3, 30
342+/// ```
343+@warn_unused_result
344+public func interdig<
345+ S0 : LazySequenceType, S1 : LazySequenceType where
346+ S0.Generator.Element == S1.Generator.Element
347+ >(s0: S0, _ s1: S1) -> InterDigSeq<S0, S1> {
348+ return InterDigSeq(s0: s0, s1: s1, aN: 1, bN: 1)
349+}
350+
351+/// Returns a lazy sequence of two sequences interdigitated, with the respective length of
352+/// each interdigitation specified
353+/// - Parameter s0Len: The length of the first sequence's interdigitations
354+/// - Parameter s1Len: The length of the second sequence's interdigitations
355+/// ```swift
356+/// interdig([1, 2, 3, 4, 5].lazy, [10, 20, 30, 40, 50, 60].lazy, s0Len: 2, s1Len: 3)
357+///
358+/// 1, 2, 10, 20, 30, 3, 4, 40, 50, 60, 5
359+/// ```
360+@warn_unused_result
361+public func interdig<
362+ S0 : SequenceType, S1 : SequenceType where
363+ S0.Generator.Element == S1.Generator.Element
364+ >(s0: S0, _ s1: S1, s0Len: Int, s1Len: Int = 1) -> InterDigSeq<S0, S1> {
365+ return InterDigSeq(s0: s0, s1: s1, aN: s0Len, bN: s1Len)
366+}
PixelImage/SwiftSugar/SwiftSequences/Iterate.swiftnew file+34
@@ -0,0 +1,34 @@
1+public struct IterateGenerator<Element>: GeneratorType {
2+ private var x: Element
3+ private let f: Element -> Element
4+ public mutating func next() -> Element? {
5+ defer { x = f(x) }
6+ return x
7+ }
8+}
9+
10+public struct IterateSequence<Element>: SequenceType {
11+ private let x: Element
12+ private let f: Element -> Element
13+ public func generate() -> IterateGenerator<Element> {
14+ return IterateGenerator(x: x, f: f)
15+ }
16+}
17+
18+public struct IterateEndGenerator<Element>: GeneratorType {
19+ private var x: Element?
20+ private var f: Element -> Element?
21+ public mutating func next() -> Element? {
22+ guard let y = x else { return nil }
23+ defer { x = f(y) }
24+ return y
25+ }
26+}
27+
28+public struct IterateEndSequence<Element>: SequenceType {
29+ private let x: Element
30+ private let f: Element -> Element?
31+ public func generate() -> IterateEndGenerator<Element> {
32+ return IterateEndGenerator(x: x, f: f)
33+ }
34+}
PixelImage/SwiftSugar/SwiftSequences/NestedSequences.swiftnew file+229
@@ -0,0 +1,229 @@
1+// MARK: - Eager
2+
3+// MARK: Cartesian Product
4+
5+private extension GeneratorType where Element : CollectionType {
6+ mutating private func product() -> [[Element.Generator.Element]] {
7+ guard let x = next() else { return [[]] }
8+ let xs = product()
9+ return x.flatMap { h in xs.map { [h] + $0 } }
10+ }
11+}
12+
13+public extension SequenceType where Generator.Element : SequenceType, Generator.Element : CollectionType {
14+
15+ /// Returns a cartesian product of self
16+ /// ```swift
17+ /// [[1, 2], [3, 4]].product()
18+ /// [[1, 3], [1, 4], [2, 3], [2, 4]]
19+ /// ```
20+ @warn_unused_result
21+ public func product() -> [[Generator.Element.Generator.Element]] {
22+ var g = generate()
23+ return g.product()
24+ }
25+}
26+
27+public extension SequenceType where Generator.Element : SequenceType {
28+
29+ /// Returns a cartesian product of self
30+ /// ```swift
31+ /// [[1, 2], [3, 4]].product()
32+ /// [[1, 3], [1, 4], [2, 3], [2, 4]]
33+ /// ```
34+ @warn_unused_result
35+ public func product() -> [[Generator.Element.Generator.Element]] {
36+ return map(Array.init).product()
37+ }
38+}
39+
40+/// Cartesian product
41+/// ```swift
42+/// product([1, 2], [3, 4])
43+/// [[1, 3], [1, 4], [2, 3], [2, 4]]
44+/// ```
45+@warn_unused_result
46+public func product<C : CollectionType>(cols: C...) -> [[C.Generator.Element]] {
47+ return cols.product()
48+}
49+
50+/// Cartesian product
51+/// ```swift
52+/// product([1, 2], [3, 4])
53+/// [[1, 3], [1, 4], [2, 3], [2, 4]]
54+/// ```
55+
56+public func product<S : SequenceType>(cols: S...) -> [[S.Generator.Element]] {
57+ return cols.product()
58+}
59+
60+// MARK: Transposition
61+
62+private extension SequenceType {
63+ private func mapM<U>(@noescape transform: Generator.Element -> U?) -> [U]? {
64+ var result: [U] = []
65+ result.reserveCapacity(underestimateCount())
66+ for e in self {
67+ if let r = transform(e) { result.append(r) } else { return nil }
68+ }
69+ return result
70+ }
71+}
72+
73+public extension SequenceType where Generator.Element : SequenceType {
74+
75+ /// Returns a transposed self
76+ /// ```swift
77+ /// [[1, 2, 3], [1, 2, 3], [1, 2, 3]].transpose()
78+ ///
79+ /// [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
80+ /// ```
81+ @warn_unused_result
82+ func transpose() -> [[Generator.Element.Generator.Element]] {
83+ return Array(TransposeSeq(seq: self))
84+ }
85+}
86+
87+// MARK: - Lazy
88+
89+// MARK: Cartesian Product
90+/// :nodoc:
91+public struct ProdGen<C : CollectionType> : GeneratorType {
92+
93+ private let cols: [C] // Must be collections, not sequences, in order to be multi-pass
94+
95+ private var gens: [C.Generator]
96+ private var curr: [C.Generator.Element]
97+ /// :nodoc:
98+ public mutating func next() -> [C.Generator.Element]? {
99+
100+ for i in gens.indices.reverse() { // Loop through generators in reverse order, rolling over
101+ if let n = gens[i].next() { // if generator isn't finished, just increment that column, return
102+ curr[i] = n
103+ return curr
104+ } else { // generator is finished
105+ gens[i] = cols[i].generate() // reset the generator
106+ curr[i] = gens[i].next()! // set the current column to the first element of the generator
107+ }
108+ }
109+ return nil
110+ }
111+
112+ private init(cols: [C]) {
113+ var gens = cols.map{$0.generate()}
114+ self.cols = cols
115+ curr = gens.dropLast().indices.map{gens[$0].next()!} + [self.cols.last!.first!]
116+ /**
117+ set curr to the first value of each of the generators, except the last: don't
118+ increment this generator, so that the first value returned contains it.
119+ */
120+ self.gens = gens
121+ }
122+}
123+/// :nodoc:
124+public struct ProdSeq<C : CollectionType> : LazySequenceType {
125+ private let cols: [C]
126+ /// :nodoc:
127+ public func generate() -> ProdGen<C> {
128+ return ProdGen( cols: cols )
129+ }
130+ /// :nodoc:
131+ public func underestimateCount() -> Int {
132+ return cols.reduce(1) { (n,c) in n * c.underestimateCount() }
133+ }
134+}
135+
136+/// Lazy Cartesian Product
137+/// ```swift
138+/// lazyProduct([1, 2], [3, 4])
139+///
140+/// [1, 3], [1, 4], [2, 3], [2, 4]
141+/// ```
142+@warn_unused_result
143+public func lazyProduct<C : CollectionType>
144+ (cols: C...) -> ProdSeq<C> {
145+ return ProdSeq(cols: cols)
146+}
147+
148+/// Lazy Cartesian Product
149+/// ```swift
150+/// lazyProduct([1, 2], [3, 4])
151+///
152+/// [1, 3], [1, 4], [2, 3], [2, 4]
153+/// ```
154+@warn_unused_result
155+public func lazyProduct<S : SequenceType>
156+ (cols: S...) -> ProdSeq<[S.Generator.Element]> {
157+ return ProdSeq(cols: cols.map(Array.init))
158+}
159+
160+public extension SequenceType where Generator.Element : SequenceType {
161+
162+ /// Lazy Cartesian Product
163+ /// ```swift
164+ /// [[1, 2], [3, 4]].lazyProduct()
165+ ///
166+ /// [1, 3], [1, 4], [2, 3], [2, 4]
167+ /// ```
168+ @warn_unused_result
169+ func lazyProduct() -> ProdSeq<[Generator.Element.Generator.Element]> {
170+ return ProdSeq(cols: map(Array.init))
171+ }
172+}
173+
174+public extension SequenceType where Generator.Element : CollectionType {
175+
176+ /// Lazy Cartesian Product
177+ /// ```swift
178+ /// [[1, 2], [3, 4]].lazyProduct()
179+ ///
180+ /// [1, 3], [1, 4], [2, 3], [2, 4]
181+ /// ```
182+ @warn_unused_result
183+ func lazyProduct() -> ProdSeq<Generator.Element> {
184+ return ProdSeq(cols: Array(self))
185+ }
186+}
187+
188+// MARK: Transposition
189+/// :nodoc:
190+public struct TransposeGen<T, G : GeneratorType where G.Element == T> : GeneratorType {
191+ private var gens: [G]
192+ /// :nodoc:
193+ mutating public func next() -> [T]? {
194+ return gens.indices.mapM { i in gens[i].next() }
195+ }
196+}
197+/// :nodoc:
198+public struct TransposeSeq<
199+ S : SequenceType where
200+ S.Generator.Element : SequenceType
201+ > : LazySequenceType {
202+ private let seq: S
203+ /// :nodoc:
204+ public func generate()
205+ -> TransposeGen<S.Generator.Element.Generator.Element, S.Generator.Element.Generator>{
206+ return TransposeGen(gens: seq.map { g in g.generate() })
207+ }
208+}
209+
210+public extension TransposeSeq where S: CollectionType {
211+ @warn_unused_result
212+ public func underestimateCount() -> Int {
213+ return seq.first?.underestimateCount() ?? 0
214+ }
215+}
216+
217+public extension LazySequenceType where Generator.Element: SequenceType {
218+
219+ /// Returns a lazily transposed self
220+ /// ```swift
221+ /// lazy([[1, 2, 3], [1, 2, 3], [1, 2, 3]]).transpose()
222+ ///
223+ /// [1, 1, 1], [2, 2, 2], [3, 3, 3]
224+ /// ```
225+ @warn_unused_result
226+ func transpose() -> TransposeSeq<Self> {
227+ return TransposeSeq(seq: self)
228+ }
229+}
PixelImage/SwiftSugar/SwiftSequences/Permutations.swiftnew file+187
@@ -0,0 +1,187 @@
1+// MARK: - Common
2+
3+public extension MutableCollectionType {
4+
5+ /// [Algorithm](https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order)
6+
7+ public mutating func nextLexPerm
8+ (isOrderedBefore: (Generator.Element, Generator.Element) -> Bool) -> Self? {
9+ for k in indices.reverse().dropFirst()
10+ where isOrderedBefore(self[k], self[k.successor()]) {
11+ for l in indices.reverse() where isOrderedBefore(self[k], self[l]) {
12+ swap(&self[k], &self[l])
13+ let r = (k.successor()..<endIndex)
14+ for (x, y) in zip(r, r.reverse()) {
15+ if x == y || x == y.successor() { return self }
16+ swap(&self[x], &self[y])
17+ }
18+ }
19+ }
20+ return nil
21+ }
22+}
23+
24+public extension MutableCollectionType where Generator.Element : Comparable {
25+
26+ /// [Algorithm](https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order)
27+
28+ public mutating func nextLexPerm() -> Self? {
29+ return nextLexPerm(<)
30+ }
31+}
32+/// :nodoc:
33+public struct LexPermGen<C : MutableCollectionType> : GeneratorType {
34+ private var col: C?
35+ private let order: (C.Generator.Element, C.Generator.Element) -> Bool
36+ /// :nodoc:
37+ mutating public func next() -> C? {
38+ defer { col = col?.nextLexPerm(order) }
39+ return col
40+ }
41+}
42+/// :nodoc:
43+public struct LexPermSeq<C : MutableCollectionType> : LazySequenceType {
44+ private let col: C
45+ private let order: (C.Generator.Element, C.Generator.Element) -> Bool
46+ /// :nodoc:
47+ public func generate() -> LexPermGen<C> {
48+ return LexPermGen(col: col, order: order)
49+ }
50+}
51+
52+// MARK: - Eager
53+
54+public extension SequenceType {
55+
56+ /// Returns an array of the permutations of self, ordered lexicographically, according
57+ /// to the closure `isOrderedBefore`.
58+ /// - Note: The permutations returned follow self, so if self is not the first
59+ /// lexicographically ordered permutation, not all permutations will be returned.
60+ /// ```swift
61+ /// [1, 2, 3].lexPermutations(<)
62+ ///
63+ /// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
64+ /// ```
65+ /// ```swift
66+ /// [1, 2, 3].lexPermutations(>)
67+ ///
68+ /// [[1, 2, 3]]
69+ /// ```
70+ @warn_unused_result
71+ public func lexPermutations
72+ (isOrderedBefore: (Generator.Element, Generator.Element) -> Bool) -> [[Generator.Element]] {
73+ return Array(LexPermSeq(col: Array(self), order: isOrderedBefore))
74+ }
75+}
76+
77+public extension MutableCollectionType where Generator.Element : Comparable {
78+
79+ /// Returns an array of the permutations of self, ordered lexicographically.
80+ /// - Note: The permutations returned follow self, so if self is not the first
81+ /// lexicographically ordered permutation, not all permutations will be returned.
82+ /// ```swift
83+ /// [1, 2, 3].lexPermutations()
84+ ///
85+ /// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
86+ /// ```
87+ /// ```swift
88+ /// [3, 2, 1].lexPermutations()
89+ ///
90+ /// [[3, 2, 1]]
91+ /// ```
92+ @warn_unused_result
93+ public func lexPermutations() -> [[Generator.Element]] {
94+ return Array(LexPermSeq(col: Array(self), order: <))
95+ }
96+}
97+
98+public extension SequenceType {
99+
100+ /// Returns an array of the permutations of self.
101+ /// ```swift
102+ /// [1, 2, 3].permutations()
103+ ///
104+ /// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
105+ /// ```
106+ @warn_unused_result
107+ public func permutations() -> [[Generator.Element]] {
108+ var col = Array(self)
109+ return Array(LexPermSeq(col: Array(col.indices), order: <).map { inds in inds.map{col[$0]} })
110+ }
111+ /// Returns an array of the permutations of length `n` of self.
112+ /// ```swift
113+ /// [1, 2, 3].permutations()
114+ ///
115+ /// [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
116+ /// ```
117+ public func permutations(n: Int) -> [[Generator.Element]] {
118+ return Array(lazyCombos(n).flatMap { a in a.permutations() })
119+ }
120+}
121+
122+// MARK: - Lazy
123+
124+public extension SequenceType {
125+
126+ /// Returns a lazy sequence of the permutations of self, ordered lexicographically,
127+ /// according to the closure `isOrderedBefore`.
128+ /// - Note: The permutations returned follow self, so if self is not the first
129+ /// lexicographically ordered permutation, not all permutations will be returned.
130+ /// ```swift
131+ /// lazy([1, 2, 3]).lazyLexPermutations(<)
132+ ///
133+ /// [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
134+ /// ```
135+ /// ```swift
136+ /// lazy([1, 2, 3]).lazyLexPermutations(>)
137+ ///
138+ /// [1, 2, 3]
139+ /// ```
140+ @warn_unused_result
141+ public func lazyLexPermutations(isOrderedBefore: (Generator.Element, Generator.Element) -> Bool)
142+ -> LexPermSeq<[Generator.Element]> {
143+ return LexPermSeq(col: Array(self), order: isOrderedBefore)
144+ }
145+}
146+
147+public extension SequenceType where Generator.Element : Comparable {
148+
149+ /// Returns a lazy sequence of the permutations of self, ordered lexicographically.
150+ /// - Note: The permutations returned follow self, so if self is not the first
151+ /// lexicographically ordered permutation, not all permutations will be returned.
152+ /// ```swift
153+ /// lazy([1, 2, 3]).lazyLexPermutations()
154+ ///
155+ /// [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
156+ /// ```
157+ /// ```swift
158+ /// lazy([3, 2, 1]).lazyLexPermutations()
159+ ///
160+ /// [3, 2, 1]
161+ /// ```
162+ @warn_unused_result
163+ public func lazyLexPermutations() -> LexPermSeq<[Generator.Element]> {
164+ return LexPermSeq(col: Array(self), order: <)
165+ }
166+}
167+
168+public extension SequenceType {
169+
170+ /// Returns a lazy sequence of the permutations of self.
171+ /// - Note: The permutations are lexicographically ordered, based on the indices of self
172+ /// ```swift
173+ /// lazy([1, 2, 3]).lazyPermutations()
174+ ///
175+ /// [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
176+ /// ```
177+ /// ```swift
178+ /// lazy([3, 2, 1]).lazyPermutations()
179+ ///
180+ /// [3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]
181+ /// ```
182+ @warn_unused_result
183+ public func lazyPermutations() -> LazyMapSequence<LexPermSeq<[Int]>, [Self.Generator.Element]> {
184+ let col = Array(self)
185+ return col.indices.lazyLexPermutations().map { $0.map { col[$0] } }
186+ }
187+}
PixelImage/SwiftSugar/SwiftSequences/ScanReduce.swiftnew file+152
@@ -0,0 +1,152 @@
1+// MARK: - Eager
2+
3+public extension SequenceType {
4+
5+ // MARK: Reduce1
6+
7+ /// Return the result of repeatedly calling combine with an accumulated value
8+ /// initialized to the first element of self and each element of self, in turn, i.e.
9+ /// return combine(combine(...combine(combine(self[0], self[1]),
10+ /// self[2]),...self[count-2]), self[count-1]).
11+ /// ```swift
12+ /// [1, 2, 3].reduce(+) // 6
13+ /// ```
14+ @warn_unused_result
15+ func reduce
16+ (@noescape combine: (accumulator: Generator.Element, element: Generator.Element) throws -> Generator.Element)
17+ rethrows -> Generator.Element? {
18+ var g = generate()
19+ guard let a = g.next() else { return nil }
20+ var accu = a
21+ while let next = g.next() {
22+ accu = try combine(accumulator: accu, element: next)
23+ }
24+ return accu
25+ }
26+
27+ // MARK: Scan
28+
29+ /// Return an array where every value is equal to combine called on the previous
30+ /// element, and the current element. The first element is taken to be initial.
31+ /// ```swift
32+ /// [1, 2, 3].scan(0, combine: +)
33+ ///
34+ /// [1, 3, 6]
35+ /// ```
36+ @warn_unused_result
37+ func scan<T>(initial: T, @noescape combine: (accumulator: T, element: Generator.Element) throws -> T) rethrows -> [T] {
38+ var accu = initial
39+ return try map { e in
40+ accu = try combine(accumulator: accu, element: e)
41+ return accu
42+ }
43+ }
44+
45+ // MARK: Scan1
46+
47+ /// Return an array where every value is equal to combine called on the previous
48+ /// element, and the current element.
49+ /// ```swift
50+ /// [1, 2, 3].scan(+)
51+ ///
52+ /// [3, 6]
53+ /// ```
54+ @warn_unused_result
55+ func scan(@noescape combine: (accumulator: Generator.Element, element: Generator.Element) throws -> Generator.Element) rethrows -> [Generator.Element] {
56+ var g = generate()
57+ guard let i = g.next() else { return [] }
58+ return try GeneratorSequence(g).scan(i, combine: combine)
59+ }
60+}
61+
62+// MARK: - Lazy
63+
64+// MARK: Scan
65+
66+/// :nodoc:
67+public struct ScanGen<G : GeneratorType, T> : GeneratorType {
68+
69+ private let combine: (T, G.Element) -> T
70+ private var initial: T
71+ private var g: G
72+ /// :nodoc:
73+ public mutating func next() -> T? {
74+ guard let e = g.next() else { return nil }
75+ initial = combine(initial, e)
76+ return initial
77+ }
78+}
79+
80+/// :nodoc:
81+public struct LazyScanSeq<S : SequenceType, T> : LazySequenceType {
82+
83+ private let seq : S
84+ private let combine: (T, S.Generator.Element) -> T
85+ private let initial: T
86+ /// :nodoc:
87+ public func generate() -> ScanGen<S.Generator, T> {
88+ return ScanGen(combine: combine, initial: initial, g: seq.generate())
89+ }
90+}
91+
92+public extension LazySequenceType {
93+
94+ /// Return a lazy sequence where every value is equal to combine called on the previous
95+ /// element, and the current element. The first element is taken to be initial.
96+ /// ```swift
97+ /// lazy([1, 2, 3]).scan(0, combine: +)
98+ ///
99+ /// 1, 3, 6
100+ /// ```
101+ @warn_unused_result
102+ func scan<T>(initial: T, combine: (accumulator: T, element: Generator.Element) -> T) -> LazyScanSeq<Self, T> {
103+ return LazyScanSeq(seq: self, combine: combine, initial: initial)
104+ }
105+}
106+
107+// MARK: Scan1
108+/// :nodoc:
109+public struct Scan1Gen<G : GeneratorType> : GeneratorType {
110+
111+ private let combine: (G.Element, G.Element) -> G.Element
112+ private var accu: G.Element?
113+ private var g: G
114+
115+ public mutating func next() -> G.Element? {
116+ guard let a = accu, e = g.next() else { return nil }
117+ accu = combine(a, e)
118+ return accu!
119+ }
120+
121+ private init(combine: (G.Element, G.Element) -> G.Element, generator: G) {
122+ g = generator
123+ self.combine = combine
124+ accu = g.next()
125+ }
126+}
127+/// :nodoc:
128+public struct LazyScan1Seq<S : SequenceType> : LazySequenceType {
129+
130+ private let seq: S
131+ private let combine: (S.Generator.Element, S.Generator.Element) -> S.Generator.Element
132+ /// :nodoc:
133+ public func generate() -> Scan1Gen<S.Generator> {
134+ return Scan1Gen(combine: combine, generator: seq.generate())
135+ }
136+}
137+
138+public extension LazySequenceType {
139+
140+ /// Return a lazy sequence where every value is equal to combine called on the previous
141+ /// element, and the current element.
142+ /// ```swift
143+ /// lazy([1, 2, 3]).scan(+)
144+ ///
145+ /// 3, 6
146+ /// ```
147+ @warn_unused_result
148+ func scan(combine: (accumulator: Generator.Element, element: Generator.Element) -> Generator.Element)
149+ -> LazyScan1Seq<Self> {
150+ return LazyScan1Seq(seq: self, combine: combine)
151+ }
152+}
PixelImage/SwiftSugar/SwiftSequences/Slicing.swiftnew file+138
@@ -0,0 +1,138 @@
1+// IntervalTypes
2+
3+public protocol OpenIntervalType {
4+ typealias Value
5+ func contains(v: Value) -> Bool
6+}
7+public protocol OpenEndedIntervalType: OpenIntervalType {
8+ typealias Value: Comparable
9+ var val: Value { get }
10+}
11+public protocol OpenStartedIntervalTypeTo: OpenIntervalType {
12+ typealias Value: Comparable
13+ var val: Value { get }
14+}
15+public protocol OpenStartedIntervalTypeThrough: OpenIntervalType {
16+ typealias Value: Comparable
17+ var val: Value { get }
18+}
19+
20+// Interval Structs
21+
22+public struct OpenEndedInterval<C: Comparable>: OpenEndedIntervalType {
23+ public let val: C
24+}
25+public struct OpenStartedIntervalTo<C: Comparable>: OpenStartedIntervalTypeTo {
26+ public let val: C
27+}
28+public struct OpenStartedIntervalThrough<C: Comparable>: OpenStartedIntervalTypeThrough {
29+ public let val: C
30+}
31+
32+// Range structs
33+
34+public struct OpenEndedRange<I: ForwardIndexType where I: Comparable>: OpenEndedIntervalType {
35+ public var val: I
36+}
37+public struct OpenStartedRangeTo<I: BidirectionalIndexType where I: Comparable>: OpenStartedIntervalTypeTo {
38+ public var val: I
39+}
40+public struct OpenStartedRangeThrough<I: BidirectionalIndexType where I: Comparable>: OpenStartedIntervalTypeThrough {
41+ public var val: I
42+}
43+
44+// Generators
45+
46+public struct EndlessIncrement<I: ForwardIndexType>: GeneratorType {
47+ private var i: I
48+ public mutating func next() -> I? {
49+ defer { i = i.successor() }
50+ return i
51+ }
52+}
53+
54+// SequenceType
55+
56+extension OpenEndedRange: SequenceType {
57+ public func generate() -> EndlessIncrement<I> {
58+ return EndlessIncrement(i: val)
59+ }
60+}
61+
62+// Operators
63+
64+postfix operator ... {}
65+prefix operator ... {}
66+prefix operator ..< {}
67+
68+public postfix func ...<C: Comparable>(c: C) -> OpenEndedInterval<C> {
69+ return OpenEndedInterval(val: c)
70+}
71+public postfix func ...<I: ForwardIndexType>(c: I) -> OpenEndedRange<I> {
72+ return OpenEndedRange(val: c)
73+}
74+public prefix func ..<<C: Comparable>(c: C) -> OpenStartedIntervalTo<C> {
75+ return OpenStartedIntervalTo(val: c)
76+}
77+public prefix func ..<<C: BidirectionalIndexType>(c: C) -> OpenStartedRangeTo<C> {
78+ return OpenStartedRangeTo(val: c)
79+}
80+public prefix func ... <C: Comparable>(c: C) -> OpenStartedIntervalThrough<C> {
81+ return OpenStartedIntervalThrough(val: c)
82+}
83+public prefix func ... <C: BidirectionalIndexType>(c: C) -> OpenStartedRangeThrough<C> {
84+ return OpenStartedRangeThrough(val: c)
85+}
86+
87+// Contains
88+
89+extension OpenEndedIntervalType {
90+ public func contains(v: Value) -> Bool { return val <= v }
91+}
92+extension OpenStartedIntervalTypeTo {
93+ public func contains(v: Value) -> Bool { return val > v }
94+}
95+extension OpenStartedIntervalTypeThrough {
96+ public func contains(v: Value) -> Bool { return val >= v }
97+}
98+
99+// Pattern Matching
100+
101+public func ~=<I: OpenIntervalType>(lhs: I, rhs: I.Value) -> Bool {
102+ return lhs.contains(rhs)
103+}
104+
105+// Indexing
106+
107+public extension CollectionType where Index: Comparable {
108+ subscript(r: OpenEndedRange<Index>) -> SubSequence {
109+ return suffixFrom(r.val)
110+ }
111+}
112+
113+public extension CollectionType where Index: Comparable, Index: BidirectionalIndexType {
114+ subscript(r: OpenStartedRangeTo<Index>) -> SubSequence {
115+ return prefixUpTo(r.val)
116+ }
117+ subscript(r: OpenStartedRangeThrough<Index>) -> SubSequence {
118+ return prefixThrough(r.val)
119+ }
120+}
121+
122+public extension MutableCollectionType where Index: Comparable {
123+ subscript(r: OpenEndedRange<Index>) -> SubSequence {
124+ get { return suffixFrom(r.val) }
125+ set { self[r.val..<endIndex] = newValue }
126+ }
127+}
128+
129+public extension MutableCollectionType where Index: Comparable, Index: BidirectionalIndexType {
130+ subscript(r: OpenStartedRangeTo<Index>) -> SubSequence {
131+ get { return prefixUpTo(r.val) }
132+ set { self[startIndex..<r.val] = newValue }
133+ }
134+ subscript(r: OpenStartedRangeThrough<Index>) -> SubSequence {
135+ get { return prefixThrough(r.val) }
136+ set { self[startIndex...r.val] = newValue }
137+ }
138+}
PixelImage/SwiftSugar/SwiftSequences/TakeDrop.swiftnew file+208
@@ -0,0 +1,208 @@
1+// MARK: - Eager
2+
3+// MARK: prefixWhile
4+
5+public extension SequenceType {
6+
7+ /// Returns an array of self up until the first element that returns false for condition
8+ /// ```swift
9+ /// [1, 2, 3, 4, 5, 2].prefixWhile { $0 < 4 }
10+ ///
11+ /// [1, 2, 3]
12+ /// ```
13+ @warn_unused_result
14+ func prefixWhile(@noescape condition: Generator.Element throws -> Bool) rethrows -> [Generator.Element] {
15+ var ret : [Generator.Element] = []
16+ var g = generate()
17+ while let next = g.next() where try condition(next) { ret.append(next) }
18+ return ret
19+ }
20+}
21+
22+// MARK: DropWhile
23+
24+public extension SequenceType {
25+
26+ /// Returns an array of self with the first elements that return true for condition
27+ /// dropped
28+ /// ```swift
29+ /// [1, 2, 3, 4, 5, 2].dropWhile { $0 < 4 }
30+ ///
31+ /// [4, 5, 2]
32+ /// ```
33+ @warn_unused_result
34+ func dropWhile(@noescape condition: Generator.Element throws -> Bool) rethrows -> [Generator.Element] {
35+ var g = generate()
36+ while let next = g.next() {
37+ if try !condition(next) {
38+ return [next] + GeneratorSequence(g)
39+ }
40+ }
41+ return []
42+ }
43+}
44+
45+public extension SequenceType {
46+ /**
47+ Returns a tuple of the prefix and suffix of `self`, the first element
48+ being the prefix up to `n`.
49+ */
50+ public func breakAt(n: Int) -> ([Generator.Element],[Generator.Element]) {
51+ let r = max(0, underestimateCount() - n)
52+ var f,b : [Generator.Element]
53+ (f,b) = ([],[])
54+ f.reserveCapacity(n)
55+ b.reserveCapacity(r)
56+ var g = generate()
57+ for _ in 0..<n {
58+ if let e = g.next() { f.append(e) } else { return (f,b) }
59+ }
60+ while let e = g.next() { b.append(e) }
61+ return (f,b)
62+ }
63+}
64+
65+public extension CollectionType {
66+ /**
67+ Returns a tuple of the prefix and suffix of `self`, the first element
68+ being the prefix up to `n`.
69+ */
70+ public func breakAt(n: Index) -> (SubSequence, SubSequence) {
71+ return (prefixUpTo(n),suffixFrom(n))
72+ }
73+}
74+
75+public extension CollectionType where Index == Int {
76+ /**
77+ Returns a tuple of the prefix and suffix of `self`, the first element
78+ being the prefix up to `n`.
79+ */
80+ public func breakAt(n: Int) -> (SubSequence, SubSequence) {
81+ return (prefixUpTo(n),suffixFrom(n))
82+ }
83+}
84+public extension SequenceType {
85+ /**
86+ Returns a tuple of the prefix and suffix of `self`, the first element
87+ being the prefix up to the first elements of `self` which returns
88+ `true` for `isBreak`.
89+ */
90+ public func breakAt(@noescape isBreak: Generator.Element throws -> Bool)
91+ rethrows -> ([Generator.Element],[Generator.Element]) {
92+ var f,b : [Generator.Element]
93+ (f,b) = ([],[])
94+ var g = generate()
95+ while let e = g.next() {
96+ if try isBreak(e) {
97+ b.append(e)
98+ while let be = g.next() { b.append(be) }
99+ return (f,b)
100+ } else {
101+ f.append(e)
102+ }
103+ }
104+ return (f,b)
105+ }
106+}
107+public extension CollectionType {
108+ /**
109+ Returns a tuple of the prefix and suffix of `self`, the first element
110+ being the prefix up to the first elements of `self` which returns
111+ `true` for `isBreak`.
112+ */
113+ public func breakAt(@noescape isBreak: Generator.Element throws -> Bool) rethrows -> (SubSequence, SubSequence) {
114+ return try indexOf(isBreak).map(breakAt) ?? (suffixFrom(startIndex),prefixUpTo(startIndex))
115+ }
116+}
117+// MARK: - Lazy
118+
119+// MARK: TakeWhile
120+/// :nodoc:
121+public struct WhileGen<G : GeneratorType> : GeneratorType {
122+
123+ private var g: G
124+ private let condition : G.Element -> Bool
125+ /// :nodoc:
126+ mutating public func next() -> G.Element? {
127+ if let next = g.next() where condition(next) {
128+ return next
129+ }
130+ return nil
131+ }
132+}
133+/// :nodoc:
134+public struct WhileSeq<S : SequenceType> : LazySequenceType {
135+
136+ private let seq: S
137+ private let condition: S.Generator.Element -> Bool
138+ /// :nodoc:
139+ public func generate() -> WhileGen<S.Generator> {
140+ return WhileGen(g: seq.generate(), condition: condition)
141+ }
142+}
143+
144+public extension LazySequenceType {
145+
146+ /// Returns a lazy sequence of self up until the first element that returns false for
147+ /// condition
148+ /// ```swift
149+ /// [1, 2, 3, 4, 5, 2].lazy.takeWhile { $0 < 4 }
150+ ///
151+ /// 1, 2, 3
152+ /// ```
153+ @warn_unused_result
154+ func prefixWhile(condition: Generator.Element -> Bool) -> WhileSeq<Self> {
155+ return WhileSeq(seq: self, condition: condition)
156+ }
157+}
158+
159+// MARK: DropWhile
160+/// :nodoc:
161+public struct DropWhileGen<G : GeneratorType> : GeneratorType {
162+
163+ private let predicate: G.Element -> Bool
164+ private var nG: G?
165+ private var oG: G
166+
167+ private init(g: G, predicate: G.Element -> Bool) {
168+ nG = nil
169+ oG = g
170+ self.predicate = predicate
171+ }
172+ /// :nodoc:
173+ public mutating func next() -> G.Element? {
174+ guard nG == nil else { return nG!.next() }
175+ while let next = oG.next() {
176+ if !predicate(next) {
177+ nG = oG
178+ return next
179+ }
180+ }
181+ return nil
182+ }
183+}
184+/// :nodoc:
185+public struct DropWhileSeq<S : SequenceType> : LazySequenceType {
186+
187+ private let predicate: S.Generator.Element -> Bool
188+ private let seq: S
189+ /// :nodoc:
190+ public func generate() -> DropWhileGen<S.Generator> {
191+ return DropWhileGen(g: seq.generate(), predicate: predicate)
192+ }
193+}
194+
195+public extension LazySequenceType {
196+
197+ /// Returns a lazy sequence of self with the first elements that return true for
198+ /// condition dropped
199+ /// ```swift
200+ /// [1, 2, 3, 4, 5, 2].lazy.dropWhile { $0 < 4 }
201+ ///
202+ /// 4, 5, 2
203+ /// ```
204+ @warn_unused_result
205+ func dropWhile(predicate: Generator.Element -> Bool) -> DropWhileSeq<Self> {
206+ return DropWhileSeq(predicate: predicate, seq: self)
207+ }
208+}
PixelImage/SwiftSugar/SwiftSequences/Zip.swiftnew file+90
@@ -0,0 +1,90 @@
1+/// :nodoc:
2+public struct NilPaddedZipGenerator<G0: GeneratorType, G1: GeneratorType> : GeneratorType {
3+
4+ private var (g0, g1): (G0?, G1?)
5+
6+ public mutating func next() -> (G0.Element?, G1.Element?)? {
7+ let (e0,e1) = (g0?.next(),g1?.next())
8+ switch (e0,e1) {
9+ case (nil,nil): return nil
10+ case ( _,nil): g1 = nil
11+ case (nil, _): g0 = nil
12+ default: break
13+ }
14+ return (e0,e1)
15+ }
16+}
17+/// :nodoc:
18+public struct NilPaddedZip<S0: SequenceType, S1: SequenceType> : LazySequenceType {
19+
20+ private let (s0, s1): (S0, S1)
21+ /// :nodoc:
22+ public func generate() -> NilPaddedZipGenerator<S0.Generator, S1.Generator> {
23+ return NilPaddedZipGenerator(g0: s0.generate(), g1: s1.generate())
24+ }
25+}
26+
27+/// A sequence of pairs built out of two underlying sequences, where the elements of the
28+/// ith pair are optional ith elements of each underlying sequence. If one sequence is
29+/// shorter than the other, pairs will continue to be returned after it is exhausted, but
30+/// with its elements replaced by nil.
31+/// ```swift
32+/// zipWithPadding([1, 2, 3], [1, 2])
33+///
34+/// (1?, 1?), (2?, 2?), (3?, nil)
35+/// ```
36+@warn_unused_result
37+public func zipWithPadding<S0: SequenceType, S1: SequenceType>(s0: S0, _ s1: S1)
38+ -> NilPaddedZip<S0, S1> {
39+ return NilPaddedZip(s0: s0, s1: s1)
40+}
41+/// :nodoc:
42+public struct PaddedZipGenerator<G0: GeneratorType, G1: GeneratorType> : GeneratorType {
43+
44+ typealias E0 = G0.Element
45+ typealias E1 = G1.Element
46+
47+ private var g: NilPaddedZipGenerator<G0, G1>
48+ private let (p0, p1): (E0, E1)
49+
50+ public mutating func next() -> (E0, E1)? {
51+ guard let (e0,e1) = g.next() else { return nil }
52+ return (e0 ?? p0, e1 ?? p1)
53+ }
54+}
55+/// :nodoc:
56+public struct PaddedZip<S0: SequenceType, S1: SequenceType> : LazySequenceType {
57+
58+ private let (s0, s1): (S0, S1)
59+ private let (p0, p1): (S0.Generator.Element, S1.Generator.Element)
60+ /// :nodoc:
61+ public func generate() -> PaddedZipGenerator<S0.Generator, S1.Generator> {
62+ return PaddedZipGenerator(
63+ g: NilPaddedZipGenerator(
64+ g0: s0.generate(),
65+ g1: s1.generate()
66+ ),
67+ p0: p0,
68+ p1: p1
69+ )
70+ }
71+}
72+
73+/// A sequence of pairs built out of two underlying sequences, where the elements of the
74+/// ith pair are the ith elements of each underlying sequence. If one sequence is
75+/// shorter than the other, pairs will continue to be returned after it is exhausted, but
76+/// with its elements replaced by its respective pad.
77+/// - Parameter pad0: the element to pad `s0` with after it is exhausted
78+/// - Parameter pad1: the element to pad `s1` with after it is exhausted
79+/// ```swift
80+/// zipWithPadding([1, 2, 3], [1, 2], pad0: 100, pad1: 900)
81+///
82+/// (1, 1), (2, 2), (3, 900)
83+/// ```
84+@warn_unused_result
85+public func zipWithPadding<
86+ S0: SequenceType, S1: SequenceType
87+ >(s0: S0, _ s1: S1, pad0: S0.Generator.Element, pad1: S1.Generator.Element)
88+ -> PaddedZip<S0, S1> {
89+ return PaddedZip(s0: s0, s1: s1, p0: pad0, p1: pad1)
90+}
PixelImage/SwiftSugar/TestCommons.swiftnew file+95
@@ -0,0 +1,95 @@
1+// TODO: Preconditions
2+// TODO: Test memoization
3+// TODO: Reorganize Swift Sugar folders
4+// TODO: Sugar documentation
5+// TODO: Add Swift Sugar to git
6+// TODO: Add LINT to EngineKit
7+// TODO: Add @warnunusedresult where appropriate
8+
9+import Darwin
10+
11+class Random <T: Numeric> {
12+
13+ let max: Double = Double(INT32_MAX)
14+ let exponent: Double = 7
15+
16+ init(example: T) {
17+ setupRandomSeed()
18+ }
19+
20+ private func expRandom() -> Double {
21+ let rawRandom = Double(rand()) / max
22+ let exponentiated = (3 * rawRandom) ^ exponent
23+ return exponentiated
24+ }
25+
26+ private func uniRandom() -> Double {
27+ return Double(rand()) / max
28+ }
29+
30+ private func setupRandomSeed() {
31+ var now = time(nil)
32+ var date = tm()
33+ localtime_r(&now, &date)
34+ let day = date.tm_yday
35+ let year = date.tm_year
36+ srand(UInt32(365 * year + day))
37+ }
38+
39+ func nonnegativeRandomNumber() -> T {
40+ let random = expRandom()
41+ return T.fromDouble(random)
42+ }
43+
44+ func positiveRandomNumber() -> T {
45+ let random = expRandom()
46+ let result = T.fromDouble(random)
47+
48+ guard result != 0 else {
49+ return positiveRandomNumber()
50+ }
51+
52+ return result
53+ }
54+
55+ func randomNumber() -> T {
56+ let random = expRandom()
57+ let signed = random * ±(Double(rand()) - max)
58+ return T.fromDouble(signed)
59+ }
60+
61+ func uniformRandomNumber(from tStart: T, to tEnd: T) -> T {
62+ let start = tStart.toDouble
63+ let end = tEnd.toDouble
64+
65+ let rawRandom = uniRandom()
66+ let interval = end - start
67+ let result = start + (rawRandom * interval)
68+ return T.fromDouble(result)
69+ }
70+
71+ func uniformRandomNumber(start tStart: T, interval tInterval: T)
72+ -> T {
73+ let start = tStart.toDouble
74+ let interval = tInterval.toDouble
75+
76+ let rawRandom = uniRandom()
77+ let result = start + (rawRandom * interval)
78+ return T.fromDouble(result)
79+ }
80+
81+ func uniformRandomNumber(center tCenter: T,
82+ maxDeviation tInterval: T) -> T {
83+ let center = tCenter.toDouble
84+ let interval = tInterval.toDouble
85+ let start = T.fromDouble(center - interval / 2)
86+
87+ return uniformRandomNumber(start: start, interval: tInterval)
88+ }
89+
90+ func randomSign() -> T {
91+ let rawRandom = rand() % 2
92+ let result = Double((2 * rawRandom) - 1)
93+ return T.fromDouble(result)
94+ }
95+}
PixelImage/UIColor.swiftdeleted−15
@@ -1,15 +0,0 @@
1−import UIKit
2−
3−extension UIColor {
4− var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
5− var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
6− getRed(&r, green: &g, blue: &b, alpha: &a)
7− return (r, g, b, a)
8− }
9−}
10−
11−extension UIColor {
12− convenience init(red255 red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
13− self.init(red: red / 255, green: green / 255, blue: blue / 255, alpha: alpha / 255)
14− }
15−}
PixelImage/UIKit.swift+19−132
@@ -1,5 +1,3 @@
1−// TODO: Unite UIView and CALayer extensions under a common protocol
2−
3import UIKit
1import UIKit
4
2
5func - (left: CGPoint, right: CGPoint) -> CGVector {
3func - (left: CGPoint, right: CGPoint) -> CGVector {
@@ -33,7 +31,6 @@ extension CGVector {
33 dx = dx / norm
31 dx = dx / norm
34 dy = dy / norm
32 dy = dy / norm
35 }
33 }
36−
37}
34}
38
35
39extension CGFloat: DoubleValuable {
36extension CGFloat: DoubleValuable {
@@ -42,31 +39,22 @@ extension CGFloat: DoubleValuable {
42 }
39 }
43 }
40 }
44
41
45− static func fromDouble(_ double: Double) -> CGFloat {
42+ static func fromDouble(double: Double) -> CGFloat {
46 return CGFloat(double)
43 return CGFloat(double)
47 }
44 }
48−
49}
45}
50
46
51extension CGFloat: Numeric {}
47extension CGFloat: Numeric {}
52
48
53extension CGRect {
49extension CGRect {
54 var x: CGFloat {
50 var x: CGFloat {
55− get {
56− return origin.x
51+ get { return origin.x }
57− }
58− set {
59− origin.x = newValue
52+ set { origin.x = newValue }
60− }
61 }
53 }
62
54
63 var y: CGFloat {
55 var y: CGFloat {
64− get {
65− return origin.y
56+ get { return origin.y }
66− }
67− set {
68− origin.y = newValue
57+ set { origin.y = newValue }
69− }
70 }
58 }
71}
59}
72
60
@@ -78,142 +66,41 @@ extension CGSize {
78
66
79extension UIView {
67extension UIView {
80 var origin: CGPoint {
68 var origin: CGPoint {
81− get {
82− return frame.origin
83− }
84− set {
85− frame.origin = newValue
86− }
87− }
88−
89− var size: CGSize {
90− get {
91− return frame.size
69+ get { return frame.origin }
92− }
70+ set { frame.origin = newValue }
93− set {
94− frame.size = newValue
95− }
96− }
97−
98− var width: CGFloat {
99− get {
100− return frame.width
101− }
102− set {
103− frame.size = CGSize(width: newValue, height: height)
104− }
105− }
106−
107− var height: CGFloat {
108− get {
109− return frame.height
110− }
111− set {
112− frame.size = CGSize(width: width, height: newValue)
113− }
114− }
115−
116− var middle: CGPoint {
117− get {
118− return CGPoint(x: origin.x + width / 2, y: origin.y + height / 2)
119− }
120− set {
121− origin = CGPoint(x: newValue.x - width / 2, y: newValue.y - height / 2)
122− }
123− }
124−
125− var midX: CGFloat {
126− get {
127− return middle.x
128− }
129− set {
130− middle = CGPoint(x: newValue, y: midY)
131− }
132− }
133−
134− var midY: CGFloat {
135− get {
136− return middle.y
137− }
138− set {
139− middle = CGPoint(x: midX, y: newValue)
140− }
141− }
142−}
143−
144−extension CALayer {
145− var origin: CGPoint {
146− get {
147− return frame.origin
148− }
149− set {
150− frame.origin = newValue
151− }
152 }
71 }
153
72
154 var size: CGSize {
73 var size: CGSize {
155− get {
156− return frame.size
74+ get { return frame.size }
157− }
158− set {
159− frame.size = newValue
75+ set { frame.size = newValue }
160− }
161 }
76 }
162
77
163 var width: CGFloat {
78 var width: CGFloat {
164− get {
165− return frame.width
79+ get { return frame.width }
166− }
167− set {
168− frame.size = CGSize(width: newValue, height: height)
80+ set { frame.size = CGSize(width: newValue, height: height) }
169− }
170 }
81 }
171
82
172 var height: CGFloat {
83 var height: CGFloat {
173− get {
174− return frame.height
84+ get { return frame.height }
175− }
176− set {
177− frame.size = CGSize(width: width, height: newValue)
85+ set { frame.size = CGSize(width: width, height: newValue) }
178− }
179 }
86 }
180
87
181 var middle: CGPoint {
88 var middle: CGPoint {
182 get {
89 get {
183− return CGPoint(x: origin.x + width / 2, y: origin.y + height / 2)
90+ return CGPoint(x: origin.x + width/2, y: origin.y + height/2)
184 }
91 }
185 set {
92 set {
186− origin = CGPoint(x: newValue.x - width / 2, y: newValue.y - height / 2)
93+ origin = CGPoint(x: newValue.x - width/2, y: newValue.y - height/2)
187 }
94 }
188 }
95 }
189
96
190 var midX: CGFloat {
97 var midX: CGFloat {
191− get {
192− return middle.x
98+ get { return middle.x }
193− }
194− set {
195− middle = CGPoint(x: newValue, y: midY)
99+ set { middle = CGPoint(x: newValue, y: midY) }
196− }
197 }
100 }
198
101
199 var midY: CGFloat {
102 var midY: CGFloat {
200− get {
201− return middle.y
103+ get { return middle.y }
202− }
203− set {
204− middle = CGPoint(x: midX, y: newValue)
104+ set { middle = CGPoint(x: midX, y: newValue) }
205− }
206 }
105 }
207}
106}
208−
209−let screenRect = UIScreen.main.bounds
210−let screenWidth = screenRect.size.width
211−let screenHeight = screenRect.size.height
212−
213−func * <T: Numeric>(vector: CGVector, scalar: T) -> CGVector {
214− return CGVector(dx: vector.dx * CGFloat(scalar.toDouble), dy: vector.dy * CGFloat(scalar.toDouble))
215−}
216−
217−func + (point: CGPoint, vector: CGVector) -> CGPoint {
218− return CGPoint(x: point.x + vector.dx, y: point.y + vector.dy)
219−}
PixelImage/ViewController.swift+78−220
@@ -1,226 +1,84 @@
1+
1import UIKit
2import UIKit
2
3
3class ViewController: UIViewController, MetaballDataSource {
4class ViewController: UIViewController, MetaballDataSource {
4
5
6+ let dynamicRendering = true
7+ typealias Renderer = MetalMetaballRenderer // ImageMetaballRenderer // MetalMetaballRenderer
8+ typealias TargetView = Renderer.TargetView
9+
5− var metaballView: UIImageView!
10+ var metaballView: TargetView!
6− var renderer: MetalMetaballRenderer!
11+ var renderer: Renderer!
7−
12+
8− let width = 350
13+ let width = 350
9− let height = 600
14+ let height = 600
10−
15+
11− var metaballGraph: Graph<Metaball>!
16+ var metaballs = [CGPoint(x: 70, y: 70), CGPoint(x: 270, y: 470), CGPoint(x: 270, y: 70), CGPoint(x: 70, y: 470)].map {
17+ Metaball(position: $0)
18+ }
12− var previousLocation: CGPoint!
19+ var previousLocation: CGPoint!
13−
20+
14− var selectedMetaball: Metaball?
15−
16− let edgeAnimationDuration: Float = 1
17−
18− override func viewDidLoad() {
21+ override func viewDidLoad() {
19− super.viewDidLoad()
22+ super.viewDidLoad()
20−
23+
21− view.backgroundColor = UIColor.white
24+ renderer = Renderer(dataSource: self)
22−
25+
23− let recognizer = UIPanGestureRecognizer(
26+ let recognizer = UIPanGestureRecognizer(target: self, action: "handlePan:")
24− target: self,
25− action: #selector(ViewController.handlePan(_:)))
26− view.addGestureRecognizer(recognizer)
27+ view.addGestureRecognizer(recognizer)
27−
28+
28− var positions = [CGPoint]()
29+
29− positions.append(CGPoint(
30+ let border = 20
30− x: Double(screenWidth) / 2,
31+ let metaballViewFrame = CGRect(x: border/2, y: border/2, width: width, height: height)
31− y: Double(screenHeight) / 2))
32− for i in 1...5 {
33− let sine = sin(Double(i) * 2 * .pi / 5)
34− let cosine = cos(Double(i) * 2 * .pi / 5)
35− let radius: Double = 150
36− let x = Double(screenWidth) / 2 + sine * radius
37− let y = Double(screenHeight) / 2 + cosine * radius
38− positions.append(CGPoint(x: x, y: y))
39− }
40−
41− let colors =
42− [UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0),
43− UIColor(red255: 250, green: 235, blue: 50, alpha: 1.0),
44− UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0),
45− UIColor(red255: 90, green: 170, blue: 170, alpha: 1.0),
46− UIColor(red255: 90, green: 170, blue: 170, alpha: 1.0),
47− UIColor(red255: 110, green: 220, blue: 220, alpha: 1.0)]
48− let metaballs = zip(positions, colors).map {
49− Metaball(position: $0.0, color: $0.1)
50− }
51−
52− metaballGraph = Graph(vertices: metaballs)
53−
54− let metaballViewFrame = screenRect
55− renderer = MetalMetaballRenderer(dataSource: self,
56− frame: metaballViewFrame)
57− metaballView = renderer.targetView
32+ metaballView = renderer.targetView
58− view.addSubview(metaballView)
33+ metaballView.frame = metaballViewFrame
59−
34+
60− for metaball in metaballs {
35+ let bigView = UIView(frame: CGRect(x: 10, y: 70, width: width + border, height: height + border))
61− metaballView.addSubview(metaball)
36+ bigView.backgroundColor = UIColor.redColor()
62− }
37+ bigView.addSubview(metaballView)
63−
38+ view.addSubview(bigView)
64− delay(1.0) {
39+
65− self.addEdge(0, 1)
40+
66− self.addEdge(0, 2)
41+ for metaball in metaballs {
67− self.addEdge(0, 3)
42+ metaballView.addSubview(metaball)
68− self.addEdge(0, 4)
43+ }
69− self.addEdge(0, 5)
44+
70− }
45+
71−
46+ renderer.updateTargetView()
72− delay(2.3) {
73− self.removeEdge(0, 1)
74− self.removeEdge(0, 2)
75− self.removeEdge(0, 3)
76− self.removeEdge(0, 4)
77− self.removeEdge(0, 5)
78− }
79−
80− delay(4) {
81− for i in 1...5 {
82− UIView.animate(withDuration: 1.0, delay: 0,
83− options: UIView.AnimationOptions(),
84− animations: { () -> Void in
85− let sine = sin(Double(i) * 2 * .pi / 5)
86− let cosine = cos(Double(i) * 2 * .pi / 5)
87− let radius: Double = 85
88− let x = Double(screenWidth) / 2 + sine * radius
89− let y = Double(screenHeight) / 2 + cosine * radius
90− let metaball = metaballs[i]
91− self.animateMetaball(metaball, toPoint: CGPoint(x: x, y: y))
92− }, completion: nil)
93− }
94− }
95−
96− delay(6) { () -> () in
97− for i in 1...5 {
98− UIView.animate(withDuration: 1.0, delay: 0,
99− usingSpringWithDamping: 0.5,
100− initialSpringVelocity: 0,
101− options: UIView.AnimationOptions(),
102− animations: { () -> Void in
103− let sine = sin(Double(i) * 2 * .pi / 5)
104− let cosine = cos(Double(i) * 2 * .pi / 5)
105− let radius: Double = 150
106− let x = Double(screenWidth) / 2 + sine * radius
107− let y = Double(screenHeight) / 2 + cosine * radius
108− let metaball = metaballs[i]
109− self.animateMetaball(metaball, toPoint: CGPoint(x: x, y: y))
110− }, completion: nil)
111− }
112− }
113−
114− renderer.state = .running
115− }
116−
117− func addEdge(_ i: Int, _ j: Int) {
118− animateEdge(i, j, fadeIn: true)
119− }
120−
121− func removeEdge(_ i: Int, _ j: Int) {
122− animateEdge(i, j, fadeIn: false)
123− }
124−
125− func animateMetaball(_ metaball: Metaball, toPoint destination: CGPoint) {
126− let parameters = VertexAnimationParameters(startDate: Date(),
127− duration: 1.0,
128− origin: metaball.center,
129− destination: destination,
130− metaball: metaball)
131− Timer.scheduledTimer(
132− timeInterval: 1.0 / 60.0,
133− target: self,
134− selector: #selector(ViewController.animateMetaball(withTimer:)),
135− userInfo: parameters,
136− repeats: true)
137− }
138−
139− @objc func animateMetaball(withTimer timer: Timer) {
140− guard let userInfo = timer.userInfo as? VertexAnimationParameters else {
141− preconditionFailure()
142− }
143− let (animationStart, duration, origin, destination, metaball) =
144− (userInfo).unpack()
145−
146− let now = Date()
147− var timeElapsed = Float(now.timeIntervalSince(animationStart))
148−
149− if timeElapsed > duration {
150− timer.invalidate()
151− timeElapsed = duration
152− }
153−
154− let linearValue = timeElapsed / duration
155− let interpolatedValue = interpolateSmooth(linearValue)
156−
157− let position = origin + ((destination - origin) * interpolatedValue)
158− metaball.center = position
159−
160− renderer.state = .running
161− }
162−
163− func animateEdge(_ i: Int, _ j: Int, fadeIn: Bool) {
164− let parameters = EdgeAnimationParameters(startDate: Date(),
165− duration: edgeAnimationDuration,
166− fadeIn: fadeIn,
167− i: i,
168− j: j)
169− Timer.scheduledTimer(
170− timeInterval: 1.0 / 60.0,
171− target: self,
172− selector: #selector(ViewController.animateEdge(withTimer:)),
173− userInfo: parameters,
174− repeats: true)
175− }
176−
177− @objc func animateEdge(withTimer timer: Timer) {
178− guard let userInfo = timer.userInfo as? EdgeAnimationParameters else {
179− preconditionFailure()
180− }
181− let (animationStart, duration, fadeIn, i, j) = (userInfo).unpack()
182−
183− let now = Date()
184− var timeElapsed = Float(now.timeIntervalSince(animationStart))
185−
186− if timeElapsed > duration {
187− timer.invalidate()
188− timeElapsed = duration
189− }
190−
191− let linearValue = timeElapsed / duration
192− let interpolatedValue = fadeIn ?
193− interpolateSquareEaseOut(linearValue) :
194− (1 - interpolateSquareEaseIn(linearValue))
195−
196− metaballGraph.adjacencyMatrix.set(i, j, value: interpolatedValue)
197− metaballGraph.adjacencyMatrix.set(j, i, value: interpolatedValue)
198−
199− renderer.state = .running
200− }
47+ }
201−
48+
202− @objc func handlePan(_ recognizer: UIPanGestureRecognizer) {
49+ func handlePan(recognizer: UIPanGestureRecognizer) {
203− let location = recognizer.location(in: metaballView)
50+ let location = recognizer.locationInView(metaballView)
204−
51+
205− if selectedMetaball == nil {
52+ var selectedMetaball: UIView?
53+
206− for metaball in metaballs where
54+ for metaball in metaballs where
207− abs(metaball.midX - location.x) < 50 &&
55+ abs(metaball.midX - location.x) < 50 && abs(metaball.midY - location.y) < 50 {
208− abs(metaball.midY - location.y) < 50
209− {
210− selectedMetaball = metaball
56+ selectedMetaball = metaball
211− break
57+ break
212− }
58+ }
213− }
59+
214−
215− guard selectedMetaball != nil else { return }
216−
217− selectedMetaball?.middle = location
60+ selectedMetaball?.middle = location
218−
61+
219− renderer.state = .running
62+ if recognizer.state == .Changed && dynamicRendering {
220−
63+ renderer.updateTargetView()
64+ }
221− if recognizer.state == .ended {
65+ if recognizer.state == .Ended {
222− selectedMetaball = nil
66+ renderer.updateTargetView()
223− }
67+ }
68+ }
69+}
70+
71+class Metaball: UIView {
72+
73+ init(position: CGPoint) {
74+ super.init(frame: CGRect.zero)
75+
76+ size = CGSize(50)
77+ middle = position
78+ backgroundColor = UIColor(red: 0.1306, green: 0.7522, blue: 0.0307, alpha: 0.3)
224− }
79+ }
225
80
81+ required init?(coder aDecoder: NSCoder) {
82+ super.init(coder: aDecoder)
83+ }
226}
84}
PixelImage/shaders.metal+25−94
@@ -3,118 +3,49 @@
3
3
4using namespace metal;
4using namespace metal;
5
5
6−struct metaballData {
7− float x;
8− float y;
9− float r;
10− float g;
11− float b;
12−};
13−
14kernel void
6kernel void
15 drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)]],
7 drawMetaballs(texture2d<float, access::write> outTexture[[texture(0)]],
16− constant float *edgesBuffer[[buffer(1)]],
8+ texture2d<float, access::read>
17− constant metaballData *metaballBuffer[[buffer(0)]],
9+ metaballTexture[[texture(1)]],
18 uint2 gid[[thread_position_in_grid]]) {
10 uint2 gid[[thread_position_in_grid]]) {
19
11
20− char numberOfMetaballs = metaballBuffer[0].x - 1;
12+ char numberOfMetaballs = metaballTexture.read(0)[0];
13+ char metaballArraySize = numberOfMetaballs * 2 + 1;
21
14
22 float sum = 0;
15 float sum = 0;
23− float3 colorSum = float3(0, 0, 0);
24− float colorAccumulation = 0;
25− float3 colorSumLink = float3(0, 0, 0);
26−
27− char x, y;
28−
29− float metaballDistances[10];
30− float2 metaballDirections[10];
31− float3 metaballColors[10];
32−
33− for (x = 1; x <= numberOfMetaballs; x += 1) {
34− metaballData metaball = metaballBuffer[x];
35− float2 metaballPosition = float2(metaball.x, metaball.y);
36− float2 vector = float2(metaballPosition.x - gid.x,
37− metaballPosition.y - gid.y);
38− float dotProduct = dot(vector, vector);
39− float squaredDistance = dotProduct > 0 ? dotProduct : 1;
40− float realDistance = sqrt(squaredDistance);
41− metaballDistances[x - 1] = squaredDistance;
42− metaballDirections[x - 1] = vector / realDistance;
43− metaballColors[x - 1] = float3(metaball.r, metaball.g, metaball.b);
44− }
45−
46− float bendClose = 0.0;
47− float bendCloseCount = 0.0;
48− float ball = 0.0;
49
16
50− for (x = 0; x < numberOfMetaballs; x += 1) {
17+ for (char i = 1; i < metaballArraySize; i += 2) {
51− float distance1 = metaballDistances[x];
18+ for (char j = i + 2; j < metaballArraySize; j += 2) {
52− float value1 = 1500 / distance1;
19+ float2 metaball1 = float2(metaballTexture.read(i)[0],
53− float2 direction1 = metaballDirections[x];
20+ metaballTexture.read(i + 1)[0]);
54
21
55− float colorContribution = 1 / distance1;
22+ float2 metaball2 = float2(metaballTexture.read(j)[0],
56− colorAccumulation += colorContribution;
23+ metaballTexture.read(j + 1)[0]);
57− colorSum += metaballColors[x] * colorContribution;
58
24
59− for (y = x + 1; y < numberOfMetaballs; y += 1) {
25+ float2 metaball1Vector
60− float distance2 = metaballDistances[y];
26+ = float2(metaball1.x - gid.x, metaball1.y - gid.y);
61− float value2 = 1500 / distance2;
27+ float2 metaball2Vector
62− float2 direction2 = metaballDirections[y];
28+ = float2(metaball2.x - gid.x, metaball2.y - gid.y);
63
29
64− float v = value1 + value2;
30+ float2 direction1 = normalize(metaball1Vector);
65− float weightedValue = 0.5 * v;
31+ float2 direction2 = normalize(metaball2Vector);
66
32
67− char edgeIndex = y * numberOfMetaballs + x;
68− float edgeWeight = edgesBuffer[edgeIndex];
69 float cosine = dot(direction1, direction2);
33 float cosine = dot(direction1, direction2);
70− float link = pow(((1 - cosine) * 0.5), 100);
71− float weightedLink = 0.6 * link * edgeWeight;
72
34
73− float result = weightedValue + weightedLink;
35+ float value1 = 2048 / (dot(metaball1Vector, metaball1Vector) + 1);
36+ float value2 = 2048 / (dot(metaball2Vector, metaball2Vector) + 1);
74
37
75− ball += step(0.4, weightedValue);
38+ float v = value1 + value2;
76−
39+ float link = pow(((1 - cosine) * 0.5), 100);
77− float metaballValue = step(0.5, weightedValue + weightedLink);
78−
79− if (metaballValue > 0.0) {
80− colorSumLink = float3(0.0, 0.0, 0.0);
81− colorSumLink += metaballColors[x] / distance1;
82− colorSumLink += metaballColors[y] / distance2;
83− colorSumLink /= (1 / distance1) + (1 / distance2);
84− }
85
40
86− if (result > 0.4) {
41+ float weightedLink = 0.6 * link;
87− bendClose += result;
42+ float weightedValue = 0.5 * v;
88− bendCloseCount += 1.0;
89− }
90
43
91− sum += metaballValue;
44+ sum += mix(0.0, 1.0, step(0.5, weightedValue + weightedLink));
92 }
45 }
93 }
46 }
94
47
95− // bendClose = bendClose / bendCloseCount;
96−
97− if (bendClose != 0.0) {
98− bendClose = (bendClose - 0.4) * (1 / (0.6 - 0.4));
99− } else {
100− bendClose = 0.0;
101− }
102−
103−
104− float result = step(0.4, sum);
48+ float result = sum;
105− result = clamp(result, 0.0, 1.0);
106−
107− colorSum = colorSum / colorAccumulation;
108−
109− if (result > 0.0 && ball < 1.0) {
110− colorSum = colorSumLink;
111− }
112−
113− colorSum *= result;
114−
115− if (colorSum.r == 0 && colorSum.g == 0 && colorSum.b == 0) {
116− colorSum = float3(1, 1, 1);
117− }
118
49
119− outTexture.write(float4(colorSum.bgr, 1), gid);
50+ outTexture.write(float4(result, result / 2, 0, 1), gid);
120}
51}
Podfiledeleted−6
@@ -1,6 +0,0 @@
1−platform :ios, '9.2'
2−use_frameworks!
3−
4−target 'PixelImage' do
5− pod 'ChameleonFramework/Swift', :git => 'https://github.com/ViccAlexander/Chameleon.git'
6−end
Podfile.lockdeleted−23
@@ -1,23 +0,0 @@
1−PODS:
2− - ChameleonFramework/Default (2.1.0)
3− - ChameleonFramework/Swift (2.1.0):
4− - ChameleonFramework/Default
5−
6−DEPENDENCIES:
7− - ChameleonFramework/Swift (from `https://github.com/ViccAlexander/Chameleon.git`)
8−
9−EXTERNAL SOURCES:
10− ChameleonFramework:
11− :git: https://github.com/ViccAlexander/Chameleon.git
12−
13−CHECKOUT OPTIONS:
14− ChameleonFramework:
15− :commit: 6dd284bde21ea2e7f9fd89bc36f40df16e16369d
16− :git: https://github.com/ViccAlexander/Chameleon.git
17−
18−SPEC CHECKSUMS:
19− ChameleonFramework: d21a3cc247abfe5e37609a283a8238b03575cf64
20−
21−PODFILE CHECKSUM: 01ad8f20bdbed983c319dde08426f855f26bc5a0
22−
23−COCOAPODS: 1.5.2
README.md+2−19
@@ -1,19 +1,2 @@
1−![Example Animation](https://raw.githubusercontent.com/vinivendra/metal-metaballs/master/Examples/Animation.gif)
1+# metal-metaballs
2−
2+A 'playground' project for rendering metaball-like graphics in metal.
3−# Metal Metaballs
4−
5−Metal Metaballs is a framework for rendering graphs in an aesthetically pleasing way. It uses an adapted version of [metaball](https://en.wikipedia.org/wiki/Metaballs) math to create fluid graphics, allow vertices to merge with each other and allow edges to flow and animate smoothly.
6−
7−Vertices and edges may be added and removed at will and can interact with gestures. Rendering a fullscreen view continuously uses only about 19% of the CPU at 60 fps, though normally the view will only be updated when needed. All rendering is done in a background thread, so the main thread remains almost completely free. These measurements were done using an iPhone 6S Plus (which has more pixels to calculate but more power to do so), so YMMV.
8−
9−This framework is being developed to make me learn several different design patters, APIs and features used in iOS and in graphics applications. So far, it uses:
10−
11−- [**Metaball**](https://en.wikipedia.org/wiki/Metaballs) math, in an adapted version, to render the graphics.
12−- [**Metal**](https://developer.apple.com/metal/) compute shaders to draw the metaballs dynamically.
13−- [**Grand Central Dispatch**](https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/) for doing CPU and GPU calculations simultaneously.
14−- [**Double buffering**](https://en.wikipedia.org/wiki/Multiple_buffering), to speed up rendering times.
15−- Different [**interpolations**](http://flexmonkey.blogspot.ca/2016/01/playing-with-interpolation-functions-in.html) for animations.
16−
17−## Installation
18−
19−Just download the app and run it on your metal-enabled device of choice :)