ios - 在添加新节点之前删除节点 Swift

标签 ios swift arkit scnnode coreml

我正在开发一个 iOS 应用程序,它应该识别墙上的数字(使用 CoreML + Vision),然后将几个平面(平面数量取决于房间时间表(horario))添加到同一面墙上各种内容,如工作日和开盘 (inicio) 或闭盘 (fim) 时间。我遇到的问题是,如果我在添加第一架飞机后继续将相机对准数字,那么飞机会不断添加,这是不应该发生的。我有一些想法,比如删除所有节点/让它们在添加新节点之前立即消失,或者停止为已经检测到的特定房间添加,但请随意思考并提出不同的方法!

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor)
{

    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

    let dataformatter = DateFormatter()
    dataformatter.dateFormat = "HH:mm"

    let dataformatter_wk = DateFormatter()
    dataformatter_wk.dateFormat = "EEEE"

    var i = 0

    for horario in (self.room?.horario)!{

        //Convert Dates
        let comp_inicio: DateComponents = Calendar.current.dateComponents([.hour, .minute], from: (horario.hora_ini)!)
        let comp_fim: DateComponents = Calendar.current.dateComponents([.hour, .minute], from: (horario.hora_fim)!)
        let comp_wk: DateComponents = Calendar.current.dateComponents([.weekday, .day, .month, .year, .hour, .minute], from: (horario.hora_ini)!)

        let data_inicio = Calendar.current.date(from: comp_inicio)
        let data_fim = Calendar.current.date(from: comp_fim)
        let data_wk = Calendar.current.date(from: comp_wk)

        let hora_inicio = dataformatter.string(from: data_inicio!)
        let hora_fim = dataformatter.string(from: data_fim!)
        let horario_final =  (hora_inicio + "-" + hora_fim).uppercased()

        let weekday = dataformatter_wk.string(from: data_wk!).uppercased()

        //Plane
        let plane = SCNPlane(width: CGFloat(0.09), height: CGFloat(0.09))
        plane.materials.first?.diffuse.contents = UIColor.planeColor
        let planeNode = SCNNode(geometry: plane)

        //Text
        let material_text = SCNMaterial()
        material_text.diffuse.contents = UIColor.black

        //Get the content from JSON
        let text_horario = SCNText(string: horario_final, extrusionDepth: 0.1)
        let text_weekday = SCNText(string: weekday, extrusionDepth: 0.1)
        let text_descr = SCNText(string: horario.descr?.uppercased() ?? 0, extrusionDepth: 0.1)

        text_weekday.materials = [material_text]
        text_descr.materials = [material_text]
        text_horario.materials = [material_text]

        let node_text_weekday = SCNNode(geometry: text_weekday)
        let node_text_horario = SCNNode(geometry: text_horario)
        let node_text_descr = SCNNode(geometry: text_descr)

        //Piones
        let piones = SCNCylinder(radius: 0.002, height: 0.005)
        let material_piones = SCNMaterial()
        material_piones.diffuse.contents = UIColor.red
        piones.materials = [material_piones]
        let node_piones = SCNNode(geometry: piones)

        // 5 Get the planeAnchor positions
        let x = CGFloat(planeAnchor.center.x) // Esquerda e direita
        let y = CGFloat(planeAnchor.center.y) // +y = Mais perto do telemovel
        let z = CGFloat(planeAnchor.center.z) // -z = Mais alto

        // Rotate and scale the nodes
        planeNode.eulerAngles.x = -.pi / 2
        node_text_weekday.eulerAngles.x = -.pi / 2
        node_text_horario.eulerAngles.x = -.pi / 2
        node_text_descr.eulerAngles.x = -.pi / 2
        node_text_weekday.scale = SCNVector3(x: 0.0005, y: 0.0005, z: 0.0005)
        node_text_horario.scale = SCNVector3(x: 0.0005, y: 0.0005, z: 0.0005)
        node_text_descr.scale = SCNVector3(x: 0.0007, y: 0.0007, z: 0.0007)

        // Add the nodes positions
        planeNode.position =            SCNVector3(x         + CGFloat(i%3)/10  ,y , z       + CGFloat(i/3)/10)
        node_text_weekday.position =    SCNVector3(x - 0.025 + CGFloat(i%3)/10  ,y , z       + CGFloat(i/3)/10)
        node_text_horario.position =    SCNVector3(x - 0.020 + CGFloat(i%3)/10  ,y , z+0.035 + CGFloat(i/3)/10)
        node_text_descr.position =      SCNVector3(x - 0.029 + CGFloat(i%3)/10  ,y , z-0.015 + CGFloat(i/3)/10)
        node_piones.position =          SCNVector3(x         + CGFloat(i%3)/10  ,y , z-0.035 + CGFloat(i/3)/10)


        node.addChildNode(planeNode)
        node.addChildNode(node_text_weekday)
        node.addChildNode(node_text_horario)
        node.addChildNode(node_text_descr)
        node.addChildNode(node_piones)

        //Used for positioning of the planes on the wall
        i=i+1
    }
}

