drlukeparry / libSLM

libSLM is a c++ library for generating and transfering to SLM Machine Systems
http://lukeparry.uk/projects
GNU Lesser General Public License v2.1
29 stars 4 forks source link

Support binary .sli EOS File Format #8

Open drlukeparry opened 2 years ago

drlukeparry commented 2 years ago

The .sli file format is the 'internal' EOS file format used for defining the scan vectors within the job package archive file (.openjz).

The job manifest file, typically compressed, consists of the following:

These files are collectively can be used and referenced within the supplied EOS preprocessor toolset (RPTools or EOSPrint 1.7-2.8)

Part of the binary .sli file format has been partially documented here. The exact file format specification required by the SLM System is not available.

The .sli file format is based on the former open .cli specification, but has specific extensions adopted for more efficient access to each layers. These include a header offset and a 'layer seek table' used for efficient access to the LayerGeometry across each Layer.

An excerpt taken from a job file is displayed below:

cube.openjob.txt

A preliminary example script for interpreting the .sli is shared below for reference:

`

import numpy as np

import pyslm
import pyslm.geometry
import pyslm.visualise

def read_uint32(file, count=1):
    return np.fromfile(file, count=count, dtype=np.uint32)

def read_int32(file, count=1):
    return np.fromfile(file, count=count, dtype=np.int32)

def read_int16(file, count=1):
    return np.fromfile(file, count=count, dtype=np.int16)

def read_uint16(file, count=1):
    return np.fromfile(file, count=count, dtype=np.uint16)

def read_uint8(file, count=1):
    return np.fromfile(file, count=count, dtype=np.uint8)

def read_floats(file, count=1):
    return np.fromfile(file, count=count, dtype=np.float32)

"""
Read the .sli header
"""
filename = "../models/cube 01_p.sli"
file = open(filename, "rb")
header = file.read(40).decode("ascii")

"""
Read and locate the file preamble
"""
if "EOS 1993 SLI FILE" not in header:
    raise ValueError("Not .sls file")

"""
Read the header information
"""
vMajor = read_uint16(file)
i2 = read_uint16(file)
headerSize = int(read_uint32(file))
i3 = read_uint32(file)
i4 = read_uint32(file)

"""
Locate the slice offset position
"""
sliceOffset = int(read_uint32(file))
print('file pos', file.tell())
print('slice offset, ')

""" 
Locate the seek table position in the file
"""
seekTablePos = int(read_uint32(file))
creator = file.read(40).decode("ascii")
numLayers = int(read_uint32(file))
polyLineCount = read_uint32(file)
i6 = read_uint32(file)
unknown = file.read(32).decode("ascii")

"""
Locate the scale factor for the entire part and the part bounding box
"""
scaleFactor = read_floats(file, 1)[0]
bbox = read_floats(file, 6)

# Move to the layer seek table
file.seek(seekTablePos+headerSize)

def parseLayer(file, layer):
    file.seek(layer.seekPos)

    print('layer seek pos', layer.seekPos)
    opCode = 0

    while opCode != 2:
        opCode = read_uint8(file)

        if opCode == 1:
            # Read the layer header
            layerZPos = int(read_uint16(file)) * scaleFactor # scale factor height as a uin16,
            layerThickness = read_floats(file, 2)
            print("Layer z pos: {:.3f}, thickness: {:.3f}, {:.3f}".format(layerZPos, *layerThickness))

            # padding
            unknownId = read_uint8(file) # Typically zero
        elif opCode == 2:
            """ Upon reaching op-code 2 - the layer has been successfully parsed"""
            return

        elif opCode == 3:
            # Parse a contour
            geom = pyslm.geometry.ContourGeometry()
            geom.bid = read_uint8(file)
            numPoints = read_uint16(file)

            # Note a closed closed loop must be created for the contours
            geom.coords = read_int16(file, 2*int(numPoints)).astype(np.float32).reshape(-1,2)  * scaleFactor
            layer.geometry.append(geom)

        elif opCode == 4:
            # Prase the hatch
            geom = pyslm.geometry.HatchGeometry()
            geom.bid = read_uint8(file)
            numPoints = read_uint16(file)

            geom.coords = read_int16(file, 4 * int(numPoints)).astype(np.float32).reshape(-1,2) * scaleFactor
            layer.geometry.append(geom)

        else:
            raise ValueError("unknown layer op-code")

layers = []

currentFilePos = file.tell()
for i in range(numLayers):

    layer = pyslm.geometry.Layer()

    # The layer position is stored in the layer seek table, but also later in the Layer Definition Header
    layer.z = read_uint16(file) * scaleFactor
    layer.seekPos = int(read_uint32(file)) + headerSize
    layer.layerId = i # not used in the sli implementation but used for reference in PySLM

    # Store current file pos
    currentFilePos = file.tell()

    parseLayer(file, layer)
    layers.append(layer)
    file.seek(currentFilePos)

pyslm.visualise.plot(layers[1], plot3D=False, plotOrderLine=True, plotArrows=False)

`