Skip to content
This repository has been archived by the owner on Oct 12, 2019. It is now read-only.

Types are too specific #21

Closed
sjkelly opened this issue Aug 14, 2014 · 12 comments
Closed

Types are too specific #21

sjkelly opened this issue Aug 14, 2014 · 12 comments
Milestone

Comments

@sjkelly
Copy link
Member

sjkelly commented Aug 14, 2014

@SimonDanisch mentioned on Julia-users

These considerations won't necessarily slow down the development of any Julia algorithm, as the implementation is rather orthogonal

  • which is why I don't see any harm in getting OpenCL into the discussion.

I just mentioned, what I will be doing, in the hope, that people who develop any geometric algorithm in Julia keep it in mind, while designing the library.
For example, the library should only use parametric types, which would enable me to use Float32.
It's a small thing if you do it from the beginning, but gives you quite a headache if you try to integrate it later on.
This way it becomes a lot simpler, to smuggle in some OpenCL implementations( e.g. via multiple dispatch) parallel to the already established algorithms written in Julia.
I'm not talking theoretically about this, but I mention this because this is the reason why I can't use two very nice packages (namely Color.jl and Meshes.jl), without a lot of unnecessary conversions.

I'm very well aware, that not everyone wants to put the extra effort into developing in OpenCL.
That's why I wrote: "lets start with julia and add OpenCL later"

@SimonDanisch
Copy link
Member

Thanks Steve!
I need to add to this:
Having your own face type is also a little bit troublesome.
As long as you can't simply inherit from fixed array like I proposed on JuliaLang/julia#7568, this means I can't do any algebra with that type.
Which is needed, as for example the indices in OpenGL start at 0.
Also, I need to have at least normals and texture coordinates in the Mesh type.
I see the value in keeping Mesh clean and simple, but if some attribute are missing, I can't use the Mesh type altogether.
There are quite a few more attributes which might turn up.
The only nice solution that I can come up with is using a dictionary, which I don't feel too comfortable with. Maybe having one type with all attributes from the Obj format is more sensitive, as the user can actually see, what attributes are possible.

I started fixing your Obj importer and introducing parametric types, but it breaks isosurfaces so far.
I can't continue working on this right now, so I guess I should just push my changes in another branch so that you can take a look at it?

Best,
Simon

SimonDanisch added a commit to SimonDanisch/Meshes.jl that referenced this issue Aug 14, 2014
@twadleigh
Copy link
Contributor

@SimonDanisch I can help resolve isosurface breakage as necessary. @sjkelly has a good amount of momentum going, so I'd let him take the lead on how the Mesh type evolves for now.

Is the Mesh type currently not parameterized over field type? What an oversight! I'm embarrassed. Might be worth a near term quick fix.

@SimonDanisch
Copy link
Member

I just created a pull request with half of the fixes ;)
Some good news: I was able to hack something together to visualize the meshes.
I imported an obj file and instanced it. Like this I was able to display 60 million triangles, with normals and colors, which is not too bad for my HD 4000 on-board graphic card.

@sjkelly
Copy link
Member Author

sjkelly commented Aug 14, 2014

@SimonDanisch I started a branch with changes very similar to yours. I'll pull in the commit to my branch and try to adjust things as needed.

@twadleigh mentioned Images.jl had a good system for extensible properties. I am looking into it now. For my slicing stuff anything more than triangles would lead to a perfomance increase, so supporting this is a priority for me. Would you need to triangulate for OpenGL.jl?

I am thinking we could start with the following for faces, in a similar manner as Images:

Implement AbstractFace

Make Face{T<:Integer} or a similar function indicate the number of vertices. Move v1, v2, v3 into a vertices member of a an appropriate array size. Anything greater than 4 would need to be bumped to a regular Julia array. I think by default we should support face normals and vertex normals so we can do geometric operations.

A TexturedFace<:AbstractFace could easily extend this composite type. Full OBJ/MTL import would be a good exercise for this.

Also, @twadleigh do you think it would be a good time to tag a v0.0.4 release and bump to v0.1.x? These seem like these will be API breaking.

@sjkelly
Copy link
Member Author

sjkelly commented Aug 22, 2014

I needed to take an impromteu vacation to move apartments. I am back now.

I've tagged and published a v0.0.4 release so we can start working on this for the v0.1.x release. This issue will be top priority.

@sjkelly sjkelly added this to the v0.1.0 milestone Aug 22, 2014
@SimonDanisch
Copy link
Member

Hi,
I made a little prototype for the mesh type.
Things I considered important for the prototype:

  • One wants to do multiple dispatch on the attributes a mesh holds
  • a Mesh should be able to hold arbitrary attributes

Code:

immutable Mesh{Attributes}
    data::Dict{Symbol, Any}
end
# Automatically creates a mesh with a dict [attributename => value] 
# and with the correct parametric types
function Mesh(data...)
    result = {}
    meshattributes = (Symbol => Any)[]
    for elem in data
        push!(result, eltype(elem))
        meshattributes[symbol(string(eltype(elem)))] = elem
    end
       #The parametric types should be sorted, so that we have a standardized order
    Mesh{tuple(result...)}(meshattributes)
end
# These should be fixed size arrays, to have a more generic way of 
# defining attributes of different dimensions
immutable Triangle{T}
    v1::T
    v2::T
    v3::T
