Skip to content

Commit

Permalink
migrate to new fileio api JuliaIO/FileIO.jl#15
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonDanisch committed Aug 9, 2015
1 parent 5ebe9d2 commit 76130a5
Show file tree
Hide file tree
Showing 2 changed files with 204 additions and 81 deletions.
152 changes: 136 additions & 16 deletions src/io/ply.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ export exportBinaryPly,
exportAsciiPly,
importAsciiPly

add_format(format"PLY_ASCII", b"ply\nformat ascii 1.0\n", ".ply")
add_format(format"PLY_BINARY", b"ply\nformat binary_little_endian 1.0\n", ".ply")

immutable FileEnding{Disambiguated_Ending}
real_ending ::Symbol
magic_number ::Vector{Uint8}
end
const ply_binary = FileEnding{:ply_binary}(:ply, b"ply\nformat binary_little_endian 1.0\n")
add_loader(format"PLY_ASCII", :GeometryTypes)
add_saver(format"PLY_BINARY", :GeometryTypes)

function Base.write(fn::File{:ply_binary}, msh::Mesh)
function save(f::File{format"PLY_BINARY"}, msh::Mesh)

vts = msh[Point3{Float32}]
fcs = msh[Face3{Int32, -1}]
Expand Down Expand Up @@ -39,7 +38,7 @@ end
const ply_ascii = FileEnding{:ply_binary}(:ply, b"ply\nformat binary_little_endian 1.0\n")


function Base.write(fn::File{:ply_ascii}, msh::Mesh)
function save(f::File{format"PLY_ASCII"}, msh::Mesh)

vts = msh[Point3{Float32}]
fcs = msh[Face3{Int32, -1}]
Expand Down Expand Up @@ -68,16 +67,16 @@ function Base.write(fn::File{:ply_ascii}, msh::Mesh)
close(io)
end


function Base.read(fn::File{:ply_ascii}, MeshType=GLNormalMesh)
io = open(fn, "r")
mesh = read_ascii_ply(io, MeshType)
function load(f::File{format"PLY_ASCII"}; typ=GLNormalMesh)
io = open(fn)
skipmagic(io, f)
mesh = load(io, typ)
close(io)
return mesh
end


function read_ascii_ply(io::IO, MeshType=GLNormalMesh)
function load(fs::Stream{format"PLY_ASCII"}; typ=GLNormalMesh)
io = stream(fs)
nV = 0
nF = 0

Expand All @@ -96,9 +95,9 @@ function read_ascii_ply(io::IO, MeshType=GLNormalMesh)
end
line = readline(io)
end
VertexType = vertextype(iscorrect)
FaceType = facetype(MeshType)
FaceEltype = eltype(FaceType)
VertexType = vertextype(typ)
FaceType = facetype(typ)
FaceEltype = eltype(FaceType)

vts = Array(VertexType, nV)
fcs = Array(FaceType, nF)
Expand All @@ -120,6 +119,127 @@ function read_ascii_ply(io::IO, MeshType=GLNormalMesh)
end
end

return MeshType(vts, fcs)
endexport exportBinaryPly,
exportAsciiPly,
importAsciiPly

add_format(format"PLY_ASCII", b"ply\nformat ascii 1.0\n", ".ply")
add_format(format"PLY_BINARY", b"ply\nformat binary_little_endian 1.0\n", ".ply")

add_loader(format"PLY_ASCII", :GeometryTypes)
add_saver(format"PLY_BINARY", :GeometryTypes)

function save(f::File{format"PLY_BINARY"}, msh::Mesh)

vts = msh[Point3{Float32}]
fcs = msh[Face3{Int32, -1}]

nV = length(vts)
nF = length(fcs)

io = open(fn, "w")
# write the header
write(io, "ply\n")
write(io, "format binary_little_endian 1.0\n")
write(io, "element vertex $nV\n")
write(io, "property float x\nproperty float y\nproperty float z\n")
write(io, "element face $nF\n")
write(io, "property list uchar int vertex_index\n")
write(io, "end_header\n")

# write the vertices and faces
write(io, vts)

for f in fcs
write(io, convert(Uint8, 3))
write(io, f...)
end
close(io)
end
const ply_ascii = FileEnding{:ply_binary}(:ply, b"ply\nformat binary_little_endian 1.0\n")