最佳答案

没有看到所有的代码,很难提供一个正确的答案。

但是,您可以考虑一些事项。

首先你可以创建一个 var 叫做:

var detectedRoomNumber: Int?

Vision Framework 检测到它时将设置它。

由于您还说每个房间号都是唯一的,因此您可以创建一个Array [Int] 来存储对这些房间号的初始引用,例如:

var roomNumbers: [Int] = [1, 2, 3, 4, 5]

一旦 Vision Framework 检测到一个数字,您就可以将其设置为 detectedRoomNumber 并将其从 Array 中删除,确保它只能检测一次。

此外,作为额外的保护措施,您可以存储对每个 ARPlaneAnchor 的引用。

每个 ARPlaneAnchor 都有一个唯一的 UUID 标识符,因此你可以创建一些逻辑来确保如果这个 ARPlaneAnchor 已经被检测到,新的内容将不会被检测到添加例如:

var roomPlanes = [UUID: ARPlaneAnchor]()

因此一些伪代码可能看起来像这样:

//---------------------------
// MARK: -  ARSCNViewDelegate
//---------------------------

extension ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check To See Whether An ARPlaneAnchor Has Been Detected
        guard let roomPlaneAnchor = anchor as? ARPlaneAnchor else { return }

        /*
         Vision Has Detected Our Room Number, So We Check To See If Our Array Of Room Numbers Contains The Room
         We Also Check To See If The ARPlaneAnchor Has Already Been Detected
         */

        if let validRoom = detectedRoomNumber, roomNumbers.contains(validRoom), !roomPlanes.keys.contains(roomPlaneAnchor.identifier){

            //a. If Our Array Isnt Empty Get The Index Of The Room & Remove It From Our Array So It Cant Be Redected
            if roomNumbers.count != 0, let itemIndexToRemove = roomNumbers.index(of: validRoom) {
                roomNumbers.remove(at: itemIndexToRemove)
            }

            print("Room Area Not Detected Before Adding Content")

            //b. Add The Plane Anchor To Our Array & Then Generate Our Content
            roomPlanes[roomPlaneAnchor.identifier] = roomPlaneAnchor

            let width = CGFloat(roomPlaneAnchor.extent.x)
            let height = CGFloat(roomPlaneAnchor.extent.z)

            let sphereNode = SCNNode(geometry: SCNPlane(width: width, height: height))
            sphereNode.geometry?.firstMaterial?.diffuse.contents = colours[roomPlanes.keys.count-1]
            sphereNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2, 1, 0, 0)
            node.addChildNode(sphereNode)

            detectedRoomNumber = nil

        }
    }
}

希望我能够以一种对我以外的其他人有意义的方式表达我的想法:)

当然,希望它能为您指明正确的方向...

关于ios - 在添加新节点之前删除节点 Swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51391646/

相关文章:

ios - 使用 Firebase 显示用户名

ios - AVAudioPlayer 失败并出现错误 "The operation couldn’ t 无法完成。 (操作系统状态错误 2003334207。)”

ios - 如何在 iOS 代码中创建和访问 UI

ios - 如何在集合单元格中重绘动态大小的 UIView

swift - 使用 ARCamera 后 BarcodeScanner 无法读取 UPC 代码

arrays - 一次添加一个值作为数组的字典保持为空

swift - 如何计算 3D 空间中相机方向的两点之间的角度

ios - 替换 uilabel 字符串中的所有阿拉伯数字

macos - 添加到父 View 时,以编程方式创建的 NSView 不会出现

arrays - 在此过程中创建包含 UIBezierPath 和 NSArray x Array 的 CGRect