cgmath 1.0.4__tar.gz → 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. {cgmath-1.0.4/cgmath.egg-info → cgmath-3.0.0}/PKG-INFO +40 -9
  2. {cgmath-1.0.4 → cgmath-3.0.0}/README.md +39 -8
  3. {cgmath-1.0.4 → cgmath-3.0.0}/__init__.py +1 -1
  4. cgmath-3.0.0/_tests/__init__.py +1 -0
  5. cgmath-3.0.0/_tests/_examples_curves.py +198 -0
  6. cgmath-3.0.0/_tests/_examples_deform.py +171 -0
  7. cgmath-3.0.0/_tests/_examples_geometry.py +366 -0
  8. cgmath-3.0.0/_tests/_examples_hierarchy.py +280 -0
  9. cgmath-3.0.0/_tests/_examples_render.py +268 -0
  10. cgmath-3.0.0/_tests/_maya_rotate_order.py +64 -0
  11. cgmath-3.0.0/_tests/test_assets/maya_euler.npz +0 -0
  12. cgmath-3.0.0/_tests/test_assets/mikktspace_deformed_data.json +1331 -0
  13. cgmath-3.0.0/_tests/test_assets/mikktspace_test_data.json +1836 -0
  14. cgmath-3.0.0/_tests/test_assets/test_data_module.curve.pkl +0 -0
  15. cgmath-3.0.0/_tests/test_assets/test_data_module.mesh.pkl +0 -0
  16. cgmath-3.0.0/_tests/test_assets/test_data_module.patch.pkl +0 -0
  17. cgmath-3.0.0/_tests/test_assets/test_data_module.saved_by_2_0_0.zip +0 -0
  18. cgmath-3.0.0/_tests/test_assets/test_geometry.bspline_best_fit_params.npz +0 -0
  19. cgmath-3.0.0/_tests/test_assets/test_geometry.bspline_maya_curves.json +67 -0
  20. cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.json +136 -0
  21. cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.npz +0 -0
  22. cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.pkl +0 -0
  23. cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node_clip.json +331 -0
  24. cgmath-3.0.0/_tests/test_assets/test_hierarchy.results.npz +0 -0
  25. cgmath-3.0.0/_tests/test_assets/test_hierarchy.skeleton.json +1064 -0
  26. cgmath-3.0.0/_tests/test_assets/test_ngon.bitmap_buffer.npz +0 -0
  27. cgmath-3.0.0/_tests/test_assets/test_ngon.source_mesh_data.json +1547 -0
  28. cgmath-3.0.0/_tests/test_assets/test_ngon.source_uv_list.json +2349 -0
  29. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data.npz +0 -0
  30. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_ngons_only.npz +0 -0
  31. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_preserve_order.npz +0 -0
  32. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_preserve_order_ngons_only.npz +0 -0
  33. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list.npz +0 -0
  34. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_ngons_only.npz +0 -0
  35. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_preserve_order.npz +0 -0
  36. cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_preserve_order_ngons_only.npz +0 -0
  37. cgmath-3.0.0/_tests/test_assets/test_resample.dst_bs_data.npz +0 -0
  38. cgmath-3.0.0/_tests/test_assets/test_resample.dst_mesh_data.npz +0 -0
  39. cgmath-3.0.0/_tests/test_assets/test_resample.dst_skin_data.npz +0 -0
  40. cgmath-3.0.0/_tests/test_assets/test_resample.dst_uv_data.npz +0 -0
  41. cgmath-3.0.0/_tests/test_assets/test_resample.overlap.pkl +0 -0
  42. cgmath-3.0.0/_tests/test_assets/test_resample.src_bs_data.npz +0 -0
  43. cgmath-3.0.0/_tests/test_assets/test_resample.src_mesh_data.npz +0 -0
  44. cgmath-3.0.0/_tests/test_assets/test_resample.src_skin_data.npz +0 -0
  45. cgmath-3.0.0/_tests/test_assets/test_resample.src_uv_data.npz +0 -0
  46. cgmath-3.0.0/_tests/test_assets/test_sdf.igloo.npz +0 -0
  47. cgmath-3.0.0/_tests/test_base.py +1689 -0
  48. cgmath-3.0.0/_tests/test_base_setattr.py +1144 -0
  49. cgmath-3.0.0/_tests/test_bspline_kernels.py +333 -0
  50. cgmath-3.0.0/_tests/test_clip.py +12395 -0
  51. cgmath-3.0.0/_tests/test_constraints.py +96 -0
  52. cgmath-3.0.0/_tests/test_curves_empty.py +90 -0
  53. cgmath-3.0.0/_tests/test_curves_types.py +538 -0
  54. cgmath-3.0.0/_tests/test_data_module.py +390 -0
  55. cgmath-3.0.0/_tests/test_deform_files.py +314 -0
  56. cgmath-3.0.0/_tests/test_deform_utils.py +349 -0
  57. cgmath-3.0.0/_tests/test_delta_mush.py +538 -0
  58. cgmath-3.0.0/_tests/test_euler_maya.py +210 -0
  59. cgmath-3.0.0/_tests/test_fbx_export.py +1216 -0
  60. cgmath-3.0.0/_tests/test_fbx_import.py +983 -0
  61. cgmath-3.0.0/_tests/test_fbx_labels.py +1284 -0
  62. cgmath-3.0.0/_tests/test_fbx_lifetime.py +1026 -0
  63. cgmath-3.0.0/_tests/test_ffd.py +573 -0
  64. cgmath-3.0.0/_tests/test_file_routes.py +1031 -0
  65. cgmath-3.0.0/_tests/test_geometry.py +7428 -0
  66. cgmath-3.0.0/_tests/test_geometry_io.py +215 -0
  67. cgmath-3.0.0/_tests/test_geometry_utils.py +360 -0
  68. cgmath-3.0.0/_tests/test_glb.py +336 -0
  69. cgmath-3.0.0/_tests/test_glb_materials.py +182 -0
  70. cgmath-3.0.0/_tests/test_hierarchy.py +6688 -0
  71. cgmath-3.0.0/_tests/test_hierarchy_io.py +317 -0
  72. cgmath-3.0.0/_tests/test_import_order.py +116 -0
  73. cgmath-3.0.0/_tests/test_imports.py +520 -0
  74. cgmath-3.0.0/_tests/test_list_item_class.py +368 -0
  75. cgmath-3.0.0/_tests/test_map.py +91 -0
  76. cgmath-3.0.0/_tests/test_mesh_usd.py +58 -0
  77. cgmath-3.0.0/_tests/test_morph_target.py +1106 -0
  78. cgmath-3.0.0/_tests/test_namespaces.py +235 -0
  79. cgmath-3.0.0/_tests/test_ngon.py +163 -0
  80. cgmath-3.0.0/_tests/test_normals_quadmatch_utils.py +287 -0
  81. cgmath-3.0.0/_tests/test_object_skin.py +1312 -0
  82. cgmath-3.0.0/_tests/test_pack.py +206 -0
  83. cgmath-3.0.0/_tests/test_parent_lookups.py +393 -0
  84. cgmath-3.0.0/_tests/test_patch_relax.py +607 -0
  85. cgmath-3.0.0/_tests/test_procrustes_rotation.py +189 -0
  86. cgmath-3.0.0/_tests/test_quadrangulate.py +517 -0
  87. cgmath-3.0.0/_tests/test_raycast.py +1157 -0
  88. cgmath-3.0.0/_tests/test_raycast_bvh.py +193 -0
  89. cgmath-3.0.0/_tests/test_rbf.py +540 -0
  90. cgmath-3.0.0/_tests/test_render_cache.py +220 -0
  91. cgmath-3.0.0/_tests/test_render_fit_padding.py +343 -0
  92. cgmath-3.0.0/_tests/test_render_roundtrip_extra.py +143 -0
  93. cgmath-3.0.0/_tests/test_render_serialization.py +512 -0
  94. cgmath-3.0.0/_tests/test_render_threads.py +1684 -0
  95. cgmath-3.0.0/_tests/test_resample.py +1112 -0
  96. cgmath-3.0.0/_tests/test_resample_bezier.py +218 -0
  97. cgmath-3.0.0/_tests/test_robust_skinweights_transfer_bilinear.py +310 -0
  98. cgmath-3.0.0/_tests/test_roundtrip.py +1073 -0
  99. cgmath-3.0.0/_tests/test_saddle_surface.py +480 -0
  100. cgmath-3.0.0/_tests/test_scene.py +4068 -0
  101. cgmath-3.0.0/_tests/test_scene_animate.py +702 -0
  102. cgmath-3.0.0/_tests/test_sdf.py +379 -0
  103. cgmath-3.0.0/_tests/test_short_names.py +1329 -0
  104. cgmath-3.0.0/_tests/test_skin_deform.py +1506 -0
  105. cgmath-3.0.0/_tests/test_skin_fbx.py +322 -0
  106. cgmath-3.0.0/_tests/test_skin_glb.py +538 -0
  107. cgmath-3.0.0/_tests/test_skin_kernels.py +323 -0
  108. cgmath-3.0.0/_tests/test_skin_weights.py +1174 -0
  109. cgmath-3.0.0/_tests/test_symmetry.py +157 -0
  110. cgmath-3.0.0/_tests/test_triangulation.py +108 -0
  111. cgmath-3.0.0/_tests/test_usd_prim.py +47 -0
  112. cgmath-3.0.0/_tests/test_utils.py +686 -0
  113. cgmath-3.0.0/_tests/test_wrap.py +299 -0
  114. {cgmath-1.0.4 → cgmath-3.0.0/cgmath.egg-info}/PKG-INFO +40 -9
  115. cgmath-3.0.0/cgmath.egg-info/SOURCES.txt +410 -0
  116. {cgmath-1.0.4 → cgmath-3.0.0}/constraints/procrustes.py +36 -22
  117. cgmath-3.0.0/data.py +3292 -0
  118. cgmath-3.0.0/formats/_fbx_io.py +186 -0
  119. {cgmath-1.0.4 → cgmath-3.0.0}/formats/fbx.py +748 -171
  120. {cgmath-1.0.4 → cgmath-3.0.0}/formats/glb.py +50 -4
  121. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/__init__.py +1 -1
  122. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/_saddle_surface.py +109 -63
  123. cgmath-3.0.0/geometry/bspline.py +2544 -0
  124. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/bspline_patch.py +941 -112
  125. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/delta_mush.py +101 -98
  126. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/ffd.py +63 -28
  127. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/patch_relax.py +59 -52
  128. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/skin_deform.py +182 -72
  129. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/wrap.py +56 -28
  130. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/map.py +18 -16
  131. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/mesh.py +887 -278
  132. cgmath-3.0.0/geometry/morph_target.py +674 -0
  133. cgmath-3.0.0/geometry/resample.py +707 -0
  134. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/sdf.py +88 -19
  135. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/skin_weights.py +285 -169
  136. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/__init__.py +1 -0
  137. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_bilinear.py +1095 -254
  138. cgmath-3.0.0/geometry/utils/_numba/_bspline.py +4161 -0
  139. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_cdt.py +17 -2
  140. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_ffd.py +1 -1
  141. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_main.py +2 -0
  142. cgmath-3.0.0/geometry/utils/_numba/_skin_deform.py +831 -0
  143. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_skin_weights.py +2 -0
  144. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_topology.py +44 -0
  145. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/main.py +186 -8
  146. {cgmath-1.0.4 → cgmath-3.0.0}/hierarchy/__init__.py +8 -3
  147. cgmath-3.0.0/hierarchy/hierarchy.py +13058 -0
  148. {cgmath-1.0.4 → cgmath-3.0.0}/pyproject.toml +14 -4
  149. cgmath-3.0.0/render/_tiles.py +757 -0
  150. {cgmath-1.0.4 → cgmath-3.0.0}/render/raytracer.py +76 -11
  151. {cgmath-1.0.4 → cgmath-3.0.0}/render/scene.py +1017 -419
  152. cgmath-3.0.0/transforms/_numba/__init__.py +116 -0
  153. {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_axis.py +2 -2
  154. {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_euler.py +69 -4
  155. {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_matrix.py +8 -8
  156. {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_quaternion.py +142 -43
  157. cgmath-3.0.0/transforms/_numba/_vector.py +413 -0
  158. cgmath-3.0.0/transforms/_tests/__init__.py +1 -0
  159. cgmath-3.0.0/transforms/_tests/test_axis.py +167 -0
  160. cgmath-3.0.0/transforms/_tests/test_broadcasting.py +357 -0
  161. cgmath-3.0.0/transforms/_tests/test_euler.py +411 -0
  162. cgmath-3.0.0/transforms/_tests/test_exports.py +43 -0
  163. cgmath-3.0.0/transforms/_tests/test_matrix.py +125 -0
  164. cgmath-3.0.0/transforms/_tests/test_quaternion.py +137 -0
  165. cgmath-3.0.0/transforms/_tests/test_rotation_conversions.py +403 -0
  166. cgmath-3.0.0/transforms/_tests/test_slerp.py +909 -0
  167. cgmath-3.0.0/transforms/_tests/test_threads.py +392 -0
  168. cgmath-3.0.0/transforms/_tests/test_vector.py +183 -0
  169. {cgmath-1.0.4 → cgmath-3.0.0}/transforms/main.py +248 -93
  170. {cgmath-1.0.4 → cgmath-3.0.0}/transforms/utils.py +1 -1
  171. {cgmath-1.0.4 → cgmath-3.0.0}/utils.py +252 -33
  172. cgmath-1.0.4/cgmath.egg-info/SOURCES.txt +0 -178
  173. cgmath-1.0.4/geometry/_base.py +0 -890
  174. cgmath-1.0.4/geometry/bspline.py +0 -1225
  175. cgmath-1.0.4/geometry/camera.py +0 -38
  176. cgmath-1.0.4/geometry/delta_mush.py +0 -29
  177. cgmath-1.0.4/geometry/ffd.py +0 -29
  178. cgmath-1.0.4/geometry/morph_target.py +0 -494
  179. cgmath-1.0.4/geometry/patch_relax.py +0 -29
  180. cgmath-1.0.4/geometry/raytracer.py +0 -38
  181. cgmath-1.0.4/geometry/resample.py +0 -393
  182. cgmath-1.0.4/geometry/surface_plotting.py +0 -1077
  183. cgmath-1.0.4/geometry/texture.py +0 -29
  184. cgmath-1.0.4/geometry/utils/_numba/_bspline.py +0 -2350
  185. cgmath-1.0.4/geometry/utils/_numba/_skin_deform.py +0 -535
  186. cgmath-1.0.4/hierarchy/hierarchy.py +0 -3841
  187. cgmath-1.0.4/transforms/_numba/__init__.py +0 -15
  188. cgmath-1.0.4/transforms/_numba/_vector.py +0 -266
  189. {cgmath-1.0.4 → cgmath-3.0.0}/LICENSE +0 -0
  190. {cgmath-1.0.4 → cgmath-3.0.0}/cgmath.egg-info/dependency_links.txt +0 -0
  191. {cgmath-1.0.4 → cgmath-3.0.0}/cgmath.egg-info/requires.txt +0 -0
  192. {cgmath-1.0.4 → cgmath-3.0.0}/cgmath.egg-info/top_level.txt +0 -0
  193. {cgmath-1.0.4 → cgmath-3.0.0}/constraints/__init__.py +0 -0
  194. {cgmath-1.0.4 → cgmath-3.0.0}/formats/__init__.py +0 -0
  195. {cgmath-1.0.4 → cgmath-3.0.0}/formats/usd/__init__.py +0 -0
  196. {cgmath-1.0.4 → cgmath-3.0.0}/formats/usd/prim.py +0 -0
  197. {cgmath-1.0.4 → cgmath-3.0.0}/formats/usd/stage.py +0 -0
  198. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/_cdt.py +0 -0
  199. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/__init__.py +0 -0
  200. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/pack.py +0 -0
  201. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/robust_skinweights_transfer_bilinear.py +0 -0
  202. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/__init__.py +0 -0
  203. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_blur.py +0 -0
  204. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_bvh.py +0 -0
  205. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_connectivity.py +0 -0
  206. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_delta_mush.py +0 -0
  207. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_normals.py +0 -0
  208. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_pack.py +0 -0
  209. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_patch_relax.py +0 -0
  210. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_rasterize.py +0 -0
  211. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_sdf.py +0 -0
  212. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_subdivide.py +0 -0
  213. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_subdivision.py +0 -0
  214. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_tangent_space.py +0 -0
  215. {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_wrap.py +0 -0
  216. {cgmath-1.0.4 → cgmath-3.0.0}/rbf/__init__.py +0 -0
  217. {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_kernels.py +0 -0
  218. {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_numba/__init__.py +0 -0
  219. {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_numba/_kernels.py +0 -0
  220. {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_numba/_lu.py +0 -0
  221. {cgmath-1.0.4 → cgmath-3.0.0}/render/__init__.py +0 -0
  222. {cgmath-1.0.4 → cgmath-3.0.0}/render/_numba/__init__.py +0 -0
  223. {cgmath-1.0.4 → cgmath-3.0.0}/render/_numba/_texture.py +0 -0
  224. {cgmath-1.0.4 → cgmath-3.0.0}/render/camera.py +0 -0
  225. {cgmath-1.0.4 → cgmath-3.0.0}/render/frame.py +0 -0
  226. {cgmath-1.0.4 → cgmath-3.0.0}/render/texture.py +0 -0
  227. {cgmath-1.0.4 → cgmath-3.0.0}/setup.cfg +0 -0
  228. {cgmath-1.0.4 → cgmath-3.0.0}/transforms/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cgmath
3
- Version: 1.0.4
3
+ Version: 3.0.0
4
4
  Summary: A DCC-agnostic CG math library: batched matrix, quaternion and euler math, mesh topology, deformers, resampling, skeletal hierarchies, SDFs, a software raytracer and asset IO, all numpy-native.
5
5
  Author-email: Eric Vignola <eric.vignola@gmail.com>
6
6
  License: ## License
@@ -133,8 +133,9 @@ for it) and a **CHEATSHEET** (every public name, with a runnable example).
133
133
  | `cgmath.constraints` | `ProcrustesData` — rivet a transform to a deforming patch | [README](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/README.md) · [CHEATSHEET](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/CHEATSHEET.md) |
134
134
 
135
135
  [`REFERENCE.md`](https://github.com/Eric-Vignola/cgmath/blob/main/REFERENCE.md), a flat API listing, also sits in this
136
- directory. It is generated from the live code by `gen_reference.py` (kept in
137
- the `tools/` folder beside the packages, not in this repository): every public
136
+ directory. It is generated from the live code by `gen_reference.py` (kept
137
+ outside this repository, in the maintainer's own tools folder; the
138
+ repository's `tools/` holds only the Maya fixture generator): every public
138
139
  name with its real signature and first docstring line.
139
140
 
140
141
  ---
@@ -146,6 +147,7 @@ name with its real signature and first docstring line.
146
147
 
147
148
  ```
148
149
  cgmath/
150
+ ├── data.py Data / DataList / Array / ImmutableArray + serialization
149
151
  ├── utils.py info() / docstring(), pretty_json, profile(), run_tests()
150
152
  │
151
153
  ├── hierarchy/ TransformData, TransformList, HierarchyData, ClipData
@@ -153,15 +155,12 @@ cgmath/
153
155
  │ └── hierarchy.py the four types, the fbx / glb readers, the batched clip evaluator
154
156
  │
155
157
  ├── geometry/ meshes, UVs, curves, fields, transfer
156
- │ ├── _base.py Data / DataList / ImmutableArray + serialization
157
158
  │ ├── mesh.py MeshData, MeshList, UVData, UVList, the loaders
158
159
  │ ├── map.py morph_target.py skin_weights.py MapData, MorphData, SkinData
159
160
  │ ├── bspline.py bspline_patch.py _saddle_surface.py _cdt.py
160
161
  │ ├── sdf.py SDF primitives + dual marching cubes
161
- │ ├── pack.py resample.py surface_plotting.py
162
+ │ ├── pack.py resample.py
162
163
  │ ├── robust_skinweights_transfer_bilinear.py
163
- │ ├── camera.py delta_mush.py ffd.py patch_relax.py raytracer.py texture.py
164
- │ │ one-release deprecation shims -- they warn and re-export
165
164
  │ ├── deform/ FFDData, DeltaMushData, PatchRelaxData,
166
165
  │ │ SkinDeformData, WrapData
167
166
  │ └── utils/ main.py + _numba/ -- the kernel floor
@@ -170,7 +169,10 @@ cgmath/
170
169
  ├── render/ scene.py raytracer.py camera.py frame.py texture.py
171
170
  ├── formats/ fbx.py, glb.py, usd/prim.py, usd/stage.py
172
171
  ├── rbf/ _kernels.py + _numba/ (__init__.py is a docstring, on purpose)
173
- └── constraints/ procrustes.py
172
+ ├── constraints/ procrustes.py
173
+ │
174
+ └── _tests/ the test suite + test_assets/, the fixtures it reads;
175
+ transforms/_tests/ holds the transforms suite
174
176
  ```
175
177
 
176
178
  The batched matrix / quaternion / euler / axis / vector functions that all
@@ -225,6 +227,13 @@ If you know Maya, nothing below will surprise you.
225
227
  face and a raycast miss.
226
228
  - **A mesh is a face-vertex stream**, `indices` + `counts` + `points`.
227
229
  Mixed triangles, quads and n-gons in one mesh are normal.
230
+ - **Arrays have fixed dtypes.** Indices and counts are `int32`; points,
231
+ normals, offsets, weights and values are `float64`; masks are `bool`. A
232
+ value is converted when it is set or loaded.
233
+ - **One saved form.** `.pkl`, `.npz` and `.json` hold the same tree and
234
+ load as the class they name. A file written by an older cgmath raises
235
+ `LegacyFileError` — details in
236
+ [`geometry/README.md`](https://github.com/Eric-Vignola/cgmath/blob/main/geometry/README.md#saving-and-loading).
228
237
  - **Camera is OpenGL**: `-Z` forward, `+Y` up, `+X` right. `look_at()`
229
238
  and `Frame.camera_matrix` are **column**-major (eye at `M[:3, 3]`)
230
239
  while node matrices are row-major (eye at `M[3, :3]`).
@@ -275,7 +284,7 @@ Each block below builds on the `cube` from the top of this page.
275
284
  ```python
276
285
  print(cube.point_count, cube.face_count, cube.edge_count) # 8 6 12
277
286
  print(cube.closed, cube.quads, round(cube.area, 4)) # True 6 6.0
278
- print(cube.get_border_vertices(flatten=True)) # [] -- closed
287
+ print(cube.get_border_vertices(flatten=True)) # [] -- closed, an empty int32 array
279
288
  print(cube.e2v.shape, cube.ue2v.shape) # (12, 2) deduped vs (24, 2) raw
280
289
  ```
281
290
 
@@ -399,6 +408,28 @@ second `pxr` on `sys.path` conflicts with the one the host has loaded.
399
408
  The Autodesk FBX SDK (FBX read and write) is not on PyPI; install it by hand.
400
409
 
401
410
 
411
+ ## Tests
412
+
413
+ Both test suites ship in the wheel, `cgmath._tests` with the fixtures it
414
+ reads and `cgmath.transforms._tests`, so an installed copy tests itself as a
415
+ checkout does. `run_tests()` with no target runs both suites; a module, a
416
+ class, one test or a filename glob narrows it, found in whichever suite
417
+ holds it:
418
+
419
+ ```python
420
+ from cgmath.utils import run_tests
421
+
422
+ result = run_tests("test_exports", verbosity=0) # one module of the transforms suite
423
+ assert result.wasSuccessful()
424
+ ```
425
+
426
+ From a shell, `python -m cgmath.utils` runs everything and exits 0 when it
427
+ all passes. A test that needs an optional dependency the install lacks,
428
+ such as the FBX SDK, `pxr`, Pillow or pygltflib, is skipped, so a plain
429
+ `pip install cgmath` passes too, with more tests skipped than under
430
+ `cgmath[all]`.
431
+
432
+
402
433
  ## Author
403
434
 
404
435
  * **Eric Vignola** (eric.vignola@gmail.com)
@@ -61,8 +61,9 @@ for it) and a **CHEATSHEET** (every public name, with a runnable example).
61
61
  | `cgmath.constraints` | `ProcrustesData` — rivet a transform to a deforming patch | [README](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/README.md) · [CHEATSHEET](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/CHEATSHEET.md) |
62
62
 
63
63
  [`REFERENCE.md`](https://github.com/Eric-Vignola/cgmath/blob/main/REFERENCE.md), a flat API listing, also sits in this
64
- directory. It is generated from the live code by `gen_reference.py` (kept in
65
- the `tools/` folder beside the packages, not in this repository): every public
64
+ directory. It is generated from the live code by `gen_reference.py` (kept
65
+ outside this repository, in the maintainer's own tools folder; the
66
+ repository's `tools/` holds only the Maya fixture generator): every public
66
67
  name with its real signature and first docstring line.
67
68
 
68
69
  ---
@@ -74,6 +75,7 @@ name with its real signature and first docstring line.
74
75
 
75
76
  ```
76
77
  cgmath/
78
+ ├── data.py Data / DataList / Array / ImmutableArray + serialization
77
79
  ├── utils.py info() / docstring(), pretty_json, profile(), run_tests()
78
80
  │
79
81
  ├── hierarchy/ TransformData, TransformList, HierarchyData, ClipData
@@ -81,15 +83,12 @@ cgmath/
81
83
  │ └── hierarchy.py the four types, the fbx / glb readers, the batched clip evaluator
82
84
  │
83
85
  ├── geometry/ meshes, UVs, curves, fields, transfer
84
- │ ├── _base.py Data / DataList / ImmutableArray + serialization
85
86
  │ ├── mesh.py MeshData, MeshList, UVData, UVList, the loaders
86
87
  │ ├── map.py morph_target.py skin_weights.py MapData, MorphData, SkinData
87
88
  │ ├── bspline.py bspline_patch.py _saddle_surface.py _cdt.py
88
89
  │ ├── sdf.py SDF primitives + dual marching cubes
89
- │ ├── pack.py resample.py surface_plotting.py
90
+ │ ├── pack.py resample.py
90
91
  │ ├── robust_skinweights_transfer_bilinear.py
91
- │ ├── camera.py delta_mush.py ffd.py patch_relax.py raytracer.py texture.py
92
- │ │ one-release deprecation shims -- they warn and re-export
93
92
  │ ├── deform/ FFDData, DeltaMushData, PatchRelaxData,
94
93
  │ │ SkinDeformData, WrapData
95
94
  │ └── utils/ main.py + _numba/ -- the kernel floor
@@ -98,7 +97,10 @@ cgmath/
98
97
  ├── render/ scene.py raytracer.py camera.py frame.py texture.py
99
98
  ├── formats/ fbx.py, glb.py, usd/prim.py, usd/stage.py
100
99
  ├── rbf/ _kernels.py + _numba/ (__init__.py is a docstring, on purpose)
101
- └── constraints/ procrustes.py
100
+ ├── constraints/ procrustes.py
101
+ │
102
+ └── _tests/ the test suite + test_assets/, the fixtures it reads;
103
+ transforms/_tests/ holds the transforms suite
102
104
  ```
103
105
 
104
106
  The batched matrix / quaternion / euler / axis / vector functions that all
@@ -153,6 +155,13 @@ If you know Maya, nothing below will surprise you.
153
155
  face and a raycast miss.
154
156
  - **A mesh is a face-vertex stream**, `indices` + `counts` + `points`.
155
157
  Mixed triangles, quads and n-gons in one mesh are normal.
158
+ - **Arrays have fixed dtypes.** Indices and counts are `int32`; points,
159
+ normals, offsets, weights and values are `float64`; masks are `bool`. A
160
+ value is converted when it is set or loaded.
161
+ - **One saved form.** `.pkl`, `.npz` and `.json` hold the same tree and
162
+ load as the class they name. A file written by an older cgmath raises
163
+ `LegacyFileError` — details in
164
+ [`geometry/README.md`](https://github.com/Eric-Vignola/cgmath/blob/main/geometry/README.md#saving-and-loading).
156
165
  - **Camera is OpenGL**: `-Z` forward, `+Y` up, `+X` right. `look_at()`
157
166
  and `Frame.camera_matrix` are **column**-major (eye at `M[:3, 3]`)
158
167
  while node matrices are row-major (eye at `M[3, :3]`).
@@ -203,7 +212,7 @@ Each block below builds on the `cube` from the top of this page.
203
212
  ```python
204
213
  print(cube.point_count, cube.face_count, cube.edge_count) # 8 6 12
205
214
  print(cube.closed, cube.quads, round(cube.area, 4)) # True 6 6.0
206
- print(cube.get_border_vertices(flatten=True)) # [] -- closed
215
+ print(cube.get_border_vertices(flatten=True)) # [] -- closed, an empty int32 array
207
216
  print(cube.e2v.shape, cube.ue2v.shape) # (12, 2) deduped vs (24, 2) raw
208
217
  ```
209
218
 
@@ -327,6 +336,28 @@ second `pxr` on `sys.path` conflicts with the one the host has loaded.
327
336
  The Autodesk FBX SDK (FBX read and write) is not on PyPI; install it by hand.
328
337
 
329
338
 
339
+ ## Tests
340
+
341
+ Both test suites ship in the wheel, `cgmath._tests` with the fixtures it
342
+ reads and `cgmath.transforms._tests`, so an installed copy tests itself as a
343
+ checkout does. `run_tests()` with no target runs both suites; a module, a
344
+ class, one test or a filename glob narrows it, found in whichever suite
345
+ holds it:
346
+
347
+ ```python
348
+ from cgmath.utils import run_tests
349
+
350
+ result = run_tests("test_exports", verbosity=0) # one module of the transforms suite
351
+ assert result.wasSuccessful()
352
+ ```
353
+
354
+ From a shell, `python -m cgmath.utils` runs everything and exits 0 when it
355
+ all passes. A test that needs an optional dependency the install lacks,
356
+ such as the FBX SDK, `pxr`, Pillow or pygltflib, is skipped, so a plain
357
+ `pip install cgmath` passes too, with more tests skipped than under
358
+ `cgmath[all]`.
359
+
360
+
330
361
  ## Author
331
362
 
332
363
  * **Eric Vignola** (eric.vignola@gmail.com)
@@ -4,4 +4,4 @@ The underlying matrix, quaternion, euler and vector math lives in
4
4
  :mod:`cgmath.transforms`.
5
5
  """
6
6
 
7
- __version__ = "1.0.4"
7
+ __version__ = "3.0.0"
@@ -0,0 +1 @@
1
+ """Unit tests for the :mod:`cgmath` package."""
@@ -0,0 +1,198 @@
1
+ """
2
+ Round-trip builders for the curve and surface data: BSplineData and its
3
+ sample, BSplinePatchData and its sample and raycast, the saddle surface's
4
+ sample and raycast, and ProcrustesData.
5
+
6
+ Each builder makes a new object the way users do, through the public
7
+ constructors, fit, sample and raycast, with every saved field away from its
8
+ default where that is valid. ``test_roundtrip`` saves and loads each one.
9
+ None of these classes has a name or nested data. Their arrays share one
10
+ length, so an empty one leaves them all empty: ``test_curves_empty`` round
11
+ trips those.
12
+ """
13
+
14
+ import numpy as np
15
+ from cgmath.constraints.procrustes import ProcrustesData
16
+ from cgmath.geometry._saddle_surface import RaycastData as SaddleRaycastData
17
+ from cgmath.geometry._saddle_surface import SampleData as SaddleSampleData
18
+ from cgmath.geometry.bspline import BSplineData
19
+ from cgmath.geometry.bspline import SampleData as CurveSampleData
20
+ from cgmath.geometry.bspline_patch import (
21
+ BSplinePatchData,
22
+ PatchRaycastData,
23
+ PatchSampleData,
24
+ )
25
+ from cgmath.geometry.mesh import MeshData
26
+
27
+ # ---------------------------------- SHAPES ---------------------------------- #
28
+
29
+
30
+ def arm(n=6):
31
+ """the joint positions of a bending arm chain"""
32
+ t = np.linspace(0.0, 1.0, n)
33
+ return np.column_stack([t * 10.0, np.sin(t * 3.0) * 2.0, np.cos(t * 2.0)])
34
+
35
+
36
+ def ring(n=8):
37
+ """a closed loop of n points, an ellipse that rises and falls twice"""
38
+ a = np.linspace(0.0, 2.0 * np.pi, n, endpoint=False)
39
+ return np.column_stack([np.cos(a) * 4.0, np.sin(a) * 2.5, np.sin(a * 2.0) * 0.5])
40
+
41
+
42
+ def tube(nu=6, nv=5):
43
+ """the control grid of a tube: u closes around it, v runs along it"""
44
+ a = np.linspace(0.0, 2.0 * np.pi, nu, endpoint=False)[:, None]
45
+ height = np.linspace(0.0, 6.0, nv)[None, :]
46
+ radius = 2.0 + 0.3 * np.sin(height)
47
+ return np.stack(
48
+ np.broadcast_arrays(np.cos(a) * radius, np.sin(a) * radius, height), axis=-1
49
+ )
50
+
51
+
52
+ def sheet(nu=5, nv=6):
53
+ """the control grid of a wavy sheet in the xy plane, facing +z"""
54
+ u, v = np.meshgrid(np.linspace(-4, 4, nu), np.linspace(-5, 5, nv), indexing="ij")
55
+ return np.stack([u, v, np.sin(u * 0.5) * np.cos(v * 0.5)], axis=-1)
56
+
57
+
58
+ def strip():
59
+ """a mesh of one quad and two triangles, facing +z"""
60
+ points = np.array(
61
+ [
62
+ [0.0, 0.0, 0.0],
63
+ [1.0, 0.0, 0.0],
64
+ [2.0, 0.0, 0.2],
65
+ [0.0, 1.0, 0.0],
66
+ [1.0, 1.0, 0.0],
67
+ [2.0, 1.0, 0.2],
68
+ ]
69
+ )
70
+ return MeshData(
71
+ points = points,
72
+ indices = np.array([0, 1, 4, 3, 1, 2, 5, 1, 5, 4]),
73
+ counts = np.array([4, 3, 3]),
74
+ )
75
+
76
+
77
+ # --------------------------------- BUILDERS --------------------------------- #
78
+
79
+
80
+ def curve() -> BSplineData:
81
+ """a closed quadratic through a ring of edit points, every setting changed"""
82
+ return BSplineData.from_edit_points(
83
+ ring(),
84
+ degree = 2,
85
+ periodic = True,
86
+ uniform = True,
87
+ registered = True,
88
+ use_numba = False,
89
+ arc_length_samples = 257,
90
+ )
91
+
92
+
93
+ def curve_sample() -> CurveSampleData:
94
+ """points beside a spine with stacked ends and Maya's knots, projected onto it"""
95
+ spine = BSplineData.from_edit_points(arm(), collapse=(2, 2))
96
+ offsets = np.array(
97
+ [
98
+ [0.0, 0.5, 0.0],
99
+ [0.2, -0.4, 0.3],
100
+ [0.0, 0.0, -0.6],
101
+ [-0.3, 0.2, 0.1],
102
+ [0.4, 0.4, 0.4], # past the stacked end, where there is no tangent
103
+ ]
104
+ )
105
+ return spine.sample(arm(5) + offsets)
106
+
107
+
108
+ def patch() -> BSplinePatchData:
109
+ """a tube closed in u, open in v, every setting changed"""
110
+ return BSplinePatchData(
111
+ points = tube(),
112
+ degree_u = 2,
113
+ degree_v = 3,
114
+ periodic_u = True,
115
+ periodic_v = False,
116
+ uniform_u = True,
117
+ uniform_v = True,
118
+ use_numba = False,
119
+ registered_u = True,
120
+ registered_v = True,
121
+ arc_length_samples = 300,
122
+ )
123
+
124
+
125
+ def patch_sample() -> PatchSampleData:
126
+ """points inside and outside a tube, projected onto it"""
127
+ surface = BSplinePatchData(
128
+ points=tube(), degree_u=2, degree_v=3, periodic_u=True, periodic_v=False
129
+ )
130
+ queries = np.array(
131
+ [[3.0, 0.0, 1.0], [0.0, 1.0, 2.5], [-2.5, -2.5, 4.0], [0.5, -3.0, 5.5]]
132
+ )
133
+ return surface.sample(queries)
134
+
135
+
136
+ def patch_raycast() -> PatchRaycastData:
137
+ """rays down onto a sheet, one up into it from below, and one that misses (NaN)"""
138
+ surface = BSplinePatchData(
139
+ points=sheet(), degree_u=3, degree_v=3, periodic_u=False, periodic_v=False
140
+ )
141
+ origins = np.array(
142
+ [[0.0, 0.0, 5.0], [1.0, -2.0, 5.0], [-1.0, 1.0, -5.0], [40.0, 40.0, 5.0]]
143
+ )
144
+ directions = np.array(
145
+ [[0.0, 0.0, -1.0], [0.0, 0.0, -1.0], [0.0, 0.0, 1.0], [0.0, 0.0, -1.0]]
146
+ )
147
+ return surface.raycast(origins, directions, forward_only=False)
148
+
149
+
150
+ def saddle_sample() -> SaddleSampleData:
151
+ """points above, below and on a quad-and-triangles mesh, sampled on it"""
152
+ queries = np.array(
153
+ [
154
+ [0.5, 0.5, 0.5], # above the quad
155
+ [0.3, 0.6, -0.4], # below it: occluded
156
+ [1.6, 0.4, 0.3], # above a triangle: its geometry is -1 padded
157
+ [2.0, 1.0, 0.2], # on a vertex: matched exactly
158
+ ]
159
+ )
160
+ return strip().sample(queries)
161
+
162
+
163
+ def saddle_raycast() -> SaddleRaycastData:
164
+ """a ray down onto a quad, one up into a triangle, and one that misses (NaN, -1)"""
165
+ origins = np.array([[0.5, 0.5, 2.0], [1.7, 0.5, -2.0], [9.0, 9.0, 2.0]])
166
+ directions = np.array([[0.0, 0.0, -1.0], [0.0, 0.0, 1.0], [0.0, 0.0, -1.0]])
167
+ return strip().raycast(origins, directions, forward_only=False)
168
+
169
+
170
+ def procrustes() -> ProcrustesData:
171
+ """a cube held by two clusters, one of half its points, no scale offset"""
172
+ cube = np.array(
173
+ [[x, y, z] for z in (0.5, -0.5) for y in (-0.5, 0.5) for x in (-0.5, 0.5)]
174
+ )
175
+ lid = np.eye(4)
176
+ lid[3, :3] = [0.0, 0.5, 0.0]
177
+
178
+ constraint = ProcrustesData(cube)
179
+ constraint.attach(lid, [2, 3, 4, 5]) # the shorter cluster is -1 padded
180
+ constraint.attach(np.eye(4))
181
+ constraint.scale_offset = False
182
+
183
+ moved = cube * 1.2
184
+ moved[:2, 2] += 0.3
185
+ constraint.update(moved) # the per-frame target and results are not saved
186
+ return constraint
187
+
188
+
189
+ EXAMPLES = {
190
+ BSplineData: curve,
191
+ CurveSampleData: curve_sample,
192
+ BSplinePatchData: patch,
193
+ PatchSampleData: patch_sample,
194
+ PatchRaycastData: patch_raycast,
195
+ SaddleSampleData: saddle_sample,
196
+ SaddleRaycastData: saddle_raycast,
197
+ ProcrustesData: procrustes,
198
+ }
@@ -0,0 +1,171 @@
1
+ """Filled-in deformers, for test_roundtrip.
2
+
3
+ Each builder makes a deformer the way a user does -- from a mesh, a skin, a
4
+ rig or a lattice -- changes every setting from its default and binds it, so
5
+ every saved field holds a value of its own. The meshes are small: a few dozen
6
+ points.
7
+ """
8
+
9
+ import numpy as np
10
+ from cgmath.geometry.deform import (
11
+ DeltaMushData,
12
+ FFDData,
13
+ PatchRelaxData,
14
+ SkinDeformData,
15
+ WrapData,
16
+ )
17
+ from cgmath.geometry.mesh import MeshData
18
+ from cgmath.geometry.skin_weights import SkinData
19
+ from cgmath.hierarchy import HierarchyData, TransformData
20
+
21
+
22
+ def _grid(n: int = 6, height: float = 0.3, name: str = "grid") -> MeshData:
23
+ """an open quad grid on XY with a sine bump in Z: it has a border"""
24
+ t = np.linspace(0.0, 1.0, n)
25
+ points = np.array([[x, y, 0.0] for y in t for x in t])
26
+ points[:, 2] = height * np.sin(np.pi * points[:, 0]) * np.sin(np.pi * points[:, 1])
27
+
28
+ indices = []
29
+ for j in range(n - 1):
30
+ for i in range(n - 1):
31
+ a = j * n + i
32
+ indices.extend([a, a + 1, a + n + 1, a + n])
33
+
34
+ return MeshData(
35
+ points = points,
36
+ indices = np.asarray(indices, dtype=np.int32),
37
+ counts = np.full((n - 1) ** 2, 4, dtype=np.int32),
38
+ name = name,
39
+ )
40
+
41
+
42
+ def _torus(around: int = 8, across: int = 6, name: str = "torus") -> MeshData:
43
+ """a closed quad torus: it has no border"""
44
+ u = np.linspace(0.0, 2.0 * np.pi, around, endpoint=False)
45
+ v = np.linspace(0.0, 2.0 * np.pi, across, endpoint=False)
46
+ uu, vv = np.meshgrid(u, v, indexing="ij")
47
+ ring = 1.0 + 0.35 * np.cos(vv)
48
+ points = np.stack(
49
+ [ring * np.cos(uu), ring * np.sin(uu), 0.35 * np.sin(vv)], axis=-1
50
+ ).reshape(-1, 3)
51
+
52
+ indices = []
53
+ for i in range(around):
54
+ for j in range(across):
55
+ k, l = (i + 1) % around, (j + 1) % across
56
+ indices.extend(
57
+ [i * across + j, k * across + j, k * across + l, i * across + l]
58
+ )
59
+
60
+ return MeshData(
61
+ points = points,
62
+ indices = np.asarray(indices, dtype=np.int32),
63
+ counts = np.full(around * across, 4, dtype=np.int32),
64
+ name = name,
65
+ )
66
+
67
+
68
+ def delta_mush() -> DeltaMushData:
69
+ """bound with DDM on an open mesh; pinning turned off after the border was read"""
70
+ mush = DeltaMushData(
71
+ _grid(),
72
+ smooth_iterations = 6,
73
+ smooth_step_size = 0.4,
74
+ weight = 0.7,
75
+ method = "ddm",
76
+ )
77
+ # the border read at construction stays saved, pinned or not
78
+ mush.pin_borders = False
79
+ mush.bind()
80
+ return mush
81
+
82
+
83
+ def patch_relax() -> PatchRelaxData:
84
+ """bound on a closed mesh, so its border is an empty array, with a painted mask"""
85
+ mesh = _torus()
86
+ relaxer = PatchRelaxData(
87
+ mesh,
88
+ iterations = 12,
89
+ alpha = 0.8,
90
+ surface_blend = 0.3,
91
+ step_size = 0.4,
92
+ pin_borders = False,
93
+ mask = np.linspace(0.0, 1.0, len(mesh.points)),
94
+ )
95
+ relaxer.bind()
96
+ return relaxer
97
+
98
+
99
+ def ffd() -> FFDData:
100
+ """a lattice over part of a mesh, bound, with falloff past its edge"""
101
+ lattice = FFDData.create_lattice(
102
+ (3, 4, 3), bbox_min=[-0.1, -0.1, -0.5], bbox_max=[0.7, 1.1, 0.5], name="ffd_box"
103
+ )
104
+ ffd = FFDData.from_mesh(lattice, divisions=(3, 4, 3))
105
+ ffd.local_influence = (3, 4, 2)
106
+ ffd.outside = "falloff"
107
+ ffd.falloff_radius = 1.5
108
+
109
+ # the grid runs to x = 1, past the lattice: those points fall off
110
+ ffd.bind(_grid())
111
+
112
+ deformed = ffd.lattice.copy()
113
+ deformed[:, :, -1, 2] += 0.4
114
+ ffd.update(deformed)
115
+ return ffd
116
+
117
+
118
+ def skin_deform() -> SkinDeformData:
119
+ """dual quaternion, bound, its matrices from a bind rig, joints reordered"""
120
+ root = TransformData(name="A:root", translate=(0.0, 0.0, 0.0))
121
+ spine = TransformData(name="A:spine", translate=(0.5, 0.0, 0.0))
122
+ tip = TransformData(name="A:tip", translate=(0.5, 0.0, 0.0), rotate=(0.0, 0.0, 15.0))
123
+ rig = HierarchyData([root, spine, tip])
124
+
125
+ spine.parent_uuid = root.uuid
126
+ tip.parent_uuid = spine.uuid
127
+
128
+ mesh = _grid(name="A:body")
129
+ x = mesh.points[:, 0]
130
+ # at most two influences per vertex: root fades into spine, spine into tip
131
+ weights = np.zeros((len(x), 3))
132
+ low, high = x <= 0.5, x > 0.5
133
+ weights[low, 0] = 1.0 - 2.0 * x[low]
134
+ weights[low, 1] = 2.0 * x[low]
135
+ weights[high, 1] = 2.0 - 2.0 * x[high]
136
+ weights[high, 2] = 2.0 * x[high] - 1.0
137
+ skin = SkinData(weights=weights, influences=["A:root", "A:spine", "A:tip"], name="A:skin")
138
+
139
+ deformer = SkinDeformData(
140
+ mesh,
141
+ skin,
142
+ bind_rig = rig,
143
+ joints = ["A:tip", "A:root", "A:spine"],
144
+ method = "dqs",
145
+ name = "A:body_skin",
146
+ )
147
+ deformer.bind()
148
+ return deformer
149
+
150
+
151
+ def wrap() -> WrapData:
152
+ """a geodesic cage wrap with a compact kernel, solved, so its pseudo-inverse is saved"""
153
+ cage = _grid(4, height=0.4, name="cage")
154
+ moved = cage.points + np.random.default_rng(5).normal(scale=0.05, size=cage.points.shape)
155
+
156
+ wrap = WrapData(kernel="wendland_c2", name="cage_wrap")
157
+ wrap.set_source(cage)
158
+ wrap.set_target(moved)
159
+ wrap.set_radius(0.9)
160
+ wrap.set_geodesic_radius(1.0)
161
+ wrap.deform(_grid().points)
162
+ return wrap
163
+
164
+
165
+ EXAMPLES = {
166
+ DeltaMushData: delta_mush,
167
+ FFDData: ffd,
168
+ PatchRelaxData: patch_relax,
169
+ SkinDeformData: skin_deform,
170
+ WrapData: wrap,
171
+ }