function save(f::File{format"PLY_ASCII"}, msh::Mesh)

vts = msh[Point3{Float32}]
fcs = msh[Face3{Int32, -1}]

nV = length(vts)
nF = length(fcs)

io = open(fn, "w")

# write the header
write(io, "ply\n")
write(io, "format ascii 1.0\n")
write(io, "element vertex $nV\n")
write(io, "property float x\nproperty float y\nproperty float z\n")
write(io, "element face $nF\n")
write(io, "property list uchar int vertex_index\n")
write(io, "end_header\n")

# write the vertices and faces
for v in vts
println(io, join(v, " "))
end
for f in fcs
println(io, length(f), " ", join(f, " "))
end
close(io)
end

function load(f::File{format"PLY_ASCII"}; typ=GLNormalMesh)
io = open(fn)
skipmagic(io, f)
mesh = load(io, typ)
close(io)
return mesh
end

function load(fs::Stream{format"PLY_ASCII"}; typ=GLNormalMesh)
io = stream(fs)
nV = 0
nF = 0

properties = String[]

# read the header
line = readline(io)

while !startswith(line, "end_header")
if startswith(line, "element vertex")
nV = parse(Int, split(line)[3])
elseif startswith(line, "element face")
nF = parse(Int, split(line)[3])
elseif startswith(line, "property")
push!(properties, line)
end
line = readline(io)
end
VertexType = vertextype(typ)
FaceType = facetype(typ)
FaceEltype = eltype(FaceType)

vts = Array(VertexType, nV)
fcs = Array(FaceType, nF)

# read the data
for i = 1:nV
vts[i] = VertexType(split(readline(io))) # line looks like: "-0.018 0.038 0.086"
end

for i = 1:nF
line = split(readline(io))
len = parse(Int, shift!(line))
if len == 3 # workaround for not having generic Face type like Face{4, T}
fcs[i] = FaceType(Face3{FaceEltype, -1}(line)) # line looks like: "3 0 1 2"
elseif len == 4
fcs[i] = FaceType(Face4{FaceEltype, -1}(line))
else
error("face type with length $len is not supported yet")
end
end

return MeshType(vts, fcs)
end
133 changes: 68 additions & 65 deletions src/io/stl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,108 +4,111 @@ export exportStl,

import Base.writemime

function exportStl(msh::Mesh, fn::String)
exportStl(msh, open(fn, "w"))
function detect_stlbinary(io)
seekstart(io)
header = readbytes(io, 80)
header[1:6] == b"solid " && return false
number_of_triangle_blocks = read(io, Uint32)
size_triangleblock = (4*3*sizeof(Float32)) + sizeof(Uint16) #1 normal, 3 vertices in Float32 + attrib count, usually 0
skip(io, number_of_triangle_blocks*size_triangleblock-sizeof(Uint16))
eof(io) && return false # should not end here
attrib_byte_count = read(io, Uint16) # read last attrib_byte

attrib_byte_count != zero(Uint16) && return false # should be zero as not used
eof(io) && return true
false
end

function exportStl(msh::Mesh, str::IO, closeAfterwards::Bool)
vts = msh.vertices
fcs = msh.faces
nV = size(vts,1)
nF = size(fcs,1)
add_format(format"STL_ASCII", "solid ", ".stl")
add_format(format"STL_BINARY", detect_stlbinary, ".stl")

# write the header
write(str,"solid vcg\n")

function save(f::Union(File{format"PLY_ASCII"}, File{format"PLY_BINARY"}), msh::Mesh)
fs = open(f)
save(fs, msh)
close(fs)
end

