
///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//                    User Interface                     //
//                                                       //
//                    Program: SAGA                      //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                     WKSP_Grid.h                       //
//                                                       //
//          Copyright (C) 2005 by Olaf Conrad            //
//                                                       //
//-------------------------------------------------------//
//                                                       //
// This file is part of 'SAGA - System for Automated     //
// Geoscientific Analyses'. SAGA 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 2 of the     //
// License, or (at your option) any later version.       //
//                                                       //
// SAGA 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 this program; if not, see   //
// <http://www.gnu.org/licenses/>.                       //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//    contact:    Olaf Conrad                            //
//                Institute of Geography                 //
//                University of Goettingen               //
//                Goldschmidtstr. 5                      //
//                37077 Goettingen                       //
//                Germany                                //
//                                                       //
//    e-mail:     oconrad@saga-gis.org                   //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
#ifndef _HEADER_INCLUDED__SAGA_GUI__WKSP_Grid_H
#define _HEADER_INCLUDED__SAGA_GUI__WKSP_Grid_H


///////////////////////////////////////////////////////////
//                                                       //
//                                                       //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
#include "wksp_layer.h"


///////////////////////////////////////////////////////////
//                                                       //
//                                                       //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
class CWKSP_Grid : public CWKSP_Layer
{
public:
	CWKSP_Grid(CSG_Grid *pGrid);

	virtual TWKSP_Item			Get_Type				(void)	{	return( WKSP_ITEM_Grid );	}

	CSG_Grid *					Get_Grid				(void)	{	return( (CSG_Grid *)m_pObject );	}

	virtual wxString			Get_Description			(void);

	virtual wxToolBarBase *		Get_ToolBar				(void);
	virtual wxMenu *			Get_Menu				(void);

	virtual bool				On_Command				(int Cmd_ID);
	virtual bool				On_Command_UI			(wxUpdateUIEvent &event);

	virtual wxString			Get_Value				(CSG_Point ptWorld, double Epsilon);

	virtual bool				Set_Stretch_Extent		(const CSG_Rect &Extent);

	virtual bool				asImage					(CSG_Grid *pImage);

	virtual bool				Update					(CWKSP_Layer *pChanged);

	virtual wxMenu *			Edit_Get_Menu			(void);
	virtual TSG_Rect			Edit_Get_Extent			(void);
	virtual bool				Edit_On_Key_Down		(int KeyCode);
	virtual bool				Edit_On_Mouse_Up		(const CSG_Point &Point, double ClientToWorld, int Key);
	virtual bool				Edit_Set_Attributes		(void);


protected:

	bool						Get_Image				(wxImage  &Image , bool bFitSize = true, int Width = 0, int Height = 0);
	bool						Get_Bitmap				(wxBitmap &Bitmap, bool bFitSize = true, int Width = 0, int Height = 0);
	bool						Get_Bitmap_Legend		(wxBitmap &Bitmap, double Zoom);

	virtual void				On_Create_Parameters	(void);
	virtual void				On_DataObject_Changed	(void);
	virtual void				On_Parameters_Changed	(void);
	virtual int					On_Parameter_Changed	(CSG_Parameters *pParameters, CSG_Parameter *pParameter, int Flags);

	virtual void				On_Draw					(CSG_Map_DC &dc_Map, int Flags);


private:

	int							m_Stretch_Extent = -1, m_xSel = 0, m_ySel = 0;

	CTransparency				m_Alpha;

	//-----------------------------------------------------
	class COverlay
	{
	public:
		CSG_Grid *pReference = NULL, *pGrid = NULL; CSG_Scaler Scaler;

		COverlay &				operator =				(const COverlay &Overlay)
		{
			pReference = Overlay.pReference; pGrid = Overlay.pGrid; Scaler = Overlay.Scaler;

			return( *this );
		}

		bool					Set_Color				(BYTE &Color, int x, int y)
		{
			if( pGrid )
			{
				if( pReference && pReference != pGrid && pReference->Get_System() != pGrid->Get_System() )
				{
					return( Set_Color(Color, pReference->Get_System().Get_Grid_to_World(x, y), CSG_Grid_Resampling::NearestNeighbour) );
				}

				if( pGrid->is_InGrid(x, y) )
				{
					double Value = Scaler.to_Relative(pGrid->asDouble(x, y));

					Color = Value <= 0. ? 0 : Value >= 1. ? 255 : (BYTE)(255. * Value);

					return( true );
				}
			}

			if( pGrid != pReference )
			{
				Color = 255;

				return( true );
			}

			return( false );
		}

		bool					Set_Color				(BYTE &Color, const CSG_Point &Point, CSG_Grid_Resampling Resampling)
		{
			if( pGrid )
			{
				double Value;
				
				if( pGrid->Get_Value(Point, Value, Resampling) )
				{
					Value = Scaler.to_Relative(Value);

					Color = Value <= 0. ? 0 : Value >= 1. ? 255 : (BYTE)(255. * Value);

					return( true );
				}
			}

			if( pGrid != pReference )
			{
				Color = 255;

				return( true );
			}

			return( false );
		}

	}							m_Overlay[3];


