|
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