我是Julia的新手,使用类型方法进行编程时遇到一些困难。
我想从文件中加载3D网格进行练习,并做了一些自定义类型来存储它。
这是我的类型:
struct Vertex
x::Number
y::Number
z::Number
Vertex(x::Number, y::Number, z::Number) = new(x, y, z)
Vertex(t::Tuple{Number, Number, Number}) = new(t[1], t[2], t[3])
Vertex(x::Number, y::Number) = new(x, y, 0)
Vertex(t::Tuple{Number, Number}) = new(t[1], t[2], 0)
Vertex(x::Number) = new(x, 0, 0)
Vertex(t::Tuple{Number}) = new(t[1], 0, 0)
Vertex() = new(0, 0, 0)
Vertex(t::Tuple{}) = new(0, 0, 0)
end
struct Mesh
t::Vector{Vertex} # List of triangles
f::Vector{Vertex} # List of faces
n::Vector{Vertex} # List of normals
Mesh(t::Vertex, f::Vertex) = new([t], [f], [])
Mesh(t::Vector{Vertex}, f::Vector{Vertex}, n::Vector{Vertex}) = new(t, f, n)
Mesh(t::Vector{Vertex}, f::Vector{Vertex}, n::Vector) = new(t, f, n)
Mesh(t::Vector, f::Vector, n::Vector) = new(t, f, n)
#Mesh(t::Triangle) = new([t], [])
#Mesh(t::Vector{Triangle}) = new(t, [])
end
我可以有效地以网格类型加载网格。
现在,我想使用 PyPlot 中的 plot_trisurf 方法来绘制它。但是,此方法需要一个数组数组,我不确定我的处理方法是否正确:
function plotMesh(M)
Xv = map(e -> e.x, M.t[:])
Yv = map(e -> e.x, M.t[:])
Zv = map(e -> e.x, M.t[:])
Fv = map(e -> (e.x, e.y, e.z), M.f[:])
plot_trisurf(Xv, Yv, Zv, triangles=Fv, alpha=1)
gca()[:projection] = "3d"
end
问:
Xv,Yv,Zv目前感觉不正确
谢谢
[编辑]
经过更多测试之后,我终于设法使它工作了,但是我仍然不确定这是否是在Julia中做事的最佳方法,还是我的类型系统是否是一个好的系统。
function plotMesh(M::Mesh)
Xv = map(e -> e.x, M.t[:])
Yv = map(e -> e.y, M.t[:])
Zv = map(e -> e.z, M.t[:])
Fv = map(e -> [Int(e.x)-1, Int(e.y)-1, Int(e.z)-1], M.f[:])
print(size(Xv))
print(size(Fv))
plot_trisurf(Xv, Yv, Zv, triangles=Fv)
gca()[:projection] = "3d"
end
First 3D plot in Julia
[编辑]
顶点和法线通常是浮点数,而面是整数。
我正在使用的对象是bunny.obj
我在结构中加载对象的代码是:
function read_obj(filename::String)
v = []
f = []
n = []
tof(x) = parse(Float64, x)
open(filename) do file
for line in eachline(file)
l = split(line, ' ')
if l[1] ∈ ["v", "f", "n"]
values = (tof(l[2]), tof(l[3]), tof(l[4]))
if l[1] == "v"
push!(v, Vertex(values))
elseif l[1] == "f"
faces = (Int(values[1]), Int(values[2]), Int(values[3]))
push!(f, Vertex(faces))
elseif l[1] == "n"
push!(n, Vertex(values))
end
end
end
end
return Mesh(v, f, n)
end
我加载对象的方式肯定不是最好的方式。如果您有任何提高我的技能的材料,请随时分享:)
最佳答案
首先,我将像这样更改Vertex
的定义(似乎在下面,您要求条目为整数,如果不是,则可以将Integer
更改为Number
)
struct Vertex{T<:Integer}
x::T
y::T
z::T
end
Vertex(x::T=0, y::T=zero(T)) where {T<:Integer} = Vertex(x,y,zero(T))
Vertex(t::Tuple) = Vertex(t...)
接下来在
Mesh
中,您可以像这样使用StructArrays.jl包(通过这种方式,您可以轻松地将Vertex
的字段作为矢量进行访问):using StructArrays
struct Mesh{S<:StructArray, T}
t::S
f::S
n::S
function Mesh(t::Vector{T}, f::Vector{T}, n::Vector{T}) where {T<:Vertex}
st, sf, sn = StructArray(t), StructArray(f), StructArray(n)
new{typeof(st), T}(st, sf, sn)
end
end
Mesh(t::T, f::T) where {T<:Vertex} = Mesh([t], [f], T[])
现在您可以将绘图功能定义为:
function plotMesh(M::Mesh{S, T}) where {S,T}
Fv = eachrow([M.f.x M.f.y M.f.z] .- one(T))
print(size(M.t.x))
print(size(Fv))
plot_trisurf(M.t.x, M.t.y, M.t.z, triangles=Fv)
gca()[:projection] = "3d"
end
注1:所有代码均确保所有结构都对具体类型进行操作,因此该代码将比使用抽象类型(如
Number
)更快。我还要确保所有条目都具有相同的类型。注意2:由于您没有提供用于测试代码的数据(因此请告诉我该代码中是否有任何失败),是我写的。严格来说,您不必使用StructArrays.jl即可达到目标,但我希望您同意使用它们可以使您的代码更具可读性。
关于julia - 如何将自定义数据类型转换为数组数组,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57349738/