end
immutable Vertex3{T}
    x::T
    y::T
    z::T
end
immutable TextureCoordinate2{T}
    u::T
    v::T
end
immutable Normal{T}
    x::T
    y::T
    z::T
end
a = Triangle(1,2,3)
b = Vertex3(0,0,0)
c = TextureCoordinate2(0,0)
d = Normal(0,0,0)

Mesh([a], [b], [c], [d])
=> Mesh{(Triangle{Int64},Vertex3{Int64},TextureCoordinate2{Int64},Normal{Int64})}
([
:TextureCoordinate2{Int64}=>[TextureCoordinate2{Int64}(0,0)],
:Triangle{Int64}=>[Triangle{Int64}(1,2,3)],
:Vertex3{Int64}=>[Vertex3{Int64}(0,0,0)],
:Normal{Int64}=>[Normal{Int64}(0,0,0)]
])

@sjkelly
Copy link
Member Author

sjkelly commented Aug 25, 2014

@SimonDanisch I've been thinking about this for a couple of days. I really like your solution. The only thing I wish for is cleaner syntax for accessing properties. However, I don't think that will be immediately possible. I think once Julia enables overloading the "." operator this will be much better.

I really like this since would encapsulate fairly complicated and extensible formats. I implemented AMF import (to some extent), since I see this as a more extreme case.

The only other option I could see is a macro-generated type. This would only afford some brevity and cleaner access, but would sacrifice easy multiple-dispatch.

Your code above seems to be a very good basis. If you don't mind, I can put this into a new branch and build out the concept.

@SimonDanisch
Copy link
Member

Cool sounds good to me!
My friend actually implemented a pretty sophisticated Obj importer!
We just need to think about how to put all the pieces together.
I actually updated my Mesh type, to have nicer access via mesh[:attribute].
Here is the newest code:

immutable Mesh{Attributes}
    data::Dict{Symbol, Any}
end
immutable Triangle{T}
    v1::T
    v2::T
    v3::T
end
immutable Vertex3{T}
    x::T
    y::T
    z::T
end
immutable TextureCoordinate2{T}
    u::T
    v::T
end
immutable Normal{T}
    x::T
    y::T
    z::T
end
function Mesh(data...)
    result = (Symbol => DataType)[]
    meshattributes = (Symbol => Any)[]
    for elem in data
        keyname                 = symbol(lowercase(replace(string(eltype(elem).name), r"\d", "")))
        result[keyname]         = eltype(elem)
        meshattributes[keyname] = elem
    end
    #sorting of parameters... Solution a little ugly for my taste
    result = sort(map(x->x, result))
    Mesh{tuple(map(x->x[2],result)...)}(meshattributes)
end
Base.getindex(m::Mesh, key::Symbol) = m.data[key]
function Base.show(io::IO, m::Mesh)
    println(io, "Mesh:")
    maxnamelength = 0
    maxtypelength = 0
    names = map(m.data) do x
        n = string(x[1])
        t = string(eltype(x[2]).parameters...)
        namelength = length(n)
        typelength = length(t)
        maxnamelength = maxnamelength < namelength ? namelength : maxnamelength
        maxtypelength = maxtypelength < typelength ? typelength : maxtypelength

        return (n, t, length(x[2]))
    end

    for elem in names
        kname, tname, alength = elem
        namespaces = maxnamelength - length(kname)
        typespaces = maxtypelength - length(tname)
        println(io, "   ", kname, " "^namespaces, " : ", tname, " "^typespaces, ", length: ", alength)
    end
end


a = Triangle(1,2,3)
b = Vertex3(0,0,0)
c = TextureCoordinate2(0,0)
d = Normal(0,0,0)

@show m = Mesh([a], [b], [c], [d])
@show m[:triangle]
#=
m = Mesh([a],[b],[c],[d]) => Mesh:
   texturecoordinate : Int64, length: 1
   triangle          : Int64, length: 1
   vertex            : Int64, length: 1
   normal            : Int64, length: 1

m[:triangle] => [Triangle{Int64}(1,2,3)]
=#

Here is a screen shot of an imported obj:
butterfly

@sjkelly
Copy link
Member Author

sjkelly commented Aug 25, 2014

\me speechless!!!
Amazing!

@PetrKryslUCSD
Copy link

@SimonDanisch
It seems to me your mesh would support storage of JFinEALE element sets? Or am I wrong?

One of the design features I think are important is to have a way of maintaining association of "similar" or "analogous" element types. For instance, for boundary-integral operations the elements should support being embedded in spaces of dimension equal to or greater than their manifold dimension, calculation of normals, ... The mesh storage mechanism should allow for this association to be carried through, I think.

P

@SimonDanisch
Copy link
Member

Preferably, everything mesh like is supported!
I'm not sure if that is sensible with the current design, though... Dict CAN represent everything, but the question is, if everything should be represented by the dict in the mesh.
I know mighty little about the mesh types that you're using for your FE algorithms.
I hope you can help out a little with that ;)
Probably sketch out minimal examples, or verify if the proposed mesh type would fit you.

sjkelly added a commit that referenced this issue Mar 23, 2015
@sjkelly
Copy link
Member Author

sjkelly commented Apr 12, 2015

I think this can be closed. We still need to make some functionality more generic though, but the types are more parametric.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants