如何在Swift中对simd_float4x4元素数组进行编码(将simd_float4x4转换为Data)? [英] How can I encode an array of simd_float4x4 elements in Swift (convert simd_float4x4 to Data)?
问题描述
我正在构建一个可从iPhone TrueDepth相机捕获面部跟踪数据的应用程序.
I am building an app that captures facetracking data from the iPhone TrueDepth camera.
我需要将此数据写入文件,以便可以将其用作其他应用程序的基础.
I need to write this data to files so I can use it as the basis for another app.
在该应用程序中,数据被保存到四个单独的数组中,一个包含ARFaceGeometry对象,其他三个具有作为simd_float4x4矩阵的变换坐标.
Within the app, the data is saved into four separate arrays, one containing ARFaceGeometry objects, and the other three with transform coordinates as simd_float4x4 matrices.
我正在使用 archivedData(withRootObject:RequiredSecureCoding:)
将数组转换为Data对象,然后在其上调用 write(to:)
创建文件.
I am converting the arrays into Data objects using archivedData(withRootObject: requiringSecureCoding:)
then calling write(to:)
on them to create the files.
包含ARFaceGeometry数据的文件被正确写入和读回.但是,三个simd_float4x4数组没有被写入,即使这样做的代码是相同的.连同我的打印日志,给出的错误是无法识别的选择器已发送到实例".
The file containing the ARFaceGeometry data is written and read back in correctly. But the three simd_float4x4 arrays aren't being written, even though the code for doing so is identical. Along with my print logs, the error being given is 'unrecognized selector sent to instance'.
属性:
var faceGeometryCapture = [ARFaceGeometry]()
var faceTransformCapture = [simd_float4x4]()
var leftEyeTransformCapture = [simd_float4x4]()
var rightEyeTransformCapture = [simd_float4x4]()
var faceGeometryCaptureFilePath: URL!
var faceTransformCaptureFilePath: URL!
var leftEyeTransformCaptureFilePath: URL!
var rightEyeTransformCaptureFilePath: URL!
用于建立文件URL的代码:
Code for establishing file URLs:
let fileManager = FileManager.default
let dirPaths = fileManager.urls(for: .documentDirectory,
in: .userDomainMask)
faceGeometryCaptureFilePath = dirPaths[0].appendingPathComponent("face-geometries.txt")
faceTransformCaptureFilePath = dirPaths[0].appendingPathComponent("face-transforms.txt")
leftEyeTransformCaptureFilePath = dirPaths[0].appendingPathComponent("left-eye-transforms.txt")
rightEyeTransformCaptureFilePath = dirPaths[0].appendingPathComponent("right-eye-transforms.txt")
用于将数据写入文件的代码:
Code for writing the data to files:
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: faceGeometryCapture, requiringSecureCoding: false)
try data.write(to: faceGeometryCaptureFilePath)
} catch { print("Error writing face geometries to file") }
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: faceTransformCapture, requiringSecureCoding: false)
try data.write(to: faceTransformCaptureFilePath)
} catch { print("Error writing face transforms to file") }
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: leftEyeTransformCapture, requiringSecureCoding: false)
try data.write(to: leftEyeTransformCaptureFilePath)
} catch { print("Error writing left eye transforms to file") }
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: rightEyeTransformCapture, requiringSecureCoding: false)
try data.write(to: rightEyeTransformCaptureFilePath)
} catch { print("Error writing right eye transforms to file") }
我猜测是导致问题的原因是simd_float4x4结构,因为这是工作与不工作之间的唯一区别.谁能确认并提出解决方案?
I'm guessing it's the simd_float4x4 struct that is causing the issue, as this is the only difference between working and not working. Can anyone confirm and suggest a solution?
谢谢.
推荐答案
正如注释结构中所述,该结构不符合NSCoding,但您可以使simd_float4x4符合Codable并保留其数据:
As already mentioned in comments structures can't conform to NSCoding but you can make simd_float4x4 conform to Codable and persist its data:
extension simd_float4x4: Codable {
public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
try self.init(container.decode([SIMD4<Float>].self))
}
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode([columns.0,columns.1, columns.2, columns.3])
}
}
游乐场测试:
Playground testing:
do {
let vector = simd_float4x4(2.7) // simd_float4x4([[2.7, 0.0, 0.0, 0.0], [0.0, 2.7, 0.0, 0.0], [0.0, 0.0, 2.7, 0.0], [0.0, 0.0, 0.0, 2.7]])
let data = try JSONEncoder().encode(vector) // 111 bytes
let json = String(data: data, encoding: .utf8)
print(json ?? "") // [[[2.7000000476837158,0,0,0],[0,2.7000000476837158,0,0],[0,0,2.7000000476837158,0],[0,0,0,2.7000000476837158]]]\n"
let decoded = try JSONDecoder().decode(simd_float4x4.self, from: data)
print(decoded) // "simd_float4x4([[2.7, 0.0, 0.0, 0.0], [0.0, 2.7, 0.0, 0.0], [0.0, 0.0, 2.7, 0.0], [0.0, 0.0, 0.0, 2.7]])\n"
decoded == vector // true
} catch {
print(error)
}
编辑/更新:
edit/update:
另一个选择是保存其原始字节.它将仅使用64个字节:
Another option is to save its raw bytes. It will use only 64 bytes:
extension simd_float4x4: ContiguousBytes {
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
try Swift.withUnsafeBytes(of: self) { try body($0) }
}
}
extension ContiguousBytes {
init<T: ContiguousBytes>(_ bytes: T) {
self = bytes.withUnsafeBytes { $0.load(as: Self.self) }
}
var bytes: [UInt8] { withUnsafeBytes { .init($0) } }
var data: Data { withUnsafeBytes { .init($0) } }
func object<T>() -> T { withUnsafeBytes { $0.load(as: T.self) } }
func objects<T>() -> [T] { withUnsafeBytes { .init($0.bindMemory(to: T.self)) } }
var simdFloat4x4: simd_float4x4 { object() }
var simdFloat4x4Collection: [simd_float4x4] { objects() }
}
extension Array where Element: ContiguousBytes {
var bytes: [UInt8] { withUnsafeBytes { .init($0) } }
var data: Data { withUnsafeBytes { .init($0) } }
}
let vector1 = simd_float4x4(.init(2, 1, 1, 1), .init(1, 2, 1, 1), .init(1, 1, 2, 1), .init(1, 1, 1, 2))
let vector2 = simd_float4x4(.init(3, 1, 1, 1), .init(1, 3, 1, 1), .init(1, 1, 3, 1), .init(1, 1, 1, 3))
let data = [vector1,vector2].data // 128 bytes
let loaded = data.simdFloat4x4Collection
print(loaded) // "[simd_float4x4([[2.0, 1.0, 1.0, 1.0], [1.0, 2.0, 1.0, 1.0], [1.0, 1.0, 2.0, 1.0], [1.0, 1.0, 1.0, 2.0]]), simd_float4x4([[3.0, 1.0, 1.0, 1.0], [1.0, 3.0, 1.0, 1.0], [1.0, 1.0, 3.0, 1.0], [1.0, 1.0, 1.0, 3.0]])]\n"
loaded[0] == vector1 // true
loaded[1] == vector2 // true
这篇关于如何在Swift中对simd_float4x4元素数组进行编码(将simd_float4x4转换为Data)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!