packages feed

hgis-1.0.0.2: dbf/Geometry/Shapefile/Types.hs

{-|
Module      : Geometry.Shapefile.Types
Description : Type definitions used by the library. Currently (24 Nov 2015)
              MultiPatch record types are not implemented. Only Point and
              Polygon are (somewhat) tested. YMMV
              https://www.esri.com/library/whitepapers/pdfs/shapefile.pdf
Author      : Sam van Herwaarden <samvherwaarden@gmail.com>
-}

module Geometry.Shapefile.Types ( ShpData (..)
                                , ShpHeader (..)
                                , ShpType (..)
                                , zTypes
                                , mTypes
                                , shpTypeFromId
                                , RecBBox (..)
                                , RecContents (..)
                                , ShpRec (..)
                                , ShpBBox (..)
                                , DbfFieldDesc (..)
                                , DbfData (..)
                                , DbfRecord (..)
                                ) where

import qualified Data.ByteString             as BS
import           Geometry.Shapefile.Internal

-- * SHP Types

data ShpData =
  ShpData {
    shpHeader     :: ShpHeader,
    dbfFieldDescs :: Maybe [DbfFieldDesc],
    shpRecs       :: [ShpRec]
  }

data ShpHeader =
  ShpHeader {
    shpFileLength :: Int,
    shpVersion    :: Int,
    shpType       :: ShpType,
    shpBB         :: ShpBBox
  }

data ShpType = ShpNull
             | ShpPoint
             | ShpPolyLine
             | ShpPolygon
             | ShpMultiPoint
             | ShpPointZ
             | ShpPolyLineZ
             | ShpPolygonZ
             | ShpMultiPointZ
             | ShpPointM
             | ShpPolyLineM
             | ShpPolygonM
             | ShpMultiPointM
             | ShpMultiPatch
             deriving (Eq)

-- | Types with Z values
zTypes :: [ShpType]
zTypes = [ShpPointZ, ShpPolyLineZ, ShpPolygonZ, ShpMultiPointZ]

-- | Types with M values
mTypes :: [ShpType]
mTypes = [ShpPointM, ShpPolyLineM, ShpPolygonM, ShpMultiPointM]

-- | Numeric codes used for record types
shpTypeFromId :: Int -> ShpType
shpTypeFromId i =
  case i of 0  -> ShpNull
            1  -> ShpPoint
            3  -> ShpPolyLine
            5  -> ShpPolygon
            8  -> ShpMultiPoint
            11 -> ShpPointZ
            13 -> ShpPolyLineZ
            15 -> ShpPolygonZ
            18 -> ShpMultiPointZ
            21 -> ShpPointM
            23 -> ShpPolyLineM
            25 -> ShpPolygonM
            28 -> ShpMultiPointM
            31 -> ShpMultiPatch
            _  -> error "shpTypeFromId: Unknown Shape Type"

data ShpBBox =
  ShpBBox {
    shpXMin :: Double,
    shpXMax :: Double,
    shpYMin :: Double,
    shpYMax :: Double,
    shpZMin :: Maybe Double,
    shpZMax :: Maybe Double,
    shpMMin :: Maybe Double,
    shpMMax :: Maybe Double
  }


data ShpRec =
  ShpRec {
    shpRecNum      :: Int,
    shpRecLen      :: Int,
    shpRecContents :: Maybe RecContents, -- Can be null type
    shpRecLabel    :: Maybe [DbfRecord], -- Should be usable without dbf
    shpRecType     :: ShpType
  }

data RecContents =
    RecNull
  | RecPoint Point
  | RecPointM {
      pmPoint :: Point,
      pmM     :: Double }
  | RecPointZ {
      pzPoint :: Point,
      pzZ     :: Double,
      pzM     :: Double }
  | RecMultiPoint {
      recMPBBox      :: RecBBox,
      recMPNumPoints :: Int,
      recMPPoints    :: [Point] }
  | RecMultiPointM {
      recMPMBBox      :: RecBBox,
      recMPMNumPoints :: Int,
      recMPMPoints    :: [Point],
      recMPMMRange    :: (Double, Double),
      recMPMMs        :: [Double] }
  | RecMultiPointZ {
      recMPZBBox      :: RecBBox,
      recMPZNumPoints :: Int,
      recMPZPoints    :: [Point],
      recMPZZRange    :: (Double, Double),
      recMPZZs        :: [Double],
      recMPZMRange    :: (Double, Double),
      recMPZMs        :: [Double] }
  | RecPolyLine {
      recPolLBBox        :: RecBBox,
      recPolLNumParts    :: Int,
      recPolLNumPoints   :: Int,
      recPolLPartLengths :: [Int],
      recPolLPoints      :: [[Point]] }
  | RecPolyLineM {
      recPolLMBBox        :: RecBBox,
      recPolLMNumParts    :: Int,
      recPolLMNumPoints   :: Int,
      recPolLMPartLengths :: [Int],
      recPolLMPoints      :: [[Point]],
      recPolLMMRange      :: (Double, Double),
      recPolLMMs          :: [Double] }
  | RecPolyLineZ {
      recPolLZBBox        :: RecBBox,
      recPolLZNumParts    :: Int,
      recPolLZNumPoints   :: Int,
      recPolLZPartLengths :: [Int],
      recPolLZPoints      :: [[Point]],
      recPolLZZRange      :: (Double, Double),
      recPolLZZs          :: [Double],
      recPolLZMRange      :: (Double, Double),
      recPolLZMs          :: [Double] }
  | RecPolygon {
      recPolBBox        :: RecBBox,
      recPolNumParts    :: Int,
      recPolNumPoints   :: Int,
      recPolPartLengths :: [Int],
      recPolPoints      :: [[Point]] }
  | RecPolygonM {
      recPolMBBox        :: RecBBox,
      recPolMNumParts    :: Int,
      recPolMNumPoints   :: Int,
      recPolMPartLengths :: [Int],
      recPolMPoints      :: [[Point]],
      recPolMMRange      :: (Double, Double),
      recPolMMs          :: [Double] }
  | RecPolygonZ {
      recPolZBBox        :: RecBBox,
      recPolZNumParts    :: Int,
      recPolZNumPoints   :: Int,
      recPolZPartLengths :: [Int],
      recPolZPoints      :: [[Point]],
      recPolZZRange      :: (Double, Double),
      recPolZZs          :: [Double],
      recPolZMRange      :: (Double, Double),
      recPolZMs          :: [Double] }
  -- RecMultiPatch

data RecBBox =
  RecBBox {
    recXMin :: Double,
    recXMax :: Double,
    recYMin :: Double,
    recYMax :: Double
  }

-- * DBF Types

data DbfData =
  DbfData {
    dbfNumRecs :: Int,
    dbfFields  :: [DbfFieldDesc],
    dbfRecords :: [[DbfRecord]]
  }

data DbfFieldDesc =
  DbfFieldDesc {
    fieldName :: String,
    fieldType :: Char,
    fieldLen  :: Int
  }

-- | Not all record types are implemented. Use your favorite method to
--   convert any bytestring (and feel free to add functionality).
data DbfRecord = DbfString String
               | DbfNum String
               | DbfBS BS.ByteString
               deriving (Show)