cgmath 1.0.3__tar.gz → 2.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 (213) hide show
  1. {cgmath-1.0.3/cgmath.egg-info → cgmath-2.0.0}/PKG-INFO +73 -23
  2. {cgmath-1.0.3 → cgmath-2.0.0}/README.md +56 -16
  3. {cgmath-1.0.3 → cgmath-2.0.0}/__init__.py +1 -1
  4. cgmath-2.0.0/_tests/__init__.py +1 -0
  5. cgmath-2.0.0/_tests/_examples_curves.py +198 -0
  6. cgmath-2.0.0/_tests/_examples_deform.py +171 -0
  7. cgmath-2.0.0/_tests/_examples_geometry.py +366 -0
  8. cgmath-2.0.0/_tests/_examples_hierarchy.py +277 -0
  9. cgmath-2.0.0/_tests/_examples_render.py +266 -0
  10. cgmath-2.0.0/_tests/_maya_rotate_order.py +64 -0
  11. cgmath-2.0.0/_tests/test_assets/maya_euler.npz +0 -0
  12. cgmath-2.0.0/_tests/test_assets/mikktspace_deformed_data.json +1331 -0
  13. cgmath-2.0.0/_tests/test_assets/mikktspace_test_data.json +1836 -0
  14. cgmath-2.0.0/_tests/test_assets/test_geometry.bspline_best_fit_params.npz +0 -0
  15. cgmath-2.0.0/_tests/test_assets/test_geometry.bspline_maya_curves.json +67 -0
  16. cgmath-2.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.json +136 -0
  17. cgmath-2.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.npz +0 -0
  18. cgmath-2.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.pkl +0 -0
  19. cgmath-2.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node_clip.json +331 -0
  20. cgmath-2.0.0/_tests/test_assets/test_hierarchy.results.npz +0 -0
  21. cgmath-2.0.0/_tests/test_assets/test_hierarchy.skeleton.json +1064 -0
  22. cgmath-2.0.0/_tests/test_assets/test_ngon.bitmap_buffer.npz +0 -0
  23. cgmath-2.0.0/_tests/test_assets/test_ngon.source_mesh_data.json +1547 -0
  24. cgmath-2.0.0/_tests/test_assets/test_ngon.source_uv_list.json +2349 -0
  25. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data.npz +0 -0
  26. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_ngons_only.npz +0 -0
  27. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_preserve_order.npz +0 -0
  28. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_preserve_order_ngons_only.npz +0 -0
  29. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_uv_list.npz +0 -0
  30. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_ngons_only.npz +0 -0
  31. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_preserve_order.npz +0 -0
  32. cgmath-2.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_preserve_order_ngons_only.npz +0 -0
  33. cgmath-2.0.0/_tests/test_assets/test_resample.dst_bs_data.npz +0 -0
  34. cgmath-2.0.0/_tests/test_assets/test_resample.dst_mesh_data.npz +0 -0
  35. cgmath-2.0.0/_tests/test_assets/test_resample.dst_skin_data.npz +0 -0
  36. cgmath-2.0.0/_tests/test_assets/test_resample.dst_uv_data.npz +0 -0
  37. cgmath-2.0.0/_tests/test_assets/test_resample.overlap.pkl +0 -0
  38. cgmath-2.0.0/_tests/test_assets/test_resample.src_bs_data.npz +0 -0
  39. cgmath-2.0.0/_tests/test_assets/test_resample.src_mesh_data.npz +0 -0
  40. cgmath-2.0.0/_tests/test_assets/test_resample.src_skin_data.npz +0 -0
  41. cgmath-2.0.0/_tests/test_assets/test_resample.src_uv_data.npz +0 -0
  42. cgmath-2.0.0/_tests/test_assets/test_sdf.igloo.npz +0 -0
  43. cgmath-2.0.0/_tests/test_base.py +1681 -0
  44. cgmath-2.0.0/_tests/test_base_setattr.py +348 -0
  45. cgmath-2.0.0/_tests/test_bspline_kernels.py +333 -0
  46. cgmath-2.0.0/_tests/test_clip.py +7838 -0
  47. cgmath-2.0.0/_tests/test_constraints.py +96 -0
  48. cgmath-2.0.0/_tests/test_curves_empty.py +90 -0
  49. cgmath-2.0.0/_tests/test_curves_types.py +538 -0
  50. cgmath-2.0.0/_tests/test_deform_files.py +314 -0
  51. cgmath-2.0.0/_tests/test_deform_utils.py +349 -0
  52. cgmath-2.0.0/_tests/test_delta_mush.py +538 -0
  53. cgmath-2.0.0/_tests/test_euler_maya.py +210 -0
  54. cgmath-2.0.0/_tests/test_fbx_export.py +1182 -0
  55. cgmath-2.0.0/_tests/test_fbx_import.py +978 -0
  56. cgmath-2.0.0/_tests/test_fbx_lifetime.py +1026 -0
  57. cgmath-2.0.0/_tests/test_ffd.py +573 -0
  58. cgmath-2.0.0/_tests/test_geometry.py +7372 -0
  59. cgmath-2.0.0/_tests/test_geometry_io.py +215 -0
  60. cgmath-2.0.0/_tests/test_geometry_utils.py +360 -0
  61. cgmath-2.0.0/_tests/test_glb.py +336 -0
  62. cgmath-2.0.0/_tests/test_glb_materials.py +182 -0
  63. cgmath-2.0.0/_tests/test_hierarchy.py +6704 -0
  64. cgmath-2.0.0/_tests/test_hierarchy_io.py +317 -0
  65. cgmath-2.0.0/_tests/test_imports.py +520 -0
  66. cgmath-2.0.0/_tests/test_map.py +91 -0
  67. cgmath-2.0.0/_tests/test_mesh_usd.py +58 -0
  68. cgmath-2.0.0/_tests/test_morph_target.py +640 -0
  69. cgmath-2.0.0/_tests/test_namespaces.py +235 -0
  70. cgmath-2.0.0/_tests/test_ngon.py +163 -0
  71. cgmath-2.0.0/_tests/test_normals_quadmatch_utils.py +287 -0
  72. cgmath-2.0.0/_tests/test_object_skin.py +846 -0
  73. cgmath-2.0.0/_tests/test_pack.py +206 -0
  74. cgmath-2.0.0/_tests/test_parent_lookups.py +393 -0
  75. cgmath-2.0.0/_tests/test_patch_relax.py +607 -0
  76. cgmath-2.0.0/_tests/test_procrustes_rotation.py +189 -0
  77. cgmath-2.0.0/_tests/test_quadrangulate.py +517 -0
  78. cgmath-2.0.0/_tests/test_raycast.py +1106 -0
  79. cgmath-2.0.0/_tests/test_raycast_bvh.py +193 -0
  80. cgmath-2.0.0/_tests/test_rbf.py +540 -0
  81. cgmath-2.0.0/_tests/test_render_cache.py +220 -0
  82. cgmath-2.0.0/_tests/test_render_fit_padding.py +343 -0
  83. cgmath-2.0.0/_tests/test_render_roundtrip_extra.py +143 -0
  84. cgmath-2.0.0/_tests/test_render_serialization.py +512 -0
  85. cgmath-2.0.0/_tests/test_resample.py +403 -0
  86. cgmath-2.0.0/_tests/test_resample_bezier.py +218 -0
  87. cgmath-2.0.0/_tests/test_robust_skinweights_transfer_bilinear.py +310 -0
  88. cgmath-2.0.0/_tests/test_roundtrip.py +1072 -0
  89. cgmath-2.0.0/_tests/test_saddle_surface.py +480 -0
  90. cgmath-2.0.0/_tests/test_scene.py +4035 -0
  91. cgmath-2.0.0/_tests/test_scene_animate.py +702 -0
  92. cgmath-2.0.0/_tests/test_sdf.py +379 -0
  93. cgmath-2.0.0/_tests/test_skin_deform.py +1506 -0
  94. cgmath-2.0.0/_tests/test_skin_fbx.py +322 -0
  95. cgmath-2.0.0/_tests/test_skin_glb.py +538 -0
  96. cgmath-2.0.0/_tests/test_skin_kernels.py +323 -0
  97. cgmath-2.0.0/_tests/test_skin_weights.py +1124 -0
  98. cgmath-2.0.0/_tests/test_symmetry.py +130 -0
  99. cgmath-2.0.0/_tests/test_triangulation.py +108 -0
  100. cgmath-2.0.0/_tests/test_usd_prim.py +47 -0
  101. cgmath-2.0.0/_tests/test_utils.py +686 -0
  102. cgmath-2.0.0/_tests/test_wrap.py +299 -0
  103. {cgmath-1.0.3 → cgmath-2.0.0/cgmath.egg-info}/PKG-INFO +73 -23
  104. cgmath-2.0.0/cgmath.egg-info/SOURCES.txt +384 -0
  105. cgmath-2.0.0/cgmath.egg-info/requires.txt +23 -0
  106. {cgmath-1.0.3 → cgmath-2.0.0}/constraints/procrustes.py +33 -22
  107. cgmath-2.0.0/formats/_fbx_io.py +186 -0
  108. {cgmath-1.0.3 → cgmath-2.0.0}/formats/fbx.py +686 -161
  109. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/__init__.py +1 -1
  110. cgmath-2.0.0/geometry/_base.py +2701 -0
  111. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/_cdt.py +4 -2
  112. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/_saddle_surface.py +93 -59
  113. cgmath-2.0.0/geometry/bspline.py +2525 -0
  114. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/bspline_patch.py +919 -112
  115. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/deform/delta_mush.py +91 -98
  116. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/deform/ffd.py +60 -28
  117. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/deform/patch_relax.py +56 -52
  118. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/deform/skin_deform.py +186 -69
  119. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/deform/wrap.py +53 -28
  120. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/map.py +18 -16
  121. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/mesh.py +593 -230
  122. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/morph_target.py +11 -17
  123. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/sdf.py +85 -19
  124. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/skin_weights.py +222 -159
  125. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/__init__.py +1 -0
  126. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_bilinear.py +1095 -254
  127. cgmath-2.0.0/geometry/utils/_numba/_bspline.py +4161 -0
  128. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_cdt.py +17 -2
  129. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_ffd.py +1 -1
  130. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_main.py +2 -0
  131. cgmath-2.0.0/geometry/utils/_numba/_skin_deform.py +831 -0
  132. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_skin_weights.py +2 -0
  133. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_topology.py +44 -0
  134. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/main.py +186 -8
  135. {cgmath-1.0.3 → cgmath-2.0.0}/hierarchy/__init__.py +1 -1
  136. cgmath-2.0.0/hierarchy/hierarchy.py +10134 -0
  137. {cgmath-1.0.3 → cgmath-2.0.0}/pyproject.toml +42 -17
  138. {cgmath-1.0.3 → cgmath-2.0.0}/render/scene.py +834 -407
  139. cgmath-2.0.0/transforms/_numba/__init__.py +116 -0
  140. {cgmath-1.0.3 → cgmath-2.0.0}/transforms/_numba/_axis.py +2 -2
  141. {cgmath-1.0.3 → cgmath-2.0.0}/transforms/_numba/_euler.py +69 -4
  142. {cgmath-1.0.3 → cgmath-2.0.0}/transforms/_numba/_matrix.py +8 -8
  143. {cgmath-1.0.3 → cgmath-2.0.0}/transforms/_numba/_quaternion.py +11 -11
  144. {cgmath-1.0.3 → cgmath-2.0.0}/transforms/_numba/_vector.py +61 -64
  145. cgmath-2.0.0/transforms/_tests/__init__.py +1 -0
  146. cgmath-2.0.0/transforms/_tests/test_axis.py +167 -0
  147. cgmath-2.0.0/transforms/_tests/test_broadcasting.py +357 -0
  148. cgmath-2.0.0/transforms/_tests/test_euler.py +411 -0
  149. cgmath-2.0.0/transforms/_tests/test_exports.py +43 -0
  150. cgmath-2.0.0/transforms/_tests/test_matrix.py +125 -0
  151. cgmath-2.0.0/transforms/_tests/test_quaternion.py +137 -0
  152. cgmath-2.0.0/transforms/_tests/test_rotation_conversions.py +403 -0
  153. cgmath-2.0.0/transforms/_tests/test_threads.py +392 -0
  154. cgmath-2.0.0/transforms/_tests/test_vector.py +183 -0
  155. {cgmath-1.0.3 → cgmath-2.0.0}/transforms/main.py +111 -90
  156. {cgmath-1.0.3 → cgmath-2.0.0}/transforms/utils.py +1 -1
  157. {cgmath-1.0.3 → cgmath-2.0.0}/utils.py +252 -33
  158. cgmath-1.0.3/cgmath.egg-info/SOURCES.txt +0 -178
  159. cgmath-1.0.3/cgmath.egg-info/requires.txt +0 -9
  160. cgmath-1.0.3/geometry/_base.py +0 -890
  161. cgmath-1.0.3/geometry/bspline.py +0 -1225
  162. cgmath-1.0.3/geometry/camera.py +0 -38
  163. cgmath-1.0.3/geometry/delta_mush.py +0 -29
  164. cgmath-1.0.3/geometry/ffd.py +0 -29
  165. cgmath-1.0.3/geometry/patch_relax.py +0 -29
  166. cgmath-1.0.3/geometry/raytracer.py +0 -38
  167. cgmath-1.0.3/geometry/surface_plotting.py +0 -1077
  168. cgmath-1.0.3/geometry/texture.py +0 -29
  169. cgmath-1.0.3/geometry/utils/_numba/_bspline.py +0 -2350
  170. cgmath-1.0.3/geometry/utils/_numba/_skin_deform.py +0 -535
  171. cgmath-1.0.3/hierarchy/hierarchy.py +0 -3841
  172. cgmath-1.0.3/transforms/_numba/__init__.py +0 -15
  173. {cgmath-1.0.3 → cgmath-2.0.0}/LICENSE +0 -0
  174. {cgmath-1.0.3 → cgmath-2.0.0}/cgmath.egg-info/dependency_links.txt +0 -0
  175. {cgmath-1.0.3 → cgmath-2.0.0}/cgmath.egg-info/top_level.txt +0 -0
  176. {cgmath-1.0.3 → cgmath-2.0.0}/constraints/__init__.py +0 -0
  177. {cgmath-1.0.3 → cgmath-2.0.0}/formats/__init__.py +0 -0
  178. {cgmath-1.0.3 → cgmath-2.0.0}/formats/glb.py +0 -0
  179. {cgmath-1.0.3 → cgmath-2.0.0}/formats/usd/__init__.py +0 -0
  180. {cgmath-1.0.3 → cgmath-2.0.0}/formats/usd/prim.py +0 -0
  181. {cgmath-1.0.3 → cgmath-2.0.0}/formats/usd/stage.py +0 -0
  182. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/deform/__init__.py +0 -0
  183. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/pack.py +0 -0
  184. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/resample.py +0 -0
  185. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/robust_skinweights_transfer_bilinear.py +0 -0
  186. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/__init__.py +0 -0
  187. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_blur.py +0 -0
  188. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_bvh.py +0 -0
  189. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_connectivity.py +0 -0
  190. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_delta_mush.py +0 -0
  191. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_normals.py +0 -0
  192. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_pack.py +0 -0
  193. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_patch_relax.py +0 -0
  194. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_rasterize.py +0 -0
  195. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_sdf.py +0 -0
  196. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_subdivide.py +0 -0
  197. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_subdivision.py +0 -0
  198. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_tangent_space.py +0 -0
  199. {cgmath-1.0.3 → cgmath-2.0.0}/geometry/utils/_numba/_wrap.py +0 -0
  200. {cgmath-1.0.3 → cgmath-2.0.0}/rbf/__init__.py +0 -0
  201. {cgmath-1.0.3 → cgmath-2.0.0}/rbf/_kernels.py +0 -0
  202. {cgmath-1.0.3 → cgmath-2.0.0}/rbf/_numba/__init__.py +0 -0
  203. {cgmath-1.0.3 → cgmath-2.0.0}/rbf/_numba/_kernels.py +0 -0
  204. {cgmath-1.0.3 → cgmath-2.0.0}/rbf/_numba/_lu.py +0 -0
  205. {cgmath-1.0.3 → cgmath-2.0.0}/render/__init__.py +0 -0
  206. {cgmath-1.0.3 → cgmath-2.0.0}/render/_numba/__init__.py +0 -0
  207. {cgmath-1.0.3 → cgmath-2.0.0}/render/_numba/_texture.py +0 -0
  208. {cgmath-1.0.3 → cgmath-2.0.0}/render/camera.py +0 -0
  209. {cgmath-1.0.3 → cgmath-2.0.0}/render/frame.py +0 -0
  210. {cgmath-1.0.3 → cgmath-2.0.0}/render/raytracer.py +0 -0
  211. {cgmath-1.0.3 → cgmath-2.0.0}/render/texture.py +0 -0
  212. {cgmath-1.0.3 → cgmath-2.0.0}/setup.cfg +0 -0
  213. {cgmath-1.0.3 → cgmath-2.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.3
3
+ Version: 2.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
@@ -52,12 +52,22 @@ License-File: LICENSE
52
52
  Requires-Dist: numpy
53
53
  Requires-Dist: scipy
54
54
  Requires-Dist: numba
55
- Requires-Dist: pillow
56
- Requires-Dist: opencv-python
57
- Requires-Dist: scikit-image
58
- Requires-Dist: pygltflib
59
- Requires-Dist: trimesh
60
- Requires-Dist: usd-core
55
+ Provides-Extra: image
56
+ Requires-Dist: pillow; extra == "image"
57
+ Requires-Dist: opencv-python; extra == "image"
58
+ Requires-Dist: scikit-image; extra == "image"
59
+ Provides-Extra: gltf
60
+ Requires-Dist: pygltflib; extra == "gltf"
61
+ Requires-Dist: trimesh; extra == "gltf"
62
+ Provides-Extra: usd
63
+ Requires-Dist: usd-core; extra == "usd"
64
+ Provides-Extra: all
65
+ Requires-Dist: pillow; extra == "all"
66
+ Requires-Dist: opencv-python; extra == "all"
67
+ Requires-Dist: scikit-image; extra == "all"
68
+ Requires-Dist: pygltflib; extra == "all"
69
+ Requires-Dist: trimesh; extra == "all"
70
+ Requires-Dist: usd-core; extra == "all"
61
71
  Dynamic: license-file
62
72
 
63
73
  # `cgmath` — a DCC-agnostic CG math library
@@ -123,8 +133,9 @@ for it) and a **CHEATSHEET** (every public name, with a runnable example).
123
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) |
124
134
 
