
///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//                     Tool Library                      //
//                    shapes_polygons                    //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                polygon_split_parts.cpp                //
//                                                       //
//                 Copyright (C) 2011 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/>.                       //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//    e-mail:     oconrad@saga-gis.org                   //
//                                                       //
//    contact:    Olaf Conrad                            //
//                Institute of Geography                 //
//                University of Hamburg                  //
//                Germany                                //
//                                                       //
///////////////////////////////////////////////////////////

//---------------------------------------------------------
#include "polygon_split_parts.h"


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

//---------------------------------------------------------
CPolygon_Split_Parts::CPolygon_Split_Parts(void)
{
	Set_Name		(_TL("Polygon Parts to Separate Polygons"));

	Set_Author		("O.Conrad (c) 2011");

	Set_Description	(_TW(
		"Splits parts of multipart polygons into separate polygons. "
		"The 'simple' method separates all parts of a multipart polygon "
		"no matter if it is an island (outer ring) or a lake (inner ring). "
		"The 'fast' method takes respect of lakes but might fail on complex "
		"nestings (islands in lakes in islands in lakes...). Default is "
		"the 'precise' method, which also takes respect of complex nestings "
		"but processing might take significantly more time on large "
		"and complex polygons. "
	));

	//-----------------------------------------------------
	Parameters.Add_Shapes("", "POLYGONS", _TL("Polygons"), _TL(""), PARAMETER_INPUT , SHAPE_TYPE_Polygon);
	Parameters.Add_Shapes("", "PARTS"   , _TL("Parts"   ), _TL(""), PARAMETER_OUTPUT, SHAPE_TYPE_Polygon);

	Parameters.Add_Choice("", "METHOD"  , _TL("Method"  ), _TL(""),
		CSG_String::Format("%s|%s|%s",
			_TL("precise"),
			_TL("fast"),
			_TL("simple")
		)
	);
}


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

//---------------------------------------------------------
bool CPolygon_Split_Parts::On_Execute(void)
{
	CSG_Shapes &Polygons = *Parameters("POLYGONS")->asShapes();
	CSG_Shapes &Parts    = *Parameters("PARTS"   )->asShapes();

	Parts.Create(SHAPE_TYPE_Polygon, CSG_String::Format("%s [%s]", Polygons.Get_Name(), _TL("Parts")), &Polygons, Polygons.Get_Vertex_Type());

	//-----------------------------------------------------
	switch( Parameters("METHOD")->asInt() )
	{
	case  2: // simple
		{
			for(sLong iPolygon=0; iPolygon<Polygons.Get_Count() && Set_Progress(iPolygon, Polygons.Get_Count()); iPolygon++)
			{
				CSG_Shape_Polygon &Polygon = *Polygons.Get_Shape(iPolygon)->asPolygon();

				for(int iPart=0; iPart<Polygon.Get_Part_Count() && Process_Get_Okay(); iPart++)
				{
					Parts.Add_Shape(&Polygon, SHAPE_COPY_ATTR)->asPolygon()->Add_Part(Polygon.Get_Part(iPart));
				}
			}
		}
		break;

	//-----------------------------------------------------
	case  1: // fast
		{
			for(sLong iPolygon=0; iPolygon<Polygons.Get_Count() && Set_Progress(iPolygon, Polygons.Get_Count()); iPolygon++)
			{
				CSG_Shape_Polygon *pPolygon = Polygons.Get_Shape(iPolygon)->asPolygon();

				for(int iPart=0; iPart<pPolygon->Get_Part_Count() && Process_Get_Okay(); iPart++)
				{
					if( !pPolygon->is_Lake(iPart) )
					{
						CSG_Shape_Polygon &Part = *Parts.Add_Shape(pPolygon, SHAPE_COPY_ATTR)->asPolygon();

						Part.Add_Part(pPolygon->Get_Part(iPart));

						for(int jPart=0; jPart<pPolygon->Get_Part_Count(); jPart++)
						{
							if(	pPolygon->is_Lake(jPart) && Part.Contains(pPolygon->Get_Point(0, jPart)) )
							{
								Part.Add_Part(pPolygon->Get_Part(jPart));
							}
						}
					}
				}
			}
		}
		break;

	//-----------------------------------------------------
	default: // precise
		{
			for(sLong iPolygon=0; iPolygon<Polygons.Get_Count() && Set_Progress(iPolygon, Polygons.Get_Count()); iPolygon++)
			{
				CSG_Shape_Polygon &Polygon = *Polygons.Get_Shape(iPolygon)->asPolygon();

				#pragma omp parallel for
				for(int iPart=0; iPart<Polygon.Get_Part_Count(); iPart++) // pre-process is-lake-state
				{
					Polygon.is_Lake(iPart);
				}

				CSG_Array_Int isLakeOf(Polygon.Get_Part_Count()); isLakeOf.Assign(-1);

				for(int iPart=0; iPart<Polygon.Get_Part_Count() && Process_Get_Okay(); iPart++)
				{
					if( !Polygon.is_Lake(iPart) )
					{
						#pragma omp parallel for
						for(int jPart=0; jPart<Polygon.Get_Part_Count(); jPart++)
						{
							if( isLakeOf[jPart] < 0 && Polygon.is_Lake(jPart) && Polygon.Contains(Polygon.Get_Point(0, jPart), iPart, true) )
							{
								isLakeOf[jPart] = iPart;
							}
						}
					}
				}

				for(int iPart=0; iPart<Polygon.Get_Part_Count() && Process_Get_Okay(); iPart++)
				{
					if( isLakeOf[iPart] < 0 ) // island
					{
						CSG_Shape_Polygon &Part = *Parts.Add_Shape(&Polygon, SHAPE_COPY_ATTR)->asPolygon();

						Part.Add_Part(Polygon.Get_Part(iPart));

						for(int jPart=0; jPart<Polygon.Get_Part_Count(); jPart++)
						{
							if( isLakeOf[jPart] == iPart ) // lake belongs to this island
							{
								Part.Add_Part(Polygon.Get_Part(jPart));
							}
						}
					}
				}
			}
		}
		break;
	}

	//-----------------------------------------------------
	return( true );
}


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

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