1

大家好,

我最近一直在尝试实现一个基于节点的图形系统,它使用插件在节点之间传递数据。类似于许多 3D 应用程序,如 houdini 和 maya。

在使用 Python 之前,我已经编写了一个类似的系统,并且想尝试使用 Swift 作为我的第一个学习练习。男孩,我在这个问题上跳入了深渊。

我现在被 Swifts Arrays 困住了,因为我想存储一个通用插件列表。每个插件可以有自己的值类型float、int、color、string、Vector Matrix。

我已经阅读了有关类型橡皮擦和不透明类型的信息,但似乎仍然无法以一种可以对它们执行一些算术运算的方式将我的值从列表中获取。

非常感谢所有可能使我朝着这个方向前进的帮助:D

import Foundation
import MetalKit

protocol genericPlug {
    associatedtype T
    func GetValue() -> T
}


class Plug<T>:genericPlug{
    var _value:T?
    var value:T {
        get{GetValue()}
        set(val){
            value = val
        }
    }

    func GetValue() -> T{
        return _value!
    }

    init(_ newValue:T){
        _value=newValue
    }
}

class Node{
    var plugs:[genericPlug] = []
    init(){
        var p1 = Plug<Int>(0)
        var p2 = Plug(vector2(1.2, 3.1))
        var p3 = Plug([0.0, 3.1, 0.6, 1])

        plugs.append(p1)
        plugs.append(p2)
        plugs.append(p3)
    }

    func execute(){
        // will access the plugs in the array and perform some sort of calculations on them.
        plugs[0].value + 1      // should equal 1
        plugs[1].value.x + 0.8  // should have x=2.0 y=3.1
        plugs[2].value[1] - 0.1 // should equal 3.0
    }
}

谢谢大家

4

2 回答 2

0

我设法找到了适合我需求的解决方案。

我仍在寻找一种更好的方法来处理获取数据及其正确类型。

import Foundation
import MetalKit

// Creating the PlugType Enum
enum PlugType{
    case Integer(Int?)
    case Float_(Float?)
    case Double_(Double?)
    case Vector3(simd_int3)

    // default types
    static func IntegerType() -> PlugType{ return PlugType.Integer(nil)}
    static func FloatType() -> PlugType{ return PlugType.Float_(nil)}
    static func DoubleType() -> PlugType{ return PlugType.Double_(nil)}
}

// Implements a way to retrieve the correct value type
extension PlugType{
    var IntegerValue: Int{
        switch self{
            case .Integer(let value):
                return value ?? 0
            default:
                return 0
        }
    }

    var FloatValue: Float{
        switch self
        {
        case .Float_(let value):
            return value ?? 0
        default:
            return 0
        }
    }

    var DoubleValue: Double{
        switch self
        {
        case .Double_(let value):
            return value ?? 0
        default:
            return 0
        }
    }
}

// Get the string representation of the PlugType
extension PlugType {
    var typeName: String{
        switch self {
        case .Integer: return "Integer"
        case .Float_: return "Float"
        case .Double_: return "Double"
        case .Vector3: return "Vector3"
        }
    }

    var swiftType: Any.Type {
        switch self {
        case .Integer: return Int.self
        case .Float_: return Float.self
        case .Double_: return Double.self
        case .Vector3: return simd_int3.self
        }
    }
}

class Plug{
    var _value:PlugType?
    var type:String? { get{ return _value?.typeName } }

    init(_ newValue:PlugType){
        _value = newValue
    }

    func geee<T>(_ input:T) -> T{
        switch type {
            case "Integer":
                return getVal(_value!.IntegerValue) as! T
            case "Double":
                return getVal(_value!.DoubleValue) as! T
            default:
            return 0 as! T
        }

    }

    func getVal(_ val:Int) -> Int {
        return val
    }
    func getVal(_ val:Float) -> Float {
        return val
    }
    func getVal(_ val:Double) -> Double {
        return val
    }
}

var plugs:[Plug] = []
var p1 = Plug(PlugType.Integer(2))
于 2020-05-03T23:43:42.090 回答
0

使用通用的东西来提取你需要的东西。您的选项是方法和下标。

protocol PlugValue {
  init()
}

extension Int: PlugValue { }
extension Float: PlugValue { }
extension Double: PlugValue { }
extension SIMD3: PlugValue where Scalar == Int32 { }
struct Plug<Value: PlugValue> {
  var value: Value

  init(_ value: Value) {
    self.value = value
  }
}
protocol AnyPlug {
  var anyValue: PlugValue { get }
}

extension AnyPlug {
  subscript<Value: PlugValue>(type: Value.Type = Value.self) -> Value {
    anyValue as? Value ?? .init()
  }

  func callAsFunction<Value: PlugValue>(_ type: Value.Type = Value.self) -> Value {
    anyValue as? Value ?? .init()
  }
}

extension Plug: AnyPlug {
  var anyValue: PlugValue { value }
}
let plugs: [AnyPlug] = [
  Plug(1),
  Plug(2.3 as Float),
  Plug(4.5),
  Plug([6, 7, 8] as SIMD3)
]

plugs[0][Int.self] // 1
plugs[1][Double.self] // 0
plugs[1][] as Float // 2.3
let double: Double = plugs[2]() // 4.5
plugs[3](SIMD3.self).y // 7

使用一系列协议,每次检索它们时,您是否必须将它们向下投射到它们的 Plug 中?

本质上。这适用于所有异源序列。以下是您的选择:

extension Array: PlugValue where Element: PlugValue { }

let plug: AnyPlug = Plug([0.1, 1.1, 2.1])
(plug as? Plug<[Double]>)?.value[1]
(plug.anyValue as? [Double])?[1]
extension Plug {
  enum Error: Swift.Error {
    case typeMismatch
  }
}

extension AnyPlug {
  func callAsFunction<Value: PlugValue, Return>(_ closure: (Value) -> Return) throws {
    guard let value = anyValue as? Value
    else { throw Plug<Value>.Error.typeMismatch }

    closure(value)
  }
}

try plug { (doubles: [Double]) in doubles[1] } // 1.1
try plug { ($0 as [Double])[1] } // 1.1
try plug { $0 as Int } // <Swift.Int>.Error.typeMismatch
于 2020-05-04T00:35:19.327 回答