/**********************************************************
 * Version $Id$
 *********************************************************/

///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//           Application Programming Interface           //
//                                                       //
//                  Library: SAGA_API                    //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                   shapes_ogis.cpp                     //
//                                                       //
//          Copyright (C) 2010 by Olaf Conrad            //
//                                                       //
//-------------------------------------------------------//
//                                                       //
// This file is part of 'SAGA - System for Automated     //
// Geoscientific Analyses'.                              //
//                                                       //
// This library is free software; you can redistribute   //
// it and/or modify it under the terms of the GNU Lesser //
// General Public License as published by the Free       //
// Software Foundation, either version 2.1 of the        //
// License, or (at your option) any later version.       //
//                                                       //
// This library 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 Lesser General Public //
// License for more details.                             //
//                                                       //
// You should have received a copy of the GNU Lesser     //
// General Public License along with this program; if    //
// not, see <http://www.gnu.org/licenses/>.              //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//    contact:    Olaf Conrad                            //
//                Institute of Geography                 //
//                University of Hamburg                  //
//                Germany                                //
//                                                       //
//    e-mail:     oconrad@saga-gis.org                   //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------


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

//---------------------------------------------------------
#include "shapes.h"


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

//---------------------------------------------------------
CSG_String	CSG_Shapes_OGIS_Converter::Type_asWKText	(DWORD Type)
{
	switch( Type )
	{
	case SG_OGIS_TYPE_Point					: return( "Point"                );
	case SG_OGIS_TYPE_LineString			: return( "LineString"           );
	case SG_OGIS_TYPE_Polygon				: return( "Polygon"              );
	case SG_OGIS_TYPE_MultiPoint			: return( "MultiPoint"           );
	case SG_OGIS_TYPE_MultiLineString		: return( "MultiLineString"      );
	case SG_OGIS_TYPE_MultiPolygon			: return( "MultiPolygon"         );
	case SG_OGIS_TYPE_GeometryCollection	: return( "GeometryCollection"   );
	case SG_OGIS_TYPE_PolyhedralSurface		: return( "PolyhedralSurface"    );
	case SG_OGIS_TYPE_TIN					: return( "TIN"                  );
	case SG_OGIS_TYPE_Triangle				: return( "Triangle"             );

	case SG_OGIS_TYPE_PointZ				: return( "PointZ"               );
	case SG_OGIS_TYPE_LineStringZ			: return( "LineStringZ"          );
	case SG_OGIS_TYPE_PolygonZ				: return( "PolygonZ"             );
	case SG_OGIS_TYPE_MultiPointZ			: return( "MultiPointZ"          );
	case SG_OGIS_TYPE_MultiLineStringZ		: return( "MultiLineStringZ"     );
	case SG_OGIS_TYPE_MultiPolygonZ			: return( "MultiPolygonZ"        );
	case SG_OGIS_TYPE_GeometryCollectionZ	: return( "GeometryCollectionZ"  );
	case SG_OGIS_TYPE_PolyhedralSurfaceZ	: return( "PolyhedralSurfaceZ"   );
	case SG_OGIS_TYPE_TINZ					: return( "TINZ"                 );
	case SG_OGIS_TYPE_TriangleZ				: return( "TriangleZ"            );

	case SG_OGIS_TYPE_PointM				: return( "PointM"               );
	case SG_OGIS_TYPE_LineStringM			: return( "LineStringM"          );
	case SG_OGIS_TYPE_PolygonM				: return( "PolygonM"             );
	case SG_OGIS_TYPE_MultiPointM			: return( "MultiPointM"          );
	case SG_OGIS_TYPE_MultiLineStringM		: return( "MultiLineStringM"     );
	case SG_OGIS_TYPE_MultiPolygonM			: return( "MultiPolygonM"        );
	case SG_OGIS_TYPE_GeometryCollectionM	: return( "GeometryCollectionM"  );
	case SG_OGIS_TYPE_PolyhedralSurfaceM	: return( "PolyhedralSurfaceM"   );
	case SG_OGIS_TYPE_TINM					: return( "TINM"                 );
	case SG_OGIS_TYPE_TriangleM				: return( "TriangleM"            );

	case SG_OGIS_TYPE_PointZM				: return( "PointZM"              );
	case SG_OGIS_TYPE_LineStringZM			: return( "LineStringZM"         );
	case SG_OGIS_TYPE_PolygonZM				: return( "PolygonZM"            );
	case SG_OGIS_TYPE_MultiPointZM			: return( "MultiPointZM"         );
	case SG_OGIS_TYPE_MultiLineStringZM		: return( "MultiLineStringZM"    );
	case SG_OGIS_TYPE_MultiPolygonZM		: return( "MultiPolygonZM"       );
	case SG_OGIS_TYPE_GeometryCollectionZM	: return( "GeometryCollectionZM" );
	case SG_OGIS_TYPE_PolyhedralSurfaceZM	: return( "PolyhedralSurfaceZM"  );
	case SG_OGIS_TYPE_TINZM					: return( "TINZM"                );
	case SG_OGIS_TYPE_TriangleZM			: return( "TriangleZM"           );
	}

	return( "" );
}

