CadQuery / OCP

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

BinTools.Read_s not working with BytesIO stream

bernhard-42 opened this issue · comments

I'd like to serialize OCP objects and found that BinTools is faster than BRepTools. Do I'd like to give BinTools a try.

Storing as a file works:

obj = cq.Workplane().box(1,2,1).val().wrapped

rv = BinTools.Write_s(obj, "obj.bin")

shape = TopoDS_Shape()
BinTools.Read_s(shape, "obj.bin")

However, using BytesIO stream doesn't:

obj = cq.Workplane().box(1,2,1).val().wrapped

bio = io.BytesIO()
rv = BinTools.Write_s(obj, bio)
buffer = bio.getvalue()

bio2 = io.BytesIO(buffer)
BinTools.Read_s(shape, bio2)

fails with

---------------------------------------------------------------------------
Standard_Failure                          Traceback (most recent call last)
Input In [47], in <module>
      5 buffer = bio.getvalue()
      7 bio2 = io.BytesIO(buffer)
----> 8 BinTools.Read_s(shape, bio2)

Standard_Failure: EXCEPTION in BinTools_Curve2dSet::ReadCurve2d(...)
0x560930b56d30 : Standard_ConstructionError: gp_Dir2d::SetCoord() - result vector has zero norm

What am I doing wrong?

Btw., it works with an BRepTools and BytesIO stream:

obj = cq.Workplane().box(2,2,1).val().wrapped

bio = io.BytesIO()
rv = BRepTools.Write_s(obj, bio)
buffer = bio.getvalue()

bio2 = io.BytesIO(buffer)
builder = BRep_Builder()
BRepTools.Read_s(shape, bio2, builder)

I compared the file written by the file version or BinTools.Write_s and the buffer, and it turns out that the BytesIO buffer seems to have omitted the bytes 1024, 2048, 3072, ...
Could it be that the BytesIO stream works with a 1024 byte buffer and something is going wrong with reading the chunks?

I don't know if this will fix your problem, but in my apps I successfully use BinTool_ShapeSet (not the BinTools static methods).

This isn't a complete example, but you should get the gist of it.

def to_bytes(shape) -> bytes:
    s = BinTools.BinTools_ShapeSet()
    s.Add(shape)
    s.SetWithTriangles(False)  # don't serialize triangulations
    b = io.BytesIO()
    s.Write(b)
    return b.getvalue()

def from_bytes(b: bytes):
    s = BinTools.BinTools_ShapeSet()
    stream = io.BytesIO(b)
    s.Read(stream)
    shape = s.Shape(s.NbShapes())
    return shape

Thanks @whophil

Trying

obj = cq.Workplane().box(1,2,1).val().wrapped

x = to_bytes(obj)
s = from_bytes(bytes(x))

I get

---------------------------------------------------------------------------
Standard_Failure                          Traceback (most recent call last)
Input In [159], in <module>
      1 obj = cq.Workplane().box(1,2,1).val().wrapped
      3 x = to_bytes(obj)
----> 4 s = from_bytes(bytes(x))

Input In [154], in from_bytes(b)
     10 s = BinTools_ShapeSet()
     11 stream = io.BytesIO(b)
---> 12 s.Read(stream)
     13 shape = s.Shape(s.NbShapes())
     14 return shape

Standard_Failure: EXCEPTION in BinTools_Curve2dSet::ReadCurve2d(...)
0x560930b56d30 : Standard_ConstructionError: gp_Dir2d::SetCoord() - result vector has zero norm

I just checked, I use OCP 7.5.2

@whophil I quickly created a new environment with cadquery=master and OCP=7.5.3
In this environment your code works. So it's a bug in 7.5.2

Upgraded my environment to the latest master (including OCP 7.5.3).
Now all works, @whophil 's code and mine above.
Thanks