From 2b184ed93324d3fded1f54ec9422bf34aab521b8 Mon Sep 17 00:00:00 2001 From: Laurent Sansonetti Date: Tue, 3 Apr 2012 21:19:26 +0200 Subject: [PATCH] add swipe gestures, add alan kay --- .../mustache/app/mustache_view_controller.rb | 54 ++++++++++++++++-- sample/mustache/resources/kay.jpg | Bin 0 -> 13179 bytes 2 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 sample/mustache/resources/kay.jpg diff --git a/sample/mustache/app/mustache_view_controller.rb b/sample/mustache/app/mustache_view_controller.rb index 34091082..15480d96 100644 --- a/sample/mustache/app/mustache_view_controller.rb +++ b/sample/mustache/app/mustache_view_controller.rb @@ -5,20 +5,38 @@ class MustacheViewController < UIViewController end def viewDidLoad - view.image = UIImage.imageNamed('matz.jpg') + @images = %w{matz guido kay jmccolor}.map { |name| UIImage.imageNamed(name + '.jpg') } + view.image = @images.first view.contentMode = UIViewContentModeScaleAspectFit + view.userInteractionEnabled = true + + previousGesture = UISwipeGestureRecognizer.alloc.initWithTarget(self, action:'swipePreviousGesture:') + previousGesture.direction = UISwipeGestureRecognizerDirectionLeft + view.addGestureRecognizer(previousGesture) + nextGesture = UISwipeGestureRecognizer.alloc.initWithTarget(self, action:'swipeNextGesture:') + nextGesture.direction = UISwipeGestureRecognizerDirectionRight + view.addGestureRecognizer(nextGesture) end def viewDidAppear(animated) + mustachify + end + + def mustachify + # Remove previous mustaches. + view.subviews.each { |v| v.removeFromSuperview } + # CoreImage used a coordinate system which is flipped on the Y axis # compared to UIKit. Also, a UIImageView can return an image larger than # itself. To properly translate points, we use an affine transform. transform = CGAffineTransformMakeScale(view.bounds.size.width / view.image.size.width, -1 * (view.bounds.size.height / view.image.size.height)) transform = CGAffineTransformTranslate(transform, 0, -view.image.size.height) - @detector ||= CIDetector.detectorOfType CIDetectorTypeFace, context:nil, options: { CIDetectorAccuracy: CIDetectorAccuracyHigh } image = CIImage.imageWithCGImage(view.image.CGImage) + @detector ||= CIDetector.detectorOfType CIDetectorTypeFace, context:nil, options: { CIDetectorAccuracy: CIDetectorAccuracyHigh } @detector.featuresInImage(image).each do |feature| + # We need the mouth and eyes positions to determine where the mustache + # should be added. next unless feature.hasMouthPosition and feature.hasLeftEyePosition and feature.hasRightEyePosition if @debug_face @@ -31,27 +49,51 @@ class MustacheViewController < UIViewController end end + # Create the mustache view. mustacheView = UIImageView.alloc.init mustacheView.image = UIImage.imageNamed('mustache') mustacheView.contentMode = UIViewContentModeScaleAspectFit + # Compute its location and size, based on the position of the eyes and + # mouth. w = feature.bounds.size.width h = feature.bounds.size.height / 5 x = (feature.mouthPosition.x + (feature.leftEyePosition.x + feature.rightEyePosition.x) / 2) / 2 - w / 2 y = feature.mouthPosition.y - mustacheView.frame = CGRectApplyAffineTransform([[x, y], [w, h]], transform) + # Apply a rotation on the mustache, based on the face inclination. mustacheAngle = Math.atan2(feature.leftEyePosition.x - feature.rightEyePosition.x, feature.leftEyePosition.y - feature.rightEyePosition.y) + Math::PI/2 mustacheView.transform = CGAffineTransformMakeRotation(mustacheAngle) - + view.addSubview(mustacheView) end end def shouldAutorotateToInterfaceOrientation(*) - view.subviews.each { |v| v.removeFromSuperview } - viewDidAppear(true) + mustachify true end + + def swipePreviousGesture(gesture) + idx = @images.index(view.image) + view.image = + if idx == 0 + @images.last + else + @images[idx - 1] + end + mustachify + end + + def swipeNextGesture(gesture) + idx = @images.index(view.image) + view.image = + if idx == @images.size - 1 + @images.first + else + @images[idx + 1] + end + mustachify + end end diff --git a/sample/mustache/resources/kay.jpg b/sample/mustache/resources/kay.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1b8e12daa367ea3140c9f57c5d8a5f4cbb4bc4b5 GIT binary patch literal 13179 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 literal 0 HcmV?d00001