苹果手机运行python_iPhone是卖的最好的手机?用Python照样把他玩弄鼓掌之间!

关于 iOS 的技术解读有很多,但是却鲜有设备可视化同步的介绍文章。本文一起了解下这个酷炫的 iOS 黑科技。

152818793145723fe0f22b0

1528187940452324f09ac81

我们的任务很简单——如上图所示,实时获取设备的当前方向。

UIDevice.current.orientation

首先,需要调用

beginGeneratingDeviceOrientationNotifications()

但仅仅这样还不行。因为如果设备上的旋转被锁定了,那么就不会产生以上通知。我的相机应用程序从头到尾都需要知道方向——所以我意识到我需要直接根据设备的加速度计算方向。

1528187972893fb4f6222b3

好了,现在有了这些值,我们该做些什么呢?这是一个较难的部分。如果将所有内容都输出到控制台,那么我们很快就会被大量数据淹没。我认为还是在屏幕上显示这些值比较好。

但是,等等,如果将数值显示在图表上,会怎么样?别想图表了,我们可以来用开源的 Blender 试试,它可以实现这些值的可视化,并且很容易扩展。

152818799860213f5ec97b2

1528188021765d184aff75e

1528188036071f4f149fddc

152818804774424fcebb8d4

然而 Blender 并不是很好的代码编辑器,所以我们还是使用钟爱的外部编辑器吧。为了调用外部文件,我们可以将 print("hi") 替换成以下代码:

import bpy

import os

filename = os.path.join(os.path.dirname(bpy.data.filepath), "server.py")

exec(compile(open(filename).read(), filename, ‘exec‘))

下一步,我们需要在与 .blend 文件相同的文件夹中创建新的 server.py 文件,我们真正的代码就要保存在这里。现在我们可以用任何编辑器打开它,你可以选择 Atom、Sublime,甚至 Word 2007 都行。

1528188077922bdda259c32

1528188110125e5bb3fc403

找到该 Cube 对象,点击右键并选择重命名,重命名为 iPhone。现在让我们再来看一看 server.py。

import socket

import select

import json

import threading

import traceback

class ServerThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

self.running = True

def stopServer(self):

self.running = False

self.server.running = False

def run(self):

try:

self.server = Server()

while self.running:

self.server.receive()

except:

pass

class Server:

def __init__(self):

self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

self.socket.setblocking(False)

self.socket.bind((str(socket.INADDR_ANY), 9845))

self.socket.listen(2)

self.running = True

def __exit__(self, exc_type, exc_value, traceback):

self.socket.close()

def receive(self):

pairs = []

timeout = 1

while self.running:

sockets = list(map(lambda x: x[0], pairs))

if len(pairs) > 0:

read_sockets, write_sockets, error_sockets = select.select(sockets, [], [], timeout)

for sock in read_sockets:

data = sock.recv(4096)

if not data :

print(‘Client disconnected‘)

pairs = []

else :

self.connectionReceivedData(connection, data.decode())

try:

try:

connection,address = self.socket.accept()

print("new connection: ", connection)

pairs.append((connection, address))

except:

pass

except:

pass

for pair in pairs:

(connection, address) = pair

connection.close()

def connectionReceivedData(self, connection, data):

try:

motionData = json.loads(data)

except json.decoder.JSONDecodeError:

print("Invalid JSON: ", data)

return None

receivedMotionData(motionData)

# This is a global so when we run the script again, we can keep the server alive

# but change how it works

import bpy

def receivedMotionData(motionData):

phone = bpy.context.scene.objects["iPhone"]

phone.rotation_quaternion.x = float(motionData[‘x‘])

phone.rotation_quaternion.y = 0 - float(motionData[‘z‘])

phone.rotation_quaternion.z = float(motionData[‘y‘])

phone.rotation_quaternion.w = float(motionData[‘w‘])

pass

try:

if serverThread.running == False:

serverThread = ServerThread()

serverThread.start()

print("Starting server")

else:

print("Server already running, using new motion handler.")

except:

serverThread = ServerThread()

serverThread.start()

print("Starting server")

1528188134330d92d6baef4

检查 Blender,你应该看到 iPhone 根本没有改变。这是因为上面的脚本使用四元组设置了 iPhone 的旋转角度,并且它使用了欧拉角进行旋转。需要做一些修改。将 Python 控制台面切换到 “Properties”,然后单击该面板顶部的橙色立方体图标。中部 Transform 的下面,点击 XYZ Euler 并选择 Quaternion。现在尝试再次运行 client.py。

你应该看到 iPhone 立即翻转过来了。不要惊慌,这就是我们想要的。现在,我们需要让这个模型跟着实际的 iPhone 旋转。

15281881747273b38e450e0

我们需要将运动数据从 iPhone 发送到运行 Blender 的计算机。感谢上苍我们不需要深入到 Swift 中的原始 C 套接字级别,因为 Foundation 具有抽象。

我们可以将以下代码放入新的 iOS 项目中,以替换默认的 ViewController。请确保使用计算机的本地 IP 地址替换 host 变量。

import UIKit

import CoreMotion