//---------------------------------------------------------
DWORD CSG_Shapes_OGIS_Converter::Type_asWKBinary(const CSG_String &Type)
{
	#define TYPE_AS_WKB(t)	if( !Type.CmpNoCase(Type_asWKText(t)) )	return( t );

	TYPE_AS_WKB(SG_OGIS_TYPE_Point                );
	TYPE_AS_WKB(SG_OGIS_TYPE_LineString           );
	TYPE_AS_WKB(SG_OGIS_TYPE_Polygon              );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPoint           );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiLineString      );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPolygon         );
	TYPE_AS_WKB(SG_OGIS_TYPE_GeometryCollection   );
	TYPE_AS_WKB(SG_OGIS_TYPE_PolyhedralSurface    );
	TYPE_AS_WKB(SG_OGIS_TYPE_TIN                  );
	TYPE_AS_WKB(SG_OGIS_TYPE_Triangle             );

	TYPE_AS_WKB(SG_OGIS_TYPE_PointZ               );
	TYPE_AS_WKB(SG_OGIS_TYPE_LineStringZ          );
	TYPE_AS_WKB(SG_OGIS_TYPE_PolygonZ             );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPointZ          );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiLineStringZ     );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPolygonZ        );
	TYPE_AS_WKB(SG_OGIS_TYPE_GeometryCollectionZ  );
	TYPE_AS_WKB(SG_OGIS_TYPE_PolyhedralSurfaceZ   );
	TYPE_AS_WKB(SG_OGIS_TYPE_TINZ                 );
	TYPE_AS_WKB(SG_OGIS_TYPE_TriangleZ            );

	TYPE_AS_WKB(SG_OGIS_TYPE_PointM               );
	TYPE_AS_WKB(SG_OGIS_TYPE_LineStringM          );
	TYPE_AS_WKB(SG_OGIS_TYPE_PolygonM             );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPointM          );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiLineStringM     );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPolygonM        );
	TYPE_AS_WKB(SG_OGIS_TYPE_GeometryCollectionM  );
	TYPE_AS_WKB(SG_OGIS_TYPE_PolyhedralSurfaceM   );
	TYPE_AS_WKB(SG_OGIS_TYPE_TINM                 );
	TYPE_AS_WKB(SG_OGIS_TYPE_TriangleM            );

	TYPE_AS_WKB(SG_OGIS_TYPE_PointZM              );
	TYPE_AS_WKB(SG_OGIS_TYPE_LineStringZM         );
	TYPE_AS_WKB(SG_OGIS_TYPE_PolygonZM            );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPointZM         );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiLineStringZM    );
	TYPE_AS_WKB(SG_OGIS_TYPE_MultiPolygonZM       );
	TYPE_AS_WKB(SG_OGIS_TYPE_GeometryCollectionZM );
	TYPE_AS_WKB(SG_OGIS_TYPE_PolyhedralSurfaceZM  );
	TYPE_AS_WKB(SG_OGIS_TYPE_TINZM                );
	TYPE_AS_WKB(SG_OGIS_TYPE_TriangleZM           );

	return( SG_OGIS_TYPE_Undefined );
}


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

