iOS全景浏览App涉及到的技术

一、网络通信

1. 获取服务器数据

AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
    mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"application/json",nil];
    //拼接请求参数
    NSDictionary *parameter = @{@"user" : @"user",
                                @"title" : @"title",
                                @"description" : @"description",
                                @"panorama" : @"panorama",
                                @"filesize" : @"filesize",
                                @"width" : @"width",
                                @"thumbnail" : @"thumbnail",
                                @"likes" : @"likes",
                                @"collections" : @"collections",
                                @"created" : @"created"
                                };
    // 取出最前面的微博(最新的微博,ID最大的微博)
    HWStatusFrame *firstStatusF = [self.statusFrames firstObject];
    [mgr GET:@"http://114.214.164.105:8000/api/panoramas/" parameters:parameter success:^(AFHTTPRequestOperation *operation, id responseObject) {
        
        //获取相应用户的微博微博字典数组,由于服务器上的是最新发出的排在最后和我们这个微博要求相反,所以要倒过来拿
        NSArray *reverseArray = [[responseObject reverseObjectEnumerator] allObjects];
        //李明杰mj的框架
        /*
         MJExtension是一套字典和模型之间互相转换的超轻量级框架
         MJExtension能完成的功能
         字典(JSON) --> 模型(Model)
         模型(Model) --> 字典(JSON)
         字典数组(JSON Array) --> 模型数组(Model Array)
         模型数组(Model Array) --> 字典数组(JSON Array)
         */
        //这里将字典数组转成模型数组
        /*
         如何从plist中读取字典,并转换成对象模型
         http://www.cnblogs.com/fxiaoquan/archive/2015/04/18/4438126.html
         下面的直接利用第三份开源框架字典转模型工具
         */
        NSArray *newStatuses = [HWStatus mj_objectArrayWithKeyValuesArray:reverseArray];
        //将HWStatus数组转换成HWstatusFrame数组
        NSMutableArray *Frames = [NSMutableArray array];
        //这个newFrames包含所有数据,所以要加上判断
        for(HWStatus *status in newStatuses)
        {
            if(status.created > firstStatusF.status.created)
            {
                HWStatusFrame *f = [[HWStatusFrame alloc] init];
                f.status = status;
                [Frames addObject:f];
            }
            else
                break;
        }
        [self.statusFrames addObjectsFromArray:Frames];
        //可以获取数据
        //NSLog(@"%@",reverseArray);
        //刷新表格
        [self.tableView reloadData];
        
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error == %@",error);
    }];


2.拼接请求参数查看原图

//点击全景图片进行展示,此处用原图
#pragma mark - 代理方法
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //获取的全部内容的key
    HWStatusCell *cell = [HWStatusCell cellWithTableView:tableView];
    //statusFrames所有数据模型的集合
    cell.statusFrame = self.statusFrames[indexPath.row];
    //拼url
    NSString *panoString = [NSString stringWithFormat:@"http://114.214.164.105:8000%@",cell.statusFrame.status.panorama];
    PanoViewController *panoView = [[PanoViewController alloc] init];
    panoView.urlString = panoString;
    NSString *biaoti = [NSString stringWithFormat:@"%@",cell.statusFrame.status.title];
    panoView.title = biaoti;
    // 当test1控制器被push的时候,test1所在的tabbarcontroller的tabbar会自动隐藏
    // 当test1控制器被pop的时候,test1所在的tabbarcontroller的tabbar会自动显示
    //    test1.hidesBottomBarWhenPushed = YES;
    
    // self.navigationController === HWNavigationController
    //push进来的会被拦截
    [self.navigationController pushViewController:panoView animated:YES];
    //[self presentViewController:panoView animated:YES completion:nil];
}

3. 上传数据

AFHTTPRequestOperationManager *mgr= [AFHTTPRequestOperationManager manager];
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"user"] = @"1";
    params[@"description"] = @"Panoramic Picture";
    params[@"title"] = self.textView.text;
    [mgr POST:@"http://114.214.164.105:8000/api/panoramas/" parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        UIImage *image = [self.photosView.photos firstObject];
        NSData *data = UIImageJPEGRepresentation(image, 1.0);
        [formData appendPartWithFileData:data name:@"panorama" fileName:@"PIC" mimeType:@"image/jpeg"];
        
    } success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [MBProgressHUD showSuccess:@"发送成功"];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        [MBProgressHUD showSuccess:@"发送失败"];
        NSLog(@"%@", self.textView.text);
        NSLog(@"%@", error.localizedDescription);
        NSLog(@"%@", error.localizedFailureReason);
        NSLog(@"%@", error.userInfo);
    }];