function save(f::Stream{format"PLY_ASCII"}, msh::Mesh)
io = stream(f)
vts = Vector{Point{3, Float32}(msh)
fcs = Vector{Face{3, Float32, -1}(msh)
normals = Vector{Normal{3, Float32}(msh)

nV = length(vts)
nF = length(fcs)

# write the header
write(io,"solid vcg\n")
# write the data
for i = 1:nF
f = fcs[i]
n = [0,0,0] # TODO: properly compute normal(f)
@printf str " facet normal %e %e %e\n" n[1] n[2] n[3]
write(str," outer loop\n")
v = vts[f.v1]
@printf str " vertex %e %e %e\n" v[1] v[2] v[3]
n = normals[i] # TODO: properly compute normal(f)
v1, v2, v3 = vts[f]
@printf io " facet normal %e %e %e\n" n[1] n[2] n[3]
write(io," outer loop\n")

v = vts[f.v2]
@printf str " vertex %e %e %e\n" v[1] v[2] v[3]
@printf io " vertex %e %e %e\n" v1[1] v1[2] v1[3]
@printf io " vertex %e %e %e\n" v2[1] v2[2] v2[3]
@printf io " vertex %e %e %e\n" v3[1] v3[2] v3[3]

v = vts[f.v3]
@printf str " vertex %e %e %e\n" v[1] v[2] v[3]

write(str," endloop\n")
write(str," endfacet\n")
end

write(str,"endsolid vcg\n")
if closeAfterwards
close(str)
write(io," endloop\n")
write(io," endfacet\n")
end
write(io,"endsolid vcg\n")
end

exportStl(msh::Mesh, str::IO) = exportStl(msh, str, true)

function writemime(io::IO, ::MIME"model/stl+ascii", msh::Mesh)
exportSTL(msh, io)
end

writemime(io::IO, ::MIME"model/stl+ascii", msh::Mesh) = save(io, msh)

function importBinarySTL(file::String; topology=false)
fn = open(file,"r")
mesh = importBinarySTL(fn, topology=topology)
close(fn)
return mesh
end

function importBinarySTL(file::IO; topology=false, read_header=false)
function load(fs::Stream{format"PLY_BINARY"}; typ=GLNormalMesh)
#Binary STL
#https://en.wikipedia.org/wiki/STL_%28file_format%29#Binary_STL

binarySTLvertex(file) = Vertex(float64(read(file, Float32)),
float64(read(file, Float32)),
float64(read(file, Float32)))

vts = Vertex[]
fcs = Face{Int}[]
io = stream(fs)
seekstart(io)
readbytes(file, 80) # throw out header

if !read_header
readbytes(file, 80) # throw out header
end
read(file, Uint32) # throwout triangle count
triangle_count = read(file, Uint32)
FaceType = facetype(typ)
VertexType = vertextype(typ)
NormalType = normaltype(typ)

vert_count = 0
vert_idx = [0,0,0]
faces = Array(FaceType, triangle_count)
vertices = Array(VertexType, triangle_count*3)
normals = Array(NormalType, triangle_count)
i = 1
while !eof(file)
normal = binarySTLvertex(file)
for i = 1:3
vertex = binarySTLvertex(file)
if topology
idx = findfirst(vts, vertex)
end
if topology && idx != 0
vert_idx[i] = idx
else
push!(vts, vertex)
vert_count += 1
vert_idx[i] = vert_count
end
end
faces[i+1] = Face{3, Int, -1}(i*3, i*3+1, i*3+2)
normals[i+1] = read(io, Normal{3, Float32})
vertices[i*3+1] = read(io, Point{3, Float32})
vertices[i*3+2] = read(io, Point{3, Float32})
vertices[i*3+3] = read(io, Point{3, Float32})

skip(file, 2) # throwout 16bit attribute
push!(fcs, Face{Int}(vert_idx...))
i += 1
end

return Mesh{Vertex, Face{Int}}(vts, fcs, topology)
return typ(vts, fcs, topology)
end

function importAsciiSTL(file::String; topology=false)
function load(file::String; topology=false)
fn = open(file,"r")
mesh = importAsciiSTL(fn, topology=topology)
close(fn)
return mesh
end

function importAsciiSTL(file::IO; topology=false)
function importAsciiSTL(fs::Stream{format"PLY_BINARY"}; typ=GLNormalMesh)
#ASCII STL
#https://en.wikipedia.org/wiki/STL_%28file_format%29#ASCII_STL
io = stream(fs)
skipmagic(io)

vts = Vertex[]
fcs = Face{Int}[]
Expand Down Expand Up @@ -136,5 +139,5 @@ function importAsciiSTL(file::IO; topology=false)
end
end

return Mesh{Vertex, Face{Int}}(vts, fcs, topology)
return typ(vts, fcs, topology)
end

0 comments on commit 76130a5

Please sign in to comment.