| 
1 | 1 | # Decomposition  | 
2 | 2 | 
 
  | 
3 |  | - | 
4 |  | -## GeometryBasics Mesh interface  | 
5 |  | - | 
6 |  | -GeometryBasics defines an interface to decompose abstract geometries into  | 
7 |  | -points and triangle meshes.  | 
8 |  | -This can be done for any arbitrary primitive, by overloading the following interface:  | 
9 |  | - | 
10 |  | -```julia  | 
11 |  | - | 
12 |  | -function GeometryBasics.coordinates(rect::Rect2, nvertices=(2,2))  | 
13 |  | -    mini, maxi = extrema(rect)  | 
14 |  | -    xrange, yrange = LinRange.(mini, maxi, nvertices)  | 
15 |  | -    return ivec(((x,y) for x in xrange, y in yrange))  | 
16 |  | -end  | 
17 |  | - | 
18 |  | -function GeometryBasics.faces(rect::Rect2, nvertices=(2, 2))  | 
19 |  | -    w, h = nvertices  | 
20 |  | -    idx = LinearIndices(nvertices)  | 
21 |  | -    quad(i, j) = QuadFace{Int}(idx[i, j], idx[i+1, j], idx[i+1, j+1], idx[i, j+1])  | 
22 |  | -    return ivec((quad(i, j) for i=1:(w-1), j=1:(h-1)))  | 
23 |  | -end  | 
24 |  | -```  | 
25 |  | -Those methods, for performance reasons, expect you to return an iterator, to make  | 
26 |  | -materializing them with different element types allocation free. But of course,  | 
27 |  | -can also return any `AbstractArray`.  | 
28 |  | - | 
29 |  | -With these methods defined, this constructor will magically work:  | 
30 |  | - | 
31 |  | -```julia  | 
32 |  | -rect = Rect2(0.0, 0.0, 1.0, 1.0)  | 
33 |  | -m = GeometryBasics.mesh(rect)  | 
34 |  | -```  | 
35 |  | -If you want to set the `nvertices` argument, you need to wrap your primitive in a `Tesselation`  | 
36 |  | -object:  | 
37 |  | -```julia  | 
38 |  | -m = GeometryBasics.mesh(Tesselation(rect, (50, 50)))  | 
39 |  | -length(coordinates(m)) == 50^2  | 
40 |  | -```  | 
41 |  | - | 
42 |  | -As you can see, `coordinates` and `faces` are also defined on a mesh  | 
43 |  | -```julia  | 
44 |  | -coordinates(m)  | 
45 |  | -faces(m)  | 
46 |  | -```  | 
47 |  | -But will actually not be an iterator anymore. Instead, the mesh constructor uses  | 
48 |  | -the `decompose` function, that will collect the result of coordinates and will  | 
49 |  | -convert it to a concrete element type:  | 
50 |  | -```julia  | 
51 |  | -decompose(Point2f, rect) == convert(Vector{Point2f}, collect(coordinates(rect)))  | 
52 |  | -```  | 
53 |  | -The element conversion is handled by `simplex_convert`, which also handles convert  | 
54 |  | -between different face types:  | 
55 |  | -```julia  | 
56 |  | -decompose(QuadFace{Int}, rect) == convert(Vector{QuadFace{Int}}, collect(faces(rect)))  | 
57 |  | -length(decompose(QuadFace{Int}, rect)) == 1  | 
58 |  | -fs = decompose(GLTriangleFace, rect)  | 
59 |  | -fs isa Vector{GLTriangleFace}  | 
60 |  | -length(fs) == 2 # 2 triangles make up one quad ;)  | 
61 |  | -```  | 
62 |  | -`mesh` uses the most natural element type by default, which you can get with the unqualified Point type:  | 
63 |  | -```julia  | 
64 |  | -decompose(Point, rect) isa Vector{Point{2, Float64}}  | 
65 |  | -```  | 
66 |  | -You can also pass the element type to `mesh`:  | 
67 |  | -```julia  | 
68 |  | -m = GeometryBasics.mesh(rect, pointtype=Point2f, facetype=QuadFace{Int})  | 
69 |  | -```  | 
70 |  | -You can also set the uv and normal type for the mesh constructor, which will then  | 
71 |  | -calculate them for you, with the requested element type:  | 
72 |  | -```julia  | 
73 |  | -m = GeometryBasics.mesh(rect, uv=Vec2f, normaltype=Vec3f)  | 
74 |  | -```  | 
75 |  | - | 
76 |  | -As you can see, the normals are automatically calculated,  | 
77 |  | -the same is true for texture coordinates. You can overload this behavior by overloading  | 
78 |  | -`normals` or `texturecoordinates` the same way as coordinates.  | 
79 |  | -`decompose` works a bit different for normals/texturecoordinates, since they dont have their own element type.  | 
80 |  | -Instead, you can use `decompose` like this:  | 
81 |  | -```julia  | 
82 |  | -decompose(UV(Vec2f), rect)  | 
83 |  | -decompose(Normal(Vec3f), rect)  | 
84 |  | -# the short form for the above:  | 
85 |  | -decompose_uv(rect)  | 
86 |  | -decompose_normals(rect)  | 
87 |  | -```  | 
88 |  | -You can also use `triangle_mesh`, `normal_mesh` and `uv_normal_mesh` to call the  | 
89 |  | -`mesh` constructor with predefined element types (Point2/3f, Vec2/3f), and the requested attributes.  | 
 | 3 | +## decompose functions  | 
 | 4 | + | 
 | 5 | +The `decompose` functions allow you to grab certain data from an `AbstractGeometry` like a mesh or primitive and convert it to a requested type, if possible.  | 
 | 6 | +They can also be used to convert an array of e.g. faces into a different face type directly.  | 
 | 7 | +The default decomposition implemented by GeoemtryBasics are:  | 
 | 8 | +- `decompose(::Type{<: Point}, source)` which collects data from `source` using `coordinates(source)` and converts it to the given point type.  | 
 | 9 | +- `decompose_normals([::Type{<: Vec},] source) = decompose([::Type{Normals{<: Vec}}},] source)` which collects data with `normals(source)` and converts it to the given Vec type.  | 
 | 10 | +- `decompose_uv([::Type{<: Vec},] source) = decompose([::Type{UV{<: Vec}}},] source)` which collects data with `texturecoordinates(source)` and converts it to the given Vec type. This function also exists with `UVW` texture coordinates.  | 
 | 11 | +- `decompose(::Type{<: AbstractFace}, source)` which collects data with `faces(source)` and converts it to the given face type.   | 
 | 12 | + | 
 | 13 | +### Extending decompose  | 
 | 14 | + | 
 | 15 | +For `decompose` to work there needs to be a conversion from some element type to some target type.   | 
 | 16 | +GeometryBasics relies on `GeometryBasics.convert_simplex(TargetType, value)` for this.  | 
 | 17 | +If you want to add new types to decompose, e.g. a new face type, you will need to add a method to that function.  | 
 | 18 | + | 
 | 19 | +## Primitive decomposition  | 
 | 20 | + | 
 | 21 | +GeometryBasics defines an interface to decompose geometry primitives into vertex attributes and faces.  | 
 | 22 | +The interface includes four functions:  | 
 | 23 | +- `coordinates(primitive[, nvertices])` which produces the positions associated with the primitive  | 
 | 24 | +- `faces(primitive[, nvertices])` which produces the faces which connect the vertex positions to a mesh  | 
 | 25 | +- `normals(primitive[, nvertices])` which optionally provide normal vectors of the primitive  | 
 | 26 | +- `texturecoordinates(primitive[, nvertices])` which optional provide texture coordinates (uv/uvw) of the primitive  | 
0 commit comments