二、手写代码而非拖控件需要做的事

下列函数都在AppDelegate中

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // 1.创建窗口
    self.window = [[UIWindow alloc] init];
    self.window.frame = [UIScreen mainScreen].bounds;
    
    // 2.设置根控制器
    NSString *key = @"CFBundleVersion";
    // 上一次的使用版本(存储在沙盒中的版本号)
    NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:key];
    // 当前软件的版本号(从Info.plist中获得)
    NSString *currentVersion = [NSBundle mainBundle].infoDictionary[key];
    
   if ([currentVersion isEqualToString:lastVersion]) { // 版本号相同:这次打开和上次打开的是同一个版本
        self.window.rootViewController = [[loginViewController alloc] init];
   } else { // 这次打开的版本和上一次不一样,显示新特性
        self.window.rootViewController = [[HWNewfeatureViewController alloc] init];

        // 将当前的版本号存进沙盒
       [[NSUserDefaults standardUserDefaults] setObject:currentVersion forKey:key];
        [[NSUserDefaults standardUserDefaults] synchronize];//内存数据立即传入沙盒
    }
    
    // 3.显示窗口
    [self.window makeKeyAndVisible];
    return YES;
}
- (void) applicationDidReceiveMemoryWarning:(UIApplication *)application
{
    SDWebImageManager *mgr = [SDWebImageManager sharedManager];
    //取消下载
    [mgr cancelAll];
    [mgr.imageCache clearMemory];
}

三、自定义cell

//从可复用的队列里拿出来
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
    static NSString *ID = @"status";
    //一个表视图维护着一个可复用单元的队列或者列表。当要显示一个新的单元的时候就调用这个方法,这个方法会出列一个已经存在的单元。
    HWStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (!cell) {
        cell = [[HWStatusCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }
    return cell;
}

//定义每个cell的样式
- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if(self)
    {
        //体框架
        UIView *originalView = [[UIView alloc] init];
        [self.contentView addSubview:originalView];
        self.originalView = originalView;
        //头像
        UIImageView *iconView = [[UIImageView alloc] init];
        [originalView addSubview:iconView];
        self.iconView = iconView;
        
        //配图
        UIImageView *photoView = [[UIImageView alloc] init];
        [originalView addSubview:photoView];
        self.photoView = photoView;
        
        //昵称
        UILabel *nameLabel = [[UILabel alloc] init];
        nameLabel.font = HWStatusCellNameFont;
        [originalView addSubview:nameLabel];
        self.nameLabel = nameLabel;
        
        //时间
        UILabel *timeLabel = [[UILabel alloc] init];
        timeLabel.font = HWStatusCellTimeFont;
        [originalView addSubview:timeLabel];
        self.timeLabel = timeLabel;
        
        //正文
        UILabel *contentLabel =[[UILabel alloc] init];
        contentLabel.font = HWContentCellContentFont;
        [originalView addSubview:contentLabel];
        self.contentLabel = contentLabel;  
    }
    return self;
}
NSData *iconData = [user objectForKey:@"icon"];
//对象归档,二进制数据转换为响应格式
UIImage *icon = [NSKeyedUnarchiver unarchiveObjectWithData:iconData];
//拼url
NSString *urlString = [NSString stringWithFormat:@"http://114.214.164.105:8000%@",status.thumbnail];
[self.photoView sd_setImageWithURL:[NSURL URLWithString:urlString] placeholderImage:nil];
self.photoView.backgroundColor = [UIColor orangeColor];



四、系统框架的搭建

1.NavigationController的设置

+ (void)initialize
{
    // 设置整个项目所有item的主题样式
    UIBarButtonItem *item = [UIBarButtonItem appearance];
    
    // 设置普通状态
    // key:NS****AttributeName
    NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
    textAttrs[NSForegroundColorAttributeName] = [UIColor orangeColor];
    textAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:15];
    [item setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
    
    // 设置不可用状态,不好使颜色
    NSMutableDictionary *disableTextAttrs = [NSMutableDictionary dictionary];
    disableTextAttrs[NSForegroundColorAttributeName] = [UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:0.7];
    disableTextAttrs[NSFontAttributeName] = textAttrs[NSFontAttributeName];
    [item setTitleTextAttributes:disableTextAttrs forState:UIControlStateDisabled];
    
}