class CoreMotionViewController: UIViewController, StreamDelegate {

let motionManager = CMMotionManager()

let queue = OperationQueue()

let host = "192.168.1.2"

override func viewDidLoad() {

super.viewDidLoad()

setUpStreams(host: host)

motionManager.startDeviceMotionUpdates(to: queue) { (data: CMDeviceMotion?, error: Error?) in

guard let data = data else {

print("Error: \(error!)")

return

}

let attitude: CMAttitude = data.attitude

let quaternion = attitude.quaternion

var motionData = MotionData()

motionData.x = quaternion.x

motionData.y = quaternion.y

motionData.z = quaternion.z

motionData.w = quaternion.w

let encoder = JSONEncoder()

do {

let json = try encoder.encode(motionData)

self.send(data: json)

} catch let error {

print("Couldn‘t send data, error: \(error)")

}

}

}

// MARK: - Streams

var inputStream: InputStream?

var outputStream: OutputStream?

func setUpStreams(host: String) {

var readStream: Unmanaged?

var writeStream: Unmanaged?

CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,

host as CFString, 9845,

&readStream,

&writeStream)

inputStream = readStream!.takeRetainedValue()

outputStream = writeStream!.takeRetainedValue()

guard let inputStream = inputStream, let outputStream = outputStream else {

print("Failed to create streams")

return

}

inputStream.delegate = self

outputStream.delegate = self

inputStream.schedule(in: .current, forMode: .commonModes)

outputStream.schedule(in: .current, forMode: .commonModes)

inputStream.open()

outputStream.open()

}

func send(data: Data) {

guard let outputStream = outputStream else {

return

}

_ = data.withUnsafeBytes {

outputStream.write($0, maxLength: data.count)

}

}

func stream(_ aStream: Stream, handle eventCode: Stream.Event) {

if eventCode == .errorOccurred {

inputStream = nil

outputStream = nil

print("Error: Stream error")

} else if eventCode == .endEncountered {

inputStream = nil

outputStream = nil

print("Error: Encountered end of stream")

}

let maxReadLength = 4096

if eventCode == .hasBytesAvailable {

guard let inputStream = inputStream else {

return

}

while inputStream.hasBytesAvailable {

let buffer = UnsafeMutablePointer.allocate(capacity: maxReadLength)

inputStream.read(buffer, maxLength: maxReadLength)

buffer.deallocate()

}

}

}

}

// MARK: - Data Model

private struct MotionData: Codable {

var x: Double = 0

var y: Double = 0

var z: Double = 0

var w: Double = 0

}

15281882107940010a81870

15281882187904381609f92

那么最终我是如何从移动管理器获取方向信息的?

欢迎关注我的博客或者公众号:https://home.cnblogs.com/u/Python1234/ Python学习交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305002.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

这几个动图告诉你科学的神奇,看完瞬间觉得智商都提高了

生活中简单平常的事物和现象背后,往往有着奇妙的原理,赶快跟着一起来看看涨点知识吧! 夹心雪糕的制作原理 ▼ 难怪雪糕大小,厚度都一模一样 原来都是从一个模子里出来的 ▼ 煎饼可以统一翻面 再也不用担心烤焦了 ▼ 冰淇淋蛋筒的制…

自定义 ocelot 中间件输出自定义错误信息

自定义 ocelot 中间件输出自定义错误信息Introocelot 中默认的 Response 中间件在出错的时候只会设置 StatusCode 没有具体的信息,想要展示自己定义的错误信息的时候就需要做一些自定义了,对 ocelot 中的 Response 中间件做了一些小改动,实现…

shapenet网络_GRNet网络:3D网格进行点云卷积,实现点云补全

Date:2020-11-23作者:三弟来源:GRNet网络:3D网格进行点云卷积,实现点云补全Gridding Residual Network for Dense Point Cloud Completion在点云分割方面,有一些方法尝试通过更通用的卷积操作来捕捉点云的空…

c语言随机数循环延迟,C语言生成随机数的函数、延时函数

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼下面C语言代码使用了生成随机数的函数、延时函数。请大家仔细观察其显示效果。从以下代码,我们可以得出一个重要的结论:当上述两类函数被放入循环时,应作出一定修改。同时还应关注其参数的定义位…

盘点小坏蛋的礼物

我们家小坏蛋一天天长大了,妈妈从觉得很辛苦过渡到习惯了很辛苦,苦中作乐的妈妈终于抽出空来写博客啦! 为什么叫他小坏蛋呢?因为他吃饭不乖。没满月的时候蛮乖的,每顿奶都吃的很香,咕咚咕咚的喝下去&#x…

《笨办法学python》6_笨办法学Python 习题 25: 更多更多的练习

我们将做一些关于函数和变量的练习,以确认你真正掌握了这些知识。这节练习对你来说可以说是一本道:写程序,逐行研究,弄懂它。 不过这节练习还是有些不同,你不需要运行它,取而代之,你需要将它导入到 python …

为什么对gRPC做负载均衡会很棘手?

