3MFConsortium / spec_core

3MF's Core specification
BSD 2-Clause "Simplified" License
55 stars 16 forks source link

More Compact NDArray #56

Open mikedh opened 2 years ago

mikedh commented 2 years ago

Hi, thanks for the great work! Currently 3MF encodes vertices and triangles with one node per vertex:

<vertices>
<vertex x="20.700998" y="5.546816" z="-4.762500"/>
<vertex x="8.512669" y="7.142977" z="-4.762500"/>
<vertex x="5.556250" y="9.623708" z="-4.762500"/>
<vertex x="-5.556250" y="-9.623708" z="-4.762500"/>
<vertex x="-1.929665" y="-10.943676" z="-4.762500"/>
...

Which is quite verbose and slow in languages with a large object overhead (like Python :). As a proposal: add support for an NDArray element as a child of <vertices> (and probably <triangles> too), such as:

<vertices>
<ndarray shape="10,3" values = "0.84144, 0.37634, 0.924 , 0.95611, 0.42108, 0.73491, 0.84039,
       0.1341, 0.19072, 0.87648, 0.42177, 0.72928, 0.1192, 0.91388,
       0.44683, 0.01963, 0.33069, 0.28099, 0.58583, 0.66842"/>
</vertices>

This reduces storage use by roughly 24%, which isn't infinity but also isn't trivial:

In [39]: v = np.random.random((10, 3))

In [40]: format_original = '<vertex x="{}" y="{}" z="{}"/>\n'

In [41]: format_proposed = '<ndarray shape="{shape}" values={values}"'

In [42]: len(format_proposed.format(shape=str(v.shape)[1:-1], values=',
    ...: '.join(v.flatten().astype(str))))
Out[42]: 605

In [43]: len((format_original * len(v)).format(*v.flatten()))
Out[43]: 795

In [44]: (795-605) / 795
Out[44]: 0.2389937106918239