/**
 *  重写这个方法目的:能够拦截所有push进来的控制器
 *
 *  @param viewController 即将push进来的控制器
 */
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (self.viewControllers.count > 0) { // 这时push进来的控制器viewController,不是第一个子控制器(不是根控制器)
        /* 自动显示和隐藏tabbar */
        viewController.hidesBottomBarWhenPushed = YES;
        
        /* 设置导航栏上面的内容 */
        // 设置左边的返回按钮
        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(back) image:@"navigationbar_back" highImage:@"navigationbar_back_highlighted"];
        
        // 设置右边的更多按钮
        viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithTarget:self action:@selector(more) image:@"navigationbar_more" highImage:@"navigationbar_more_highlighted"];
    }

    [super pushViewController:viewController animated:animated];
}

- (void)back
{
#warning 这里要用self,不是self.navigationController
    // 因为self本来就是一个导航控制器,self.navigationController这里是nil的
    [self popViewControllerAnimated:YES];
}

2.系统整体架构是一个TabBar

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // 1.初始化子控制器
    HWHomeViewController *home = [[HWHomeViewController alloc] init];
    [self addChildVc:home title:@"首页" image:@"tabbar_home" selectedImage:@"tabbar_home_selected"];
    
    HWMessageCenterViewController *messageCenter = [[HWMessageCenterViewController alloc] init];
    [self addChildVc:messageCenter title:@"消息" image:@"tabbar_message_center" selectedImage:@"tabbar_message_center_selected"];
    
    HWDiscoverViewController *discover = [[HWDiscoverViewController alloc] init];
    [self addChildVc:discover title:@"发现" image:@"tabbar_discover" selectedImage:@"tabbar_discover_selected"];
    
    HWProfileViewController *profile = [[HWProfileViewController alloc] init];
    [self addChildVc:profile title:@"我" image:@"tabbar_profile" selectedImage:@"tabbar_profile_selected"];
    
    // 2.更换系统自带的tabbar
    HWTabBar *tabBar = [[HWTabBar alloc] init];
    [self setValue:tabBar forKeyPath:@"tabBar"];
    /*
     [self setValue:tabBar forKeyPath:@"tabBar"];相当于self.tabBar = tabBar;
     [self setValue:tabBar forKeyPath:@"tabBar"];这行代码过后,tabBar的delegate就是HWTabBarViewController
     说明,不用再设置tabBar.delegate = self;
     */
    
    /*
     1.如果tabBar设置完delegate后,再执行下面代码修改delegate,就会报错
     tabBar.delegate = self;

     2.如果再次修改tabBar的delegate属性,就会报下面的错误
     错误信息:Changing the delegate of a tab bar managed by a tab bar controller is not allowed.
     错误意思:不允许修改TabBar的delegate属性(这个TabBar是被TabBarViewController所管理的)
     */
    
}

五、新特性界面

- (void)viewDidLoad
{
    [super viewDidLoad];
    // 1.创建一个scrollView:显示所有的新特性图片
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.frame = self.view.bounds;
    [self.view addSubview:scrollView];
    self.scrollView = scrollView;
    
    // 2.添加图片到scrollView中
    CGFloat scrollW = scrollView.width;
    CGFloat scrollH = scrollView.height;
    for (int i = 0; i<HWNewfeatureCount; i++) {
        UIImageView *imageView = [[UIImageView alloc] init];
        imageView.width = scrollW;
        imageView.height = scrollH;
        imageView.y = 0;
        imageView.x = i * scrollW;
        // 显示图片
        NSString *name = [NSString stringWithFormat:@"new_feature_%d", i + 1];
        imageView.image = [UIImage imageNamed:name];
        [scrollView addSubview:imageView];
        
        // 如果是最后一个imageView,就往里面添加其他内容
        if (i == HWNewfeatureCount - 1) {
            [self setupLastImageView:imageView];
        }
    }
    
#warning 默认情况下,scrollView一创建出来,它里面可能就存在一些子控件了
#warning 就算不主动添加子控件到scrollView中,scrollView内部还是可能会有一些子控件
    
    // 3.设置scrollView的其他属性
    // 如果想要某个方向上不能滚动,那么这个方向对应的尺寸数值传0即可
    scrollView.contentSize = CGSizeMake(HWNewfeatureCount * scrollW, 0);
    scrollView.bounces = NO; // 去除弹簧效果
    scrollView.pagingEnabled = YES;
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.delegate = self;
    
    // 4.添加pageControl:分页,展示目前看的是第几页
    UIPageControl *pageControl = [[UIPageControl alloc] init];
    pageControl.numberOfPages = HWNewfeatureCount;
    pageControl.backgroundColor = [UIColor redColor];
    pageControl.currentPageIndicatorTintColor = HWColor(253, 98, 42);
    pageControl.pageIndicatorTintColor = HWColor(189, 189, 189);
    pageControl.centerX = scrollW * 0.5;
    pageControl.centerY = scrollH - 50;
    [self.view addSubview:pageControl];
    self.pageControl = pageControl;
    
    // UIPageControl就算没有设置尺寸,里面的内容还是照常显示的
    //    pageControl.width = 100;
    //    pageControl.height = 50;
    //    pageControl.userInteractionEnabled = NO;
    
//    UITextField *text = [[UITextField alloc] init];
//    text.frame = CGRectMake(10, 20, 100, 50);
//    text.borderStyle = UITextBorderStyleRoundedRect;
//    [self.view addSubview:text];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    double page = scrollView.contentOffset.x / scrollView.width;
    // 四舍五入计算出页码
    self.pageControl.currentPage = (int)(page + 0.5);

}