//---------------------------------------------------------
inline bool CSG_Shapes_OGIS_Converter::_WKT_Read_Point(const CSG_String &Text, CSG_Shape *pShape, int iPart)
{
	double		x, y, z, m;

	switch( pShape->Get_Vertex_Type() )
	{
	case SG_VERTEX_TYPE_XY:
		if( SG_SSCANF(Text.c_str(), SG_T("%lf %lf"), &x, &y) == 2 )
		{
			pShape->Add_Point(x, y, iPart);
			
			return( true );
		}
		break;

	case SG_VERTEX_TYPE_XYZ:
		if( SG_SSCANF(Text.c_str(), SG_T("%lf %lf %lf"), &x, &y, &z) == 3 )
		{
			pShape->Add_Point(x, y, iPart);
			pShape->Set_Z    (z, pShape->Get_Point_Count(iPart) - 1, iPart);
			
			return( true );
		}
		break;

	case SG_VERTEX_TYPE_XYZM:
		if( SG_SSCANF(Text.c_str(), SG_T("%lf %lf %lf %lf"), &x, &y, &z, &m) == 4 )
		{
			pShape->Add_Point(x, y, iPart);
			pShape->Set_Z    (z, pShape->Get_Point_Count(iPart) - 1, iPart);
			pShape->Set_M    (m, pShape->Get_Point_Count(iPart) - 1, iPart);
			
			return( true );
		}
		break;
	}

	return( false );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKT_Read_Points(const CSG_String &Text, CSG_Shape *pShape)
{
	int			iPart	= pShape->Get_Part_Count();
	CSG_String	s(Text.AfterFirst('(').BeforeFirst(')'));

	while( s.Length() > 0 )
	{
		if( !_WKT_Read_Point(s, pShape, iPart) )
		{
			return( false );
		}

		s	= s.AfterFirst(',');
	}

	return( pShape->Get_Point_Count(iPart) > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKT_Read_Parts(const CSG_String &Text, CSG_Shape *pShape)
{
	CSG_String	s	= Text.AfterFirst('(').BeforeLast(')');

	while( s.Length() > 0 )
	{
		_WKT_Read_Points(s, pShape);

		s	= s.AfterFirst(',');
	}

	return( pShape->Get_Part_Count() > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKT_Read_Polygon(const CSG_String &Text, CSG_Shape *pShape)
{
	CSG_String	Part;

	for(int i=0, Level=-2; i<(int)Text.Length(); i++)
	{
		if( Text[i] == '(' )
		{
			Level++;
		}
		else if( Text[i] == ')' )
		{
			if( Level == 0 )
			{
				Part	+= Text[i];
				_WKT_Read_Parts(Part, pShape);
				Part.Clear();
			}

			Level--;
		}

		if( Level >= 0 )
		{
			Part	+= Text[i];
		}
	}

	return( pShape->Get_Part_Count() > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::from_WKText(const CSG_String &Text, CSG_Shape *pShape)
{
	pShape->Del_Parts();

	CSG_String	Type(Text.BeforeFirst('('));

	Type.Trim(true );
	Type.Trim(false);

	if( pShape->Get_Type() == to_ShapeType(Type) )
	{
		switch( Type_asWKBinary(Type) )
		{
		case SG_OGIS_TYPE_Point:
		case SG_OGIS_TYPE_PointZ:
		case SG_OGIS_TYPE_PointM:
		case SG_OGIS_TYPE_PointZM:
			return( _WKT_Read_Point(Text.AfterFirst('(').BeforeFirst(')'), pShape, 0) );

		case SG_OGIS_TYPE_MultiPoint:
		case SG_OGIS_TYPE_MultiPointZ:
		case SG_OGIS_TYPE_MultiPointM:
		case SG_OGIS_TYPE_MultiPointZM:
			return( _WKT_Read_Parts  (Text, pShape) );

		case SG_OGIS_TYPE_LineString:
		case SG_OGIS_TYPE_LineStringZ:
		case SG_OGIS_TYPE_LineStringM:
		case SG_OGIS_TYPE_LineStringZM:
			return( _WKT_Read_Points (Text, pShape) );

		case SG_OGIS_TYPE_MultiLineString:
		case SG_OGIS_TYPE_MultiLineStringZ:
		case SG_OGIS_TYPE_MultiLineStringM:
		case SG_OGIS_TYPE_MultiLineStringZM:
			return( _WKT_Read_Parts  (Text, pShape) );

		case SG_OGIS_TYPE_Polygon:
		case SG_OGIS_TYPE_PolygonZ:
		case SG_OGIS_TYPE_PolygonM:
		case SG_OGIS_TYPE_PolygonZM:
			return( _WKT_Read_Parts  (Text, pShape) );

		case SG_OGIS_TYPE_MultiPolygon:
		case SG_OGIS_TYPE_MultiPolygonZ:
		case SG_OGIS_TYPE_MultiPolygonM:
		case SG_OGIS_TYPE_MultiPolygonZM:
			return( _WKT_Read_Polygon(Text, pShape) );
		}
	}

	return( false );
}


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

//---------------------------------------------------------
inline bool CSG_Shapes_OGIS_Converter::_WKT_Write_Point(CSG_String &Text, CSG_Shape *pShape, int iPoint, int iPart)
{
	TSG_Point	Point	= pShape->Get_Point(iPoint, iPart);

	switch( ((CSG_Shapes *)pShape->Get_Table())->Get_Vertex_Type() )
	{
	case SG_VERTEX_TYPE_XY:
		Text	+= CSG_String::Format("%f %f"      , Point.x, Point.y);
		break;

	case SG_VERTEX_TYPE_XYZ:
		Text	+= CSG_String::Format("%f %f %f"   , Point.x, Point.y, pShape->Get_Z(iPoint, iPart));
		break;

	case SG_VERTEX_TYPE_XYZM:
		Text	+= CSG_String::Format("%f %f %f %f", Point.x, Point.y, pShape->Get_Z(iPoint, iPart), pShape->Get_M(iPoint, iPart));
		break;
	}

	return( false );
}

//---------------------------------------------------------
inline bool CSG_Shapes_OGIS_Converter::_WKT_Write_Points(CSG_String &Text, CSG_Shape *pShape, int iPart)
{
	Text	+= SG_T("(");

	for(int iPoint=0; iPoint<pShape->Get_Point_Count(iPart); iPoint++)
	{
		if( iPoint > 0 )
		{
			Text	+= SG_T(", ");
		}

		_WKT_Write_Point(Text, pShape, iPoint, iPart);
	}

	if( pShape->Get_Type() == SHAPE_TYPE_Polygon && CSG_Point(pShape->Get_Point(0, iPart)) != pShape->Get_Point(pShape->Get_Point_Count(iPart) -1, iPart) )
	{
		Text	+= SG_T(", ");

		_WKT_Write_Point(Text, pShape, 0, iPart);
	}

	Text	+= SG_T(")");

	return( true );
}

//---------------------------------------------------------
inline bool CSG_Shapes_OGIS_Converter::_WKT_Write_Parts(CSG_String &Text, CSG_Shape *pShape)
{
	Text	+= SG_T("(");

	for(int iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
	{
		if( iPart > 0 )
		{
			Text	+= SG_T(", ");
		}

		_WKT_Write_Points(Text, pShape, iPart);
	}

	Text	+= SG_T(")");

	return( true );
}

//---------------------------------------------------------
inline bool CSG_Shapes_OGIS_Converter::_WKT_Write_Polygon(CSG_String &Text, CSG_Shape *pShape)
{
	Text	+= SG_T("(");

	for(int iPart=0, nIslands=0; iPart<pShape->Get_Part_Count(); iPart++)
	{
		if( ((CSG_Shape_Polygon *)pShape)->is_Lake(iPart) == false )
		{
			if( nIslands++ > 0 )
			{
				Text	+= SG_T(", ");
			}

			Text	+= SG_T("(");

			_WKT_Write_Points(Text, pShape, iPart);

			for(int jPart=0; jPart<pShape->Get_Part_Count(); jPart++)
			{
				if( ((CSG_Shape_Polygon *)pShape)->is_Lake(jPart) && ((CSG_Shape_Polygon *)pShape)->Contains(pShape->Get_Point(0, jPart), iPart) )
				{
					Text	+= SG_T(", ");

					_WKT_Write_Points(Text, pShape, jPart);
				}
			}

			Text	+= SG_T(")");
		}
	}

	Text	+= SG_T(")");

	return( true );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::to_WKText(CSG_Shape *pShape, CSG_String &Text)
{
	switch( pShape->Get_Type() )
	{
	default:
		return( false );

	case SHAPE_TYPE_Point:
		_WKT_Write_Points (Text = from_ShapeType(pShape->Get_Type(), pShape->Get_Vertex_Type()), pShape, 0);
		break;

	case SHAPE_TYPE_Points:
		_WKT_Write_Parts  (Text = from_ShapeType(pShape->Get_Type(), pShape->Get_Vertex_Type()), pShape);
		break;

	case SHAPE_TYPE_Line:
		_WKT_Write_Parts  (Text = from_ShapeType(pShape->Get_Type(), pShape->Get_Vertex_Type()), pShape);
		break;

	case SHAPE_TYPE_Polygon:
		_WKT_Write_Polygon(Text = from_ShapeType(pShape->Get_Type(), pShape->Get_Vertex_Type()), pShape);
		break;
	}

	return( true );
}


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

//---------------------------------------------------------
inline bool CSG_Shapes_OGIS_Converter::_WKB_Read_Point(CSG_Bytes &Bytes, bool bSwapBytes, CSG_Shape *pShape, int iPart)
{
	if( Bytes.is_EOF() )
	{
		return( false );
	}

	double	x, y;

	x	= Bytes.Read_Double(bSwapBytes);
	y	= Bytes.Read_Double(bSwapBytes);

	pShape->Add_Point(x, y, iPart);

	switch( ((CSG_Shapes *)pShape->Get_Table())->Get_Vertex_Type() )
	{
	case SG_VERTEX_TYPE_XY:
		break;

	case SG_VERTEX_TYPE_XYZ:
		pShape->Set_Z(Bytes.Read_Double(bSwapBytes), pShape->Get_Point_Count(iPart) - 1, iPart);
		break;

	case SG_VERTEX_TYPE_XYZM:
		pShape->Set_Z(Bytes.Read_Double(bSwapBytes), pShape->Get_Point_Count(iPart) - 1, iPart);
		pShape->Set_M(Bytes.Read_Double(bSwapBytes), pShape->Get_Point_Count(iPart) - 1, iPart);
		break;
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Read_Points(CSG_Bytes &Bytes, bool bSwapBytes, CSG_Shape *pShape)
{
	DWORD	iPart	= pShape->Get_Part_Count();
	DWORD	nPoints	= Bytes.Read_DWord(bSwapBytes);

	for(DWORD iPoint=0; iPoint<nPoints; iPoint++)
	{
		if( !_WKB_Read_Point(Bytes, bSwapBytes, pShape, iPart) )
		{
			return( false );
		}
	}

	return( pShape->Get_Point_Count(iPart) > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Read_Parts(CSG_Bytes &Bytes, bool bSwapBytes, CSG_Shape *pShape)
{
	DWORD	iPart, nParts	= Bytes.Read_DWord(bSwapBytes);

	for(iPart=0; iPart<nParts; iPart++)
	{
		if( !_WKB_Read_Points(Bytes, bSwapBytes, pShape) )
		{
			return( false );
		}
	}

	return( pShape->Get_Part_Count() > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Read_MultiLine(CSG_Bytes &Bytes, bool bSwapBytes, CSG_Shape *pShape)
{
	DWORD	nLines	= Bytes.Read_DWord(bSwapBytes);

	for(DWORD iLine=0; iLine<nLines; iLine++)
	{
		bSwapBytes	= Bytes.Read_Byte() != SG_OGIS_BYTEORDER_NDR;

		if( Bytes.Read_DWord(bSwapBytes) != SG_OGIS_TYPE_LineString || !_WKB_Read_Points(Bytes, bSwapBytes, pShape) )
		{
			return( false );
		}
	}

	return( pShape->Get_Part_Count() > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Read_MultiPolygon(CSG_Bytes &Bytes, bool bSwapBytes, CSG_Shape *pShape)
{
	DWORD	nPolygons	= Bytes.Read_DWord(bSwapBytes);

	for(DWORD iPolygon=0; iPolygon<nPolygons; iPolygon++)
	{
		bSwapBytes	= Bytes.Read_Byte() != SG_OGIS_BYTEORDER_NDR;

		if( Bytes.Read_DWord(bSwapBytes) != SG_OGIS_TYPE_Polygon || !_WKB_Read_Parts(Bytes, bSwapBytes, pShape) )
		{
			return( false );
		}
	}

	return( pShape->Get_Part_Count() > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::from_WKBinary(CSG_Bytes &Bytes, CSG_Shape *pShape)
{
	pShape->Del_Parts();

	if( Bytes.Get_Count() > 3 )
	{
		Bytes.Rewind();

		bool	bSwapBytes	= Bytes.Read_Byte() != SG_OGIS_BYTEORDER_NDR;

		DWORD	Type	= Bytes.Read_DWord();

		if( pShape->Get_Type() == to_ShapeType(Type) )
		{
			switch( Type )
			{
			case SG_OGIS_TYPE_Point:
			case SG_OGIS_TYPE_PointZ:
			case SG_OGIS_TYPE_PointM:
			case SG_OGIS_TYPE_PointZM:
				return( _WKB_Read_Point       (Bytes, bSwapBytes, pShape, 0) );

			case SG_OGIS_TYPE_MultiPoint:
			case SG_OGIS_TYPE_MultiPointZ:
			case SG_OGIS_TYPE_MultiPointM:
			case SG_OGIS_TYPE_MultiPointZM:
				return( _WKB_Read_Parts       (Bytes, bSwapBytes, pShape) );

			case SG_OGIS_TYPE_LineString:
			case SG_OGIS_TYPE_LineStringZ:
			case SG_OGIS_TYPE_LineStringM:
			case SG_OGIS_TYPE_LineStringZM:
				return( _WKB_Read_Points      (Bytes, bSwapBytes, pShape) );

			case SG_OGIS_TYPE_MultiLineString:
			case SG_OGIS_TYPE_MultiLineStringZ:
			case SG_OGIS_TYPE_MultiLineStringM:
			case SG_OGIS_TYPE_MultiLineStringZM:
				return( _WKB_Read_MultiLine   (Bytes, bSwapBytes, pShape) );

			case SG_OGIS_TYPE_Polygon:
			case SG_OGIS_TYPE_PolygonZ:
			case SG_OGIS_TYPE_PolygonM:
			case SG_OGIS_TYPE_PolygonZM:
				return( _WKB_Read_Parts       (Bytes, bSwapBytes, pShape) );

			case SG_OGIS_TYPE_MultiPolygon:
			case SG_OGIS_TYPE_MultiPolygonZ:
			case SG_OGIS_TYPE_MultiPolygonM:
			case SG_OGIS_TYPE_MultiPolygonZM:
				return( _WKB_Read_MultiPolygon(Bytes, bSwapBytes, pShape) );
			}
		}
	}

	return( false );
}


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

//---------------------------------------------------------
inline bool CSG_Shapes_OGIS_Converter::_WKB_Write_Point(CSG_Bytes &Bytes, CSG_Shape *pShape, int iPoint, int iPart)
{
	TSG_Point	Point	= pShape->Get_Point(iPoint, iPart);

	Bytes	+= Point.x;
	Bytes	+= Point.y;

	switch( pShape->Get_Vertex_Type() )
	{
	case SG_VERTEX_TYPE_XY:
		break;

	case SG_VERTEX_TYPE_XYZ:
		Bytes	+= pShape->Get_Z(iPoint, iPart);
		break;

	case SG_VERTEX_TYPE_XYZM:
		Bytes	+= pShape->Get_Z(iPoint, iPart);
		Bytes	+= pShape->Get_M(iPoint, iPart);
		break;
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Write_Points(CSG_Bytes &Bytes, CSG_Shape *pShape, int iPart)
{
	bool	bFirstTwice	= pShape->Get_Type() == SHAPE_TYPE_Polygon && CSG_Point(pShape->Get_Point(0, iPart)) != pShape->Get_Point(pShape->Get_Point_Count(iPart) -1, iPart);

	Bytes	+= (DWORD)(pShape->Get_Point_Count(iPart) + (bFirstTwice ? 1 : 0));

	for(int iPoint=0; iPoint<pShape->Get_Point_Count(iPart); iPoint++)
	{
		_WKB_Write_Point(Bytes, pShape, iPoint, iPart);
	}

	if( bFirstTwice )
	{
		_WKB_Write_Point(Bytes, pShape, 0, iPart);
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Write_Parts(CSG_Bytes &Bytes, CSG_Shape *pShape)
{
	Bytes	+= (DWORD)pShape->Get_Part_Count();

	for(int iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
	{
		if( !_WKB_Write_Points(Bytes, pShape, iPart) )
		{
			return( false );
		}
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Write_MultiLine(CSG_Bytes &Bytes, CSG_Shape *pShape)
{
	Bytes	+= (DWORD)pShape->Get_Part_Count();

	for(int iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
	{
		Bytes	+= (BYTE)SG_OGIS_BYTEORDER_NDR;
		Bytes	+= (DWORD)SG_OGIS_TYPE_LineString;

		if( !_WKB_Write_Points(Bytes, pShape, iPart) )
		{
			return( false );
		}
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::_WKB_Write_MultiPolygon(CSG_Bytes &Bytes, CSG_Shape *pShape)
{
	int		iPart, nPolygons, *nRings, *iPolygon;

	nPolygons	= 0;
	nRings		= new int[pShape->Get_Part_Count()];
	iPolygon	= new int[pShape->Get_Part_Count()];

	for(iPart=0, nPolygons=0; iPart<pShape->Get_Part_Count(); iPart++)
	{
		nRings  [iPart]	= 0;

		if( ((CSG_Shape_Polygon *)pShape)->is_Lake(iPart) == false )
		{
			nPolygons		++;
			nRings  [iPart]	++;
			iPolygon[iPart]	= iPart;

			for(int jPart=0; jPart<pShape->Get_Part_Count(); jPart++)
			{
				if( ((CSG_Shape_Polygon *)pShape)->is_Lake(jPart) && ((CSG_Shape_Polygon *)pShape)->Contains(pShape->Get_Point(0, jPart), iPart) )
				{
					nRings  [iPart]++;
					iPolygon[jPart]	= iPart;
				}
			}
		}
	}

	Bytes	+= (DWORD)nPolygons;

	for(iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
	{
		if( nRings[iPart] > 0 )
		{
			Bytes	+= (BYTE)SG_OGIS_BYTEORDER_NDR;
			Bytes	+= (DWORD)SG_OGIS_TYPE_Polygon;
			Bytes	+= (DWORD)nRings[iPart];

			for(int jPart=0; jPart<pShape->Get_Part_Count(); jPart++)
			{
				if( iPolygon[jPart] == iPart )
				{
					if( !_WKB_Write_Points(Bytes, pShape, jPart) )
					{
						delete[](nRings);
						delete[](iPolygon);
						return( false );
					}
				}
			}
		}
	}

	delete[](nRings);
	delete[](iPolygon);

	return( nPolygons > 0 );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::to_WKBinary(CSG_Shape *pShape, CSG_Bytes &Bytes)
{
	DWORD	Type;

	if( from_ShapeType(Type, pShape->Get_Type(), pShape->Get_Vertex_Type()) )
	{
		Bytes.Destroy();

		Bytes	+= (BYTE)SG_OGIS_BYTEORDER_NDR;
		Bytes	+= Type;

		switch( pShape->Get_Type() )
		{
		case SHAPE_TYPE_Point  :	return( _WKB_Write_Point       (Bytes, pShape, 0, 0) );
		case SHAPE_TYPE_Points :	return( _WKB_Write_Points      (Bytes, pShape, 0   ) );
		case SHAPE_TYPE_Line   :	return( _WKB_Write_MultiLine   (Bytes, pShape      ) );
		case SHAPE_TYPE_Polygon:	return( _WKB_Write_MultiPolygon(Bytes, pShape      ) );

		default:	break;
		}
	}

	return( false );
}


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

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::from_ShapeType(CSG_String &Type, TSG_Shape_Type Shape, TSG_Vertex_Type Vertex)
{
	switch( Vertex )
	{
	case SG_VERTEX_TYPE_XY:
		switch( Shape )
		{
		default:	break;
		case SHAPE_TYPE_Point:   Type	= Type_asWKText(SG_OGIS_TYPE_Point            ); return( true );
		case SHAPE_TYPE_Points:  Type	= Type_asWKText(SG_OGIS_TYPE_MultiPoint       ); return( true );
		case SHAPE_TYPE_Line:    Type	= Type_asWKText(SG_OGIS_TYPE_MultiLineString  ); return( true );
		case SHAPE_TYPE_Polygon: Type	= Type_asWKText(SG_OGIS_TYPE_MultiPolygon     ); return( true );
		}
		break;

	case SG_VERTEX_TYPE_XYZ:
		switch( Shape )
		{
		default:	break;
		case SHAPE_TYPE_Point:   Type	= Type_asWKText(SG_OGIS_TYPE_PointZ           ); return( true );
		case SHAPE_TYPE_Points:  Type	= Type_asWKText(SG_OGIS_TYPE_MultiPointZ      ); return( true );
		case SHAPE_TYPE_Line:    Type	= Type_asWKText(SG_OGIS_TYPE_MultiLineStringZ ); return( true );
		case SHAPE_TYPE_Polygon: Type	= Type_asWKText(SG_OGIS_TYPE_MultiPolygonZ    ); return( true );
		}
		break;

	case SG_VERTEX_TYPE_XYZM:
		switch( Shape )
		{
		default:	break;
		case SHAPE_TYPE_Point:   Type	= Type_asWKText(SG_OGIS_TYPE_PointZM          ); return( true );
		case SHAPE_TYPE_Points:  Type	= Type_asWKText(SG_OGIS_TYPE_MultiPointZM     ); return( true );
		case SHAPE_TYPE_Line:    Type	= Type_asWKText(SG_OGIS_TYPE_MultiLineStringZM); return( true );
		case SHAPE_TYPE_Polygon: Type	= Type_asWKText(SG_OGIS_TYPE_MultiPolygonZM   ); return( true );
		}
		break;
	}

	return( false );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::from_ShapeType(DWORD &Type, TSG_Shape_Type Shape, TSG_Vertex_Type Vertex)
{
	switch( Vertex )
	{
	case SG_VERTEX_TYPE_XY:
		switch( Shape )
		{
		default:	break;
		case SHAPE_TYPE_Point:   Type	= SG_OGIS_TYPE_Point;             return( true );
		case SHAPE_TYPE_Points:  Type	= SG_OGIS_TYPE_MultiPoint;        return( true );
		case SHAPE_TYPE_Line:    Type	= SG_OGIS_TYPE_MultiLineString;   return( true );
		case SHAPE_TYPE_Polygon: Type	= SG_OGIS_TYPE_MultiPolygon;      return( true );
		}
		break;

	case SG_VERTEX_TYPE_XYZ:
		switch( Shape )
		{
		default:	break;
		case SHAPE_TYPE_Point:   Type	= SG_OGIS_TYPE_PointZ;            return( true );
		case SHAPE_TYPE_Points:  Type	= SG_OGIS_TYPE_MultiPointZ;       return( true );
		case SHAPE_TYPE_Line:    Type	= SG_OGIS_TYPE_MultiLineStringZ;  return( true );
		case SHAPE_TYPE_Polygon: Type	= SG_OGIS_TYPE_MultiPolygonZ;     return( true );
		}
		break;

	case SG_VERTEX_TYPE_XYZM:
		switch( Shape )
		{
		default:	break;
		case SHAPE_TYPE_Point:   Type	= SG_OGIS_TYPE_PointZM;           return( true );
		case SHAPE_TYPE_Points:  Type	= SG_OGIS_TYPE_MultiPointZM;      return( true );
		case SHAPE_TYPE_Line:    Type	= SG_OGIS_TYPE_MultiLineStringZM; return( true );
		case SHAPE_TYPE_Polygon: Type	= SG_OGIS_TYPE_MultiPolygonZM;    return( true );
		}
		break;
	}

	return( false );
}

//---------------------------------------------------------
CSG_String CSG_Shapes_OGIS_Converter::from_ShapeType(TSG_Shape_Type Shape, TSG_Vertex_Type Vertex)
{
	CSG_String	Type;

	from_ShapeType(Type, Shape, Vertex);

	return( Type );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::to_ShapeType(const CSG_String &Type, TSG_Shape_Type &Shape, TSG_Vertex_Type &Vertex)
{
	switch( Type_asWKBinary(Type) )
	{
	case SG_OGIS_TYPE_Point             :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_MultiPoint        :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_LineString        :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_MultiLineString   :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_Polygon           :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_MultiPolygon      :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XY;	return( true );

	case SG_OGIS_TYPE_PointZ            :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPointZ       :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_LineStringZ       :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiLineStringZ  :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_PolygonZ          :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPolygonZ     :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );

	case SG_OGIS_TYPE_PointM            :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPointM       :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_LineStringM       :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiLineStringM  :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_PolygonM          :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPolygonM     :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );

	case SG_OGIS_TYPE_PointZM           :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_MultiPointZM      :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_LineStringZM      :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_MultiLineStringZM :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_PolygonZM         :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_MultiPolygonZM    :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	}

	Shape	= SHAPE_TYPE_Undefined;

	return( false );
}

//---------------------------------------------------------
bool CSG_Shapes_OGIS_Converter::to_ShapeType(DWORD Type, TSG_Shape_Type &Shape, TSG_Vertex_Type &Vertex)
{
	switch( Type )
	{
	case SG_OGIS_TYPE_Point             :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_MultiPoint        :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_LineString        :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_MultiLineString   :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_Polygon           :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XY;	return( true );
	case SG_OGIS_TYPE_MultiPolygon      :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XY;	return( true );

	case SG_OGIS_TYPE_PointZ            :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPointZ       :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_LineStringZ       :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiLineStringZ  :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_PolygonZ          :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPolygonZ     :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );

	case SG_OGIS_TYPE_PointM            :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPointM       :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_LineStringM       :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiLineStringM  :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_PolygonM          :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );
	case SG_OGIS_TYPE_MultiPolygonM     :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZ;	return( true );

	case SG_OGIS_TYPE_PointZM           :	Shape	= SHAPE_TYPE_Point;		Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_MultiPointZM      :	Shape	= SHAPE_TYPE_Points;	Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_LineStringZM      :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_MultiLineStringZM :	Shape	= SHAPE_TYPE_Line;		Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_PolygonZM         :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	case SG_OGIS_TYPE_MultiPolygonZM    :	Shape	= SHAPE_TYPE_Polygon;	Vertex	= SG_VERTEX_TYPE_XYZM;	return( true );
	}

	Shape	= SHAPE_TYPE_Undefined;

	return( false );
}

//---------------------------------------------------------
TSG_Shape_Type CSG_Shapes_OGIS_Converter::to_ShapeType(const CSG_String &Type)
{
	TSG_Shape_Type	Shape;
	TSG_Vertex_Type	Vertex;

	to_ShapeType(Type, Shape, Vertex);

	return( Shape );
}

//---------------------------------------------------------
TSG_Shape_Type CSG_Shapes_OGIS_Converter::to_ShapeType(DWORD Type)
{
	TSG_Shape_Type	Shape;
	TSG_Vertex_Type	Vertex;

	to_ShapeType(Type, Shape, Vertex);

	return( Shape );
}


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

//---------------------------------------------------------
// Basic Type definitions
// byte : 1 byte
// uint16 : 16 bit unsigned integer (2 bytes)
// uint32 : 32 bit unsigned integer (4 bytes)
// float64 : double precision floating point number (8 bytes)
//
// +------------------------------------------------------------+
// | RASTER                                                     |
// +---------------+-------------+------------------------------+
// | - name -      |  - type -   | - meaning -                  |
// +---------------+-------------+------------------------------+
// | endianness    | byte        | 1:ndr/little endian          |
// |               |             | 0:xdr/big endian             |
// +---------------+-------------+------------------------------+
// | version       | uint16      | format version (0 for this   |
// |               |             | structure)                   |
// +---------------+-------------+------------------------------+
// | nBands        | uint16      | Number of bands              |
// +---------------+-------------+------------------------------+
// | scaleX        | float64     | pixel width                  |
// |               |             | in geographical units        |
// +---------------+-------------+------------------------------+
// | scaleY        | float64     | pixel height                 |
// |               |             | in geographical units        |
// +---------------+-------------+------------------------------+
// | ipX           | float64     | X ordinate of upper-left     |
// |               |             | pixel's upper-left corner    |
// |               |             | in geographical units        |
// +---------------+-------------+------------------------------+
// | ipY           | float64     | Y ordinate of upper-left     |
// |               |             | pixel's upper-left corner    |
// |               |             | in geographical units        |
// +---------------+-------------+------------------------------+
// | skewX         | float64     | rotation about Y-axis        |
// +---------------+-------------+------------------------------+
// | skewY         | float64     | rotation about X-axis        |
// +---------------+-------------+------------------------------+
// | srid          | int32       | Spatial reference id         |
// +---------------+-------------+------------------------------+
// | width         | uint16      | number of pixel columns      |
// +---------------+-------------+------------------------------+
// | height        | uint16      | number of pixel rows         |
// +---------------+-------------+------------------------------+
// | bands[nBands] | RASTERBAND  | Bands data                   |
// +---------------+-------------+------------------------------+

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

//---------------------------------------------------------
#include "grid.h"


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

//---------------------------------------------------------
bool CSG_Grid_OGIS_Converter::from_WKBinary(CSG_Bytes &Bytes, class CSG_Grid *pGrid)
{
	Bytes.Rewind();

	//-----------------------------------------------------
	// Raster System

	bool	bSwap	= Bytes.Read_Byte  () == 0;	// endiannes: 1=ndr/little endian, 0=xdr/big endian
	short	version	= Bytes.Read_Short (bSwap);	// version
	short	nBands	= Bytes.Read_Short (bSwap);	// number of bands
	double	dx		= Bytes.Read_Double(bSwap);	// scaleX
	double	dy		= Bytes.Read_Double(bSwap);	// scaleY
	double	xMin	= Bytes.Read_Double(bSwap);	// ipX
	double	yMax	= Bytes.Read_Double(bSwap);	// ipY
	double	skewX	= Bytes.Read_Double(bSwap);	// skewX
	double	skewY	= Bytes.Read_Double(bSwap);	// skewY
	int   	SRID	= Bytes.Read_Int   (bSwap);	// srid
	short 	NX		= Bytes.Read_Short (bSwap);	// width
	short 	NY		= Bytes.Read_Short (bSwap);	// height

	//-----------------------------------------------------
	// Band

	TSG_Data_Type	Type;

	BYTE	Flags	= Bytes.Read_Byte();

	switch( Flags & 0x0F )
	{
	case  0:	Type	= SG_DATATYPE_Bit   ; break;	//  0:  1-bit boolean
	case  1:	Type	= SG_DATATYPE_Char  ; break;	//  1:  2-bit unsigned integer
	case  2:	Type	= SG_DATATYPE_Char  ; break;	//  2:  4-bit unsigned integer
	case  3:	Type	= SG_DATATYPE_Char  ; break;	//  3:  8-bit   signed integer
	case  4:	Type	= SG_DATATYPE_Byte  ; break;	//  4:  8-bit unsigned integer
	case  5:	Type	= SG_DATATYPE_Short ; break;	//  5: 16-bit   signed integer
	case  6:	Type	= SG_DATATYPE_Word  ; break;	//  6: 16-bit unsigned integer
	case  7:	Type	= SG_DATATYPE_Int   ; break;	//  7: 32-bit   signed integer
	case  8:	Type	= SG_DATATYPE_DWord ; break;	//  8: 32-bit unsigned integer
	case 10:	Type	= SG_DATATYPE_Float ; break;	// 10: 32-bit float
	case 11:	Type	= SG_DATATYPE_Double; break;	// 11: 64-bit float
	}

//	Flags	|= 0x80;	// isOffline: no, never here!
	Flags	|= 0x40;	// hasNodataValue
//	Flags	|= 0x20;	// isNoDataValue: no, never here!
//	Flags	|= 0x10;	// reserved (unused)

	if( !pGrid->Create(Type, NX, NY, dx, xMin + 0.5 * dx, yMax - (NY - 0.5) * dx) )
	{
		return( false );
	}

	pGrid->Get_Projection().Create(SRID);

	double	noData;

	switch( pGrid->Get_Type() )
	{
	case SG_DATATYPE_Bit   : noData	= Bytes.Read_Byte  (     ); break;	//  0:  1-bit boolean
	case SG_DATATYPE_Char  : noData	= Bytes.Read_Char  (     ); break;	//  3:  8-bit   signed integer
	case SG_DATATYPE_Byte  : noData	= Bytes.Read_Byte  (     ); break;	//  4:  8-bit unsigned integer
	case SG_DATATYPE_Short : noData	= Bytes.Read_Short (bSwap); break;	//  5: 16-bit   signed integer
	case SG_DATATYPE_Word  : noData	= Bytes.Read_Word  (bSwap); break;	//  6: 16-bit unsigned integer
	case SG_DATATYPE_Int   : noData	= Bytes.Read_Int   (bSwap); break;	//  7: 32-bit   signed integer
	case SG_DATATYPE_DWord : noData	= Bytes.Read_DWord (bSwap); break;	//  8: 32-bit unsigned integer
	case SG_DATATYPE_Float : noData	= Bytes.Read_Float (bSwap); break;	//  9: 32-bit float
	case SG_DATATYPE_Double: noData	= Bytes.Read_Double(bSwap); break;	// 10: 64-bit float
	default:
		break;
	}

	pGrid->Set_NoData_Value(noData);

	for(int y=0; y<pGrid->Get_NY() && SG_UI_Process_Set_Progress(y, pGrid->Get_NY()); y++)
	{
		for(int x=0; x<pGrid->Get_NX(); x++)
		{
			switch( pGrid->Get_Type() )
			{
			case SG_DATATYPE_Bit   : pGrid->Set_Value(x, y, Bytes.Read_Byte  (     )); break;	//  0:  1-bit boolean
			case SG_DATATYPE_Char  : pGrid->Set_Value(x, y, Bytes.Read_Char  (     )); break;	//  3:  8-bit   signed integer
			case SG_DATATYPE_Byte  : pGrid->Set_Value(x, y, Bytes.Read_Byte  (     )); break;	//  4:  8-bit unsigned integer
			case SG_DATATYPE_Short : pGrid->Set_Value(x, y, Bytes.Read_Short (bSwap)); break;	//  5: 16-bit   signed integer
			case SG_DATATYPE_Word  : pGrid->Set_Value(x, y, Bytes.Read_Word  (bSwap)); break;	//  6: 16-bit unsigned integer
			case SG_DATATYPE_Int   : pGrid->Set_Value(x, y, Bytes.Read_Int   (bSwap)); break;	//  7: 32-bit   signed integer
			case SG_DATATYPE_DWord : pGrid->Set_Value(x, y, Bytes.Read_DWord (bSwap)); break;	//  8: 32-bit unsigned integer
			case SG_DATATYPE_Float : pGrid->Set_Value(x, y, Bytes.Read_Float (bSwap)); break;	//  9: 32-bit float
			case SG_DATATYPE_Double: pGrid->Set_Value(x, y, Bytes.Read_Double(bSwap)); break;	// 10: 64-bit float
			default:
				break;
			}
		}
	}

	return( true );
}

//---------------------------------------------------------
bool CSG_Grid_OGIS_Converter::to_WKBinary(CSG_Bytes &Bytes, class CSG_Grid *pGrid, int SRID)
{
	Bytes.Clear();

	//-----------------------------------------------------
	// Raster System

	if( pGrid->Get_Projection().Get_EPSG() > 0 )
	{
		SRID	= pGrid->Get_Projection().Get_EPSG();
	}

	Bytes	+= (BYTE  )1;						// endiannes
	Bytes	+= (short )0;						// version
	Bytes	+= (short )1;						// number of bands
	Bytes	+= (double)pGrid->Get_Cellsize();	// scaleX
	Bytes	+= (double)pGrid->Get_Cellsize();	// scaleY
	Bytes	+= (double)pGrid->Get_XMin(true);	// ipX
	Bytes	+= (double)pGrid->Get_YMax(true);	// ipY
	Bytes	+= (double)0.0;						// skewX
	Bytes	+= (double)0.0;						// skewY
	Bytes	+= (int   )SRID;					// srid
	Bytes	+= (short )pGrid->Get_NX();			// width
	Bytes	+= (short )pGrid->Get_NY();			// height

	//-----------------------------------------------------
	// Band

	BYTE	Flags;

	switch( pGrid->Get_Type() )
	{
	case SG_DATATYPE_Bit   : Flags =  0; break;	//  0:  1-bit boolean
//	case SG_DATATYPE_      : Flags =  1; break;	//  1:  2-bit unsigned integer
//	case SG_DATATYPE_      : Flags =  2; break;	//  2:  4-bit unsigned integer
	case SG_DATATYPE_Char  : Flags =  3; break;	//  3:  8-bit   signed integer
	case SG_DATATYPE_Byte  : Flags =  4; break;	//  4:  8-bit unsigned integer
	case SG_DATATYPE_Short : Flags =  5; break;	//  5: 16-bit   signed integer
	case SG_DATATYPE_Word  : Flags =  6; break;	//  6: 16-bit unsigned integer
	case SG_DATATYPE_Int   : Flags =  7; break;	//  7: 32-bit   signed integer
	case SG_DATATYPE_DWord : Flags =  8; break;	//  8: 32-bit unsigned integer
	default                : Flags = 10; break;	// 10: 32-bit float
	case SG_DATATYPE_Double: Flags = 11; break;	// 11: 64-bit float
	}

//	Flags	|= 0x80;	// isOffline: no, never here!
	Flags	|= 0x40;	// hasNodataValue
//	Flags	|= 0x20;	// isNoDataValue: no, never here!
//	Flags	|= 0x10;	// reserved (unused)

	Bytes	+= Flags;

	switch( pGrid->Get_Type() )
	{
	case SG_DATATYPE_Bit   : Bytes	+= (BYTE  )0                        ; break;	//  0:  1-bit boolean
	case SG_DATATYPE_Char  : Bytes	+= (char  )pGrid->Get_NoData_Value(); break;	//  3:  8-bit   signed integer
	case SG_DATATYPE_Byte  : Bytes	+= (BYTE  )pGrid->Get_NoData_Value(); break;	//  4:  8-bit unsigned integer
	case SG_DATATYPE_Short : Bytes	+= (short )pGrid->Get_NoData_Value(); break;	//  5: 16-bit   signed integer
	case SG_DATATYPE_Word  : Bytes	+= (WORD  )pGrid->Get_NoData_Value(); break;	//  6: 16-bit unsigned integer
	case SG_DATATYPE_Int   : Bytes	+= (int   )pGrid->Get_NoData_Value(); break;	//  7: 32-bit   signed integer
	case SG_DATATYPE_DWord : Bytes	+= (DWORD )pGrid->Get_NoData_Value(); break;	//  8: 32-bit unsigned integer
	default                : Bytes	+= (float )pGrid->Get_NoData_Value(); break;	//  9: 32-bit float
	case SG_DATATYPE_Double: Bytes	+= (double)pGrid->Get_NoData_Value(); break;	// 10: 64-bit float
	}

	for(int y=0; y<pGrid->Get_NY() && SG_UI_Process_Set_Progress(y, pGrid->Get_NY()); y++)
	{
		for(int x=0; x<pGrid->Get_NX(); x++)
		{
			double	Value	= pGrid->is_NoData(x, y) ? pGrid->Get_NoData_Value() : pGrid->asDouble(x, y);

			switch( pGrid->Get_Type() )
			{
			case SG_DATATYPE_Bit   : Bytes	+= (BYTE  )Value; break;	//  0:  1-bit boolean
			case SG_DATATYPE_Char  : Bytes	+= (char  )Value; break;	//  3:  8-bit   signed integer
			case SG_DATATYPE_Byte  : Bytes	+= (BYTE  )Value; break;	//  4:  8-bit unsigned integer
			case SG_DATATYPE_Short : Bytes	+= (short )Value; break;	//  5: 16-bit   signed integer
			case SG_DATATYPE_Word  : Bytes	+= (WORD  )Value; break;	//  6: 16-bit unsigned integer
			case SG_DATATYPE_Int   : Bytes	+= (int   )Value; break;	//  7: 32-bit   signed integer
			case SG_DATATYPE_DWord : Bytes	+= (DWORD )Value; break;	//  8: 32-bit unsigned integer
			default                : Bytes	+= (float )Value; break;	//  9: 32-bit float
			case SG_DATATYPE_Double: Bytes	+= (double)Value; break;	// 10: 64-bit float
			}
		}
	}

	return( true );
}


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

//---------------------------------------------------------
