├── bodyDetection ├── Experience.rcproject │ ├── Library │ │ └── ProjectLibrary │ │ │ ├── Contents.json │ │ │ └── Version.json │ ├── SceneThumbnails │ │ ├── F9610871-0955-494F-A5C3-51D1A281BAB3 │ │ └── F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails │ │ │ ├── wide │ │ │ └── square │ └── com.apple.RCFoundation.Project ├── View │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ └── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard ├── Extensions │ ├── CGFloat+Extension.swift │ ├── ARKit+Extension.swift │ ├── UIKit+Extension.swift │ └── CGPoint+Extension.swift ├── Info.plist ├── AppDelegate.swift └── Controller │ └── ViewController.swift ├── .gitignore └── bodyDetection.xcodeproj └── project.pbxproj /bodyDetection/Experience.rcproject/Library/ProjectLibrary/Contents.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] -------------------------------------------------------------------------------- /bodyDetection/View/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /bodyDetection/Experience.rcproject/Library/ProjectLibrary/Version.json: -------------------------------------------------------------------------------- 1 | { 2 | "LibraryID" : "BBB5EDD2-CBE1-49E5-931D-2C81F724D19D", 3 | "Version" : "1.0" 4 | } -------------------------------------------------------------------------------- /bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valengo/bodyDetection/HEAD/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3 -------------------------------------------------------------------------------- /bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/wide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valengo/bodyDetection/HEAD/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/wide -------------------------------------------------------------------------------- /bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/square: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valengo/bodyDetection/HEAD/bodyDetection/Experience.rcproject/SceneThumbnails/F9610871-0955-494F-A5C3-51D1A281BAB3.thumbnails/square -------------------------------------------------------------------------------- /bodyDetection/Extensions/CGFloat+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGFloat+Extension.swift 3 | // bodyDetection 4 | // 5 | // Created by Andressa Valengo on 28/10/19. 6 | // Copyright © 2019 Andressa Valengo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGFloat { 12 | func fomatted(with pattern: String = "%.3f") -> String { 13 | return String(format: pattern, Double(self)) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | -------------------------------------------------------------------------------- /bodyDetection/View/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /bodyDetection/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | arkit 33 | 34 | UIStatusBarHidden 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /bodyDetection/Extensions/ARKit+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ARExtensions.swift 3 | // bodyDetection 4 | // 5 | // Created by Andressa Valengo on 22/10/19. 6 | // Copyright © 2019 Andressa Valengo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ARKit 11 | 12 | extension ARSkeleton.JointName { 13 | 14 | // from bottom to top 15 | @available(iOS 13.0, *) 16 | public static let spine2 = ARSkeleton.JointName(rawValue: "spine_2_joint") 17 | 18 | @available(iOS 13.0, *) 19 | public static let spine3 = ARSkeleton.JointName(rawValue: "spine_3_joint") 20 | 21 | @available(iOS 13.0, *) 22 | public static let spine4 = ARSkeleton.JointName(rawValue: "spine_4_joint") 23 | 24 | @available(iOS 13.0, *) 25 | public static let spine5 = ARSkeleton.JointName(rawValue: "spine_5_joint") 26 | 27 | @available(iOS 13.0, *) 28 | public static let spine6 = ARSkeleton.JointName(rawValue: "spine_6_joint") 29 | 30 | @available(iOS 13.0, *) 31 | public static let spine7 = ARSkeleton.JointName(rawValue: "spine_7_joint") 32 | 33 | // from bottom to top 34 | @available(iOS 13.0, *) 35 | public static let neck1 = ARSkeleton.JointName(rawValue: "neck_1_joint") 36 | 37 | @available(iOS 13.0, *) 38 | public static let neck2 = ARSkeleton.JointName(rawValue: "neck_2_joint") 39 | 40 | @available(iOS 13.0, *) 41 | public static let neck3 = ARSkeleton.JointName(rawValue: "neck_3_joint") 42 | 43 | @available(iOS 13.0, *) 44 | public static let neck4 = ARSkeleton.JointName(rawValue: "neck_4_joint") 45 | 46 | @available(iOS 13.0, *) 47 | public static let rigthArm = ARSkeleton.JointName(rawValue: "right_arm_joint") 48 | 49 | @available(iOS 13.0, *) 50 | public static let leftArm = ARSkeleton.JointName(rawValue: "left_arm_joint") 51 | } 52 | -------------------------------------------------------------------------------- /bodyDetection/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // bodyDetection 4 | // 5 | // Created by Andressa Valengo on 22/10/19. 6 | // Copyright © 2019 Andressa Valengo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 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. 29 | } 30 | 31 | func applicationWillEnterForeground(_ application: UIApplication) { 32 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 33 | } 34 | 35 | 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 | } 38 | 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /bodyDetection/View/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /bodyDetection/Experience.rcproject/com.apple.RCFoundation.Project: -------------------------------------------------------------------------------- 1 | { 2 | "__version" : 1, 3 | "__content" : [ 4 | { 5 | "tags" : { 6 | "__version" : 1, 7 | "__content" : [ 8 | { 9 | "tagsStore" : { 10 | 11 | } 12 | } 13 | ] 14 | }, 15 | "scenes" : [ 16 | { 17 | "__version" : 2, 18 | "__content" : [ 19 | { 20 | "hasGroundPlane" : true, 21 | "gravity" : [ 22 | 0, 23 | -9.8000001907348633, 24 | 0 25 | ], 26 | "arAnchorSpecification" : { 27 | "name" : "surface", 28 | "classification" : 0, 29 | "alignment" : 1 30 | }, 31 | "title" : "Box", 32 | "material" : "concrete", 33 | "layoutData" : { 34 | "version" : 1, 35 | "constraints" : [ 36 | 37 | ] 38 | }, 39 | "identifier" : "F9610871-0955-494F-A5C3-51D1A281BAB3", 40 | "behaviors" : [ 41 | 42 | ], 43 | "overrides" : { 44 | "factory" : null, 45 | "children" : { 46 | "4A213441-135C-450E-8EF8-1A4EAB267C1D" : { 47 | "overrides" : { 48 | "factory" : { 49 | "version" : "1.0", 50 | "identifier" : "com.apple.rc.af.CoreAssetFactories.PrimitiveShapeAssetFactory" 51 | }, 52 | "arguments" : [ 53 | [ 54 | "material", 55 | { 56 | "value" : "steel", 57 | "typeName" : "String" 58 | } 59 | ], 60 | [ 61 | "type", 62 | { 63 | "value" : "box", 64 | "typeName" : "String" 65 | } 66 | ] 67 | ], 68 | "runtimeAttributes" : [ 69 | [ 70 | "RuntimeIdentifier", 71 | { 72 | "value" : "3788A5B5-0388-488A-8304-7B90FEBA6FAC", 73 | "typeName" : "UUID" 74 | } 75 | ], 76 | [ 77 | "entityName", 78 | { 79 | "value" : "Steel Box", 80 | "typeName" : "String" 81 | } 82 | ] 83 | ] 84 | }, 85 | "transform" : { 86 | "matrix" : [ 87 | 1, 88 | 0, 89 | 0, 90 | 0, 91 | 0, 92 | 1, 93 | 0, 94 | 0, 95 | 0, 96 | 0, 97 | 1, 98 | 0, 99 | 0, 100 | 0.05000000074505806, 101 | 0, 102 | 1 103 | ] 104 | } 105 | }, 106 | "B91C7CA3-4AB1-4253-9A84-07383168A8A8" : null, 107 | "7F5F1ADC-E5E4-4EF5-A5B5-FC43B071FFA5" : null, 108 | "632E476F-1E55-4E30-9723-1C51DD2E8B89" : null 109 | } 110 | }, 111 | "viewTransform" : { 112 | "sceneTransform" : [ 113 | 1, 114 | 0, 115 | 0, 116 | 0, 117 | 0, 118 | 0.99999994039535522, 119 | 0, 120 | 0, 121 | 0, 122 | 0, 123 | 0.99999994039535522, 124 | 0, 125 | 0, 126 | 0, 127 | 0, 128 | 1 129 | ], 130 | "cameraTransform" : [ 131 | 0.99999994039535522, 132 | 0, 133 | 0, 134 | 0, 135 | 0, 136 | 0.80754852294921875, 137 | -0.58980101346969604, 138 | 0, 139 | 0, 140 | 0.58980101346969604, 141 | 0.80754852294921875, 142 | 0, 143 | 0, 144 | 1.135667085647583, 145 | 1.5549418926239014, 146 | 1 147 | ] 148 | } 149 | } 150 | ] 151 | } 152 | ] 153 | } 154 | ] 155 | } -------------------------------------------------------------------------------- /bodyDetection/Extensions/UIKit+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // bodyDetection 4 | // 5 | // Created by Andressa Valengo on 22/10/19. 6 | // Copyright © 2019 Andressa Valengo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import VideoToolbox 12 | 13 | extension CGImage { 14 | func colors(at: [CGPoint]) -> [UIColor]? { 15 | let colorSpace = CGColorSpaceCreateDeviceRGB() 16 | let bytesPerPixel = 4 17 | let bytesPerRow = bytesPerPixel * width 18 | let bitsPerComponent = 8 19 | let bitmapInfo: UInt32 = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue 20 | 21 | guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo), 22 | let ptr = context.data?.assumingMemoryBound(to: UInt8.self) else { 23 | return nil 24 | } 25 | 26 | context.draw(self, in: CGRect(x: 0, y: 0, width: width, height: height)) 27 | 28 | return at.map { p in 29 | let i = bytesPerRow * Int(p.y) + bytesPerPixel * Int(p.x) 30 | 31 | let a = CGFloat(ptr[i + 3]) / 255.0 32 | let r = (CGFloat(ptr[i]) / a) / 255.0 33 | let g = (CGFloat(ptr[i + 1]) / a) / 255.0 34 | let b = (CGFloat(ptr[i + 2]) / a) / 255.0 35 | 36 | return UIColor(red: r, green: g, blue: b, alpha: a) 37 | } 38 | } 39 | } 40 | 41 | extension UIImage { 42 | func rotate(radians: CGFloat) -> UIImage { 43 | let rotatedSize = CGRect(origin: .zero, size: size) 44 | .applying(CGAffineTransform(rotationAngle: CGFloat(radians))) 45 | .integral.size 46 | UIGraphicsBeginImageContext(rotatedSize) 47 | if let context = UIGraphicsGetCurrentContext() { 48 | let origin = CGPoint(x: rotatedSize.width / 2.0, 49 | y: rotatedSize.height / 2.0) 50 | context.translateBy(x: origin.x, y: origin.y) 51 | context.rotate(by: radians) 52 | draw(in: CGRect(x: -origin.y, y: -origin.x, 53 | width: size.width, height: size.height)) 54 | let rotatedImage = UIGraphicsGetImageFromCurrentImageContext() 55 | UIGraphicsEndImageContext() 56 | 57 | return rotatedImage ?? self 58 | } 59 | return self 60 | } 61 | } 62 | 63 | extension UIImage { 64 | public convenience init?(pixelBuffer: CVPixelBuffer) { 65 | var cgImage: CGImage? 66 | VTCreateCGImageFromCVPixelBuffer(pixelBuffer, options: nil, imageOut: &cgImage) 67 | 68 | if let cgImage = cgImage { 69 | self.init(cgImage: cgImage) 70 | } else { 71 | return nil 72 | } 73 | } 74 | } 75 | 76 | extension UIColor { 77 | var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { 78 | var red: CGFloat = 0 79 | var green: CGFloat = 0 80 | var blue: CGFloat = 0 81 | var alpha: CGFloat = 0 82 | getRed(&red, green: &green, blue: &blue, alpha: &alpha) 83 | 84 | return (red, green, blue, alpha) 85 | } 86 | } 87 | 88 | extension UIImage { 89 | func resizedImage(newSize: CGSize) -> UIImage? { 90 | guard self.size != newSize else { return self } 91 | UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0); 92 | self.draw(in: CGRect(origin: .zero, size: newSize)) 93 | let newImage = UIGraphicsGetImageFromCurrentImageContext() 94 | UIGraphicsEndImageContext() 95 | return newImage 96 | } 97 | 98 | func resizedImageWithinRect(rectSize: CGSize) -> UIImage? { 99 | let widthFactor = size.width / rectSize.width 100 | let heightFactor = size.height / rectSize.height 101 | 102 | var resizeFactor = widthFactor 103 | if size.height > size.width { 104 | resizeFactor = heightFactor 105 | } 106 | 107 | let newSize = CGSize(width: size.width/resizeFactor, height: size.height/resizeFactor) 108 | let resized = resizedImage(newSize: newSize) 109 | return resized 110 | } 111 | 112 | func resizedImageWithAspectFill(for rectSize: CGSize) -> UIImage? { 113 | let newWidth: CGFloat = rectSize.width / size.width 114 | let newHeight: CGFloat = rectSize.height / size.height 115 | var aspectFillSize = CGSize(width: rectSize.width, height: rectSize.height) 116 | 117 | if newHeight > newWidth { 118 | aspectFillSize.width = newHeight * size.width 119 | } else if newWidth > newHeight { 120 | aspectFillSize.height = newWidth * size.height 121 | } 122 | return resizedImage(newSize: aspectFillSize) 123 | } 124 | } 125 | 126 | extension UIImageView { 127 | var aspectFitSize: CGSize { 128 | guard let image = image else { return CGSize.zero } 129 | 130 | var aspectFitSize = CGSize(width: frame.size.width, height: frame.size.height) 131 | let newWidth: CGFloat = frame.size.width / image.size.width 132 | let newHeight: CGFloat = frame.size.height / image.size.height 133 | 134 | if newHeight < newWidth { 135 | aspectFitSize.width = newHeight * image.size.width 136 | } else if newWidth < newHeight { 137 | aspectFitSize.height = newWidth * image.size.height 138 | } 139 | 140 | return aspectFitSize 141 | } 142 | 143 | var aspectFillSize: CGSize { 144 | guard let image = image else { return CGSize.zero } 145 | 146 | var aspectFillSize = CGSize(width: frame.size.width, height: frame.size.height) 147 | let newWidth: CGFloat = frame.size.width / image.size.width 148 | let newHeight: CGFloat = frame.size.height / image.size.height 149 | 150 | if newHeight > newWidth { 151 | aspectFillSize.width = newHeight * image.size.width 152 | } else if newWidth > newHeight { 153 | aspectFillSize.height = newWidth * image.size.height 154 | } 155 | 156 | return aspectFillSize 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /bodyDetection/Extensions/CGPoint+Extension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import CoreGraphics 24 | import SpriteKit 25 | 26 | public extension CGPoint { 27 | /** 28 | * Creates a new CGPoint given a CGVector. 29 | */ 30 | init(vector: CGVector) { 31 | self.init(x: vector.dx, y: vector.dy) 32 | } 33 | 34 | /** 35 | * Given an angle in radians, creates a vector of length 1.0 and returns the 36 | * result as a new CGPoint. An angle of 0 is assumed to point to the right. 37 | */ 38 | init(angle: CGFloat) { 39 | self.init(x: cos(angle), y: sin(angle)) 40 | } 41 | 42 | /** 43 | * Adds (dx, dy) to the point. 44 | */ 45 | mutating func offset(dx: CGFloat, dy: CGFloat) -> CGPoint { 46 | x += dx 47 | y += dy 48 | return self 49 | } 50 | 51 | /** 52 | * Returns the length (magnitude) of the vector described by the CGPoint. 53 | */ 54 | func length() -> CGFloat { 55 | return sqrt(x*x + y*y) 56 | } 57 | 58 | /** 59 | * Returns the squared length of the vector described by the CGPoint. 60 | */ 61 | func lengthSquared() -> CGFloat { 62 | return x*x + y*y 63 | } 64 | 65 | /** 66 | * Normalizes the vector described by the CGPoint to length 1.0 and returns 67 | * the result as a new CGPoint. 68 | */ 69 | func normalized() -> CGPoint { 70 | let len = length() 71 | return len>0 ? self / len : CGPoint.zero 72 | } 73 | 74 | /** 75 | * Normalizes the vector described by the CGPoint to length 1.0. 76 | */ 77 | mutating func normalize() -> CGPoint { 78 | self = normalized() 79 | return self 80 | } 81 | 82 | /** 83 | * Calculates the distance between two CGPoints. Pythagoras! 84 | */ 85 | func distanceTo(_ point: CGPoint) -> CGFloat { 86 | return (self - point).length() 87 | } 88 | 89 | /** 90 | * Returns the angle in radians of the vector described by the CGPoint. 91 | * The range of the angle is -π to π; an angle of 0 points to the right. 92 | */ 93 | var angle: CGFloat { 94 | return atan2(y, x) 95 | } 96 | } 97 | 98 | /** 99 | * Adds two CGPoint values and returns the result as a new CGPoint. 100 | */ 101 | public func + (left: CGPoint, right: CGPoint) -> CGPoint { 102 | return CGPoint(x: left.x + right.x, y: left.y + right.y) 103 | } 104 | 105 | /** 106 | * Increments a CGPoint with the value of another. 107 | */ 108 | public func += (left: inout CGPoint, right: CGPoint) { 109 | left = left + right 110 | } 111 | 112 | /** 113 | * Adds a CGVector to this CGPoint and returns the result as a new CGPoint. 114 | */ 115 | public func + (left: CGPoint, right: CGVector) -> CGPoint { 116 | return CGPoint(x: left.x + right.dx, y: left.y + right.dy) 117 | } 118 | 119 | /** 120 | * Increments a CGPoint with the value of a CGVector. 121 | */ 122 | public func += (left: inout CGPoint, right: CGVector) { 123 | left = left + right 124 | } 125 | 126 | /** 127 | * Subtracts two CGPoint values and returns the result as a new CGPoint. 128 | */ 129 | public func - (left: CGPoint, right: CGPoint) -> CGPoint { 130 | return CGPoint(x: left.x - right.x, y: left.y - right.y) 131 | } 132 | 133 | /** 134 | * Decrements a CGPoint with the value of another. 135 | */ 136 | public func -= (left: inout CGPoint, right: CGPoint) { 137 | left = left - right 138 | } 139 | 140 | /** 141 | * Subtracts a CGVector from a CGPoint and returns the result as a new CGPoint. 142 | */ 143 | public func - (left: CGPoint, right: CGVector) -> CGPoint { 144 | return CGPoint(x: left.x - right.dx, y: left.y - right.dy) 145 | } 146 | 147 | /** 148 | * Decrements a CGPoint with the value of a CGVector. 149 | */ 150 | public func -= (left: inout CGPoint, right: CGVector) { 151 | left = left - right 152 | } 153 | 154 | /** 155 | * Multiplies two CGPoint values and returns the result as a new CGPoint. 156 | */ 157 | public func * (left: CGPoint, right: CGPoint) -> CGPoint { 158 | return CGPoint(x: left.x * right.x, y: left.y * right.y) 159 | } 160 | 161 | /** 162 | * Multiplies a CGPoint with another. 163 | */ 164 | public func *= (left: inout CGPoint, right: CGPoint) { 165 | left = left * right 166 | } 167 | 168 | /** 169 | * Multiplies the x and y fields of a CGPoint with the same scalar value and 170 | * returns the result as a new CGPoint. 171 | */ 172 | public func * (point: CGPoint, scalar: CGFloat) -> CGPoint { 173 | return CGPoint(x: point.x * scalar, y: point.y * scalar) 174 | } 175 | 176 | /** 177 | * Multiplies the x and y fields of a CGPoint with the same scalar value. 178 | */ 179 | public func *= (point: inout CGPoint, scalar: CGFloat) { 180 | point = point * scalar 181 | } 182 | 183 | /** 184 | * Multiplies a CGPoint with a CGVector and returns the result as a new CGPoint. 185 | */ 186 | public func * (left: CGPoint, right: CGVector) -> CGPoint { 187 | return CGPoint(x: left.x * right.dx, y: left.y * right.dy) 188 | } 189 | 190 | /** 191 | * Multiplies a CGPoint with a CGVector. 192 | */ 193 | public func *= (left: inout CGPoint, right: CGVector) { 194 | left = left * right 195 | } 196 | 197 | /** 198 | * Divides two CGPoint values and returns the result as a new CGPoint. 199 | */ 200 | public func / (left: CGPoint, right: CGPoint) -> CGPoint { 201 | return CGPoint(x: left.x / right.x, y: left.y / right.y) 202 | } 203 | 204 | /** 205 | * Divides a CGPoint by another. 206 | */ 207 | public func /= (left: inout CGPoint, right: CGPoint) { 208 | left = left / right 209 | } 210 | 211 | /** 212 | * Divides the x and y fields of a CGPoint by the same scalar value and returns 213 | * the result as a new CGPoint. 214 | */ 215 | public func / (point: CGPoint, scalar: CGFloat) -> CGPoint { 216 | return CGPoint(x: point.x / scalar, y: point.y / scalar) 217 | } 218 | 219 | /** 220 | * Divides the x and y fields of a CGPoint by the same scalar value. 221 | */ 222 | public func /= (point: inout CGPoint, scalar: CGFloat) { 223 | point = point / scalar 224 | } 225 | 226 | /** 227 | * Divides a CGPoint by a CGVector and returns the result as a new CGPoint. 228 | */ 229 | public func / (left: CGPoint, right: CGVector) -> CGPoint { 230 | return CGPoint(x: left.x / right.dx, y: left.y / right.dy) 231 | } 232 | 233 | /** 234 | * Divides a CGPoint by a CGVector. 235 | */ 236 | public func /= (left: inout CGPoint, right: CGVector) { 237 | left = left / right 238 | } 239 | 240 | /** 241 | * Performs a linear interpolation between two CGPoint values. 242 | */ 243 | public func lerp(start: CGPoint, end: CGPoint, t: CGFloat) -> CGPoint { 244 | return start + (end - start) * t 245 | } 246 | -------------------------------------------------------------------------------- /bodyDetection/View/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 33 | 34 | 35 | 36 | 37 | 41 | 53 | 59 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /bodyDetection/Controller/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // bodyDetection 4 | // 5 | // Created by Andressa Valengo on 22/10/19. 6 | // Copyright © 2019 Andressa Valengo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RealityKit 11 | import ARKit 12 | import Combine 13 | 14 | class CustomSphere: Entity, HasModel { 15 | required init(color: UIColor, radius: Float) { 16 | super.init() 17 | self.components[ModelComponent] = ModelComponent( 18 | mesh: .generateSphere(radius: radius), 19 | materials: [SimpleMaterial( 20 | color: color, 21 | isMetallic: false) 22 | ] 23 | ) 24 | } 25 | 26 | required init() { 27 | fatalError("init() has not been implemented") 28 | } 29 | } 30 | 31 | class JointViewModel { 32 | var name: ARSkeleton.JointName 33 | var transform: simd_float4x4 34 | var point: CGPoint 35 | 36 | init(name: ARSkeleton.JointName, transform: simd_float4x4, point: CGPoint) { 37 | self.name = name 38 | self.transform = transform 39 | self.point = point 40 | } 41 | } 42 | 43 | class ViewController: UIViewController { 44 | 45 | enum SceneState { 46 | case looking 47 | case detectingStart 48 | case dectingEnd 49 | case trackingStart 50 | } 51 | 52 | var sceneState: SceneState = .looking 53 | 54 | @IBOutlet weak var distancesTextView: UITextView! 55 | @IBOutlet weak var stateMessage: UILabel! 56 | @IBOutlet var arView: ARView! 57 | @IBOutlet weak var segmentationImage: UIImageView! 58 | @IBOutlet weak var startRecordingStateImage: UIImageView! 59 | @IBOutlet weak var stopRecordingStateImage: UIImageView! 60 | 61 | let jointNames: [ARSkeleton.JointName] = [.root, .spine2, .spine3, .spine4, .spine5, .spine6, .spine7] 62 | let context = CIContext(options: nil) 63 | 64 | var jointDots = [CAShapeLayer]() 65 | var jointProjections = [ARSkeleton.JointName: JointViewModel]() 66 | var estimationDots = [CAShapeLayer]() 67 | var addedSpheres = [CustomSphere]() 68 | 69 | var corePointsDistance = [ARSkeleton.JointName: CGFloat]() 70 | 71 | let spheresAnchor = AnchorEntity() 72 | 73 | var bodyAnchor: ARBodyAnchor? 74 | 75 | override func viewDidLoad() { 76 | super.viewDidLoad() 77 | arView.session.delegate = self 78 | 79 | distancesTextView.text = "" 80 | 81 | guard ARWorldTrackingConfiguration.isSupported else { 82 | fatalError("This feature is only supported on devices with an A12 chip") 83 | } 84 | 85 | // arView.debugOptions = [.showAnchorGeometry, .showAnchorOrigins, .showWorldOrigin] 86 | } 87 | 88 | func toggleCamera() { 89 | startRecordingStateImage.isHidden = !startRecordingStateImage.isHidden 90 | stopRecordingStateImage.isHidden = !stopRecordingStateImage.isHidden 91 | } 92 | 93 | @IBAction func cameraButtonTap(_ sender: Any) { 94 | switch sceneState { 95 | case .looking: 96 | sceneState = .detectingStart 97 | detectBody() 98 | case .detectingStart: 99 | sceneState = .dectingEnd 100 | case .dectingEnd: 101 | sceneState = .trackingStart 102 | detectJoints() 103 | case .trackingStart: 104 | sceneState = .looking 105 | estimateScale() 106 | estimateCoreScale() 107 | } 108 | toggleCamera() 109 | setStateMessage() 110 | } 111 | 112 | func setStateMessage() { 113 | if sceneState == .detectingStart { 114 | stateMessage.text = "Detecting body..." 115 | } else if sceneState == .trackingStart { 116 | stateMessage.text = "Detecting joints..." 117 | } else { 118 | stateMessage.text = "" 119 | } 120 | } 121 | 122 | @IBAction func resetState() { 123 | sceneState = .looking 124 | segmentationImage.image = nil 125 | hideAllJoints2D() 126 | setStateMessage() 127 | hideEstimationDots() 128 | distancesTextView.text = "" 129 | 130 | startRecordingStateImage.isHidden = false 131 | stopRecordingStateImage.isHidden = true 132 | 133 | addedSpheres.forEach { 134 | $0.removeFromParent() 135 | } 136 | addedSpheres.removeAll() 137 | } 138 | 139 | func detectJoints() { 140 | let configuration = ARBodyTrackingConfiguration() 141 | arView.session.run(configuration) 142 | arView.scene.addAnchor(spheresAnchor) 143 | } 144 | 145 | func detectBody() { 146 | let config = ARWorldTrackingConfiguration() 147 | config.frameSemantics = [.personSegmentation] 148 | arView.session.run(config) 149 | } 150 | 151 | @IBAction func hideAllJoints2D() { 152 | jointDots.forEach { 153 | $0.removeFromSuperlayer() 154 | } 155 | jointDots.removeAll() 156 | } 157 | 158 | @IBAction func hideEstimationDots() { 159 | estimationDots.forEach { 160 | $0.removeFromSuperlayer() 161 | } 162 | estimationDots.removeAll() 163 | } 164 | 165 | @IBAction func toggleSegmentationImageContentMode() { 166 | if segmentationImage.contentMode == .scaleAspectFit { 167 | segmentationImage.contentMode = .scaleAspectFill 168 | } else { 169 | segmentationImage.contentMode = .scaleAspectFit 170 | } 171 | } 172 | 173 | @IBAction func showAllJoints2D() { 174 | guard let anchors = arView.session.currentFrame?.anchors else {return} 175 | for anchor in anchors { 176 | if let bodyAnchor = anchor as? ARBodyAnchor { 177 | self.bodyAnchor = bodyAnchor 178 | 179 | hideAllJoints2D() 180 | 181 | let bodyPosition = simd_make_float3(bodyAnchor.transform.columns.3) 182 | 183 | for jointName in jointNames { 184 | if let transform = bodyAnchor.skeleton.modelTransform(for: jointName) { 185 | let position = bodyPosition + simd_make_float3(transform.columns.3) 186 | print("original \(jointName.rawValue): \(position)") 187 | let projection = arView.project([position.x, position.y, position.z])! 188 | 189 | let shapeLayer = CAShapeLayer(); 190 | shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: CGFloat(projection.x), y: CGFloat(projection.y), width: 3, height: 3)).cgPath; 191 | shapeLayer.fillColor = UIColor.green.cgColor 192 | view.layer.addSublayer(shapeLayer) 193 | jointDots.append(shapeLayer) 194 | 195 | jointProjections[jointName] = JointViewModel(name: jointName, transform: transform, point: projection) 196 | } 197 | } 198 | } 199 | } 200 | } 201 | 202 | func estimatePoint(pointsOfInterest: [CGPoint], cgImage: CGImage) { 203 | if let colors = cgImage.colors(at: pointsOfInterest) { 204 | for i in 0.. float4x4 { 253 | var normalized = matrix 254 | normalized.columns.0 = simd.normalize(normalized.columns.0) 255 | normalized.columns.1 = simd.normalize(normalized.columns.1) 256 | normalized.columns.2 = simd.normalize(normalized.columns.2) 257 | return normalized 258 | } 259 | 260 | func estimateMaxPoint(of pointsOfInterest: [CGPoint], in cgImage: CGImage) -> CGPoint? { 261 | if let colors = cgImage.colors(at: pointsOfInterest) { 262 | let offset = abs(segmentationImage.aspectFillSize.width - segmentationImage.frame.size.width) / 2 263 | let xProportion = segmentationImage.aspectFillSize.width / CGFloat(cgImage.width) 264 | let yProportion = segmentationImage.aspectFillSize.height / CGFloat(cgImage.height) 265 | 266 | for i in 0.. 3D \(CGFloat(simd_distance(rightUnp, leftUnp)).fomatted())\n") 289 | } 290 | } 291 | 292 | func addSphere(radius: Float, anchor: AnchorEntity, transform: Transform) { 293 | let sphere = CustomSphere(color: .systemPink, radius: radius) 294 | sphere.transform = transform 295 | anchor.addChild(sphere, preservingWorldTransform: true) 296 | addedSpheres.append(sphere) 297 | } 298 | 299 | func estimateCoreScale() { 300 | 301 | guard let rootData = jointProjections[.root], 302 | let spine7data = jointProjections[.spine7] else {return} 303 | 304 | let distance3D = CGFloat(simd_distance(spine7data.transform.columns.3, rootData.transform.columns.3)) 305 | let distance2D = spine7data.point.distanceTo(rootData.point) 306 | let scaleProportion = distance3D / distance2D 307 | 308 | distancesTextView.text.append(contentsOf: "Estimated distances:\n") 309 | distancesTextView.text.append(contentsOf: "Core height -> 2D: \(distance2D.fomatted()); 3D \(distance3D.fomatted())\n") 310 | 311 | if let image = segmentationImage.image, let cgImage = image.cgImage { 312 | for jointName in jointNames { 313 | let xProportion = CGFloat(cgImage.width) / view.frame.size.width 314 | let yProportion = CGFloat(cgImage.height) / view.frame.size.height 315 | if let screenPoint = jointProjections[jointName]?.point { 316 | let projectedScreenPoint = CGPoint(x: screenPoint.x * xProportion, y: screenPoint.y * yProportion) 317 | var pointsOfInterest = [CGPoint]() 318 | for i in Int(screenPoint.x)...Int(view.frame.width) { 319 | pointsOfInterest.append(CGPoint(x: CGFloat(i) * xProportion, y: projectedScreenPoint.y)) 320 | } 321 | let rightPoint = estimateMaxPoint(of: pointsOfInterest, in: cgImage) 322 | pointsOfInterest.removeAll() 323 | 324 | for i in 0...Int(view.frame.width)/2 { 325 | pointsOfInterest.append(CGPoint(x: CGFloat(i) * xProportion, y: projectedScreenPoint.y)) 326 | } 327 | let leftPoint = estimateMaxPoint(of: pointsOfInterest.reversed(), in: cgImage) 328 | 329 | if let rightPoint = rightPoint, let leftPoint = leftPoint { 330 | if jointName == .root { 331 | checkSize(left: leftPoint, right: rightPoint) 332 | } 333 | let distanceBetweenPoints = rightPoint.distanceTo(leftPoint) 334 | corePointsDistance[jointName] = distanceBetweenPoints 335 | distancesTextView.text.append(contentsOf: "\(jointName.rawValue) -> 2D: \(distanceBetweenPoints.fomatted()); 3D \((distanceBetweenPoints * scaleProportion).fomatted())\n") 336 | } 337 | 338 | } 339 | } 340 | } 341 | } 342 | } 343 | 344 | extension ViewController: ARSessionDelegate { 345 | func session(_ session: ARSession, didUpdate frame: ARFrame) { 346 | if sceneState == .detectingStart, let segmentationBuffer = frame.segmentationBuffer { 347 | if let image = UIImage(pixelBuffer: segmentationBuffer)?.rotate(radians: .pi / 2) { 348 | segmentationImage.image = image 349 | } 350 | } 351 | } 352 | 353 | func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) { 354 | for anchor in anchors { 355 | guard let _ = anchor as? ARBodyAnchor else {continue} 356 | if sceneState == .trackingStart { 357 | showAllJoints2D() 358 | } 359 | } 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /bodyDetection.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6418F775235F4A8400CE2EAE /* UIKit+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6418F774235F4A8400CE2EAE /* UIKit+Extension.swift */; }; 11 | 64853755236786B700C0FCAA /* CGPoint+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64853754236786B700C0FCAA /* CGPoint+Extension.swift */; }; 12 | 648537572367CDB500C0FCAA /* CGFloat+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648537562367CDB500C0FCAA /* CGFloat+Extension.swift */; }; 13 | 64C8C756235FE68A0099949C /* ARKit+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C8C755235FE68A0099949C /* ARKit+Extension.swift */; }; 14 | 64EC6A52235F3E0C00CB6B59 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EC6A51235F3E0C00CB6B59 /* AppDelegate.swift */; }; 15 | 64EC6A54235F3E0C00CB6B59 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64EC6A53235F3E0C00CB6B59 /* ViewController.swift */; }; 16 | 64EC6A59235F3E0C00CB6B59 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64EC6A57235F3E0C00CB6B59 /* Main.storyboard */; }; 17 | 64EC6A5B235F3E0E00CB6B59 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64EC6A5A235F3E0E00CB6B59 /* Assets.xcassets */; }; 18 | 64EC6A5E235F3E0E00CB6B59 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64EC6A5C235F3E0E00CB6B59 /* LaunchScreen.storyboard */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 6418F774235F4A8400CE2EAE /* UIKit+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKit+Extension.swift"; sourceTree = ""; }; 23 | 64853754236786B700C0FCAA /* CGPoint+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGPoint+Extension.swift"; sourceTree = ""; }; 24 | 648537562367CDB500C0FCAA /* CGFloat+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Extension.swift"; sourceTree = ""; }; 25 | 64C8C755235FE68A0099949C /* ARKit+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ARKit+Extension.swift"; sourceTree = ""; }; 26 | 64EC6A4E235F3E0C00CB6B59 /* Body Detection.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Body Detection.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 64EC6A51235F3E0C00CB6B59 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 28 | 64EC6A53235F3E0C00CB6B59 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 29 | 64EC6A58235F3E0C00CB6B59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | 64EC6A5A235F3E0E00CB6B59 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | 64EC6A5D235F3E0E00CB6B59 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | 64EC6A5F235F3E0E00CB6B59 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 64EC6A4B235F3E0C00CB6B59 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 6418F773235F4A7200CE2EAE /* Extensions */ = { 47 | isa = PBXGroup; 48 | children = ( 49 | 6418F774235F4A8400CE2EAE /* UIKit+Extension.swift */, 50 | 64C8C755235FE68A0099949C /* ARKit+Extension.swift */, 51 | 64853754236786B700C0FCAA /* CGPoint+Extension.swift */, 52 | 648537562367CDB500C0FCAA /* CGFloat+Extension.swift */, 53 | ); 54 | path = Extensions; 55 | sourceTree = ""; 56 | }; 57 | 64C8C752235FE4790099949C /* Model */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | ); 61 | path = Model; 62 | sourceTree = ""; 63 | }; 64 | 64C8C753235FE4880099949C /* View */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 64EC6A5A235F3E0E00CB6B59 /* Assets.xcassets */, 68 | 64EC6A57235F3E0C00CB6B59 /* Main.storyboard */, 69 | 64EC6A5C235F3E0E00CB6B59 /* LaunchScreen.storyboard */, 70 | ); 71 | path = View; 72 | sourceTree = ""; 73 | }; 74 | 64C8C754235FE48E0099949C /* Controller */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 64EC6A53235F3E0C00CB6B59 /* ViewController.swift */, 78 | ); 79 | path = Controller; 80 | sourceTree = ""; 81 | }; 82 | 64EC6A45235F3E0C00CB6B59 = { 83 | isa = PBXGroup; 84 | children = ( 85 | 64EC6A50235F3E0C00CB6B59 /* bodyDetection */, 86 | 64EC6A4F235F3E0C00CB6B59 /* Products */, 87 | ); 88 | sourceTree = ""; 89 | }; 90 | 64EC6A4F235F3E0C00CB6B59 /* Products */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 64EC6A4E235F3E0C00CB6B59 /* Body Detection.app */, 94 | ); 95 | name = Products; 96 | sourceTree = ""; 97 | }; 98 | 64EC6A50235F3E0C00CB6B59 /* bodyDetection */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 64C8C752235FE4790099949C /* Model */, 102 | 64C8C753235FE4880099949C /* View */, 103 | 64C8C754235FE48E0099949C /* Controller */, 104 | 6418F773235F4A7200CE2EAE /* Extensions */, 105 | 64EC6A51235F3E0C00CB6B59 /* AppDelegate.swift */, 106 | 64EC6A5F235F3E0E00CB6B59 /* Info.plist */, 107 | ); 108 | path = bodyDetection; 109 | sourceTree = ""; 110 | }; 111 | /* End PBXGroup section */ 112 | 113 | /* Begin PBXNativeTarget section */ 114 | 64EC6A4D235F3E0C00CB6B59 /* bodyDetection */ = { 115 | isa = PBXNativeTarget; 116 | buildConfigurationList = 64EC6A62235F3E0E00CB6B59 /* Build configuration list for PBXNativeTarget "bodyDetection" */; 117 | buildPhases = ( 118 | 64EC6A4A235F3E0C00CB6B59 /* Sources */, 119 | 64EC6A4B235F3E0C00CB6B59 /* Frameworks */, 120 | 64EC6A4C235F3E0C00CB6B59 /* Resources */, 121 | ); 122 | buildRules = ( 123 | ); 124 | dependencies = ( 125 | ); 126 | name = bodyDetection; 127 | productName = bodyDetection; 128 | productReference = 64EC6A4E235F3E0C00CB6B59 /* Body Detection.app */; 129 | productType = "com.apple.product-type.application"; 130 | }; 131 | /* End PBXNativeTarget section */ 132 | 133 | /* Begin PBXProject section */ 134 | 64EC6A46235F3E0C00CB6B59 /* Project object */ = { 135 | isa = PBXProject; 136 | attributes = { 137 | LastSwiftUpdateCheck = 1110; 138 | LastUpgradeCheck = 1110; 139 | ORGANIZATIONNAME = "Andressa Valengo"; 140 | TargetAttributes = { 141 | 64EC6A4D235F3E0C00CB6B59 = { 142 | CreatedOnToolsVersion = 11.1; 143 | }; 144 | }; 145 | }; 146 | buildConfigurationList = 64EC6A49235F3E0C00CB6B59 /* Build configuration list for PBXProject "bodyDetection" */; 147 | compatibilityVersion = "Xcode 9.3"; 148 | developmentRegion = en; 149 | hasScannedForEncodings = 0; 150 | knownRegions = ( 151 | en, 152 | Base, 153 | ); 154 | mainGroup = 64EC6A45235F3E0C00CB6B59; 155 | productRefGroup = 64EC6A4F235F3E0C00CB6B59 /* Products */; 156 | projectDirPath = ""; 157 | projectRoot = ""; 158 | targets = ( 159 | 64EC6A4D235F3E0C00CB6B59 /* bodyDetection */, 160 | ); 161 | }; 162 | /* End PBXProject section */ 163 | 164 | /* Begin PBXResourcesBuildPhase section */ 165 | 64EC6A4C235F3E0C00CB6B59 /* Resources */ = { 166 | isa = PBXResourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | 64EC6A5E235F3E0E00CB6B59 /* LaunchScreen.storyboard in Resources */, 170 | 64EC6A5B235F3E0E00CB6B59 /* Assets.xcassets in Resources */, 171 | 64EC6A59235F3E0C00CB6B59 /* Main.storyboard in Resources */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXResourcesBuildPhase section */ 176 | 177 | /* Begin PBXSourcesBuildPhase section */ 178 | 64EC6A4A235F3E0C00CB6B59 /* Sources */ = { 179 | isa = PBXSourcesBuildPhase; 180 | buildActionMask = 2147483647; 181 | files = ( 182 | 64C8C756235FE68A0099949C /* ARKit+Extension.swift in Sources */, 183 | 64EC6A54235F3E0C00CB6B59 /* ViewController.swift in Sources */, 184 | 648537572367CDB500C0FCAA /* CGFloat+Extension.swift in Sources */, 185 | 6418F775235F4A8400CE2EAE /* UIKit+Extension.swift in Sources */, 186 | 64853755236786B700C0FCAA /* CGPoint+Extension.swift in Sources */, 187 | 64EC6A52235F3E0C00CB6B59 /* AppDelegate.swift in Sources */, 188 | ); 189 | runOnlyForDeploymentPostprocessing = 0; 190 | }; 191 | /* End PBXSourcesBuildPhase section */ 192 | 193 | /* Begin PBXVariantGroup section */ 194 | 64EC6A57235F3E0C00CB6B59 /* Main.storyboard */ = { 195 | isa = PBXVariantGroup; 196 | children = ( 197 | 64EC6A58235F3E0C00CB6B59 /* Base */, 198 | ); 199 | name = Main.storyboard; 200 | sourceTree = ""; 201 | }; 202 | 64EC6A5C235F3E0E00CB6B59 /* LaunchScreen.storyboard */ = { 203 | isa = PBXVariantGroup; 204 | children = ( 205 | 64EC6A5D235F3E0E00CB6B59 /* Base */, 206 | ); 207 | name = LaunchScreen.storyboard; 208 | sourceTree = ""; 209 | }; 210 | /* End PBXVariantGroup section */ 211 | 212 | /* Begin XCBuildConfiguration section */ 213 | 64EC6A60235F3E0E00CB6B59 /* Debug */ = { 214 | isa = XCBuildConfiguration; 215 | buildSettings = { 216 | ALWAYS_SEARCH_USER_PATHS = NO; 217 | CLANG_ANALYZER_NONNULL = YES; 218 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 219 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 220 | CLANG_CXX_LIBRARY = "libc++"; 221 | CLANG_ENABLE_MODULES = YES; 222 | CLANG_ENABLE_OBJC_ARC = YES; 223 | CLANG_ENABLE_OBJC_WEAK = YES; 224 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 225 | CLANG_WARN_BOOL_CONVERSION = YES; 226 | CLANG_WARN_COMMA = YES; 227 | CLANG_WARN_CONSTANT_CONVERSION = YES; 228 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 229 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 230 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 231 | CLANG_WARN_EMPTY_BODY = YES; 232 | CLANG_WARN_ENUM_CONVERSION = YES; 233 | CLANG_WARN_INFINITE_RECURSION = YES; 234 | CLANG_WARN_INT_CONVERSION = YES; 235 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 236 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 237 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 238 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 239 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 240 | CLANG_WARN_STRICT_PROTOTYPES = YES; 241 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 242 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 243 | CLANG_WARN_UNREACHABLE_CODE = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | COPY_PHASE_STRIP = NO; 246 | DEBUG_INFORMATION_FORMAT = dwarf; 247 | ENABLE_STRICT_OBJC_MSGSEND = YES; 248 | ENABLE_TESTABILITY = YES; 249 | GCC_C_LANGUAGE_STANDARD = gnu11; 250 | GCC_DYNAMIC_NO_PIC = NO; 251 | GCC_NO_COMMON_BLOCKS = YES; 252 | GCC_OPTIMIZATION_LEVEL = 0; 253 | GCC_PREPROCESSOR_DEFINITIONS = ( 254 | "DEBUG=1", 255 | "$(inherited)", 256 | ); 257 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 258 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 259 | GCC_WARN_UNDECLARED_SELECTOR = YES; 260 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 261 | GCC_WARN_UNUSED_FUNCTION = YES; 262 | GCC_WARN_UNUSED_VARIABLE = YES; 263 | IPHONEOS_DEPLOYMENT_TARGET = 13.1; 264 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 265 | MTL_FAST_MATH = YES; 266 | ONLY_ACTIVE_ARCH = YES; 267 | SDKROOT = iphoneos; 268 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 269 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 270 | }; 271 | name = Debug; 272 | }; 273 | 64EC6A61235F3E0E00CB6B59 /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_ANALYZER_NONNULL = YES; 278 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 279 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 280 | CLANG_CXX_LIBRARY = "libc++"; 281 | CLANG_ENABLE_MODULES = YES; 282 | CLANG_ENABLE_OBJC_ARC = YES; 283 | CLANG_ENABLE_OBJC_WEAK = YES; 284 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 285 | CLANG_WARN_BOOL_CONVERSION = YES; 286 | CLANG_WARN_COMMA = YES; 287 | CLANG_WARN_CONSTANT_CONVERSION = YES; 288 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 289 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 290 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 291 | CLANG_WARN_EMPTY_BODY = YES; 292 | CLANG_WARN_ENUM_CONVERSION = YES; 293 | CLANG_WARN_INFINITE_RECURSION = YES; 294 | CLANG_WARN_INT_CONVERSION = YES; 295 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 296 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 297 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 298 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 299 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 300 | CLANG_WARN_STRICT_PROTOTYPES = YES; 301 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 302 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 303 | CLANG_WARN_UNREACHABLE_CODE = YES; 304 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 305 | COPY_PHASE_STRIP = NO; 306 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 307 | ENABLE_NS_ASSERTIONS = NO; 308 | ENABLE_STRICT_OBJC_MSGSEND = YES; 309 | GCC_C_LANGUAGE_STANDARD = gnu11; 310 | GCC_NO_COMMON_BLOCKS = YES; 311 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 312 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 313 | GCC_WARN_UNDECLARED_SELECTOR = YES; 314 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 315 | GCC_WARN_UNUSED_FUNCTION = YES; 316 | GCC_WARN_UNUSED_VARIABLE = YES; 317 | IPHONEOS_DEPLOYMENT_TARGET = 13.1; 318 | MTL_ENABLE_DEBUG_INFO = NO; 319 | MTL_FAST_MATH = YES; 320 | SDKROOT = iphoneos; 321 | SWIFT_COMPILATION_MODE = wholemodule; 322 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 323 | VALIDATE_PRODUCT = YES; 324 | }; 325 | name = Release; 326 | }; 327 | 64EC6A63235F3E0E00CB6B59 /* Debug */ = { 328 | isa = XCBuildConfiguration; 329 | buildSettings = { 330 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 331 | CODE_SIGN_STYLE = Automatic; 332 | DEVELOPMENT_TEAM = UDGF2JUP82; 333 | INFOPLIST_FILE = bodyDetection/Info.plist; 334 | LD_RUNPATH_SEARCH_PATHS = ( 335 | "$(inherited)", 336 | "@executable_path/Frameworks", 337 | ); 338 | PRODUCT_BUNDLE_IDENTIFIER = andydeva.bodyDetection; 339 | PRODUCT_NAME = "Body Detection"; 340 | SWIFT_VERSION = 5.0; 341 | TARGETED_DEVICE_FAMILY = "1,2"; 342 | }; 343 | name = Debug; 344 | }; 345 | 64EC6A64235F3E0E00CB6B59 /* Release */ = { 346 | isa = XCBuildConfiguration; 347 | buildSettings = { 348 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 349 | CODE_SIGN_STYLE = Automatic; 350 | DEVELOPMENT_TEAM = UDGF2JUP82; 351 | INFOPLIST_FILE = bodyDetection/Info.plist; 352 | LD_RUNPATH_SEARCH_PATHS = ( 353 | "$(inherited)", 354 | "@executable_path/Frameworks", 355 | ); 356 | PRODUCT_BUNDLE_IDENTIFIER = andydeva.bodyDetection; 357 | PRODUCT_NAME = "Body Detection"; 358 | SWIFT_VERSION = 5.0; 359 | TARGETED_DEVICE_FAMILY = "1,2"; 360 | }; 361 | name = Release; 362 | }; 363 | /* End XCBuildConfiguration section */ 364 | 365 | /* Begin XCConfigurationList section */ 366 | 64EC6A49235F3E0C00CB6B59 /* Build configuration list for PBXProject "bodyDetection" */ = { 367 | isa = XCConfigurationList; 368 | buildConfigurations = ( 369 | 64EC6A60235F3E0E00CB6B59 /* Debug */, 370 | 64EC6A61235F3E0E00CB6B59 /* Release */, 371 | ); 372 | defaultConfigurationIsVisible = 0; 373 | defaultConfigurationName = Release; 374 | }; 375 | 64EC6A62235F3E0E00CB6B59 /* Build configuration list for PBXNativeTarget "bodyDetection" */ = { 376 | isa = XCConfigurationList; 377 | buildConfigurations = ( 378 | 64EC6A63235F3E0E00CB6B59 /* Debug */, 379 | 64EC6A64235F3E0E00CB6B59 /* Release */, 380 | ); 381 | defaultConfigurationIsVisible = 0; 382 | defaultConfigurationName = Release; 383 | }; 384 | /* End XCConfigurationList section */ 385 | }; 386 | rootObject = 64EC6A46235F3E0C00CB6B59 /* Project object */; 387 | } 388 | --------------------------------------------------------------------------------