/**
 *  初始化最后一个imageView
 *
 *  @param imageView 最后一个imageView
 */
- (void)setupLastImageView:(UIImageView *)imageView
{
    // 开启交互功能
    imageView.userInteractionEnabled = YES;
    
    // 1.分享给大家(checkbox)
    UIButton *shareBtn = [[UIButton alloc] init];
    [shareBtn setImage:[UIImage imageNamed:@"new_feature_share_false"] forState:UIControlStateNormal];
    [shareBtn setImage:[UIImage imageNamed:@"new_feature_share_true"] forState:UIControlStateSelected];
    [shareBtn setTitle:@"分享给大家" forState:UIControlStateNormal];
    [shareBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    shareBtn.titleLabel.font = [UIFont systemFontOfSize:15];
    shareBtn.width = 200;
    shareBtn.height = 30;
    shareBtn.centerX = imageView.width * 0.5;
    shareBtn.centerY = imageView.height * 0.65;
    [shareBtn addTarget:self action:@selector(shareClick:) forControlEvents:UIControlEventTouchUpInside];
    [imageView addSubview:shareBtn];
//    shareBtn.backgroundColor = [UIColor redColor];
//    shareBtn.imageView.backgroundColor = [UIColor blueColor];
//    shareBtn.titleLabel.backgroundColor = [UIColor yellowColor];
    
    // top left bottom right
    
    // EdgeInsets: 自切
    // contentEdgeInsets:会影响按钮内部的所有内容(里面的imageView和titleLabel)
    //    shareBtn.contentEdgeInsets = UIEdgeInsetsMake(10, 100, 0, 0);
    
    // titleEdgeInsets:只影响按钮内部的titleLabel
    shareBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
    
    // imageEdgeInsets:只影响按钮内部的imageView
//    shareBtn.imageEdgeInsets = UIEdgeInsetsMake(20, 0, 0, 50);
    
    
    
//    shareBtn.titleEdgeInsets
//    shareBtn.imageEdgeInsets
//    shareBtn.contentEdgeInsets
    
    // 2.开始微博
    UIButton *startBtn = [[UIButton alloc] init];
    [startBtn setBackgroundImage:[UIImage imageNamed:@"new_feature_finish_button"] forState:UIControlStateNormal];
    [startBtn setBackgroundImage:[UIImage imageNamed:@"new_feature_finish_button_highlighted"] forState:UIControlStateHighlighted];
   startBtn.size = startBtn.currentBackgroundImage.size;
    startBtn.centerX = shareBtn.centerX;
    startBtn.centerY = imageView.height * 0.75;
    [startBtn setTitle:@"开始微博" forState:UIControlStateNormal];
    [startBtn addTarget:self action:@selector(startClick) forControlEvents:UIControlEventTouchUpInside];
    [imageView addSubview:startBtn];
}

六、全景图显示

- (void)viewDidLoad {
    [super viewDidLoad];
    plView = (PLView *) self.view;
    plView.delegate = self;
    //显示全景图片
    [self showPanoView];
}
- (void)showPanoView
{
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:_urlString]];
    NSURLResponse *response = nil;
    NSError *error = nil;
    
    //获取服务器端全景图片的二进制数据流
    NSData *data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
    if([data length] > 0 && error == nil) {
        UIImage *img = [UIImage imageWithData:data];//将数据流转成图片
        
        /*************将4000*2000图片降到2048*1024************/
        CGSize size = CGSizeMake(2048, 1024);
        UIImage *newImage = [self imageWithImageSimple:img scaledToSize:size ];
        
        //************************
        //加入到故事板上,PLIPanorama是一个协议
        NSObject<PLIPanorama> *panorama = nil;
        //Spherical2 panorama example (supports up 2048x1024 texture) 
        
        //调用类方法,产生一个PLSpherical2Panorama类型的对象panorama
        panorama = [PLSpherical2Panorama panorama];
        
        //img into CGImage,是用来重绘图形的类,在应用时是按照图像的像素矩阵来绘制图片的,它们可以用来处理bitmap
        CGImageRef cgimage = newImage.CGImage;
        
        //将cgimage添加到panorama上
        [(PLSpherical2Panorama *)panorama setImage:[PLImage imageWithCGImage:cgimage]];
        
        //将panorama添加到plview上
        [plView setPanorama:panorama];
        //Add a hotspot
        PLTexture *hotspotTexture = [PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"hotspot" ofType:@"png"]]];
        PLHotspot *hotspot = [PLHotspot hotspotWithId:(kIdMin + random() % ((kIdMax + 1) - kIdMin)) texture:hotspotTexture atv:0.0f ath:0.0f width:0.08f height:0.08f];
        [panorama addHotspot:hotspot];
        NSLog(@"图片加载完毕");
    }
    else{
        NSLog((@"error:%@",error));
    }

}

