EmbroidePy / pyembroidery

pyembroidery library for reading and writing a variety of embroidery formats.
MIT License
182 stars 33 forks source link

Edge Condition: rounding out of write permitted range. #43

Closed tatarize closed 5 years ago

tatarize commented 5 years ago

Turns out there's a couple ways the encoder and writer can exceed the permitted range. It is entirely possible to have something like -0.5 -> 99.5 -> 199.5 while range limited to never exceed 100 units. Since this is correctly within that range it is permitted. However, because these round to -1, 100, 200 when rounded they can end out rounding outside the permitted range. To combat this, I added a ROUND parameter for writers that rounds the incoming values. So -1, 100, 200 are used early in the encoding and it correctly then subdivides that first stitch-gap.

It is however, still an open question if it can be coaxed into exceeding the range because the interpolated stitches are rounded. Can subdivided integer positions fall on the half-unit in such a way that rounding it off that half-unit position causes it to exceed the range?

tatarize commented 5 years ago

Seems impossible unless max_stitch length is a fractional. Though fractional values there can round beyond the limit there pretty easily.

tatarize commented 5 years ago

The non-rounded to rounded distance error was 1. To reach this both endpoints would need to be exactly on the half unit, and round away from each other (rounding occurs away from zero). Thus the max_length of n was able to have a rounded distance of n + 1. If the subdivision was exactly by n, that fractional additional unit would fall on one side or the other, exceeding the permitted max_length.

Pre-rounded values have a max round error of 0. If length is an exact subdivision of max_length then the fractional part is 0 and fractional error is 0 and subdivisions exactly equal max_length. For in exact subdivisions, maximum fractional error is 1- (1 / p) where p is equal to the parts in the subdivision, but in those cases the fractional value will be 1/p so the (max error + fractional part) can only cause length to equal max_length, and never exceed it.

However, even with pre-rounded values, fractional max_length ranges can exceed their value, by (1 - fractional_part_of_max). 0, 3 max length 1.5 -> 0, 1.5, 3 which becomes 0,2,3 which has 0->2 exceed 1.5 by 0.5 0, 4 max length 1.33... -> 0, 1.33..., 2.66..., 4 which becomes 0, 1, 3, 4 which has 1->3 which exceeds 1.3 by 0.66...

integer(p * fractional_part_of_max_length) of compounding error must be distributed within the subdivision. If this subdivision is at max_length the values will exceed max_length by 1. An integer max_length has 0 for fractional_part_of_max_length and thus is safely permitted.

QED.