在过去的几年中,随着微服务的增长,gRPC在这些较小的服务之间的相互通信中获得了很大的普及,在后台,gRPC使用http/2在同一连接和双工流中复用许多请求。使用具有结构化数据的快速,轻便的二进制协议作为服务之间的通信介质确实很有吸…

给新手程序猿的16个必备小妙招

写在前面: 这个文章核心并不是程序优化的具体技巧,而是拿到一个问题如何思考和利用工具的通用方法。比如即使我们不知道 profiler 这个东西,通过搜索"代码 每一行 时间"也可以很快知道有这样的工具叫做 profiler,并且学…

openkruise 缩容_Linus 本尊也来了!为什么 KubeCon 越来越火了?

原标题:Linus 本尊也来了!为什么 KubeCon 越来越火了?2015年11月,第一届 KubeCon 在美国旧金山开始的时候,还只是个200人的小会议,2019年的7月,KubeCon 第二次在中国举办,就有 3500 …

你可能不知道的C#语言特性

关键字 yield 通常用于迭代器中,向IEnumerable对象提供值或者结束迭代。 如: yield return expression; yield break; var 用于定义隐式类型的变量。 var i 5; var s "Hello"; 注意隐式类型(Implicitly typed)并不是…

c语言中文件如何插入数据,急求如何将下列C语言程序数据存储到文件中?

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼求如何改动才能将下列程序的存储输入或输出数据(或两者一起)到指定的文件(或运行时直接创立一个文件)如Arrangement中。#include int n0;int rest[7][7]; //全局声明,以供全局调用int main(){void perm(int list[],int ,int );int …

python字符串设置字体_python怎么更改字符串后几位

python更改字符串后几位的方法:可以利用replace()函数来实现。replace()函数可以把字符串中的旧字符串替换成新字符串,并返回替换后的新字符串。具体使用方法如:【str.replace("is", "was")】。可以利用replace()函数来修…

使用 Tye 辅助开发 k8s 应用竟如此简单(二)

续上篇,这篇我们来进一步探索 Tye 更多的使用方法。本篇我们来了解一下如何在 Tye 中使用服务发现。服务发现 - 微服务开发不可缺少的部件 服务发现,就是新注册的这个服务模块能够及时的被其他调用者发现。不管是服务新增和服务删减都能实现自动发现。《…

程序猿的双十一最佳攻略

讲个恐怖故事 一年一度虐汪“光棍节”又来了 小天拍拍(不存在的)胸脯告诉大家 这个节日 我陪你们 买买买! 限时特惠专场 1 welcome 7天教你学会数学建模及Matlab编程 数学建模涉及的内容比较广泛,比如碎纸片问题中所涉及的图像识…

傅里叶变换音频可视化_HTML5如何实现音频可视化频谱跳动

本篇教程探讨了HTML5如何实现音频可视化频谱跳动&#xff0c;希望阅读本篇文章以后大家有所收获&#xff0c;帮助大家HTML5CSS3从入门到精通 。<html>HTML5音频可视化频谱跳动代码* {margin: 0;padding: 0;}#canvas {display: block;background: linear-gradient(135deg,…

android websocket封装,Android WebSocket 方案选型OkHttp

目前Android WebSocket 框架 主要包括:SocketIOJava-WebSocketOkHttp WebSocket一开始我首选的是采用SocketIO方案&#xff0c;因为考虑该方案封装接口好&#xff0c;提供异步回调机制&#xff0c;但和后端同事沟通发现目前客户端的SocketIO不支持ws wss协议, 所以无奈只能放弃…

关于Word中审阅的一个问题!

前两天&#xff0c;在帮一个杂志撰稿的过程中&#xff0c;有一个关于Word审阅的问题。&#xff08;以下内容以Word2007为例&#xff09; 本身&#xff0c;审阅的应用不算困难。 我们可以为文章添加“批注”&#xff0c;或是你的上级对文章进行修改&#xff0c;他们可以开启“审…

ASP.NET Core - 在ActionFilter中使用依赖注入

上次ActionFilter引发的一个EF异常,本质上是对Core版本的ActionFilter的知识掌握不够牢固造成的&#xff0c;所以花了点时间仔细阅读了微软的官方文档。发现除了IActionFilter、IAsyncActionFilter的问题&#xff0c;还有一个就是依赖注入在ActionFilter上的使用也是需要注意的…

魏尔斯特拉斯函数与分形图形的动画演示

一般人会直觉上认为连续的函数必然是近乎可导的。即使不可导&#xff0c;所谓不可导的点也必然只占整体的一小部分。根据魏尔斯特拉斯在他的论文中所描述&#xff0c;早期的许多数学家&#xff0c;包括高斯&#xff0c;都曾经假定连续函数不可导的部分是有限或可数的。这可能是…

大脚战场插件怎么关闭_PM工具栏插件:HonmToolBar

视频演示&#xff1a;问&#xff1a;HonmToolBar是一款什么样的插件&#xff1f;答&#xff1a;HonmToolBar是一款高度自由化的插件&#xff0c;用户可以自己增加宏文件按钮或者宏命令按钮。该插件类似工具栏&#xff0c;有水平和垂直两个工具栏。插件悬浮在PM图形窗口左上角&a…