//改变图片分辨率方法
- ( UIImage *)imageWithImageSimple:( UIImage *)image scaledToSize:( CGSize )newSize

{
    
    // Create a graphics image context
    
    UIGraphicsBeginImageContext (newSize);
    
    // Tell the old image to draw in this new context, with the desired
    
    // new size
    
    [image drawInRect : CGRectMake ( 0 , 0 ,newSize. width ,newSize. height )];
    
    // Get the new image from the context
    
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext ();
    
    // End the context
    
    UIGraphicsEndImageContext ();
    
    // Return the new image.
    
    return newImage;
    
}

七、引导式拍摄

1.自定义相机

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    //初始化会话
    self.captureSession=[[AVCaptureSession alloc]init];
    if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {//设置分辨率
        //self.captureSession.sessionPreset=AVAssetExportPresetLowQuality;
        [self.captureSession setSessionPreset:AVCaptureSessionPreset640x480];
    }
    else
    {
        NSLog(@"不支持分辨率设置");
    }
    //获得输入设备
    AVCaptureDevice *captureDevice=[self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];//取得后置摄像头
    if (!captureDevice) {
        NSLog(@"取得后置摄像头时出现问题.");
        return;
    }
    
    NSError *error=nil;
    //根据输入设备初始化设备输入对象,用于获得输入数据
    _captureDeviceInput=[[AVCaptureDeviceInput alloc]initWithDevice:captureDevice error:&error];
    if (error) {
        NSLog(@"取得设备输入对象时出错,错误原因:%@",error.localizedDescription);
        return;
    }
    //初始化设备输出对象,用于获得输出数据
    _captureStillImageOutput=[[AVCaptureStillImageOutput alloc]init];
    NSDictionary *outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
    [_captureStillImageOutput setOutputSettings:outputSettings];//输出设置
    
    //将设备输入添加到会话中
    if ([_captureSession canAddInput:_captureDeviceInput]) {
        [_captureSession addInput:_captureDeviceInput];
    }
    
    //将设备输出添加到会话中
    if ([_captureSession canAddOutput:_captureStillImageOutput]) {
        [_captureSession addOutput:_captureStillImageOutput];
    }
    
    //创建视频预览层,用于实时展示摄像头状态
    _captureVideoPreviewLayer=[[AVCaptureVideoPreviewLayer alloc]initWithSession:self.captureSession];
    
    CALayer *layer=self.viewContainer.layer;
    layer.masksToBounds=YES;
    
    _captureVideoPreviewLayer.frame=layer.bounds;
    _captureVideoPreviewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式
    //将视频预览层添加到界面中
    [layer addSublayer:_captureVideoPreviewLayer];
}

