{- This file is part of hOff-parser. hOff-parser is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. hOff-parser is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Foobar. If not, see . -} {-| Module: HOff.Parser Description: Parser to parse the OFF(Object File Format, Princeton ModelNet) Copyright: (C) Johann Lee , 2017 License: GPL-3 Maintainer: me@qinka.pro Stability: experimental Portability: unknown The types are used in parser. -} {-# LANGUAGE FlexibleContexts #-} module HOff.Parser ( offP , defParStat , module HOff.Parser.Types )where import HOff.Parser.Types import Text.Parsec import GHC.Exts (IsList(..)) import Data.Char import Control.Monad {-| The example of OFF(Object File Format, Princeton ModelNet). @ OFF 6 5 0 0 0 0 0 1 0 1 0 0 0 0 1 0 1 1 1 0 1 3 1 0 2 3 4 3 5 4 0 1 4 3 4 0 2 5 3 4 1 2 5 4 @ -} {-| TODO the description of OFF's details -} -- | Check whether there is ASCII head "OFF" checkHeadP :: Stream s m Char => ParsecT s u m () checkHeadP = do spaces str <- map toLower <$> many (oneOf "oOfF") if str == "off" then spaces else fail "fail to read OFF head" -- | Read the length of vertices and faces readLengthP :: Stream s m Char => ParsecT s ParStat m () readLengthP = do numV:numF:_ <- replicateM 3 readNumP spaces modifyState (\u -> u { numVertices = numV , numFaces = numF }) -- | Read the vertices (with contexts) verticesP :: (Stream s m Char, Read a, Num a) => ParsecT s ParStat m [Vertice a] verticesP = do n <- numVertices <$> getState replicateM n verticesPStep where verticesPStep = do x:y:z:_ <- replicateM 3 readNumP return $ Vertice (x,y,z) -- | Read the faces (with contexts) facesP :: Stream s m Char => ParsecT s ParStat m [Face Int] facesP = do n <- numFaces <$> getState replicateM n facesPStep where facesPStep = do n <- readNumP Face <$> replicateM n readNumP -- | Read a number readNumP :: (Read a, Num a, Stream s m Char) => ParsecT s u m a readNumP = do spaces read <$> many1 (hexDigit <|> oneOf "+-.") -- | parser the OFF file offP :: (Stream s m Char, Read a, Num a) => ParsecT s ParStat m (OFF a Int) offP = do checkHeadP readLengthP vs <- verticesP fs <- facesP return $ OFF vs fs -- | default par stat defParStat :: ParStat defParStat = ParStat 0 0