{-- TerraHS - Interface between TerraLib and Haskell

    (c) Sergio Costa (INPE) - Setembro, 2005

	This program is free software; you can redistribute it 
    and/or modify it under the terms of the GNU General 
    Public License 2.1 as published by the Free Software Foundation
    (http://www.opensource.org/licenses/gpl-license.php)
--}

{- | A module for supporting the functions of TerraLib TeGeometryAlgorithms

More information - <http://www.terralib.org>
-}
module TerraHS.TerraLib.TeGeometryAlgorithms where


import Foreign (unsafePerformIO)
import Foreign.C.String
import qualified Foreign.Ptr (Ptr)

--locais
import TerraHS.Algebras.Base.Object
import TerraHS.TerraLib.TeGeometry
import TerraHS.TerraLib.TePoint
import TerraHS.TerraLib.TeLine2D
import TerraHS.TerraLib.TeCell
import TerraHS.TerraLib.TeBox
import TerraHS.TerraLib.TePolygon

import TerraHS.Algebras.Base.Operations
import TerraHS.Algebras.Spatial.Geometries

		


---------------------------------------
--------- centroid operations ---------
---------------------------------------

			
instance Centroid TePointSet  TePoint where
	centroid ps = unsafePerformIO ( ( new ps ) >>= tepointset_tefindcentroid >>= fromPointer >>= return )
	

instance Centroid TeLineSet TePoint where
	centroid ls = unsafePerformIO ( ( new ls )	>>= telineset_tefindcentroid >>= fromPointer >>= return )

instance Centroid TePolygonSet TePoint where
	centroid pols = unsafePerformIO ( ( new pols )	>>= tepolygonset_tefindcentroid >>= fromPointer >>= return )

instance Centroid TePolygon TePoint where
	centroid pols = unsafePerformIO ( ( new pols )	>>= tepolygon_tefindcentroid >>= fromPointer >>= return )
	
---------------------------------------
--------- metric operations ---------
---------------------------------------

instance  DistanceDirection TePoint where
	distance p1 p2 = tedistance p1 p2


	
instance Numeric TePolygon where
	area p = tearea p
	length pol = telength (head (getlines pol) )
		where
		getlines (TePolygon ls) = ls

instance Numeric TeBox where
	area p = teareabox p
	
instance Numeric TeLine2D where
	length l = telength l
	


	
-- distance between two points	
tedistance pt1 pt2 = ( unsafePerformIO (applyf pt1 toTE pt2 toTE tepoint_tedistance))
	where
	toTE tx = new tx

-- | Returns the length of a Line 2D.
telength :: TeLine2D -> Double
telength l = ( unsafePerformIO (new l >>= \tl -> h_telength  tl >>= \r -> delete tl >> return r ))

-- | Returns the area of a TePolygon 
tearea :: TePolygon -> Double
tearea p = ( unsafePerformIO (new p >>= \tpol -> (tegeometryarea tpol) >>= \r -> delete tpol >> return r ))

teareabox :: TeBox -> Double
teareabox p = ( unsafePerformIO (new p >>= \tb -> tegeometryareabox tb >>= \r -> delete tb >> return r ))

makepolygon box = unsafePerformIO  ( (new box  ) >>=  (temakepolygon) >>= fromPointer >>= return )

tepolygonrotate pol1 angle= unsafePerformIO ((new pol1) >>= \tpol1 -> (tepolygon_rotate tpol1 angle) >>= fromPointer >>= \r -> delete tpol1 >> return r)

tepolygonradius pol1 = unsafePerformIO ((new pol1) >>= \tpol1 -> (tepolygon_radius tpol1 ) >>= \r -> delete tpol1 >> return r)
tepolygonrectangularfit pol1  = unsafePerformIO ((new pol1) >>= \tpol1 -> (tepolygon_rectangularfit tpol1 ) >>= \r -> delete tpol1 >> return r)



{--
foreign import stdcall unsafe "c_tepolygon_angle" tepolygon_angle :: TePolygonPtr ->  Prelude.IO Double

--}

--applyf ea fab ec fcd fbde  = fab ea >>= \eb -> fcd ec >>= \ed -> fbde eb ed >>= return


tebufferregion :: TePolygon  -> Double ->  Int -> [TeGeometry]
tebufferregion pol distance npoints = unsafePerformIO (tebufferregion')
	where
	tebufferregion' = do
		ptrpol <- (new pol)
		ptrpolset <- (h_tebufferregion ptrpol distance npoints)
		(polset2geoset ptrpolset)
	
polset2geoset gs = size gs >>= (polygonset2geometryset gs 0)

----------- overlay


instance Set TePolygon where

	union p1 p2 
		| (r == [] ) =  error "union: return any geometry"
		| otherwise = head r		
		where
		r =  (union [p1] [p2])
		
	difference p1 p2 =  head (difference [p1] [p2])
	intersection p1 p2 =  head (intersection [p1] [p2])
	

instance Set [TeGeometry]   where
	union gs1 gs2 = unsafePerformIO (apply1 gs1 gs2 (\ptr1 ptr2 -> teoverlay ptr1 ptr2 2))
	difference gs1 gs2 = unsafePerformIO (apply1 gs1 gs2 (\ptr1 ptr2 -> teoverlay ptr1 ptr2 1))
	intersection gs1 gs2 = unsafePerformIO (apply1 gs1 gs2 (\ptr1 ptr2 -> teoverlay ptr1 ptr2 4))

instance Set TePolygonSet   where
	union gs1 gs2 = (TePolygonSet (map toPolygon (unsafePerformIO (apply gs1 gs2 (\ptr1 ptr2 -> teoverlay ptr1 ptr2 2)))))
	difference gs1 gs2 = (TePolygonSet (map toPolygon (unsafePerformIO (apply gs1 gs2 (\ptr1 ptr2 -> teoverlay ptr1 ptr2 1)))))
	difference gs1 gs2 = (TePolygonSet (map toPolygon (unsafePerformIO (apply gs1 gs2 (\ptr1 ptr2 -> teoverlay ptr1 ptr2 4)))))

instance Set [TePolygon] where

	union p1 p2 = geos
		where
		(TePolygonSet geos) =  union (TePolygonSet p1) (TePolygonSet p2)
		
	intersection a b = geos
		where
		(TePolygonSet geos) = intersection (TePolygonSet a) (TePolygonSet b)
		
	difference a b =  geos
		where
		(TePolygonSet geos) = difference (TePolygonSet a) (TePolygonSet b)		
  
apply1 gs1 gs2 f =  (new (TePolygonSet (map toPolygon1 gs1))) >>= \ps1 -> (new (TePolygonSet (map toPolygon1 gs2))) >>= \ps2 -> f ps1 ps2 >>= \geo -> polset2geoset geo >>=  return
	where
	polset2geoset gs = size gs >>= (polygonset2geometryset gs 0)		
	toPolygon1 (GPg pg)    = pg
	
apply gs1 gs2 f = (new gs1) >>= \ps1 -> (new gs2) >>= \ps2 -> f ps1 ps2 >>= \geo -> polset2geoset  geo >>= return
	where
	polset2geoset gs = size gs >>= (polygonset2geometryset gs 0)		


foreign import stdcall unsafe "c_teoverlay" teoverlay :: TePolygonSetPtr -> TePolygonSetPtr ->  Int ->  Prelude.IO TePolygonSetPtr

	
	
-- metrics operations -------------------------
foreign import stdcall unsafe "c_tepoint_tedistance" tepoint_tedistance :: TePointPtr -> TePointPtr -> Prelude.IO Double
foreign import stdcall unsafe "c_telength" h_telength :: TeLine2DPtr ->  Prelude.IO Double
foreign import stdcall unsafe "c_tegeometryarea" tegeometryarea :: TePolygonPtr ->  Prelude.IO Double

foreign import stdcall unsafe "c_tegeometryareabox" tegeometryareabox :: TeBoxPtr ->  Prelude.IO Double

foreign import stdcall unsafe "c_tepointset_tefindcentroid" tepointset_tefindcentroid :: TePointSetPtr ->  Prelude.IO TePointPtr
foreign import stdcall unsafe "c_tepolygonset_tefindcentroid" tepolygonset_tefindcentroid :: TePolygonSetPtr ->  Prelude.IO TePointPtr
foreign import stdcall unsafe "c_telineset_tefindcentroid" telineset_tefindcentroid :: TeLineSetPtr ->  Prelude.IO TePointPtr
foreign import stdcall unsafe "c_tepolygon_tefindcentroid" tepolygon_tefindcentroid :: TePolygonPtr ->  Prelude.IO TePointPtr

foreign import stdcall unsafe "c_set_precision" setPrecision :: Double ->  Prelude.IO ()

foreign import stdcall unsafe "c_tebufferregion" h_tebufferregion :: TePolygonPtr -> Double ->  Int ->  Prelude.IO TePolygonSetPtr

foreign import stdcall unsafe "c_temakepolygon" temakepolygon :: TeBoxPtr ->  Prelude.IO TePolygonPtr

------------ thales

foreign import stdcall unsafe "c_tepolygon_rotate" tepolygon_rotate :: TePolygonPtr ->  Double -> Prelude.IO TePolygonPtr
foreign import stdcall unsafe "c_tepolygon_angle" tepolygon_angle :: TePolygonPtr ->  Prelude.IO Double
foreign import stdcall unsafe "c_tepolygon_radius" tepolygon_radius :: TePolygonPtr ->  Prelude.IO Double
foreign import stdcall unsafe "c_tepolygon_rectangularfit" tepolygon_rectangularfit :: TePolygonPtr ->  Prelude.IO Double