//拍照方法,需要一个返回值
- (void)takePhoto{
    //根据设备输出获得连接
    AVCaptureConnection *captureConnection=[self.captureStillImageOutput connectionWithMediaType:AVMediaTypeVideo];
    //根据连接取得设备输出的数据
    [self.captureStillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if (imageDataSampleBuffer) {
            NSData *imageData=[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image=[UIImage imageWithData:imageData];
            [self.imagesArray addObject:image];
            
        }      
    }];
}
-(AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position{
    NSArray *cameras= [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *camera in cameras) {
        if ([camera position]==position) {
            return camera;
        }
    }
    return nil;
}
- (void)inductionFunction
{
    [self initLabel];
    self.motionManager = [[CMMotionManager alloc] init];
    self.queue = [[NSOperationQueue alloc] init];
    __block float rotationY = 0;
    __block int count = 0;
    if (self.motionManager.deviceMotionAvailable) {
        __weak inductiveViewController *weakSelf = self;
        self.motionManager.deviceMotionUpdateInterval = 0.1;
        [self.motionManager startDeviceMotionUpdatesToQueue:self.queue withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
            static NSDate *lastUpdateTime = nil;
              //NSLog(@"%f",motion.rotationRate.y);
            
            //更新UI在主线程
            dispatch_async(dispatch_get_main_queue(), ^{
                /***********这里图标的显示文字描述*************/
                BOOL flag = YES;//flag为yes,可以显示右箭头,no为上升阶段,显示上箭头
                float absPitch = ABS(motion.attitude.pitch - 1.56);
                //动捕传感器可用且当前count拍照数小于13
                if (count < 3) {
                    if (absPitch < 0.15)
                    {
                        //显示旋转箭头
                        [weakSelf initArrow:flag];
                        flag = NO;
                        [weakSelf initUpArrow:flag];
                        if (ABS(motion.rotationRate.y) > 0.085)
                        {
                            if (lastUpdateTime != nil)
                            {
                                NSTimeInterval secondSinceLastTime = [[NSDate date] timeIntervalSinceDate:lastUpdateTime];
                                //转换成角度而不是弧度显示
                                rotationY = rotationY + motion.rotationRate.y * secondSinceLastTime/M_PI *180;
                                //旋转了28度
                                if (ABS(rotationY) >=28)
                                {
                                    [weakSelf takePhoto];
                                    count++;
                                    NSLog(@"count:%d ",count);
                                    //NSLog(@"拍照时rotationY: %+.2f",rotationY);
                                    rotationY = 0;
                                }
                            }
                            //更新时间
                            lastUpdateTime = [[NSDate alloc] init];
                            NSString *attitudeText = [NSString stringWithFormat:@"%+.2f",ABS(rotationY)];
                            weakSelf.GyrLabel.text = attitudeText;
                            
                        }
                        //当y大于一定阈值时算检测到移动
                        
                    }
                    else{
                        
                        [weakSelf initUpArrow:flag];
                        flag = NO;
                        [weakSelf initArrow:flag];
                    }
                } else {
                    /********超过13张************/
                    self.skipBtn.enabled = YES;
                    [self.view addSubview:self.skipBtn];
                    [self.skipBtn addTarget:self action:@selector(clickSkipBtn) forControlEvents:UIControlEventTouchUpInside];
                }
            });
        }];
    }
    else{
    }
    [self.view addSubview:_GyrLabel];
}
//GCD结构       
    dispatch_queue_t queue = dispatch_queue_create(, DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{

        /**


         放一些极其耗时间的任务在此执行

         */
        dispatch_async(dispatch_get_main_queue(), ^{

            /**

             耗时任务完成,拿到资源,更新UI

             更新UI只可以在主线程中更新

             */
         });
      });

八、图像拼接

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        self.panoImage = [CVWrapper processWithArray:self.MutaArray];
        dispatch_async(dispatch_get_main_queue(), ^{
            CGSize size = CGSizeMake(1024, 1024);
            UIImage *newPanoImage = [self imageWithImageSimple:self.panoImage scaledToSize:size ];
            //将cgimage添加到panorama上
            [(PLCylindricalPanorama *)panorama setImage:[PLImage imageWithCGImage:newPanoImage.CGImage]];
            //Add a hotspot
            PLTexture *hotspotTexture = [PLTexture textureWithImage:[PLImage imageWithPath:[[NSBundle mainBundle] pathForResource:@"hotspot" ofType:@"png"]]];
            PLHotspot *hotspot = [PLHotspot hotspotWithId:(kIdMin + random() % ((kIdMax + 1) - kIdMin)) texture:hotspotTexture atv:0.0f ath:0.0f width:0.08f height:0.08f];
            [panorama addHotspot:hotspot];
            [plView setPanorama:panorama];
            });
        });









  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值