Reputation: 155
I'm trying to write my "personal"(without using any modules or functions : struct,float....,int....,...) python version of STL binary file reader, according to WIKIPEDIA : A binary STL file contains :
a 80-character (byte) headern which is generally ignored.
a 4-byte unsigned integer indicating the number of triangular facets in the file.
Each triangle is described by twelve 32-bit floating-point numbers: three for the normal and then three for the X/Y/Z coordinate of each vertex – just as with the ASCII version of STL. After these follows a 2-byte ("short") unsigned integer that is the "attribute byte count" – in the standard format, this should be zero because most software does not understand anything else. (((3+3+3)+3)*4+2=50 bytes for each point)
--Floating-point numbers are represented as IEEE floating-point numbers and are assumed to be little-endian--
With the help of two saviors I discovered how unsigned integers are stored, I can figure out the number of triangular facets in the file with 3 methods (computed by hand ) :
def int_from_bytes(inbytes): # ShadowRanger's
res = 0
for i, b in enumerate(inbytes):
res |= b << (i * 8)
return res
or
def int_from_bytes(inbytes): # ShadowRanger's
res = 0
for b in inbytes:
res <<= 8 # Adjust bytes seen so far to make room for new byte
res |= b # Mask in new byte
return res
or
def unsigned_int(s): # Robᵩ's
result = 0
for ch in s[::-1]:
result *= 256
result += ch
return result
Now I have to convert the rest of the file (3rd item in the list):Floating-point numbers
for the first point the 50-bytes are :
b'\x9a'b'\xa3' b'\x14' b'\xbe' b'\x05' b'$' b'\x85' b'\xbe' b'N' b'b'
b't' b'?' b'\xcd' b'\xa6' b'\x04' b'\xc4' b'\xfb' b';' b'\xd4' b'\xc1'
b'\x84' b'w' b'\x81' b'A' b'\xcd' b'\xa6' b'\x04' b'\xc4' b'\xa5' b'\x15'
b'\xd3' b'\xc1' b'\xb2' b'\xc7' b'\x81' b'A' b'\xef' b'\xa6' b'\x04'
b'\xc4' b'\x81' b'\x14' b'\xd3' b'\xc1' b'Y' b'\xc7' b'\x81' b'A' b'\x00'
b'\x00'
How can I convert this by hand, What is the principle of the representation, what rules should I know to do the conversion by hand (some bytes don't start with \x ). ?
Thank you for your time.
Upvotes: 0
Views: 1415
Reputation: 59174
Like this:
def int_from_bytes(inbytes):
res = 0
shft = 0
for b in inbytes:
res |= ord(b) << shft
shft += 8
return res
def float_from_bytes(inbytes):
bits = int_from_bytes(inbytes)
mantissa = ((bits&8388607)/8388608.0)
exponent = (bits>>23)&255
sign = 1.0 if bits>>31 ==0 else -1.0
if exponent != 0:
mantissa+=1.0
elif mantissa==0.0:
return sign*0.0
return sign*pow(2.0,exponent-127)*mantissa
print float_from_bytes('\x9a\xa3\x14\xbe')
print float_from_bytes('\x00\x00\x00\x40')
print float_from_bytes('\x00\x00\xC0\xbf')
output:
-0.145155340433
2.0
-1.5
The format is IEEE-754 floating point. Try this out to see what each bit means: https://www.h-schmidt.net/FloatConverter/IEEE754.html
Upvotes: 2