iPhone是賣的最好的手機?用Python照樣把他玩弄鼓掌之間!

來源:互聯網
上載者:User

標籤:mon   加速   listen   out   rip   文章   live   class   max   

關於 iOS 的技術解讀有很多,但是卻鮮有裝置可視化同步的介紹文章。本文一起瞭解下這個酷炫的 iOS 黑科技。

 

 

我們的任務很簡單——如所示,即時擷取裝置的當前方向。

UIDevice.current.orientation

首先,需要調用

beginGeneratingDeviceOrientationNotifications() 

但僅僅這樣還不行。因為如果裝置上的旋轉被鎖定了,那麼就不會產生以上通知。我的相機應用程式從頭到尾都需要知道方向——所以我意識到我需要直接根據裝置的加速度計算方向。

 

好了,現在有了這些值,我們該做些什麼呢?這是一個較難的部分。如果將所有內容都輸出到控制台,那麼我們很快就會被大量資料淹沒。我認為還是在螢幕上顯示這些值比較好。

但是,等等,如果將數值顯示在圖表上,會怎麼樣?別想圖表了,我們可以來用開源的 Blender 試試,它可以實現這些值的可視化,並且很容易擴充。

 

 

 

 

然而 Blender 並不是很好的代碼編輯器,所以我們還是使用鐘愛的外部編輯器吧。為了調用外部檔案,我們可以將 print("hi") 替換成以下代碼:

import bpyimport osfilename = 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 socketimport selectimport jsonimport threadingimport tracebackclass 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: passclass 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 worksimport bpydef 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‘]) passtry: 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 UIKitimport CoreMotionclass 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<CFReadStream>? var writeStream: Unmanaged<CFWriteStream>? 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<UInt8>.allocate(capacity: maxReadLength) inputStream.read(buffer, maxLength: maxReadLength) buffer.deallocate() } } }}// MARK: - Data Modelprivate 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學習交流

 歡迎加入我的千人交流學習答疑群:125240963

iPhone是賣的最好的手機?用Python照樣把他玩弄鼓掌之間!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.