如何在Swift中对simd_float4x4元素数组进行编码(将simd_float4x4转换为Data)? [英] How can I encode an array of simd_float4x4 elements in Swift (convert simd_float4x4 to Data)?

查看:161
本文介绍了如何在Swift中对simd_float4x4元素数组进行编码(将simd_float4x4转换为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