{- ORMOLU_DISABLE -}
-- Implicit CAD. Copyright (C) 2011, Christopher Olah (chris@colah.ca)
-- Copyright (C) 2014 2015, Julia Longtin (julial@turinglace.com)
-- Copyright (C) 2015 2016, Mike MacHenry (mike.machenry@gmail.com)
-- Released under the GNU AGPLV3+, see LICENSE

-- Allow us to use real types in the type constraints.
{-# LANGUAGE FlexibleContexts #-}
-- Allows \case in export2|3
{-# LANGUAGE LambdaCase #-}

module Graphics.Implicit.Export (
  export2,
  export3,
  OutputFormat(SVG, SCAD, PNG, GCode, ASCIISTL, STL, THREEJS, OBJ, DXF),
  writeObject,
  formatObject,
  writeSVG,
  writeSTL,
  writeBinSTL,
  writeOBJ,
  writeTHREEJS,
  writeGCodeHacklabLaser,
  writeDXF2,
  writeSCAD2,
  writeSCAD3,
  writePNG,
  )
where

import Prelude (FilePath, IO, (.), ($), (<>), show, error)

-- The types of our objects (before rendering), and the type of the resolution to render with.
import Graphics.Implicit.Definitions (SymbolicObj2, SymbolicObj3, , Polyline, TriangleMesh, NormedTriangleMesh)

-- functions for outputing a file, and one of the types.
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy.IO as LT (writeFile)
import qualified Data.ByteString.Lazy as LBS (writeFile)

-- Import instances of DiscreteApproxable...
import Graphics.Implicit.Export.DiscreteAproxable (DiscreteAproxable, discreteAprox)

-- Output file formats.
import qualified Graphics.Implicit.Export.PolylineFormats as PolylineFormats (svg, hacklabLaserGCode, dxf2)
import qualified Graphics.Implicit.Export.TriangleMeshFormats as TriangleMeshFormats (stl, binaryStl, jsTHREE)
import qualified Graphics.Implicit.Export.NormedTriangleMeshFormats as NormedTriangleMeshFormats (obj)
import qualified Graphics.Implicit.Export.SymbolicFormats as SymbolicFormats (scad2, scad3)
import qualified Codec.Picture as ImageFormatCodecs (DynamicImage, savePngImage)

import Graphics.Implicit.Export.OutputFormat (OutputFormat(SVG, SCAD, PNG, GCode, ASCIISTL, STL, THREEJS, OBJ, DXF))

-- | Write an object to a file with LazyText IO, using the given format writer function.
writeObject :: (DiscreteAproxable obj aprox)
    =>                 -- ^ Resolution
    -> (aprox -> Text)  -- ^ File Format Writer (Function that formats)
    -> FilePath         -- ^ File Name
    -> obj              -- ^ Object to render
    -> IO ()            -- ^ Writing Action!
writeObject :: ℝ -> (aprox -> Text) -> FilePath -> obj -> IO ()
writeObject res aprox -> Text
formatWriter FilePath
filename obj
obj =
    let
        aprox :: Text
aprox = ℝ -> (aprox -> Text) -> obj -> Text
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (aprox -> Text) -> obj -> Text
formatObject res aprox -> Text
formatWriter obj
obj
    in FilePath -> Text -> IO ()
LT.writeFile FilePath
filename Text
aprox

-- | Serialize an object using the given format writer, which takes the filename and writes to it..
writeObject' :: (DiscreteAproxable obj aprox)
    =>                 -- ^ Resolution
    -> (FilePath -> aprox -> IO ())  -- ^ File Format writer
    -> FilePath         -- ^ File Name
    -> obj              -- ^ Object to render
    -> IO ()            -- ^ Writing Action!
writeObject' :: ℝ -> (FilePath -> aprox -> IO ()) -> FilePath -> obj -> IO ()
writeObject' res FilePath -> aprox -> IO ()
formatWriter FilePath
filename obj
obj =
    FilePath -> aprox -> IO ()
formatWriter FilePath
filename (ℝ -> obj -> aprox
forall obj aprox. DiscreteAproxable obj aprox => ℝ -> obj -> aprox
discreteAprox res obj
obj)

-- | Serialize an object using the given format writer. No file target is implied.
formatObject :: (DiscreteAproxable obj aprox)
    =>                 -- ^ Resolution
    -> (aprox -> Text)  -- ^ File Format Writer (Function that formats)
    -> obj              -- ^ Object to render
    -> Text             -- ^ Result
formatObject :: ℝ -> (aprox -> Text) -> obj -> Text
formatObject res aprox -> Text
formatWriter = aprox -> Text
formatWriter (aprox -> Text) -> (obj -> aprox) -> obj -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ℝ -> obj -> aprox
forall obj aprox. DiscreteAproxable obj aprox => ℝ -> obj -> aprox
discreteAprox res

writeSVG :: DiscreteAproxable obj [Polyline] =>  -> FilePath -> obj -> IO ()
writeSVG :: ℝ -> FilePath -> obj -> IO ()
writeSVG res = ℝ -> ([Polyline] -> Text) -> FilePath -> obj -> IO ()
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (aprox -> Text) -> FilePath -> obj -> IO ()
writeObject res [Polyline] -> Text
PolylineFormats.svg

writeDXF2 :: DiscreteAproxable obj [Polyline] =>  -> FilePath -> obj -> IO ()
writeDXF2 :: ℝ -> FilePath -> obj -> IO ()
writeDXF2 res = ℝ -> ([Polyline] -> Text) -> FilePath -> obj -> IO ()
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (aprox -> Text) -> FilePath -> obj -> IO ()
writeObject res [Polyline] -> Text
PolylineFormats.dxf2

writeSTL :: DiscreteAproxable obj TriangleMesh =>  -> FilePath -> obj -> IO ()
writeSTL :: ℝ -> FilePath -> obj -> IO ()
writeSTL res = ℝ -> (TriangleMesh -> Text) -> FilePath -> obj -> IO ()
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (aprox -> Text) -> FilePath -> obj -> IO ()
writeObject res TriangleMesh -> Text
TriangleMeshFormats.stl

writeBinSTL :: DiscreteAproxable obj TriangleMesh =>  -> FilePath -> obj -> IO ()
writeBinSTL :: ℝ -> FilePath -> obj -> IO ()
writeBinSTL res FilePath
file obj
obj = FilePath -> ByteString -> IO ()
LBS.writeFile FilePath
file (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$ TriangleMesh -> ByteString
TriangleMeshFormats.binaryStl (TriangleMesh -> ByteString) -> TriangleMesh -> ByteString
forall a b. (a -> b) -> a -> b
$ ℝ -> obj -> TriangleMesh
forall obj aprox. DiscreteAproxable obj aprox => ℝ -> obj -> aprox
discreteAprox res obj
obj

writeOBJ :: DiscreteAproxable obj NormedTriangleMesh =>  -> FilePath -> obj -> IO ()
writeOBJ :: ℝ -> FilePath -> obj -> IO ()
writeOBJ res = ℝ -> (NormedTriangleMesh -> Text) -> FilePath -> obj -> IO ()
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (aprox -> Text) -> FilePath -> obj -> IO ()
writeObject res NormedTriangleMesh -> Text
NormedTriangleMeshFormats.obj

writeTHREEJS :: DiscreteAproxable obj TriangleMesh =>  -> FilePath -> obj -> IO ()
writeTHREEJS :: ℝ -> FilePath -> obj -> IO ()
writeTHREEJS res = ℝ -> (TriangleMesh -> Text) -> FilePath -> obj -> IO ()
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (aprox -> Text) -> FilePath -> obj -> IO ()
writeObject res TriangleMesh -> Text
TriangleMeshFormats.jsTHREE

writeGCodeHacklabLaser :: DiscreteAproxable obj [Polyline] =>  -> FilePath -> obj -> IO ()
writeGCodeHacklabLaser :: ℝ -> FilePath -> obj -> IO ()
writeGCodeHacklabLaser res = ℝ -> ([Polyline] -> Text) -> FilePath -> obj -> IO ()
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (aprox -> Text) -> FilePath -> obj -> IO ()
writeObject res [Polyline] -> Text
PolylineFormats.hacklabLaserGCode

writeSCAD3 ::  -> FilePath -> SymbolicObj3 -> IO ()
writeSCAD3 :: ℝ -> FilePath -> SymbolicObj3 -> IO ()
writeSCAD3 res FilePath
filename SymbolicObj3
obj = FilePath -> Text -> IO ()
LT.writeFile FilePath
filename (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ ℝ -> SymbolicObj3 -> Text
SymbolicFormats.scad3 res SymbolicObj3
obj

writeSCAD2 ::  -> FilePath -> SymbolicObj2 -> IO ()
writeSCAD2 :: ℝ -> FilePath -> SymbolicObj2 -> IO ()
writeSCAD2 res FilePath
filename SymbolicObj2
obj = FilePath -> Text -> IO ()
LT.writeFile FilePath
filename (Text -> IO ()) -> Text -> IO ()
forall a b. (a -> b) -> a -> b
$ ℝ -> SymbolicObj2 -> Text
SymbolicFormats.scad2 res SymbolicObj2
obj

writePNG :: DiscreteAproxable obj ImageFormatCodecs.DynamicImage =>  -> FilePath -> obj -> IO ()
writePNG :: ℝ -> FilePath -> obj -> IO ()
writePNG res = ℝ
-> (FilePath -> DynamicImage -> IO ()) -> FilePath -> obj -> IO ()
forall obj aprox.
DiscreteAproxable obj aprox =>
ℝ -> (FilePath -> aprox -> IO ()) -> FilePath -> obj -> IO ()
writeObject' res FilePath -> DynamicImage -> IO ()
ImageFormatCodecs.savePngImage

-- | Output a file containing a 3D object.
export3 :: OutputFormat ->  -> FilePath -> SymbolicObj3 -> IO ()
export3 :: OutputFormat -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
export3 = \case
    OutputFormat
ASCIISTL -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
forall obj.
DiscreteAproxable obj TriangleMesh =>
ℝ -> FilePath -> obj -> IO ()
writeSTL
    OutputFormat
STL      -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
forall obj.
DiscreteAproxable obj TriangleMesh =>
ℝ -> FilePath -> obj -> IO ()
writeBinSTL
    OutputFormat
SCAD     -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
writeSCAD3
    OutputFormat
OBJ      -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
forall obj.
DiscreteAproxable obj NormedTriangleMesh =>
ℝ -> FilePath -> obj -> IO ()
writeOBJ
    OutputFormat
PNG      -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
forall obj.
DiscreteAproxable obj DynamicImage =>
ℝ -> FilePath -> obj -> IO ()
writePNG
    OutputFormat
THREEJS  -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
forall obj.
DiscreteAproxable obj TriangleMesh =>
ℝ -> FilePath -> obj -> IO ()
writeTHREEJS
    OutputFormat
fmt      -> FilePath -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
forall a. HasCallStack => FilePath -> a
error (FilePath -> ℝ -> FilePath -> SymbolicObj3 -> IO ())
-> FilePath -> ℝ -> FilePath -> SymbolicObj3 -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Unrecognized 3D format: " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> OutputFormat -> FilePath
forall a. Show a => a -> FilePath
show OutputFormat
fmt

-- | Output a file containing a 2D object.
export2 :: OutputFormat ->  -> FilePath -> SymbolicObj2 -> IO ()
export2 :: OutputFormat -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
export2 = \case
    OutputFormat
SVG   -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
forall obj.
DiscreteAproxable obj [Polyline] =>
ℝ -> FilePath -> obj -> IO ()
writeSVG
    OutputFormat
DXF   -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
forall obj.
DiscreteAproxable obj [Polyline] =>
ℝ -> FilePath -> obj -> IO ()
writeDXF2
    OutputFormat
SCAD  -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
writeSCAD2
    OutputFormat
PNG   -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
forall obj.
DiscreteAproxable obj DynamicImage =>
ℝ -> FilePath -> obj -> IO ()
writePNG
    OutputFormat
GCode -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
forall obj.
DiscreteAproxable obj [Polyline] =>
ℝ -> FilePath -> obj -> IO ()
writeGCodeHacklabLaser
    OutputFormat
fmt   -> FilePath -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
forall a. HasCallStack => FilePath -> a
error (FilePath -> ℝ -> FilePath -> SymbolicObj2 -> IO ())
-> FilePath -> ℝ -> FilePath -> SymbolicObj2 -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath
"Unrecognized 2D format: " FilePath -> FilePath -> FilePath
forall a. Semigroup a => a -> a -> a
<> OutputFormat -> FilePath
forall a. Show a => a -> FilePath
show OutputFormat
fmt