	//-----------------------------------------------------
	void						_LUT_Import				(void);

	bool						_Edit_Clr_Selection		(void);
	bool						_Edit_Del_Selection		(void);

	bool						_Save_Image				(void);
	bool						_Save_Image_Clipboard	(void);

	void						_Overlay_Update			(void);
	void						_Overlay_Get			(COverlay Overlay[3]);

	bool						_Get_Stretch_Extent		(const CSG_Rect &Extent, CSG_Grid *pGrid, double &Minimum, double &Maximum) const;

	void						_Draw_Cells				(CSG_Map_DC &dc_Map, COverlay Overlay[3]);
	void						_Draw_Points			(CSG_Map_DC &dc_Map, COverlay Overlay[3], CSG_Grid_Resampling Resampling);
	void						_Draw_Points			(CSG_Map_DC &dc_Map, COverlay Overlay[3], CSG_Grid_Resampling Resampling, int yDC, int axDC, int bxDC);

	int							_Adjust_Color			(const CSG_Point &p, int Color, CSG_Grid_Resampling Resampling);
	int							_Adjust_Color			(int    x, int    y, int Color);

	void						_Draw_Values			(CSG_Map_DC &dc_Map);
	void						_Draw_Edit				(CSG_Map_DC &dc_Map);


private:

	//-----------------------------------------------------
	class CShading
	{
	public:

		bool					Create					(int Mode, CSG_Grid *pGrid, double Height, double Azimuth, double Exaggeration, double Minimum, double Maximum)
		{
			m_Mode = pGrid && pGrid->Get_Range() > 0. && Height >= 0. && Minimum != Maximum ? Mode : 0;

			if( m_Mode )
			{
				m_pGrid        = pGrid;
				m_Sin_Height   = sin(M_DEG_TO_RAD * Height);
				m_Cos_Height   = cos(M_DEG_TO_RAD * Height);
				m_Azimuth      =     M_DEG_TO_RAD * Azimuth;
				m_Exaggeration = Exaggeration;
				m_Minimum      = Minimum;
				m_Range        = Maximum - Minimum;
			}

			return( is_Okay() );
		}

		bool					is_Okay					(void) const { return( m_Mode != 0 ); }

		bool					Set_Shading				(int &Color, int x, int y) const
		{
			double s, a; return( m_Mode && m_pGrid && m_pGrid->Get_Gradient(x, y, s, a             ) && _Set_Shading(s, a, Color) );
		}

		bool					Set_Shading				(int &Color, const CSG_Point &Point, CSG_Grid_Resampling Resampling) const
		{
			double s, a; return( m_Mode && m_pGrid && m_pGrid->Get_Gradient(Point, s, a, Resampling) && _Set_Shading(s, a, Color) );
		}


	private:

		int						m_Mode = 0;

		double					m_Sin_Height = 0., m_Cos_Height = 0, m_Azimuth = 0., m_Exaggeration = 1., m_Minimum = 0., m_Range = 1.;

		CSG_Grid				*m_pGrid = NULL;


		bool					_Set_Shading			(double s, double a, int &Color) const
		{
			s = M_PI_090 - atan(m_Exaggeration * tan(s));

			if( m_Mode == 1 )
			{
				_Set_Shading(acos(sin(s) * m_Sin_Height + cos(s) * m_Cos_Height * cos(a - m_Azimuth)), (BYTE *)&Color);
			}
			else
			{
				double sum = 0., dir = m_Azimuth - M_PI_180 / 2., sin_Slope = sin(s) * m_Sin_Height, cos_Slope = cos(s) * m_Cos_Height;

				for(int i=0; i<6; i++, dir+=M_PI_180/5.)
				{
					sum += acos(sin_Slope + cos_Slope * cos(a - dir));
				}

				_Set_Shading(sum / 6., (BYTE *)&Color);
			}

			return( true );
		}

		void					_Set_Shading			(double Shade, BYTE *Color) const
		{
			Shade = m_Range * ((1. - Shade / M_PI_090) - m_Minimum); double c;

			c = Shade * Color[0]; Color[0] = c <= 0. ? 0 : c >= 255. ? 255 : (BYTE)c;
			c = Shade * Color[1]; Color[1] = c <= 0. ? 0 : c >= 255. ? 255 : (BYTE)c;
			c = Shade * Color[2]; Color[2] = c <= 0. ? 0 : c >= 255. ? 255 : (BYTE)c;
		}

	};

	CShading					m_Shading;

};


///////////////////////////////////////////////////////////
//                                                       //
//                                                       //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
#endif // #ifndef _HEADER_INCLUDED__SAGA_GUI__WKSP_Grid_H
