苹果手机运行python_iPhone是卖的最好的手机?用Python照样把他玩弄鼓掌之间!
關于 iOS 的技術解讀有很多,但是卻鮮有設備可視化同步的介紹文章。本文一起了解下這個酷炫的 iOS 黑科技。
我們的任務很簡單——如上圖所示,實時獲取設備的當前方向。
UIDevice.current.orientation
首先,需要調用
beginGeneratingDeviceOrientationNotifications()
但僅僅這樣還不行。因為如果設備上的旋轉被鎖定了,那么就不會產生以上通知。我的相機應用程序從頭到尾都需要知道方向——所以我意識到我需要直接根據設備的加速度計算方向。
好了,現在有了這些值,我們該做些什么呢?這是一個較難的部分。如果將所有內容都輸出到控制臺,那么我們很快就會被大量數據淹沒。我認為還是在屏幕上顯示這些值比較好。
但是,等等,如果將數值顯示在圖表上,會怎么樣?別想圖表了,我們可以來用開源的 Blender 試試,它可以實現這些值的可視化,并且很容易擴展。
然而 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 都行。
找到該 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")
檢查 Blender,你應該看到 iPhone 根本沒有改變。這是因為上面的腳本使用四元組設置了 iPhone 的旋轉角度,并且它使用了歐拉角進行旋轉。需要做一些修改。將 Python 控制臺面切換到 “Properties”,然后單擊該面板頂部的橙色立方體圖標。中部 Transform 的下面,點擊 XYZ Euler 并選擇 Quaternion。現在嘗試再次運行 client.py。
你應該看到 iPhone 立即翻轉過來了。不要驚慌,這就是我們想要的。現在,我們需要讓這個模型跟著實際的 iPhone 旋轉。
我們需要將運動數據從 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
}
那么最終我是如何從移動管理器獲取方向信息的?
歡迎關注我的博客或者公眾號:https://home.cnblogs.com/u/Python1234/ Python學習交流
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的苹果手机运行python_iPhone是卖的最好的手机?用Python照样把他玩弄鼓掌之间!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wps2013 word页脚横线怎么添加
- 下一篇: lol新版妖姬怎么玩