build123d icon indicating copy to clipboard operation
build123d copied to clipboard

pickling broken for STLs imported through Mesher

Open MatthiasJ1 opened this issue 1 year ago • 5 comments

from build123d import *
import pickle

part = Box(1,1,1) - Cylinder(0.3, 2)
part.export_stl("test.stl")
stl = Mesher().read("test.stl")

dump = pickle.dumps(part)
part = pickle.loads(dump)

dump = pickle.dumps(stl)
stl = pickle.loads(dump)
    stl = pickle.loads(dump)
          ^^^^^^^^^^^^^^^^^^
OCP.Standard.Standard_Failure: EXCEPTION in BinTools_ShapeSet::ReadGeometry(S,OS)
0x16bdbc190 : Standard_Failure: BinTools_SurfaceSet::ReadGeometry: UnExpected BRep_PointRepresentation = 131

MatthiasJ1 avatar Jan 05 '24 22:01 MatthiasJ1

Probably related to https://github.com/gumyr/build123d/issues/350

jdegenstein avatar Jan 05 '24 23:01 jdegenstein

If it helps, this is not a OCCT problem:

In [115]: from build123d import *
     ...: import pickle
     ...: 
     ...: part = Box(1,1,1) - Cylinder(0.3, 2)
     ...: part.export_stl("test.stl")
     ...: stl = Mesher().read("test.stl")

In [116]: from ocp_tessellate.ocp_utils import serialize, deserialize
In [117]: dump = serialize(stl[0].wrapped)
In [118]: stl2 = deserialize(dump)
In [119]: stl2
Out[119]: <OCP.TopoDS.TopoDS_Shape at 0x2a70fe770>

So the issue is hidden in the pickle code in persistence.py, maybe some encoding issues?

bernhard-42 avatar Jan 06 '24 13:01 bernhard-42

I remember the issue now: BinTools sometimes crash with BytesIO. So in ocp_tessellate I use:

def serialize(shape):
    if shape is None:
        return None

    try:
        bio = io.BytesIO()
        BinTools.Write_s(shape, bio)
        buffer = bio.getvalue()
    except Exception:
        with tempfile.NamedTemporaryFile() as tf:
            BinTools.Write_s(shape, tf.name)
            with open(tf.name, "rb") as fd:
                buffer = fd.read()
    return buffer


def deserialize(buffer):
    if buffer is None:
        return None

    shape = TopoDS_Shape()
    try:
        bio = io.BytesIO(buffer)
        BinTools.Read_s(shape, bio)
    except Exception:
        with tempfile.NamedTemporaryFile() as tf:
            with open(tf.name, "wb") as fd:
                fd.write(buffer)
            BinTools.Read_s(shape, tf.name)
    return shape

So, whenever I detect a crash I take the slower route via the file system.

If I replace the code in persistence.py with the above, the example of this issue works

bernhard-42 avatar Jan 06 '24 14:01 bernhard-42

CC: @jdegenstein @Jojain

bernhard-42 avatar Jan 06 '24 14:01 bernhard-42

We might have found out this issue (on the work on measure tool of OCP CAD Viewer) after I proposed the PR to build123d.

As far as we know there is not really any other solution that doing what we did, i.e using the filesystem.

Jojain avatar Jan 06 '24 15:01 Jojain