{-| GCode pretty-printing functions Utilities for manipulating and filtering 'GCode' -} {-# LANGUAGE RecordWildCards #-} module Data.GCode.Utils where import Data.Maybe import Data.GCode.Types import Data.GCode.RS274 (isMove, isRapid) import qualified Data.Map.Strict as M -- | True if 'Code' is a G-code isG :: Code -> Bool isG Code{codeCls=(Just G)} = True isG _ = False -- | True if 'Code' is a M-code isM :: Code -> Bool isM Code{codeCls=(Just M)} = True isM _ = False -- | True if 'Code' is a G{N} code isGN :: Int -> Code -> Bool isGN n Code{codeCls=(Just G), codeNum=(Just x)} = x == n isGN _ _ = False -- | True if 'Code' has a coordinate in axis 'a' hasAxis :: AxisDesignator -> Code -> Bool hasAxis a Code{..} = M.member a codeAxes hasAxis _ _ = False getAxis :: AxisDesignator -> Code -> Maybe Double getAxis a Code{..} = M.lookup a codeAxes getAxis _ _ = Nothing getAxes :: [AxisDesignator] -> Code -> [Maybe Double] getAxes as c = map (\a-> getAxis a c) as getAxesToList :: Code -> [(AxisDesignator, Double)] getAxesToList Code{..} = M.toList codeAxes getAxesToList _ = [] --filterAxes :: [AxisDesignator] -> Code -> [Double] --filterAxes ax Code{..} = map (\a -> M.lookup a codeAxes) ax -- | True if 'Code' contains 'X' axis hasX :: Code -> Bool hasX = hasAxis X -- | True if 'Code' contains 'Y' axis hasY :: Code -> Bool hasY = hasAxis Y -- | True if 'Code' contains 'Z' axis hasZ :: Code -> Bool hasZ = hasAxis Z -- | True if 'Code' contains 'E' axis hasE :: Code -> Bool hasE = hasAxis E -- | True if 'Code' contains parameter with 'ParamDesignator' hasParam :: ParamDesignator -> Code -> Bool hasParam p Code{..} = M.member p codeParams hasParam _ _ = False -- | Get parameter if defined getParam :: ParamDesignator -> Code -> Maybe Double getParam p Code{..} = M.lookup p codeParams getParam _ _ = Nothing -- | True if 'Code' contains feedrate parameter (e.g. G0 F3000) hasFeedrate :: Code -> Bool hasFeedrate = hasParam F -- | Filter G-codes gcodes :: [Code] -> [Code] gcodes = filter isG -- | Filter M-codes mcodes :: [Code] -> [Code] mcodes = filter isM -- | Filter rapid moves rapids :: [Code] -> [Code] rapids = filter isRapid -- | Filter moves moves :: [Code] -> [Code] moves = filter isMove -- | Replace 'Class' of 'Code' (e.g. for chaning G0 to M0) replaceClass :: Class -> Code -> Code replaceClass newclass c = cls newclass c -- | Replace code value of 'Code' (e.g. for chaning G0 to G1) replaceCode :: Int -> Code -> Code replaceCode newcode c = num newcode c -- | Replace axis with 'AxisDesignator' in 'Code' returning new 'Code' replaceAxis :: AxisDesignator -> Double -> Code -> Code replaceAxis de val c | hasAxis de c = addReplaceAxis de val c replaceAxis _ _ c = c -- | Apply function to axis specified by 'AxisDesignator' modifyAxis :: AxisDesignator -> (Double -> Double) -> Code -> Code modifyAxis de f c | hasAxis de c = addReplaceAxis de (f $ fromJust $ getAxis de c) c modifyAxis _ _ c = c -- | Apply function to axes specified by '[AxisDesignator]' modifyAxes :: [AxisDesignator] -> (Double -> Double) -> Code -> Code modifyAxes axes' f c = foldl (\c1 ax -> modifyAxis ax f c1) c axes' -- | Test if Code has X and Y axes hasXY :: Code -> Bool hasXY c = hasAxis X c && hasAxis Y c -- | Apply function to X and Y axes modifyXY :: (Double -> Double -> (Double, Double)) -> Code -> Code modifyXY f c | hasXY c = let x = fromJust $ getAxis X c y = fromJust $ getAxis Y c (nx, ny) = f x y in c & axis X nx & axis Y ny modifyXY _ c = c -- | Replace or add axis with 'AxisDesignator' in 'Code' returning new 'Code' addReplaceAxis :: AxisDesignator -> Double -> Code -> Code addReplaceAxis de val c@Code{..} = c & (axes $ newaxes $ codeAxes) where newaxes = M.insert de val addReplaceAxis _ _ x = x -- | Replace X axis coordnate replaceX :: Double -> Code -> Code replaceX = replaceAxis X -- | Replace Y axis coordinate replaceY :: Double -> Code -> Code replaceY = replaceAxis Y -- | Replace Z axis coordinate replaceZ :: Double -> Code -> Code replaceZ = replaceAxis Z -- | Replace E axis coordinate replaceE :: Double -> Code -> Code replaceE = replaceAxis E -- | Replace or add X axis coordinate addReplaceX :: Double -> Code -> Code addReplaceX = addReplaceAxis X -- | Replace or add Y axis coordinate addReplaceY :: Double -> Code -> Code addReplaceY = addReplaceAxis Y -- | Replace or add Z axis coordinate addReplaceZ :: Double -> Code -> Code addReplaceZ = addReplaceAxis Z -- | Replace or add E axis coordinate addReplaceE :: Double -> Code -> Code addReplaceE = addReplaceAxis E -- | Replace parameter with 'ParamDesignator' in 'Code' returning new 'Code' replaceParam :: ParamDesignator -> Double -> Code -> Code replaceParam de val c | hasParam de c = addReplaceParam de val c replaceParam _ _ c = c -- | Apply function to parameter with 'ParamDesignator' modifyParam :: ParamDesignator -> (Double -> Double) -> Code -> Code modifyParam de f c | hasParam de c = addReplaceParam de (f $ fromJust $ getParam de c) c modifyParam _ _ c = c -- | Apply function to parameters specified by '[ParamDesignator]' modifyParams :: [ParamDesignator] -> (Double -> Double) -> Code -> Code modifyParams params' f c = foldl (\c1 ax -> modifyParam ax f c1) c params' -- | Apply function to parameters specified by '[ParamDesignator]' -- -- Function gets 'ParameterDesignator' passed as its first argument modifyParamsWithKey :: [ParamDesignator] -> (ParamDesignator -> Double -> Double) -> Code -> Code modifyParamsWithKey params' f c = foldl (\c1 ax -> modifyParam ax (f ax) c1) c params' -- | Replace or add parameter with 'ParamDesignator' in 'Code' returning new 'Code' addReplaceParam :: ParamDesignator -> Double -> Code -> Code addReplaceParam de val c@Code{..} = c & (params $ newparams $ codeParams) where newparams = M.insert de val addReplaceParam _ _ x = x -- | Replace feedrate (F parameter) in 'Code' returning new 'Code' replaceFeedrate :: Double -> Code -> Code replaceFeedrate = replaceParam F -- | Apply function to feedrate modifyFeedrate :: (Double -> Double) -> Code -> Code modifyFeedrate = modifyParam F -- | Sum of all axis distances of this 'Code' travelDistance :: Code -> Double travelDistance Code{codeCls=(Just G), ..} = M.foldl (+) 0 codeAxes travelDistance _ = 0 -- | Round `x` with specified precision roundprec :: (Integral a, RealFrac b, Fractional c) => a -> b -> c roundprec n x = (fromInteger $ round $ x * (10^n)) / (10.0^^n)