Use buffer matching the C type of the "co" property in foreach_get to avoid having to iterate and cast every single element in the C foreach_getset function.
Replace use of vcos_transformed_gen mesh transform helper with numpy version.
Only get cos of shape keys that are needed, since shape keys that are relative to themselves and have no other shape keys are relative to them can be skipped.
~7-12 times faster for shape keys that are entirely equal
~11-25 times faster for shape keys that are entirely different and not similar
~16-28 times faster for shape keys that are almost entirely different but similar
This patch does usually slightly change the exported file because the math for calculating the difference between a shape key and its relative key is done with float64 precision, matching the fbx export type. Beforehand, the difference would be calculated using mathutils.Vector which are single precision float (usually float32).
Because numpy.isclose is not symmetrical, this patch can also rarely result in a difference in which shape key cos are considered similar and are therefore not included in the export.
Consider the relative difference between 0.5 and 1.0:
If 1.0 is considered the reference value there is a 50% difference, but if 0.5 is considered the reference value there is a 100% difference.
math.isclose and fbx_utils.similar_values_iter always picks the value with greater magnitude as the reference value, whereas numpy.isclose picks the second argument as the reference value.
math.isclose(0.5, 1.0, rel_tol=0.5) => True
math.isclose(1.0, 0.5, rel_tol=0.5) => True
numpy.isclose(0.5, 1.0, rtol=0.5) => True
numpy.isclose(1.0, 0.5, rtol=0.5) => False
The relative key of each shape key is used as the reference value for numpy.isclose.