pcd-loader 0.2.3.2 → 0.3.0.0
raw patch · 8 files changed
+409/−89 lines, 8 filesdep +HUnitdep +directorydep +string-qqdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: HUnit, directory, string-qq, test-framework, test-framework-hunit
Dependency ranges changed: base
API changes (from Hackage documentation)
- PCD.Data: asciiToBinary :: FilePath -> FilePath -> IO ()
- PCD.Data: loadAllFields :: FilePath -> IO (Text -> Vector FieldType)
+ PCD.Conversion: asciiToBinary :: FilePath -> FilePath -> IO ()
+ PCD.Data: loadFieldsByName :: FilePath -> IO (Text -> Vector FieldType)
+ PCD.Data: loadFlexiblePoints :: Header -> Handle -> IO (Vector (Vector FieldType))
+ PCD.Internal.AsciiParsers: readPoints :: Vector v a => Header -> Handle -> Parser a -> IO (v a)
+ PCD.Internal.AsciiParsers: readPointsDefault :: Header -> Handle -> IO (Vector (Vector FieldType))
+ PCD.Internal.AsciiParsers: readXYZ :: Fractional a => Parser (V3 a)
+ PCD.Internal.AsciiParsers: readXYZW :: Fractional a => Parser (V4 a)
Files
- pcd-loader.cabal +15/−5
- src/PCD/Conversion.hs +31/−0
- src/PCD/Data.hs +37/−82
- src/PCD/Header.hs +2/−1
- src/PCD/Internal/AsciiParsers.hs +46/−0
- src/executable/Main.hs +2/−1
- tests/SampleData.hs +232/−0
- tests/SampleLoad.hs +44/−0
pcd-loader.cabal view
@@ -1,5 +1,5 @@ name: pcd-loader-version: 0.2.3.2+version: 0.3.0.0 synopsis: PCD file loader. description: Parser for PCD (point cloud data) formats. See <http://pointclouds.org/documentation/tutorials/pcd_file_format.php>@@ -12,17 +12,18 @@ category: Robotics,Graphics build-type: Simple cabal-version: >=1.10+extra-source-files: tests/SampleLoad.hs, tests/SampleData.hs source-repository head type: git location: git://github.com/acowley/pcd-loader.git library- exposed-modules: PCD.Data, PCD.Header, PCD.Internal.Types, - PCD.Internal.StorableFieldType+ exposed-modules: PCD.Data, PCD.Header, PCD.Conversion, PCD.Internal.Types, + PCD.Internal.StorableFieldType, PCD.Internal.AsciiParsers ghc-options: -O2 -Wall hs-source-dirs: src- build-depends: base >= 4.6 && < 5, text, mtl, lens, vector, bytestring, + build-depends: base >= 4.5 && < 5, text, mtl, lens, vector, bytestring, attoparsec, binary, deepseq, linear default-language: Haskell2010 @@ -30,6 +31,15 @@ hs-source-dirs: src/executable main-is: Main.hs ghc-options: -O2 -Wall- build-depends: base >= 4.6 && < 5, pcd-loader + build-depends: base >= 4.5 && < 5, pcd-loader default-language: Haskell2010 +test-suite tests+ type: exitcode-stdio-1.0+ hs-source-dirs: tests+ main-is: SampleLoad.hs+ ghc-options: -Wall -O2+ default-language: Haskell2010+ build-depends: base >= 4.5 && < 5,+ test-framework, test-framework-hunit, HUnit,+ vector, lens, text, directory, string-qq, pcd-loader
+ src/PCD/Conversion.hs view
@@ -0,0 +1,31 @@+-- |Facility to convert an ASCII PCD file to a Binary one.+module PCD.Conversion where+import Control.Lens ((^.), (.~))+import Control.Monad (when)+import qualified Data.Text.IO as T+import qualified Data.Vector as B+import Foreign.Marshal.Alloc (allocaBytes)+import System.IO (IOMode(..), openFile, hClose, hPutBuf, withBinaryFile)++import PCD.Header+import qualified PCD.Internal.AsciiParsers as A+import PCD.Internal.StorableFieldType (pokeBinaryPoints)++-- |@asciiToBinary inputFile outputFile@ converts a PCD file from+-- ASCII to Binary.+asciiToBinary :: FilePath -> FilePath -> IO ()+asciiToBinary i o = do h <- openFile i ReadMode+ (pcdh,_) <- readHeader h+ print pcdh+ when (pcdh^.format /= ASCII)+ (error "Input PCD is already binary!")+ let numBytes = totalBinarySize pcdh+ putStrLn $ "Expecting to generate "++show numBytes++" bytes"+ v <- A.readPointsDefault pcdh h+ putStrLn $ "Parsed "++show (B.length v)++" ASCII points"+ hClose h+ T.writeFile o (writeHeader (format .~ Binary $ pcdh))+ withBinaryFile o AppendMode $ \h' ->+ allocaBytes numBytes $ \ptr ->+ pokeBinaryPoints ptr v >>+ hPutBuf h' ptr numBytes
src/PCD/Data.hs view
@@ -1,21 +1,20 @@-{-# LANGUAGE ScopedTypeVariables, BangPatterns #-}--- |Parser for PCD (point cloud data) files. Also provides a facility--- for converting from ASCII to binary formatted point data.-module PCD.Data (FieldType(..), unsafeUnwrap, loadAllFields, - loadXyzw, loadXyz, asciiToBinary, saveBinaryPcd, - projectBinaryFields, mkSimpleHeader, mkHeaderXYZ) where+{-# LANGUAGE ScopedTypeVariables #-}+-- |Parser for PCD (point cloud data) files.+module PCD.Data (-- * Accessing fields+ FieldType(..), unsafeUnwrap, + -- * Loading PCD data+ loadFieldsByName, loadFlexiblePoints, loadXyzw, loadXyz, + -- * Saving PCD data+ saveBinaryPcd, projectBinaryFields,+ -- * PCD header creation+ mkSimpleHeader, mkHeaderXYZ) where import Control.Applicative import Control.DeepSeq import Control.Lens ((.~), (^.))-import Control.Monad (when)-import Data.Attoparsec.Text hiding (I) import qualified Data.Attoparsec.Text.Lazy as ATL import Data.Text (Text)-import qualified Data.Text.Lazy.IO as TL import qualified Data.Text.IO as T import qualified Data.Vector as B-import qualified Data.Vector.Generic as G-import qualified Data.Vector.Generic.Mutable as GM import qualified Data.Vector.Storable as V import qualified Data.Vector.Storable.Mutable as VM import Foreign.Marshal.Alloc (allocaBytes)@@ -23,35 +22,14 @@ import System.IO (Handle, openFile, hClose, IOMode(..), withBinaryFile, hPutBuf, hGetBuf) import PCD.Header+import qualified PCD.Internal.AsciiParsers as A import PCD.Internal.StorableFieldType import PCD.Internal.Types --- |Read point data using a user-supplied ASCII point parser.-readAsciiPoints :: (G.Vector v a) => - Header -> Handle -> ATL.Parser a -> IO (v a)-readAsciiPoints pcd h p = aux <$> TL.hGetContents h- where n = fromIntegral $ pcd^.points- aux t0 = G.create $- do v <- GM.new n- let write = GM.write v- go !i !t- | i == n = return v- | otherwise = case ATL.parse p t of- ATL.Done !t' !pt -> write i pt >> - go (i+1) t'- ATL.Fail _ _ msg -> error msg- go 0 t0---- |Load points of unknown dimension into a boxed vector with a list--- of 'FieldType' as the point representation.-readAsciiPointsDefault :: Header -> Handle -> IO (B.Vector (B.Vector FieldType))-readAsciiPointsDefault pcd h = readAsciiPoints pcd h $ - B.fromList <$> pointParser pcd- -- |Read back 'Storable' points saved as binary data.-readHomogenousBinaryPoints :: forall a. Storable a => +readStorableBinaryPoints :: forall a. Storable a => Header -> Handle -> IO (Either String (Vector a))-readHomogenousBinaryPoints pcd h+readStorableBinaryPoints pcd h | ptSize /= sz = return . Left $ "Deserialization type is not the same size as the points "++ "described by this file. The PCD file dicates "++@@ -71,20 +49,9 @@ readPointData :: Storable a => Header -> Handle -> ATL.Parser a -> IO (Either String (Vector a))-readPointData hd h pa - | hd^.format == ASCII = readAsciiPoints hd h pa >>= return . Right- | otherwise = readHomogenousBinaryPoints hd h---- |Parse 3D points serialized in ASCII.-readXYZ_ascii :: Fractional a => ATL.Parser (V3 a)-readXYZ_ascii = (\[x,y,z] -> V3 x y z) <$> - count 3 ((realToFrac <$> double) <* skipSpace)---- |Parse 4D points serialized to ASCII. This is useful for points--- with X,Y,Z, and RGB fields each represented by a single float.-readXYZW_ascii :: Fractional a => ATL.Parser (V4 a)-readXYZW_ascii = (\[x,y,z,w] -> V4 x y z w) <$>- count 4 ((realToFrac <$> double) <* skipSpace)+readPointData header handle parser+ | header^.format == ASCII = Right <$> A.readPoints header handle parser+ | otherwise = readStorableBinaryPoints header handle -- |Use an existing PCD header to save binary point data to a -- file. The supplied header is used as-is, except that its format is@@ -99,26 +66,12 @@ withBinaryFile outputFile AppendMode $ \h -> V.unsafeWith pts (flip (hPutBuf h) sz) --- |@asciiToBinary inputFile outputFile@ converts a PCD file from--- ASCII to Binary.-asciiToBinary :: FilePath -> FilePath -> IO ()-asciiToBinary i o = do h <- openFile i ReadMode- (pcdh,_) <- readHeader h- pcdh `deepseq` print pcdh- when (pcdh^.format /= ASCII)- (error "Input PCD is already binary!")- let numBytes = totalBinarySize pcdh- putStrLn $ "Expecting to generate "++show numBytes++" bytes"- v <- readAsciiPointsDefault pcdh h- putStrLn $ "Parsed "++show (B.length v)++" ASCII points"- hClose h- T.writeFile o (writeHeader (format .~ Binary $ pcdh))- withBinaryFile o AppendMode $ \h' ->- allocaBytes numBytes $ \ptr ->- pokeBinaryPoints ptr v >>- hPutBuf h' ptr numBytes---- |Save a binary PCD file including only the named fields.+-- |Save a binary PCD file including only the named fields. This is+-- useful when you have a PCD file that has more fields for each point+-- than you care about. For instance, you may wish to extract just the+-- \"x\", \"y\", and \"z\" fields for each point. This can be+-- accomplished using, @projectBinaryFields [\"x\", \"y\", \"z\"]+-- inputFile outputFile@. projectBinaryFields :: [Text] -> FilePath -> FilePath -> IO () projectBinaryFields fs i o = do h <- openFile i ReadMode@@ -142,7 +95,10 @@ -- |Load points stored in a PCD file into a 'Vector'. This requires a -- 'Storable' instance for the type used to represent a point. If the -- point is a monotyped collection of fields, consider using--- 'Linear.V2.V2' or 'Linear.V3.V3' to represent points.+-- 'Linear.V2', 'Linear.V3', or 'Linear.V4' to represent points. When+-- using a representation from the @linear@ package, you may wish to+-- use 'loadXyz' or 'loadXyzw' which can handle ASCII and Binary+-- serializations of 3D or 4D points. loadPoints :: Storable a => ATL.Parser a -> FilePath -> IO (Vector a) loadPoints parser pcdFile = do h <- openFile pcdFile ReadMode (pcdh,_) <- readHeader h@@ -153,7 +109,7 @@ -- |Read a PCD file consisting of floating point XYZ coordinates for -- each point. loadXyz :: (Fractional a, Storable a) => FilePath -> IO (Vector (V3 a))-loadXyz = loadPoints readXYZ_ascii+loadXyz = loadPoints A.readXYZ {-# SPECIALIZE loadXyz :: FilePath -> IO (Vector (V3 Float)) #-} {-# SPECIALIZE loadXyz :: FilePath -> IO (Vector (V3 Double)) #-} @@ -161,26 +117,25 @@ -- each point (where the final \"W\" field may be an RGB triple -- encoded as a float). loadXyzw :: (Fractional a, Storable a) => FilePath -> IO (Vector (V4 a))-loadXyzw = loadPoints readXYZW_ascii+loadXyzw = loadPoints A.readXYZW {-# SPECIALIZE loadXyzw :: FilePath -> IO (Vector (V4 Float)) #-} {-# SPECIALIZE loadXyzw :: FilePath -> IO (Vector (V4 Double)) #-} +-- |Load a 'B.Vector' of points, each represented as a 'B.Vector' of+-- 'FieldType' fields. If you wish to use field names to access to the+-- data, consider using 'loadFieldsByName'. loadFlexiblePoints :: Header -> Handle -> IO (B.Vector (B.Vector FieldType)) loadFlexiblePoints pcdh h | pcdh ^. format == Binary = parseBinaryPoints pcdh h- | otherwise = readAsciiPointsDefault pcdh h+ | otherwise = A.readPointsDefault pcdh h -- |Parse every field of every point in a PCD file. Returns a function -- that may be used to project out a named field.-loadAllFields :: FilePath -> IO (Text -> B.Vector FieldType)-loadAllFields f = do h <- openFile f ReadMode- (pcdh,_) <- readHeader h- (mkProjector pcdh <$>- if pcdh ^. format == ASCII- then readAsciiPoints pcdh h - (B.fromList <$> pointParser pcdh)- else parseBinaryPoints pcdh h)- <* hClose h+loadFieldsByName :: FilePath -> IO (Text -> B.Vector FieldType)+loadFieldsByName f = do h <- openFile f ReadMode+ (pcdh,_) <- readHeader h+ (mkProjector pcdh <$> loadFlexiblePoints pcdh h) + <* hClose h where mkProjector :: Header -> B.Vector (B.Vector FieldType) -> (Text -> B.Vector FieldType) mkProjector h pts = let fieldNames = B.fromList $ h ^. fields
src/PCD/Header.hs view
@@ -124,7 +124,8 @@ -- |Make a PCD header for a monotyped vector point -- type. @mkSimpleHeader fields (type,sz) n@ prepares a 'Header' for -- @n@ points with field names @fields@, field type given by @type@,--- and field size given by @sz@. Example to save 1000 3D points:+-- and field size given by @sz@. Example to save 1000 3D points using+-- a single-precision floating point number (4 bytes) for each field: -- -- > mkSimpleHeader ["x","y","z"] (F,4) 1000 mkSimpleHeader :: [Text] -> (DimType,Int) -> Int -> Header
+ src/PCD/Internal/AsciiParsers.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE BangPatterns #-}+module PCD.Internal.AsciiParsers where+import Control.Applicative+import Control.Lens ((^.))+import Data.Attoparsec.Text (double, count, skipSpace)+import qualified Data.Attoparsec.Text.Lazy as ATL+import qualified Data.Text.Lazy.IO as TL+import qualified Data.Vector as B+import qualified Data.Vector.Generic as G+import qualified Data.Vector.Generic.Mutable as GM+import System.IO (Handle)++import PCD.Header (Header, FieldType, pointParser, points)+import PCD.Internal.Types (V3(..), V4(..))++-- |Read point data using a user-supplied ASCII point parser.+readPoints :: (G.Vector v a) => + Header -> Handle -> ATL.Parser a -> IO (v a)+readPoints pcd h p = aux <$> TL.hGetContents h+ where n = fromIntegral $ pcd^.points+ aux t0 = G.create $+ do v <- GM.new n+ let write = GM.write v+ go !i !t+ | i == n = return v+ | otherwise = case ATL.parse p t of+ ATL.Done !t' !pt -> write i pt >> + go (i+1) t'+ ATL.Fail _ _ msg -> error msg+ go 0 t0++-- |Load points of arbitrary dimension into a boxed vector with a+-- 'B.Vector' of 'FieldType' as the point representation.+readPointsDefault :: Header -> Handle -> IO (B.Vector (B.Vector FieldType))+readPointsDefault pcd h = readPoints pcd h $ B.fromList <$> pointParser pcd++-- |Parse 3D points serialized in ASCII.+readXYZ :: Fractional a => ATL.Parser (V3 a)+readXYZ = (\[x,y,z] -> V3 x y z) <$> + count 3 ((realToFrac <$> double) <* skipSpace)++-- |Parse 4D points serialized to ASCII. This is useful for points+-- with X,Y,Z, and RGB fields each represented by a single float.+readXYZW :: Fractional a => ATL.Parser (V4 a)+readXYZW = (\[x,y,z,w] -> V4 x y z w) <$>+ count 4 ((realToFrac <$> double) <* skipSpace)
src/executable/Main.hs view
@@ -1,7 +1,8 @@ {-# LANGUAGE OverloadedStrings #-} module Main (main) where import System.Environment (getArgs)-import PCD.Data (asciiToBinary, projectBinaryFields)+import PCD.Conversion (asciiToBinary)+import PCD.Data (projectBinaryFields) data Args = Args { _inputFile :: FilePath , _outputFile :: FilePath
+ tests/SampleData.hs view
@@ -0,0 +1,232 @@+{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}+-- |Sample PCD file from http://pointclouds.org/documentation/tutorials/pcd_file_format.php+module SampleData where+import Data.String.QQ+import Data.Text (Text)++sampleData :: Text+sampleData = [s|+# .PCD v.7 - Point Cloud Data file format+VERSION .7+FIELDS x y z rgb+SIZE 4 4 4 4+TYPE F F F F+COUNT 1 1 1 1+WIDTH 213+HEIGHT 1+VIEWPOINT 0 0 0 1 0 0 0+POINTS 213+DATA ascii+0.93773 0.33763 0 4.2108e+06+0.90805 0.35641 0 4.2108e+06+0.81915 0.32 0 4.2108e+06+0.97192 0.278 0 4.2108e+06+0.944 0.29474 0 4.2108e+06+0.98111 0.24247 0 4.2108e+06+0.93655 0.26143 0 4.2108e+06+0.91631 0.27442 0 4.2108e+06+0.81921 0.29315 0 4.2108e+06+0.90701 0.24109 0 4.2108e+06+0.83239 0.23398 0 4.2108e+06+0.99185 0.2116 0 4.2108e+06+0.89264 0.21174 0 4.2108e+06+0.85082 0.21212 0 4.2108e+06+0.81044 0.32222 0 4.2108e+06+0.74459 0.32192 0 4.2108e+06+0.69927 0.32278 0 4.2108e+06+0.8102 0.29315 0 4.2108e+06+0.75504 0.29765 0 4.2108e+06+0.8102 0.24399 0 4.2108e+06+0.74995 0.24723 0 4.2108e+06+0.68049 0.29768 0 4.2108e+06+0.66509 0.29002 0 4.2108e+06+0.69441 0.2526 0 4.2108e+06+0.62807 0.22187 0 4.2108e+06+0.58706 0.32199 0 4.2108e+06+0.52125 0.31955 0 4.2108e+06+0.49351 0.32282 0 4.2108e+06+0.44313 0.32169 0 4.2108e+06+0.58678 0.2929 0 4.2108e+06+0.53436 0.29164 0 4.2108e+06+0.59308 0.24134 0 4.2108e+06+0.5357 0.2444 0 4.2108e+06+0.50043 0.31235 0 4.2108e+06+0.44107 0.29711 0 4.2108e+06+0.50727 0.22193 0 4.2108e+06+0.43957 0.23976 0 4.2108e+06+0.8105 0.21112 0 4.2108e+06+0.73555 0.2114 0 4.2108e+06+0.69907 0.21082 0 4.2108e+06+0.63327 0.21154 0 4.2108e+06+0.59165 0.21201 0 4.2108e+06+0.52477 0.21491 0 4.2108e+06+0.49375 0.21006 0 4.2108e+06+0.4384 0.19632 0 4.2108e+06+0.43425 0.16052 0 4.2108e+06+0.3787 0.32173 0 4.2108e+06+0.33444 0.3216 0 4.2108e+06+0.23815 0.32199 0 4.808e+06+0.3788 0.29315 0 4.2108e+06+0.33058 0.31073 0 4.2108e+06+0.3788 0.24399 0 4.2108e+06+0.30249 0.29189 0 4.2108e+06+0.23492 0.29446 0 4.808e+06+0.29465 0.24399 0 4.2108e+06+0.23514 0.24172 0 4.808e+06+0.18836 0.32277 0 4.808e+06+0.15992 0.32176 0 4.808e+06+0.08642 0.32181 0 4.808e+06+0.039994 0.32283 0 4.808e+06+0.20039 0.31211 0 4.808e+06+0.1417 0.29506 0 4.808e+06+0.20921 0.22332 0 4.808e+06+0.13884 0.24227 0 4.808e+06+0.085123 0.29441 0 4.808e+06+0.048446 0.31279 0 4.808e+06+0.086957 0.24399 0 4.808e+06+0.3788 0.21189 0 4.2108e+06+0.29465 0.19323 0 4.2108e+06+0.23755 0.19348 0 4.808e+06+0.29463 0.16054 0 4.2108e+06+0.23776 0.16054 0 4.808e+06+0.19016 0.21038 0 4.808e+06+0.15704 0.21245 0 4.808e+06+0.08678 0.21169 0 4.808e+06+0.012746 0.32168 0 4.808e+06+-0.075715 0.32095 0 4.808e+06+-0.10622 0.32304 0 4.808e+06+-0.16391 0.32118 0 4.808e+06+0.00088411 0.29487 0 4.808e+06+-0.057568 0.29457 0 4.808e+06+-0.0034333 0.24399 0 4.808e+06+-0.055185 0.24185 0 4.808e+06+-0.10983 0.31352 0 4.808e+06+-0.15082 0.29453 0 4.808e+06+-0.11534 0.22049 0 4.808e+06+-0.15155 0.24381 0 4.808e+06+-0.1912 0.32173 0 4.808e+06+-0.281 0.3185 0 4.808e+06+-0.30791 0.32307 0 4.808e+06+-0.33854 0.32148 0 4.808e+06+-0.21248 0.29805 0 4.808e+06+-0.26372 0.29905 0 4.808e+06+-0.22562 0.24399 0 4.808e+06+-0.25035 0.2371 0 4.808e+06+-0.29941 0.31191 0 4.808e+06+-0.35845 0.2954 0 4.808e+06+-0.29231 0.22236 0 4.808e+06+-0.36101 0.24172 0 4.808e+06+-0.0034393 0.21129 0 4.808e+06+-0.07306 0.21304 0 4.808e+06+-0.10579 0.2099 0 4.808e+06+-0.13642 0.21411 0 4.808e+06+-0.22562 0.19323 0 4.808e+06+-0.24439 0.19799 0 4.808e+06+-0.22591 0.16041 0 4.808e+06+-0.23466 0.16082 0 4.808e+06+-0.3077 0.20998 0 4.808e+06+-0.3413 0.21239 0 4.808e+06+-0.40551 0.32178 0 4.2108e+06+-0.50568 0.3218 0 4.2108e+06+-0.41732 0.30844 0 4.2108e+06+-0.44237 0.28859 0 4.2108e+06+-0.41591 0.22004 0 4.2108e+06+-0.44803 0.24236 0 4.2108e+06+-0.50623 0.29315 0 4.2108e+06+-0.50916 0.24296 0 4.2108e+06+-0.57019 0.22334 0 4.2108e+06+-0.59611 0.32199 0 4.2108e+06+-0.65104 0.32199 0 4.2108e+06+-0.72566 0.32129 0 4.2108e+06+-0.75538 0.32301 0 4.2108e+06+-0.59653 0.29315 0 4.2108e+06+-0.65063 0.29315 0 4.2108e+06+-0.59478 0.24245 0 4.2108e+06+-0.65063 0.24399 0 4.2108e+06+-0.70618 0.29525 0 4.2108e+06+-0.76203 0.31284 0 4.2108e+06+-0.70302 0.24183 0 4.2108e+06+-0.77062 0.22133 0 4.2108e+06+-0.41545 0.21099 0 4.2108e+06+-0.45004 0.19812 0 4.2108e+06+-0.4475 0.1673 0 4.2108e+06+-0.52031 0.21236 0 4.2108e+06+-0.55182 0.21045 0 4.2108e+06+-0.5965 0.21131 0 4.2108e+06+-0.65064 0.2113 0 4.2108e+06+-0.72216 0.21286 0 4.2108e+06+-0.7556 0.20987 0 4.2108e+06+-0.78343 0.31973 0 4.2108e+06+-0.87572 0.32111 0 4.2108e+06+-0.90519 0.32263 0 4.2108e+06+-0.95526 0.34127 0 4.2108e+06+-0.79774 0.29271 0 4.2108e+06+-0.85618 0.29497 0 4.2108e+06+-0.79975 0.24326 0 4.2108e+06+-0.8521 0.24246 0 4.2108e+06+-0.91157 0.31224 0 4.2108e+06+-0.95031 0.29572 0 4.2108e+06+-0.92223 0.2213 0 4.2108e+06+-0.94979 0.24354 0 4.2108e+06+-0.78641 0.21505 0 4.2108e+06+-0.87094 0.21237 0 4.2108e+06+-0.90637 0.20934 0 4.2108e+06+-0.93777 0.21481 0 4.2108e+06+0.22244 -0.0296 0 4.808e+06+0.2704 -0.078167 0 4.808e+06+0.24416 -0.056883 0 4.808e+06+0.27311 -0.10653 0 4.808e+06+0.26172 -0.10653 0 4.808e+06+0.2704 -0.1349 0 4.808e+06+0.24428 -0.15599 0 4.808e+06+0.19017 -0.025297 0 4.808e+06+0.14248 -0.02428 0 4.808e+06+0.19815 -0.037432 0 4.808e+06+0.14248 -0.03515 0 4.808e+06+0.093313 -0.02428 0 4.808e+06+0.044144 -0.02428 0 4.808e+06+0.093313 -0.03515 0 4.808e+06+0.044144 -0.03515 0 4.808e+06+0.21156 -0.17357 0 4.808e+06+0.029114 -0.12594 0 4.2108e+06+0.036583 -0.15619 0 4.2108e+06+0.22446 -0.20514 0 4.808e+06+0.2208 -0.2369 0 4.808e+06+0.2129 -0.208 0 4.808e+06+0.19316 -0.25672 0 4.808e+06+0.14497 -0.27484 0 4.808e+06+0.030167 -0.18748 0 4.2108e+06+0.1021 -0.27453 0 4.808e+06+0.1689 -0.2831 0 4.808e+06+0.13875 -0.28647 0 4.808e+06+0.086993 -0.29568 0 4.808e+06+0.044924 -0.3154 0 4.808e+06+-0.0066125 -0.02428 0 4.808e+06+-0.057362 -0.02428 0 4.808e+06+-0.0066125 -0.03515 0 4.808e+06+-0.057362 -0.03515 0 4.808e+06+-0.10653 -0.02428 0 4.808e+06+-0.15266 -0.025282 0 4.808e+06+-0.10653 -0.03515 0 4.808e+06+-0.16036 -0.037257 0 4.808e+06+0.0083286 -0.1259 0 4.2108e+06+0.0007442 -0.15603 0 4.2108e+06+-0.1741 -0.17381 0 4.808e+06+-0.18502 -0.02954 0 4.808e+06+-0.20707 -0.056403 0 4.808e+06+-0.23348 -0.07764 0 4.808e+06+-0.2244 -0.10653 0 4.808e+06+-0.23604 -0.10652 0 4.808e+06+-0.20734 -0.15641 0 4.808e+06+-0.23348 -0.13542 0 4.808e+06+0.0061083 -0.18729 0 4.2108e+06+-0.066235 -0.27472 0 4.808e+06+-0.17577 -0.20789 0 4.808e+06+-0.10861 -0.27494 0 4.808e+06+-0.15584 -0.25716 0 4.808e+06+-0.0075775 -0.31546 0 4.808e+06+-0.050817 -0.29595 0 4.808e+06+-0.10306 -0.28653 0 4.808e+06+-0.1319 -0.2831 0 4.808e+06+-0.18716 -0.20571 0 4.808e+06+-0.18369 -0.23729 0 4.808e+06|]
+ tests/SampleLoad.hs view
@@ -0,0 +1,44 @@+-- |Ensure that a sample PCD file can be loaded.+module Main where+import Control.Lens ((^.))+import qualified Data.Text.IO as T+import qualified Data.Vector as V+import System.Directory (getTemporaryDirectory)+import System.IO (openTempFile, hClose, hSeek, SeekMode(..))+import Test.Framework (defaultMain)+import Test.Framework.Providers.HUnit (hUnitTestToTests)+import Test.HUnit (Test(..), (~?), (~=?))++import SampleData+import PCD.Data+import PCD.Header++testLen :: Header -> V.Vector (V.Vector FieldType) -> Test+testLen header pts = TestLabel "Number of fields" $ + TestList [ 4 ~=? length (header^.fields)+ , 4 ~=? V.length (V.head pts) ]++testPts :: Header -> V.Vector a -> Test+testPts header pts = TestLabel "Number of points" $+ TestList [ 213 ~=? header^.points + , 213 ~=? V.length pts ]++within :: (Num a, Ord a) => a -> a -> a -> Bool+within delta x y = abs (y - x) < delta++testData :: V.Vector (V.Vector FieldType) -> Test+testData pts = TestLabel "Point data" $+ TestList [ within 0.001 (-0.23729) lastY ~? + "Last point's Y coordinate" ]+ where lastY = unsafeUnwrap (V.last pts V.! 1) :: Float++main :: IO ()+main = do d <- getTemporaryDirectory+ (_, h) <- openTempFile d "pcdTest"+ T.hPutStr h sampleData+ hSeek h AbsoluteSeek 0+ (header, _) <- readHeader h+ pts <- loadFlexiblePoints header h+ defaultMain . hUnitTestToTests $+ TestList [testLen header pts, testPts header pts, testData pts]+ hClose h