125
135
  [`REFERENCE.md`](https://github.com/Eric-Vignola/cgmath/blob/main/REFERENCE.md), a flat API listing, also sits in this
126
- directory. It is generated from the live code by `gen_reference.py` (kept in
127
- 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
128
139
  name with its real signature and first docstring line.
129
140
 
130
141
  ---
@@ -148,10 +159,8 @@ cgmath/
148
159
  │ ├── map.py morph_target.py skin_weights.py MapData, MorphData, SkinData
149
160
  │ ├── bspline.py bspline_patch.py _saddle_surface.py _cdt.py
150
161
  │ ├── sdf.py SDF primitives + dual marching cubes
151
- │ ├── pack.py resample.py surface_plotting.py
162
+ │ ├── pack.py resample.py
152
163
  │ ├── robust_skinweights_transfer_bilinear.py
153
- │ ├── camera.py delta_mush.py ffd.py patch_relax.py raytracer.py texture.py
154
- │ │ one-release deprecation shims -- they warn and re-export
155
164
  │ ├── deform/ FFDData, DeltaMushData, PatchRelaxData,
156
165
  │ │ SkinDeformData, WrapData
157
166
  │ └── utils/ main.py + _numba/ -- the kernel floor
@@ -160,7 +169,10 @@ cgmath/
160
169
  ├── render/ scene.py raytracer.py camera.py frame.py texture.py
161
170
  ├── formats/ fbx.py, glb.py, usd/prim.py, usd/stage.py
162
171
  ├── rbf/ _kernels.py + _numba/ (__init__.py is a docstring, on purpose)
163
- └── 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
164
176
  ```
165
177
 
166
178
  The batched matrix / quaternion / euler / axis / vector functions that all
@@ -215,6 +227,13 @@ If you know Maya, nothing below will surprise you.
215
227
  face and a raycast miss.
216
228
  - **A mesh is a face-vertex stream**, `indices` + `counts` + `points`.
217
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).
218
237
  - **Camera is OpenGL**: `-Z` forward, `+Y` up, `+X` right. `look_at()`
219
238
  and `Frame.camera_matrix` are **column**-major (eye at `M[:3, 3]`)
220
239
  while node matrices are row-major (eye at `M[3, :3]`).
@@ -234,13 +253,15 @@ follows — full detail in its [README](https://github.com/Eric-Vignola/cgmath/b
234
253
  ### Optional dependencies
235
254
 
236
255
  Imported lazily behind `try / except ImportError`, so the package loads
237
- without them and only the paths that need them complain.
256
+ without them and only the paths that need them complain. A plain
257
+ `pip install cgmath` brings in none of them; the PyPI ones come as extras,
258
+ see [Requirements](#requirements).
238
259
 
239
260
  | Dependency | Used for | Missing behaviour |
240
261
  |---|---|---|
241
262
  | `pygltflib` | GLB / glTF read | `RuntimeError("pygltflib is not installed")` at call time |
242
263
  | Autodesk FBX SDK — not on PyPI, a manual install | FBX read / write | imports fine, with one `UserWarning` naming the SDK and where to get it; every FBX call raises `RuntimeError` with that same message |
243
- | `pxr`, from `usd-core` — installed with the wheel | `cgmath.formats.usd` stage / prim helpers; `from_prim` / `to_prim` / `load_usd` in `geometry` | always present after `pip install`. Run off `sys.path` without it, `import cgmath.formats.usd.prim` itself raises `ImportError` and the `geometry` paths raise `ImportError` at call time (`geometry.utils.pxr()` is the accessor) |
264
+ | `pxr`, from `usd-core` or the host DCC's own USD | `cgmath.formats.usd` stage / prim helpers; `from_prim` / `to_prim` / `load_usd` in `geometry` | `import cgmath.formats.usd.prim` itself raises `ImportError`, and the `geometry` paths raise `ImportError` at call time (`geometry.utils.pxr()` is the accessor) |
244
265
  | `trimesh` | `GlbData.mesh_list` | that attribute is `None` |
245
266
  | `PIL` (Pillow) | `Frame.image` / `.save` / `.wireframe` / `.encode_gif`, `to_image`, texture I/O | `RuntimeError("... install Pillow.")` at call time |
246
267
  | `cv2` | `imshow()` windows; UV rasterization in `geometry.mesh` | `imshow` raises `RuntimeError`; rasterization falls back to `skimage` |
@@ -263,7 +284,7 @@ Each block below builds on the `cube` from the top of this page.
263
284
  ```python
264
285
  print(cube.point_count, cube.face_count, cube.edge_count) # 8 6 12
265
286
  print(cube.closed, cube.quads, round(cube.area, 4)) # True 6 6.0
266
- print(cube.get_border_vertices(flatten=True)) # [] -- closed
287
+ print(cube.get_border_vertices(flatten=True)) # [] -- closed, an empty int32 array
267
288
  print(cube.e2v.shape, cube.ue2v.shape) # (12, 2) deduped vs (24, 2) raw
268
289
  ```
269
290
 
@@ -369,15 +390,44 @@ Start with [`CHEATSHEET.md`](https://github.com/Eric-Vignola/cgmath/blob/main/CH
369
390
 
370
391
  ## Requirements
371
392
 
372
- Numpy, Scipy and Numba python modules.
393
+ Numpy, Scipy and Numba python modules, the only packages a plain
394
+ `pip install cgmath` brings in.
395
+
396
+ Everything else is optional, per feature (see the table above for how each
397
+ degrades), and comes as a pip extra:
398
+
399
+ pip install "cgmath[image]" Pillow, OpenCV, scikit-image: texture I/O,
400
+ rendered frames, UV rasterization
401
+ pip install "cgmath[gltf]" pygltflib, trimesh: glTF / GLB read and write
402
+ pip install "cgmath[usd]" usd-core (pxr): USD stage read and write
403
+ pip install "cgmath[all]" all of the above
404
+
405
+ Inside a DCC that ships its own USD (Maya, Houdini), leave `usd` out: a
406
+ second `pxr` on `sys.path` conflicts with the one the host has loaded.
407
+
408
+ The Autodesk FBX SDK (FBX read and write) is not on PyPI; install it by hand.
409
+
373
410
 
374
- Optional, per feature (see the table above for how each degrades):
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
+ ```
375
425
 
376
- Pillow texture I/O and rendered frames
377
- pygltflib, trimesh glTF / GLB read and write
378
- Autodesk FBX SDK FBX read and write
379
- pxr (USD) USD stage read and write
380
- scikit-image or OpenCV UV rasterization
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]`.
381
431
 
382
432
 
383
433
  ## Author
@@ -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
  ---
@@ -86,10 +87,8 @@ cgmath/
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]`).
@@ -172,13 +181,15 @@ follows — full detail in its [README](https://github.com/Eric-Vignola/cgmath/b
172
181
  ### Optional dependencies
173
182
 
174
183
  Imported lazily behind `try / except ImportError`, so the package loads
175
- without them and only the paths that need them complain.
184
+ without them and only the paths that need them complain. A plain
185
+ `pip install cgmath` brings in none of them; the PyPI ones come as extras,
186
+ see [Requirements](#requirements).
176
187
 
177
188
  | Dependency | Used for | Missing behaviour |
178
189
  |---|---|---|
179
190
  | `pygltflib` | GLB / glTF read | `RuntimeError("pygltflib is not installed")` at call time |
180
191
  | Autodesk FBX SDK — not on PyPI, a manual install | FBX read / write | imports fine, with one `UserWarning` naming the SDK and where to get it; every FBX call raises `RuntimeError` with that same message |
181
- | `pxr`, from `usd-core` — installed with the wheel | `cgmath.formats.usd` stage / prim helpers; `from_prim` / `to_prim` / `load_usd` in `geometry` | always present after `pip install`. Run off `sys.path` without it, `import cgmath.formats.usd.prim` itself raises `ImportError` and the `geometry` paths raise `ImportError` at call time (`geometry.utils.pxr()` is the accessor) |
192
+ | `pxr`, from `usd-core` or the host DCC's own USD | `cgmath.formats.usd` stage / prim helpers; `from_prim` / `to_prim` / `load_usd` in `geometry` | `import cgmath.formats.usd.prim` itself raises `ImportError`, and the `geometry` paths raise `ImportError` at call time (`geometry.utils.pxr()` is the accessor) |
182
193
  | `trimesh` | `GlbData.mesh_list` | that attribute is `None` |
183
194
  | `PIL` (Pillow) | `Frame.image` / `.save` / `.wireframe` / `.encode_gif`, `to_image`, texture I/O | `RuntimeError("... install Pillow.")` at call time |
184
195
  | `cv2` | `imshow()` windows; UV rasterization in `geometry.mesh` | `imshow` raises `RuntimeError`; rasterization falls back to `skimage` |
@@ -201,7 +212,7 @@ Each block below builds on the `cube` from the top of this page.
201
212
  ```python
202
213
  print(cube.point_count, cube.face_count, cube.edge_count) # 8 6 12
203
214
  print(cube.closed, cube.quads, round(cube.area, 4)) # True 6 6.0
204
- print(cube.get_border_vertices(flatten=True)) # [] -- closed
215
+ print(cube.get_border_vertices(flatten=True)) # [] -- closed, an empty int32 array
205
216
  print(cube.e2v.shape, cube.ue2v.shape) # (12, 2) deduped vs (24, 2) raw
206
217
  ```
207
218
 
@@ -307,15 +318,44 @@ Start with [`CHEATSHEET.md`](https://github.com/Eric-Vignola/cgmath/blob/main/CH
307
318
 
308
319
  ## Requirements
309
320
 
310
- Numpy, Scipy and Numba python modules.
321
+ Numpy, Scipy and Numba python modules, the only packages a plain
322
+ `pip install cgmath` brings in.
323
+
324
+ Everything else is optional, per feature (see the table above for how each
325
+ degrades), and comes as a pip extra:
326
+
327
+ pip install "cgmath[image]" Pillow, OpenCV, scikit-image: texture I/O,
328
+ rendered frames, UV rasterization
329
+ pip install "cgmath[gltf]" pygltflib, trimesh: glTF / GLB read and write
330
+ pip install "cgmath[usd]" usd-core (pxr): USD stage read and write
331
+ pip install "cgmath[all]" all of the above
332
+
333
+ Inside a DCC that ships its own USD (Maya, Houdini), leave `usd` out: a
334
+ second `pxr` on `sys.path` conflicts with the one the host has loaded.
335
+
336
+ The Autodesk FBX SDK (FBX read and write) is not on PyPI; install it by hand.
337
+
311
338
 
312
- Optional, per feature (see the table above for how each degrades):
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
+ ```
313
353
 
314
- Pillow texture I/O and rendered frames
315
- pygltflib, trimesh glTF / GLB read and write
316
- Autodesk FBX SDK FBX read and write
317
- pxr (USD) USD stage read and write
318
- scikit-image or OpenCV UV rasterization
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]`.
319
359
 
320
360
 
321
361
  ## Author
@@ -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.3"
7
+ __version__ = "2.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
+ }