在创建一个简单的STL解析器的上下文中,至少在我看来,get
的{{1}}中出现了一些意外行为。在我看来,它在我认为应该的32位之后不再停止读取Data.Binary
。
ByteString
尝试使用此代码读取STL文件,我会收到类似的错误
{-# LANGUAGE FlexibleContexts #-}
module STLTransform where
import qualified Data.ByteString.Lazy as BL
import Data.Binary
import Data.Binary.Get
import Data.Binary.Put
import Data.Word
import Numeric.LinearAlgebra
import GHC.Float
import System.Endian
getTriangle = do
normal <- getR3
vertices <- sequence $ take 3 $ trace (show normal) $ repeat getR3
return (normal, vertices)
where getR3 = fmap (vector.fmap float2Double)
$ sequence $ take 3 $ repeat get
getSTL :: Get ([Word8], Word32, [(Vector R, [Vector R])], Word16)
getSTL = do
header <- sequence $ take 80 $ repeat get
number <- fmap (toBE32) $ get
triangles <- sequence $ take (fromIntegral number) $ repeat getTriangle
attribute <- get
return (header, number, triangles, attribute)
readSTL fn = BL.readFile fn >>= return.runGet getSTL
经过一些调试后,我将问题隔离到*Main STLTransform> readSTL "test.stl"
*** Exception: Data.Binary.Get.runGet at position 1268784: not enough bytes
CallStack (from HasCallStack):
error, called at libraries/binary/src/Data/Binary/Get.hs:351:5 in binary-0.8.6.0:Data.Binary.Get
,更具体地说,将其解析为getTriangle
的值。通过将Float
替换为float2Double
(\a -> fromIntegral (a :: Word32))
我得到的代码可以按预期运行(尽管显然数字不正确)。所以问题是,为什么getTriangle = do
normal <- getR3
vertices <- sequence $ take 3 $ trace (show normal) $ repeat getR3
return (normal, vertices)
where getR3 = fmap (vector.fmap (\a -> fromIntegral (a :: Word32)))
$ sequence $ take 3 $ repeat get
和Float
被区别对待? Word32
也是32位值吗?
使用的软件包版本为Float
编辑: 该函数的更正版本是
binary-0.8.6.0
与上述问题无关,但已从原始帖子中更正,该属性位于三角形级别,而不是文件级别。
答案 0 :(得分:1)
The Binary
instance of Float
解析一对
(Integer, Int)
和then uses encodeFloat :: Integer -> Int -> Float
,这就是为什么它占用超过32位的原因。
这是一个向后兼容的已知问题:https://github.com/kolmodin/binary/issues/69
不要盲目使用get
,不止一种编码方式。在这种情况下,还有用于Float
的32位格式的其他解析器:https://hackage.haskell.org/package/binary-0.8.7.0/docs/Data-Binary-Get.html#v:getFloatbe