|
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