1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //           Application Programming Interface           //
9 //                                                       //
10 //                  Library: SAGA_API                    //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                     shapes.cpp                        //
15 //                                                       //
16 //          Copyright (C) 2005 by Olaf Conrad            //
17 //                                                       //
18 //-------------------------------------------------------//
19 //                                                       //
20 // This file is part of 'SAGA - System for Automated     //
21 // Geoscientific Analyses'.                              //
22 //                                                       //
23 // This library is free software; you can redistribute   //
24 // it and/or modify it under the terms of the GNU Lesser //
25 // General Public License as published by the Free       //
26 // Software Foundation, either version 2.1 of the        //
27 // License, or (at your option) any later version.       //
28 //                                                       //
29 // This library is distributed in the hope that it will  //
30 // be useful, but WITHOUT ANY WARRANTY; without even the //
31 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
32 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
33 // License for more details.                             //
34 //                                                       //
35 // You should have received a copy of the GNU Lesser     //
36 // General Public License along with this program; if    //
37 // not, see <http://www.gnu.org/licenses/>.              //
38 //                                                       //
39 //-------------------------------------------------------//
40 //                                                       //
41 //    contact:    Olaf Conrad                            //
42 //                Institute of Geography                 //
43 //                University of Goettingen               //
44 //                Goldschmidtstr. 5                      //
45 //                37077 Goettingen                       //
46 //                Germany                                //
47 //                                                       //
48 //    e-mail:     oconrad@saga-gis.org                   //
49 //                                                       //
50 ///////////////////////////////////////////////////////////
51 
52 //---------------------------------------------------------
53 
54 
55 ///////////////////////////////////////////////////////////
56 //														 //
57 //														 //
58 //														 //
59 ///////////////////////////////////////////////////////////
60 
61 //---------------------------------------------------------
62 #include "shapes.h"
63 #include "pointcloud.h"
64 #include "tool_library.h"
65 
66 
67 ///////////////////////////////////////////////////////////
68 //														 //
69 //														 //
70 //														 //
71 ///////////////////////////////////////////////////////////
72 
73 //---------------------------------------------------------
SG_Get_ShapeType_Name(TSG_Shape_Type Type)74 CSG_String	SG_Get_ShapeType_Name(TSG_Shape_Type Type)
75 {
76 	switch( Type )
77 	{
78 	case SHAPE_TYPE_Point  : return( _TL("Point"    ) );
79 	case SHAPE_TYPE_Points : return( _TL("Points"   ) );
80 	case SHAPE_TYPE_Line   : return( _TL("Line"     ) );
81 	case SHAPE_TYPE_Polygon: return( _TL("Polygon"  ) );
82 	default                : return( _TL("Undefined") );
83 	}
84 }
85 
86 
87 ///////////////////////////////////////////////////////////
88 //														 //
89 //														 //
90 //														 //
91 ///////////////////////////////////////////////////////////
92 
93 //---------------------------------------------------------
SG_Create_Shapes(void)94 CSG_Shapes *		SG_Create_Shapes(void)
95 {
96 	return( new CSG_Shapes );
97 }
98 
99 //---------------------------------------------------------
SG_Create_Shapes(const CSG_Shapes & Shapes)100 CSG_Shapes *		SG_Create_Shapes(const CSG_Shapes &Shapes)
101 {
102 	switch( Shapes.Get_ObjectType() )
103 	{
104 	case SG_DATAOBJECT_TYPE_Shapes:
105 		return( new CSG_Shapes(Shapes) );
106 
107 	case SG_DATAOBJECT_TYPE_PointCloud:
108 		return( SG_Create_PointCloud(*((CSG_PointCloud *)&Shapes)) );
109 
110 	default:
111 		return( NULL );
112 	}
113 }
114 
115 //---------------------------------------------------------
SG_Create_Shapes(const CSG_String & File_Name)116 CSG_Shapes *		SG_Create_Shapes(const CSG_String &File_Name)
117 {
118 	return( new CSG_Shapes(File_Name) );
119 }
120 
121 //---------------------------------------------------------
SG_Create_Shapes(TSG_Shape_Type Type,const SG_Char * Name,CSG_Table * pStructure,TSG_Vertex_Type Vertex_Type)122 CSG_Shapes *		SG_Create_Shapes(TSG_Shape_Type Type, const SG_Char *Name, CSG_Table *pStructure, TSG_Vertex_Type Vertex_Type)
123 {
124 	return( new CSG_Shapes(Type, Name, pStructure, Vertex_Type) );
125 }
126 
127 //---------------------------------------------------------
SG_Create_Shapes(CSG_Shapes * pTemplate)128 CSG_Shapes *		SG_Create_Shapes(CSG_Shapes *pTemplate)
129 {
130 	if( pTemplate )
131 	{
132 		switch( pTemplate->Get_ObjectType() )
133 		{
134 		case SG_DATAOBJECT_TYPE_Shapes:
135 			return( new CSG_Shapes(pTemplate->Get_Type(), pTemplate->Get_Name(), pTemplate, pTemplate->Get_Vertex_Type()) );
136 
137 		case SG_DATAOBJECT_TYPE_PointCloud:
138 			return( SG_Create_PointCloud((CSG_PointCloud *)pTemplate) );
139 
140 		default:
141 			break;
142 		}
143 	}
144 
145 	return( new CSG_Shapes() );
146 }
147 
148 
149 ///////////////////////////////////////////////////////////
150 //														 //
151 //														 //
152 //														 //
153 ///////////////////////////////////////////////////////////
154 
155 //---------------------------------------------------------
CSG_Shapes(void)156 CSG_Shapes::CSG_Shapes(void)
157 	: CSG_Table()
158 {
159 	_On_Construction();
160 }
161 
162 //---------------------------------------------------------
CSG_Shapes(const CSG_Shapes & Shapes)163 CSG_Shapes::CSG_Shapes(const CSG_Shapes &Shapes)
164 	: CSG_Table()
165 {
166 	_On_Construction();
167 
168 	Create(Shapes);
169 }
170 
171 //---------------------------------------------------------
CSG_Shapes(const CSG_String & File_Name)172 CSG_Shapes::CSG_Shapes(const CSG_String &File_Name)
173 	: CSG_Table()
174 {
175 	_On_Construction();
176 
177 	Create(File_Name);
178 }
179 
180 //---------------------------------------------------------
CSG_Shapes(TSG_Shape_Type Type,const SG_Char * Name,CSG_Table * pStructure,TSG_Vertex_Type Vertex_Type)181 CSG_Shapes::CSG_Shapes(TSG_Shape_Type Type, const SG_Char *Name, CSG_Table *pStructure, TSG_Vertex_Type Vertex_Type)
182 	: CSG_Table()
183 {
184 	_On_Construction();
185 
186 	Create(Type, Name, pStructure, Vertex_Type);
187 }
188 
189 
190 ///////////////////////////////////////////////////////////
191 //														 //
192 //														 //
193 //														 //
194 ///////////////////////////////////////////////////////////
195 
196 //---------------------------------------------------------
_On_Construction(void)197 void CSG_Shapes::_On_Construction(void)
198 {
199 	CSG_Table::_On_Construction();
200 
201 	m_Type			= SHAPE_TYPE_Undefined;
202 	m_Vertex_Type	= SG_VERTEX_TYPE_XY;
203 
204 	m_Encoding		= SG_FILE_ENCODING_UTF8;
205 }
206 
207 
208 ///////////////////////////////////////////////////////////
209 //														 //
210 //														 //
211 //														 //
212 ///////////////////////////////////////////////////////////
213 
214 //---------------------------------------------------------
Create(const CSG_Shapes & Shapes)215 bool CSG_Shapes::Create(const CSG_Shapes &Shapes)
216 {
217 	return( Assign((CSG_Data_Object *)&Shapes) );
218 }
219 
220 //---------------------------------------------------------
Create(const CSG_String & File_Name)221 bool CSG_Shapes::Create(const CSG_String &File_Name)
222 {
223 	Destroy();
224 
225 	SG_UI_Msg_Add(CSG_String::Format("%s %s: %s...", _TL("Loading"), _TL("shapes"), File_Name.c_str()), true);
226 
227 	bool	bResult	= false;
228 
229 	//-----------------------------------------------------
230 	if( File_Name.BeforeFirst(':').Cmp("PGSQL") == 0 )	// database source
231 	{
232 		CSG_String	s(File_Name);
233 
234 		s	= s.AfterFirst(':');	CSG_String	Host  (s.BeforeFirst(':'));
235 		s	= s.AfterFirst(':');	CSG_String	Port  (s.BeforeFirst(':'));
236 		s	= s.AfterFirst(':');	CSG_String	DBName(s.BeforeFirst(':'));
237 		s	= s.AfterFirst(':');	CSG_String	Table (s.BeforeFirst(':'));
238 
239 		CSG_Tool	*pTool	= SG_Get_Tool_Library_Manager().Create_Tool("db_pgsql", 0, true);	// CGet_Connections
240 
241 		if(	pTool != NULL )
242 		{
243 			SG_UI_ProgressAndMsg_Lock(true);
244 
245 			//---------------------------------------------
246 			CSG_Table	Connections;
247 			CSG_String	Connection	= DBName + " [" + Host + ":" + Port + "]";
248 
249 			pTool->Set_Manager(NULL);
250 			pTool->On_Before_Execution();
251 
252 			if( SG_TOOL_PARAMETER_SET("CONNECTIONS", &Connections) && pTool->Execute() )	// CGet_Connections
253 			{
254 				for(int i=0; !bResult && i<Connections.Get_Count(); i++)
255 				{
256 					if( !Connection.Cmp(Connections[i].asString(0)) )
257 					{
258 						bResult	= true;
259 					}
260 				}
261 			}
262 
263 			SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
264 
265 			//---------------------------------------------
266 			if( bResult && (bResult = (pTool = SG_Get_Tool_Library_Manager().Create_Tool("db_pgsql", 20, true)) != NULL) == true )	// CPGIS_Shapes_Load
267 			{
268 				pTool->Set_Manager(NULL);
269 				pTool->On_Before_Execution();
270 
271 				bResult	=  SG_TOOL_PARAMETER_SET("CONNECTION", Connection)
272 						&& SG_TOOL_PARAMETER_SET("TABLES"    , Table)
273 						&& SG_TOOL_PARAMETER_SET("SHAPES"    , this)
274 						&& pTool->Execute();
275 
276 				SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
277 			}
278 
279 			SG_UI_ProgressAndMsg_Lock(false);
280 		}
281 	}
282 	else
283 	{
284 		bResult	= _Load_ESRI(File_Name) || _Load_GDAL(File_Name);
285 	}
286 
287 	//-----------------------------------------------------
288 	if( bResult )
289 	{
290 		Set_Modified(false);
291 		Set_Update_Flag();
292 
293 		SG_UI_Process_Set_Ready();
294 		SG_UI_Msg_Add(_TL("okay"), false, SG_UI_MSG_STYLE_SUCCESS);
295 
296 		return( true );
297 	}
298 
299 	//-----------------------------------------------------
300 	for(int iShape=Get_Count()-1; iShape>=0; iShape--)	// be kind, keep at least those shapes that have been loaded successfully
301 	{
302 		if( !Get_Shape(iShape)->is_Valid() )
303 		{
304 			Del_Shape(iShape);
305 		}
306 	}
307 
308 	if( Get_Count() <= 0 )
309 	{
310 		Destroy();
311 	}
312 
313 	//-----------------------------------------------------
314 	SG_UI_Process_Set_Ready();
315 	SG_UI_Msg_Add(_TL("failed"), false, SG_UI_MSG_STYLE_FAILURE);
316 
317 	return( false );
318 }
319 
320 //---------------------------------------------------------
Create(TSG_Shape_Type Type,const SG_Char * Name,CSG_Table * pStructure,TSG_Vertex_Type Vertex_Type)321 bool CSG_Shapes::Create(TSG_Shape_Type Type, const SG_Char *Name, CSG_Table *pStructure, TSG_Vertex_Type Vertex_Type)
322 {
323 	Destroy();
324 
325 	CSG_Table::Create(pStructure);
326 
327 	if( Name )
328 	{
329 		Set_Name(CSG_String(Name));
330 	}
331 
332 	m_Type			= Type;
333 	m_Vertex_Type	= Vertex_Type;
334 
335 	return( true );
336 }
337 
338 
339 ///////////////////////////////////////////////////////////
340 //														 //
341 //														 //
342 //														 //
343 ///////////////////////////////////////////////////////////
344 
345 //---------------------------------------------------------
~CSG_Shapes(void)346 CSG_Shapes::~CSG_Shapes(void)
347 {
348 	Destroy();
349 }
350 
351 //---------------------------------------------------------
Destroy(void)352 bool CSG_Shapes::Destroy(void)
353 {
354 	return( CSG_Table::Destroy() );
355 }
356 
357 
358 ///////////////////////////////////////////////////////////
359 //														 //
360 //														 //
361 //														 //
362 ///////////////////////////////////////////////////////////
363 
364 //---------------------------------------------------------
Assign(CSG_Data_Object * pObject)365 bool CSG_Shapes::Assign(CSG_Data_Object *pObject)
366 {
367 	if(	pObject && pObject->is_Valid() && (pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_Shapes || pObject->Get_ObjectType() == SG_DATAOBJECT_TYPE_PointCloud) )
368 	{
369 		CSG_Shapes	*pShapes	= (CSG_Shapes *)pObject;
370 
371 		Create(pShapes->Get_Type(), pShapes->Get_Name(), pShapes, pShapes->Get_Vertex_Type());
372 
373 		Get_History()	= pShapes->Get_History();
374 
375 		Get_Projection().Create(pShapes->Get_Projection());
376 
377 		for(int iShape=0; iShape<pShapes->Get_Count() && SG_UI_Process_Get_Okay(); iShape++)
378 		{
379 			Add_Shape(pShapes->Get_Shape(iShape));
380 		}
381 
382 		return( true );
383 	}
384 
385 	return( false );
386 }
387 
388 
389 ///////////////////////////////////////////////////////////
390 //														 //
391 //														 //
392 //														 //
393 ///////////////////////////////////////////////////////////
394 
395 //---------------------------------------------------------
396 static TSG_Shape_File_Format	gSG_Shape_File_Format_Default	= SHAPE_FILE_FORMAT_ESRI;
397 
398 //---------------------------------------------------------
SG_Shapes_Set_File_Format_Default(int Format)399 bool					SG_Shapes_Set_File_Format_Default	(int Format)
400 {
401 	switch( Format )
402 	{
403 	case SHAPE_FILE_FORMAT_ESRI      :
404 	case SHAPE_FILE_FORMAT_GeoPackage:
405 	case SHAPE_FILE_FORMAT_GeoJSON   :
406 		gSG_Shape_File_Format_Default	= (TSG_Shape_File_Format)Format;
407 		return( true );
408 	}
409 
410 	return( false );
411 }
412 
413 //---------------------------------------------------------
SG_Shapes_Get_File_Format_Default(void)414 TSG_Shape_File_Format	SG_Shapes_Get_File_Format_Default	(void)
415 {
416 	return( gSG_Shape_File_Format_Default );
417 }
418 
419 //---------------------------------------------------------
SG_Shapes_Get_File_Extension_Default(void)420 CSG_String				SG_Shapes_Get_File_Extension_Default	(void)
421 {
422 	switch( gSG_Shape_File_Format_Default )
423 	{
424 	default:
425 	case SHAPE_FILE_FORMAT_ESRI      :	return( "shp"     );
426 	case SHAPE_FILE_FORMAT_GeoPackage:	return( "gpkg"    );
427 	case SHAPE_FILE_FORMAT_GeoJSON   :	return( "geojson" );
428 	}
429 }
430 
431 
432 ///////////////////////////////////////////////////////////
433 //														 //
434 ///////////////////////////////////////////////////////////
435 
436 //---------------------------------------------------------
Save(const CSG_String & File_Name,int Format)437 bool CSG_Shapes::Save(const CSG_String &File_Name, int Format)
438 {
439 	SG_UI_Msg_Add(CSG_String::Format("%s %s: %s...", _TL("Saving"), _TL("shapes"), File_Name.c_str()), true);
440 
441 	//-----------------------------------------------------
442 	if( Format == SHAPE_FILE_FORMAT_Undefined )
443 	{
444 		Format	= gSG_Shape_File_Format_Default;
445 
446 		if( SG_File_Cmp_Extension(File_Name, "shp"    ) )	Format	= SHAPE_FILE_FORMAT_ESRI      ;
447 		if( SG_File_Cmp_Extension(File_Name, "gpkg"   ) )	Format	= SHAPE_FILE_FORMAT_GeoPackage;
448 		if( SG_File_Cmp_Extension(File_Name, "geojson") )	Format	= SHAPE_FILE_FORMAT_GeoJSON   ;
449 	}
450 
451 	//-----------------------------------------------------
452 	bool	bResult	= false;
453 
454 	switch( Format )
455 	{
456 	case SHAPE_FILE_FORMAT_ESRI      : bResult = _Save_ESRI(File_Name           ); break;
457 	case SHAPE_FILE_FORMAT_GeoPackage: bResult = _Save_GDAL(File_Name, "GPKG"   ); break;
458 	case SHAPE_FILE_FORMAT_GeoJSON   : bResult = _Save_GDAL(File_Name, "GeoJSON"); break;
459 	}
460 
461 	//-----------------------------------------------------
462 	if( bResult )
463 	{
464 		Set_Modified(false);
465 
466 		Set_File_Name(File_Name, true);
467 
468 		SG_UI_Process_Set_Ready();
469 		SG_UI_Msg_Add(_TL("okay"), false, SG_UI_MSG_STYLE_SUCCESS);
470 
471 		return( true );
472 	}
473 
474 	SG_UI_Process_Set_Ready();
475 	SG_UI_Msg_Add(_TL("failed"), false, SG_UI_MSG_STYLE_FAILURE);
476 
477 	return( false );
478 }
479 
480 
481 ///////////////////////////////////////////////////////////
482 //														 //
483 //														 //
484 //														 //
485 ///////////////////////////////////////////////////////////
486 
487 //---------------------------------------------------------
_Get_New_Record(int Index)488 CSG_Table_Record * CSG_Shapes::_Get_New_Record(int Index)
489 {
490 	switch( m_Type )
491 	{
492 	case SHAPE_TYPE_Point:
493 		switch( m_Vertex_Type )
494 		{
495 		case SG_VERTEX_TYPE_XY:	default:
496 			return( new CSG_Shape_Point		(this, Index) );
497 
498 		case SG_VERTEX_TYPE_XYZ:
499 			return( new CSG_Shape_Point_Z	(this, Index) );
500 
501 		case SG_VERTEX_TYPE_XYZM:
502 			return( new CSG_Shape_Point_ZM	(this, Index) );
503 		}
504 
505 	case SHAPE_TYPE_Points:
506 		return( new CSG_Shape_Points	(this, Index) );
507 
508 	case SHAPE_TYPE_Line:
509 		return( new CSG_Shape_Line		(this, Index) );
510 
511 	case SHAPE_TYPE_Polygon:
512 		return( new CSG_Shape_Polygon	(this, Index) );
513 
514 	default:
515 		return( NULL );
516 	}
517 }
518 
519 //---------------------------------------------------------
Add_Shape(CSG_Table_Record * pCopy,TSG_ADD_Shape_Copy_Mode mCopy)520 CSG_Shape * CSG_Shapes::Add_Shape(CSG_Table_Record *pCopy, TSG_ADD_Shape_Copy_Mode mCopy)
521 {
522 	CSG_Shape	*pShape	= (CSG_Shape *)Add_Record();
523 
524 	if( pShape && pCopy )
525 	{
526 		if( (mCopy == SHAPE_COPY || mCopy == SHAPE_COPY_ATTR) )
527 		{
528 			((CSG_Table_Record *)pShape)->Assign(pCopy);
529 		}
530 
531 		if( (mCopy == SHAPE_COPY || mCopy == SHAPE_COPY_GEOM) && pCopy->Get_Table()->Get_ObjectType() == SG_DATAOBJECT_TYPE_Shapes )
532 		{
533 			pShape->Assign((CSG_Shape *)pCopy, false);
534 		}
535 	}
536 
537 	return( pShape );
538 }
539 
540 //---------------------------------------------------------
Del_Shape(CSG_Shape * pShape)541 bool CSG_Shapes::Del_Shape(CSG_Shape *pShape)
542 {
543 	return( Del_Record(pShape->Get_Index()) );
544 }
545 
Del_Shape(int iShape)546 bool CSG_Shapes::Del_Shape(int iShape)
547 {
548 	return( Del_Record(iShape) );
549 }
550 
551 
552 ///////////////////////////////////////////////////////////
553 //														 //
554 //														 //
555 //														 //
556 ///////////////////////////////////////////////////////////
557 
558 //---------------------------------------------------------
On_Update(void)559 bool CSG_Shapes::On_Update(void)
560 {
561 	if( Get_Count() > 0 )
562 	{
563 		CSG_Shape	*pShape	= Get_Shape(0);
564 
565 		m_Extent	= pShape->Get_Extent();
566 		m_ZMin		= pShape->Get_ZMin();
567 		m_ZMax		= pShape->Get_ZMax();
568 		m_MMin		= pShape->Get_MMin();
569 		m_MMax		= pShape->Get_MMax();
570 
571 		for(int i=1; i<Get_Count(); i++)
572 		{
573 			pShape	= Get_Shape(i);
574 
575 			m_Extent.Union(pShape->Get_Extent());
576 
577 			switch( m_Vertex_Type )
578 			{
579 			case SG_VERTEX_TYPE_XYZM:
580 				if( m_MMin > pShape->Get_MMin() )	m_MMin	= pShape->Get_MMin();
581 				if( m_MMax < pShape->Get_MMax() )	m_MMax	= pShape->Get_MMax();
582 
583 			case SG_VERTEX_TYPE_XYZ:
584 				if( m_ZMin > pShape->Get_ZMin() )	m_ZMin	= pShape->Get_ZMin();
585 				if( m_ZMax < pShape->Get_ZMax() )	m_ZMax	= pShape->Get_ZMax();
586 				break;
587 			default:
588 				break;
589 			}
590 		}
591 	}
592 	else
593 	{
594 		m_Extent.Assign(0.0, 0.0, 0.0, 0.0);
595 	}
596 
597 	return( CSG_Table::On_Update() );
598 }
599 
600 
601 ///////////////////////////////////////////////////////////
602 //														 //
603 //														 //
604 //														 //
605 ///////////////////////////////////////////////////////////
606 
607 //---------------------------------------------------------
Get_Shape(const TSG_Point & Point,double Epsilon)608 CSG_Shape * CSG_Shapes::Get_Shape(const TSG_Point &Point, double Epsilon)
609 {
610 	CSG_Rect	r(Point.x - Epsilon, Point.y - Epsilon, Point.x + Epsilon, Point.y + Epsilon);
611 
612 	CSG_Shape	*pNearest	= NULL;
613 
614 	if( r.Intersects(Get_Extent()) != INTERSECTION_None )
615 	{
616 		double	dNearest	= -1.;
617 
618 		for(int iShape=0; iShape<Get_Count(); iShape++)
619 		{
620 			CSG_Shape	*pShape	= Get_Shape(iShape);
621 
622 			if( pShape->Intersects(r) )
623 			{
624 				for(int iPart=0; iPart<pShape->Get_Part_Count(); iPart++)
625 				{
626 					if( r.Intersects(pShape->Get_Extent(iPart)) )
627 					{
628 						double	d	= pShape->Get_Distance(Point, iPart);
629 
630 						if( d == 0. )
631 						{
632 							return( pShape );
633 						}
634 						else if( d > 0. && d <= Epsilon && (pNearest == NULL || d < dNearest) )
635 						{
636 							dNearest	= d;
637 							pNearest	= pShape;
638 						}
639 					}
640 				}
641 			}
642 		}
643 	}
644 
645 	return( pNearest );
646 }
647 
648 
649 ///////////////////////////////////////////////////////////
650 //														 //
651 //														 //
652 //														 //
653 ///////////////////////////////////////////////////////////
654 
655 //---------------------------------------------------------
Make_Clean(void)656 bool CSG_Shapes::Make_Clean(void)
657 {
658 	if( m_Type != SHAPE_TYPE_Polygon )
659 	{
660 		return( true );
661 	}
662 
663 	for(int iShape=0; iShape<Get_Count() && SG_UI_Process_Set_Progress(iShape, Get_Count()); iShape++)
664 	{
665 		CSG_Shape_Polygon	*pPolygon	= (CSG_Shape_Polygon *)Get_Shape(iShape);
666 
667 		for(int iPart=0; iPart<pPolygon->Get_Part_Count(); iPart++)
668 		{
669 			if( m_Vertex_Type == SG_VERTEX_TYPE_XY )	// currently we have to disable this check for 3D shapefiles since the
670 														// _Update_Area() method can not handle polygons with no horizontal extent
671 			{
672 				//--------------------------------------------
673 				// ring direction: outer rings > clockwise, inner rings (lakes) > counterclockwise !
674 
675 				if( (pPolygon->is_Lake(iPart) == pPolygon->is_Clockwise(iPart)) )
676 				{
677 					pPolygon->Revert_Points(iPart);
678 				}
679 			}
680 
681 			//--------------------------------------------
682 			// last point == first point !
683 
684 			if( !CSG_Point(pPolygon->Get_Point(0, iPart)).is_Equal(pPolygon->Get_Point(pPolygon->Get_Point_Count(iPart) - 1, iPart)) )
685 			{
686 				((CSG_Shape *)pPolygon)->Add_Point(pPolygon->Get_Point(0, iPart), iPart);
687 
688 				if( m_Vertex_Type != SG_VERTEX_TYPE_XY )
689 				{
690 					pPolygon->Set_Z(pPolygon->Get_Z(0, iPart), pPolygon->Get_Point_Count(iPart) - 1, iPart);
691 
692 					if( m_Vertex_Type == SG_VERTEX_TYPE_XYZM )
693 					{
694 						pPolygon->Set_M(pPolygon->Get_M(0, iPart), pPolygon->Get_Point_Count(iPart) - 1, iPart);
695 					}
696 				}
697 			}
698 
699 			//--------------------------------------------
700 			// no self intersection !
701 
702 		}
703 	}
704 
705 	return( true );
706 }
707 
708 
709 ///////////////////////////////////////////////////////////
710 //														 //
711 //														 //
712 //														 //
713 ///////////////////////////////////////////////////////////
714 
715 //---------------------------------------------------------
716