1 
2 ///////////////////////////////////////////////////////////
3 //                                                       //
4 //                         SAGA                          //
5 //                                                       //
6 //      System for Automated Geoscientific Analyses      //
7 //                                                       //
8 //                    User Interface                     //
9 //                                                       //
10 //                    Program: SAGA                      //
11 //                                                       //
12 //-------------------------------------------------------//
13 //                                                       //
14 //                wksp_map_graticule.cpp                 //
15 //                                                       //
16 //          Copyright (C) 2014 by Olaf Conrad            //
17 //                                                       //
18 //-------------------------------------------------------//
19 //                                                       //
20 // This file is part of 'SAGA - System for Automated     //
21 // Geoscientific Analyses'. SAGA is free software; you   //
22 // can redistribute it and/or modify it under the terms  //
23 // of the GNU General Public License as published by the //
24 // Free Software Foundation, either version 2 of the     //
25 // License, or (at your option) any later version.       //
26 //                                                       //
27 // SAGA is distributed in the hope that it will be       //
28 // useful, but WITHOUT ANY WARRANTY; without even the    //
29 // implied warranty of MERCHANTABILITY or FITNESS FOR A  //
30 // PARTICULAR PURPOSE. See the GNU General Public        //
31 // License for more details.                             //
32 //                                                       //
33 // You should have received a copy of the GNU General    //
34 // Public License along with this program; if not, see   //
35 // <http://www.gnu.org/licenses/>.                       //
36 //                                                       //
37 //-------------------------------------------------------//
38 //                                                       //
39 //    contact:    Olaf Conrad                            //
40 //                Institute of Geography                 //
41 //                University of Hamburg                  //
42 //                Germany                                //
43 //                                                       //
44 //    e-mail:     oconrad@saga-gis.org                   //
45 //                                                       //
46 ///////////////////////////////////////////////////////////
47 
48 //---------------------------------------------------------
49 #include <wx/window.h>
50 
51 #include <saga_api/saga_api.h>
52 #include <saga_gdi/sgdi_helper.h>
53 
54 #include "helper.h"
55 
56 #include "res_commands.h"
57 
58 #include "wksp_map.h"
59 #include "wksp_map_graticule.h"
60 #include "wksp_map_dc.h"
61 
62 
63 ///////////////////////////////////////////////////////////
64 //														 //
65 //														 //
66 //														 //
67 ///////////////////////////////////////////////////////////
68 
69 //---------------------------------------------------------
CWKSP_Map_Graticule(CSG_MetaData * pEntry)70 CWKSP_Map_Graticule::CWKSP_Map_Graticule(CSG_MetaData *pEntry)
71 {
72 	m_bShow	= true;
73 
74 	//-----------------------------------------------------
75 	m_Parameters.Set_Name      ("GRATICULE");
76 	m_Parameters.Set_Identifier("GRATICULE");
77 
78 	//-----------------------------------------------------
79 	m_Parameters.Add_Node("", "NODE_GENERAL", _TL("General"), _TL(""));
80 
81 	m_Parameters.Add_String("NODE_GENERAL",
82 		"NAME"		, _TL("Name"),
83 		_TL(""),
84 		_TL("Graticule")
85 	);
86 
87 	m_Parameters.Add_Choice("NODE_GENERAL",
88 		"INTERVAL"	, _TL("Interval"),
89 		_TL(""),
90 		CSG_String::Format("%s|%s",
91 			_TL("fixed interval"),
92 			_TL("fitted interval")
93 		), 1
94 	);
95 
96 	m_Parameters.Add_Double("INTERVAL",
97 		"FIXED"		, _TL("Fixed Interval (Degree)"),
98 		_TL(""),
99 		5.0, 0.0, true, 20.0
100 	);
101 
102 	m_Parameters.Add_Int("INTERVAL",
103 		"FITTED"	, _TL("Number of Intervals"),
104 		_TL(""),
105 		5, 1, true
106 	);
107 
108 	m_Parameters.Add_Double("NODE_GENERAL",
109 		"RESOLUTION", _TL("Minimum Resolution (Degree)"),
110 		_TL(""),
111 		0.5, 0.0, true
112 	);
113 
114 	//-----------------------------------------------------
115 	m_Parameters.Add_Bool("NODE_GENERAL",
116 		"SHOW_ALWAYS", _TL("Show at all scales"),
117 		_TL(""),
118 		true
119 	);
120 
121 	m_Parameters.Add_Range("SHOW_ALWAYS",
122 		"SHOW_RANGE", _TL("Scale Range"),
123 		_TL("only show within scale range; values are given as extent measured in map units"),
124 		100.0, 1000.0, 0.0, true
125 	);
126 
127 	//-----------------------------------------------------
128 	m_Parameters.Add_Node("", "NODE_DISPLAY", _TL("Display"), _TL(""));
129 
130 	m_Parameters.Add_Color("NODE_DISPLAY",
131 		"COLOR"			, _TL("Color"),
132 		_TL(""),
133 		SG_COLOR_GREY
134 	);
135 
136 	m_Parameters.Add_Int("NODE_DISPLAY",
137 		"SIZE"			, _TL("Size"),
138 		_TL(""),
139 		0, 0, true
140 	);
141 
142 	m_Parameters.Add_Double("NODE_DISPLAY",
143 		"TRANSPARENCY"	, _TL("Transparency [%]"),
144 		_TL(""),
145 		0.0, 0.0, true, 100.0, true
146 	);
147 
148 	m_Parameters.Add_Choice("NODE_DISPLAY",
149 		"LINE_STYLE"	, _TL("Line Style"),
150 		_TL(""),
151 		CSG_String::Format("%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s",
152 			_TL("Solid style"            ),
153 			_TL("Dotted style"           ),
154 			_TL("Long dashed style"      ),
155 			_TL("Short dashed style"     ),
156 			_TL("Dot and dash style"     ),
157 			_TL("Backward diagonal hatch"),
158 			_TL("Cross-diagonal hatch"   ),
159 			_TL("Forward diagonal hatch" ),
160 			_TL("Cross hatch"            ),
161 			_TL("Horizontal hatch"       ),
162 			_TL("Vertical hatch"         )
163 		//	_TL("Use the stipple bitmap" )
164 		//	_TL("Use the user dashes"    )
165 		//	_TL("No pen is used"         )
166 		), 4
167 	);
168 
169 	//-----------------------------------------------------
170 	m_Parameters.Add_Bool("NODE_DISPLAY",
171 		"LABEL"			, _TL("Label"),
172 		_TL(""),
173 		true
174 	);
175 
176 	m_Parameters.Add_Choice("LABEL",
177 		"LABEL_UNITS"	, _TL("Units"),
178 		_TL(""),
179 		CSG_String::Format("%s|%s|%s",
180 			_TL("Decimal Degrees"),
181 			_TL("Degrees, Minutes, Seconds"),
182 			_TL("Degrees, Minutes, Seconds (significant)")
183 		), 0
184 	);
185 
186 	m_Parameters.Add_Int("LABEL",
187 		"LABEL_DECIMALS", _TL("Decimals"),
188 		_TL("Maximum number of decimals of a second to be printed."),
189 		2, 1, true
190 	);
191 
192 	m_Parameters.Add_Font("LABEL",
193 		"LABEL_FONT"	, _TL("Font"),
194 		_TL("")
195 	);
196 
197 	m_Parameters.Add_Double("LABEL",
198 		"LABEL_SIZE"	, _TL("Size"),
199 		_TL("Font size given as percentage of map size."),
200 		2.0, 0.0, true, 10.0, true
201 	);
202 
203 	m_Parameters.Add_Choice("LABEL",
204 		"LABEL_EFFECT"	, _TL("Boundary Effect"),
205 		_TL(""),
206 		CSG_String::Format("%s|%s|%s|%s|%s|%s|%s|%s|%s|%s",
207 			_TL("none"        ),
208 			_TL("full frame"  ),
209 			_TL("top"         ),
210 			_TL("top left"    ),
211 			_TL("left"        ),
212 			_TL("bottom left" ),
213 			_TL("bottom"      ),
214 			_TL("bottom right"),
215 			_TL("right"       ),
216 			_TL("top right"   )
217 		), 1
218 	);
219 
220 	m_Parameters.Add_Color("LABEL",
221 		"LABEL_EFFCOL"	, _TL("Boundary Effect Color"),
222 		_TL(""),
223 		SG_GET_RGB(255, 255, 255)
224 	);
225 
226 	//-----------------------------------------------------
227 	if( pEntry )
228 	{
229 		Load(*pEntry);
230 	}
231 }
232 
233 //---------------------------------------------------------
~CWKSP_Map_Graticule(void)234 CWKSP_Map_Graticule::~CWKSP_Map_Graticule(void)
235 {}
236 
237 
238 ///////////////////////////////////////////////////////////
239 //														 //
240 ///////////////////////////////////////////////////////////
241 
242 //---------------------------------------------------------
Load(CSG_MetaData & Entry)243 bool CWKSP_Map_Graticule::Load(CSG_MetaData &Entry)
244 {
245 	return( m_Parameters.Serialize(Entry, false) );
246 }
247 
248 //---------------------------------------------------------
Save(CSG_MetaData & Entry)249 bool CWKSP_Map_Graticule::Save(CSG_MetaData &Entry)
250 {
251 	return( m_Parameters.Serialize(*Entry.Add_Child("GRATICULE"), true) );
252 }
253 
254 
255 ///////////////////////////////////////////////////////////
256 //														 //
257 ///////////////////////////////////////////////////////////
258 
259 //---------------------------------------------------------
Get_Name(void)260 wxString CWKSP_Map_Graticule::Get_Name(void)
261 {
262 	wxString	Name(m_Parameters("NAME")->asString());
263 
264 	return( !m_bShow ? "* " + Name : Name );
265 }
266 
267 //---------------------------------------------------------
Get_Description(void)268 wxString CWKSP_Map_Graticule::Get_Description(void)
269 {
270 	wxString	s;
271 
272 	//-----------------------------------------------------
273 	s	+= wxString::Format("<h4>%s</h4>", _TL("Graticule"));
274 
275 	s	+= "<table border=\"0\">";
276 
277 	DESC_ADD_STR(_TL("Name"      ), m_Parameters("NAME")->asString());
278 	DESC_ADD_STR(_TL("Projection"), Get_Map()->Get_Projection().Get_Description().c_str());
279 
280 	s	+= wxT("</table>");
281 
282 	//-----------------------------------------------------
283 	return( s );
284 }
285 
286 //---------------------------------------------------------
Get_Menu(void)287 wxMenu * CWKSP_Map_Graticule::Get_Menu(void)
288 {
289 	wxMenu	*pMenu	= new wxMenu(m_Parameters("NAME")->asString());
290 
291 	CMD_Menu_Add_Item(pMenu, false, ID_CMD_WKSP_ITEM_CLOSE);
292 	CMD_Menu_Add_Item(pMenu,  true, ID_CMD_MAPS_LAYER_SHOW);
293 	pMenu->AppendSeparator();
294 	CMD_Menu_Add_Item(pMenu, false, ID_CMD_MAPS_MOVE_TOP);
295 	CMD_Menu_Add_Item(pMenu, false, ID_CMD_MAPS_MOVE_UP);
296 	CMD_Menu_Add_Item(pMenu, false, ID_CMD_MAPS_MOVE_DOWN);
297 	CMD_Menu_Add_Item(pMenu, false, ID_CMD_MAPS_MOVE_BOTTOM);
298 
299 	return( pMenu );
300 }
301 
302 
303 ///////////////////////////////////////////////////////////
304 //														 //
305 ///////////////////////////////////////////////////////////
306 
307 //---------------------------------------------------------
On_Command(int Cmd_ID)308 bool CWKSP_Map_Graticule::On_Command(int Cmd_ID)
309 {
310 	switch( Cmd_ID )
311 	{
312 	default:
313 		return( CWKSP_Base_Item::On_Command(Cmd_ID) );
314 
315 	case ID_CMD_WKSP_ITEM_RETURN:
316 	case ID_CMD_MAPS_LAYER_SHOW:
317 		m_bShow	= !m_bShow;
318 		((wxTreeCtrl *)Get_Control())->SetItemText(GetId(), Get_Name());
319 		((CWKSP_Map *)Get_Manager())->View_Refresh(true);
320 		break;
321 
322 	case ID_CMD_MAPS_MOVE_TOP:
323 		if( Get_Manager()->Move_Top(this) )
324 			((CWKSP_Map *)Get_Manager())->View_Refresh(false);
325 		break;
326 
327 	case ID_CMD_MAPS_MOVE_BOTTOM:
328 		if( Get_Manager()->Move_Bottom(this) )
329 			((CWKSP_Map *)Get_Manager())->View_Refresh(false);
330 		break;
331 
332 	case ID_CMD_MAPS_MOVE_UP:
333 		if( Get_Manager()->Move_Up(this) )
334 			((CWKSP_Map *)Get_Manager())->View_Refresh(false);
335 		break;
336 
337 	case ID_CMD_MAPS_MOVE_DOWN:
338 		if( Get_Manager()->Move_Down(this) )
339 			((CWKSP_Map *)Get_Manager())->View_Refresh(false);
340 		break;
341 	}
342 
343 	return( true );
344 }
345 
346 //---------------------------------------------------------
On_Command_UI(wxUpdateUIEvent & event)347 bool CWKSP_Map_Graticule::On_Command_UI(wxUpdateUIEvent &event)
348 {
349 	switch( event.GetId() )
350 	{
351 	default:
352 		return( CWKSP_Base_Item::On_Command_UI(event) );
353 
354 	case ID_CMD_MAPS_LAYER_SHOW:
355 		event.Check(m_bShow);
356 		break;
357 
358 	case ID_CMD_MAPS_MOVE_TOP:
359 	case ID_CMD_MAPS_MOVE_UP:
360 		event.Enable(Get_Index() > 0);
361 		break;
362 
363 	case ID_CMD_MAPS_MOVE_DOWN:
364 	case ID_CMD_MAPS_MOVE_BOTTOM:
365 		event.Enable(Get_Index() < Get_Manager()->Get_Count() - 1);
366 		break;
367 	}
368 
369 	return( true );
370 }
371 
372 
373 ///////////////////////////////////////////////////////////
374 //														 //
375 ///////////////////////////////////////////////////////////
376 
377 //---------------------------------------------------------
On_Parameter_Changed(CSG_Parameters * pParameters,CSG_Parameter * pParameter,int Flags)378 int CWKSP_Map_Graticule::On_Parameter_Changed(CSG_Parameters *pParameters, CSG_Parameter *pParameter, int Flags)
379 {
380 	if( Flags & PARAMETER_CHECK_ENABLE )
381 	{
382 		if(	pParameter->Cmp_Identifier("INTERVAL") )
383 		{
384 			pParameters->Set_Enabled("FIXED"       , pParameter->asInt() == 0);
385 			pParameters->Set_Enabled("FITTED"      , pParameter->asInt() == 1);
386 		}
387 
388 		if(	pParameter->Cmp_Identifier("SHOW_ALWAYS") )
389 		{
390 			pParameters->Set_Enabled("SHOW_RANGE"  , pParameter->asBool() == false);
391 		}
392 
393 		if(	pParameter->Cmp_Identifier("LABEL") )
394 		{
395 			pParameter->Set_Children_Enabled(pParameter->asBool());
396 		}
397 	}
398 
399 	return( CWKSP_Base_Item::On_Parameter_Changed(pParameters, pParameter, Flags) );
400 }
401 
402 //---------------------------------------------------------
Parameters_Changed(void)403 void CWKSP_Map_Graticule::Parameters_Changed(void)
404 {
405 	CWKSP_Base_Item::Parameters_Changed();
406 
407 	Get_Map()->View_Refresh(true);
408 }
409 
410 
411 ///////////////////////////////////////////////////////////
412 //														 //
413 ///////////////////////////////////////////////////////////
414 
415 //---------------------------------------------------------
Get_Graticule(const CSG_Rect & Extent)416 bool CWKSP_Map_Graticule::Get_Graticule(const CSG_Rect &Extent)
417 {
418 	bool	bResult	= false;
419 
420 	m_Graticule  .Create(SHAPE_TYPE_Line );
421 	m_Coordinates.Create(SHAPE_TYPE_Point);
422 
423 	CSG_Tool	*pTool	= SG_Get_Tool_Library_Manager().Create_Tool("pj_proj4", 14);
424 
425 	if(	pTool && Get_Map()->Get_Projection().is_Okay() )
426 	{
427 		SG_UI_ProgressAndMsg_Lock(true);
428 
429 		pTool->Set_Manager(NULL);
430 
431 		bResult	=  pTool->Set_Parameter("XMIN"      , Extent.Get_XMin())
432 				&& pTool->Set_Parameter("XMAX"      , Extent.Get_XMax())
433 				&& pTool->Set_Parameter("YMIN"      , Extent.Get_YMin())
434 				&& pTool->Set_Parameter("YMAX"      , Extent.Get_YMax())
435 				&& pTool->Set_Parameter("INTERVAL"  , m_Parameters("INTERVAL"  ))
436 				&& pTool->Set_Parameter("FIXED"     , m_Parameters("FIXED"     ))
437 				&& pTool->Set_Parameter("FITTED"    , m_Parameters("FITTED"    ))
438 				&& pTool->Set_Parameter("RESOLUTION", m_Parameters("RESOLUTION"))
439 				&& pTool->Set_Parameter("GRATICULE" , &m_Graticule)
440 				&& pTool->Set_Parameter("COORDS"    , &m_Coordinates)
441 				&& pTool->Set_Parameter("CRS_PROJ4" , Get_Map()->Get_Projection().Get_Proj4())
442 				&& pTool->On_Before_Execution()
443 				&& pTool->Execute();
444 
445 		SG_UI_ProgressAndMsg_Lock(false);
446 	}
447 
448 	SG_Get_Tool_Library_Manager().Delete_Tool(pTool);
449 
450 	return( bResult );
451 }
452 
453 
454 ///////////////////////////////////////////////////////////
455 //														 //
456 ///////////////////////////////////////////////////////////
457 
458 //---------------------------------------------------------
Draw(CWKSP_Map_DC & dc_Map)459 bool CWKSP_Map_Graticule::Draw(CWKSP_Map_DC &dc_Map)
460 {
461 	if( !Get_Graticule(dc_Map.m_rWorld) || m_Graticule.Get_Count() <= 0 )
462 	{
463 		return( false );
464 	}
465 
466 	if( !m_Parameters("SHOW_ALWAYS")->asBool() )
467 	{
468 		CSG_Parameter_Range	*pRange	= m_Parameters("SHOW_RANGE")->asRange();
469 		double	dRange	= dc_Map.m_rWorld.Get_XRange() > dc_Map.m_rWorld.Get_YRange() ? dc_Map.m_rWorld.Get_XRange() : dc_Map.m_rWorld.Get_YRange();
470 
471 		if( dRange < pRange->Get_Min() || pRange->Get_Max() < dRange )
472 		{
473 			return( false );
474 		}
475 	}
476 
477 	//-----------------------------------------------------
478 	CWKSP_Map_DC	*pDC	= m_Parameters("TRANSPARENCY")->asDouble() > 0.0 ? new CWKSP_Map_DC(dc_Map.m_rWorld, dc_Map.m_rDC, dc_Map.m_Scale, SG_GET_RGB(255, 255, 255)) : NULL;
479 	CWKSP_Map_DC	&dc		= pDC ? *pDC : dc_Map;
480 
481 	//-----------------------------------------------------
482 	wxPen	Pen(m_Parameters("COLOR")->asColor(), m_Parameters("SIZE")->asInt());
483 
484 	switch( m_Parameters("LINE_STYLE")->asInt() )
485 	{
486 	default:
487 	case  0:	Pen.SetStyle(wxPENSTYLE_SOLID           );	break; // Solid style.
488 	case  1:	Pen.SetStyle(wxPENSTYLE_DOT             );	break; // Dotted style.
489 	case  2:	Pen.SetStyle(wxPENSTYLE_LONG_DASH       );	break; // Long dashed style.
490 	case  3:	Pen.SetStyle(wxPENSTYLE_SHORT_DASH      );	break; // Short dashed style.
491 	case  4:	Pen.SetStyle(wxPENSTYLE_DOT_DASH        );	break; // Dot and dash style.
492 	case  5:	Pen.SetStyle(wxPENSTYLE_BDIAGONAL_HATCH );	break; // Backward diagonal hatch.
493 	case  6:	Pen.SetStyle(wxPENSTYLE_CROSSDIAG_HATCH );	break; // Cross-diagonal hatch.
494 	case  7:	Pen.SetStyle(wxPENSTYLE_FDIAGONAL_HATCH );	break; // Forward diagonal hatch.
495 	case  8:	Pen.SetStyle(wxPENSTYLE_CROSS_HATCH     );	break; // Cross hatch.
496 	case  9:	Pen.SetStyle(wxPENSTYLE_HORIZONTAL_HATCH);	break; // Horizontal hatch.
497 	case 10:	Pen.SetStyle(wxPENSTYLE_VERTICAL_HATCH  );	break; // Vertical hatch.
498 //	case 11:	Pen.SetStyle(wxPENSTYLE_STIPPLE         );	break; // Use the stipple bitmap.
499 //	case 12:	Pen.SetStyle(wxPENSTYLE_USER_DASH       );	break; // Use the user dashes: see wxPen::SetDashes.
500 //	case 13:	Pen.SetStyle(wxPENSTYLE_TRANSPARENT     );	break; // No pen is used.
501 	}
502 
503 	dc.dc.SetPen(Pen);
504 
505 	//-----------------------------------------------------
506 	for(int iLine=0; iLine<m_Graticule.Get_Count(); iLine++)
507 	{
508 		CSG_Shape	*pLine	= m_Graticule.Get_Shape(iLine);
509 
510 		for(int iPart=0; iPart<pLine->Get_Part_Count(); iPart++)
511 		{
512 			if( pLine->Get_Point_Count(iPart) > 1 )
513 			{
514 				TSG_Point_Int	B, A	= dc.World2DC(pLine->Get_Point(0, iPart));
515 
516 				for(int iPoint=1; iPoint<pLine->Get_Point_Count(iPart); iPoint++)
517 				{
518 					B		= A;
519 					A		= dc.World2DC(pLine->Get_Point(iPoint, iPart));
520 
521 					dc.dc.DrawLine(A.x, A.y, B.x, B.y);
522 				}
523 			}
524 		}
525 	}
526 
527 	//-----------------------------------------------------
528 	if( m_Parameters("LABEL")->asBool() )
529 	{
530 		int	Size	= (int)(0.5 + 0.01 * m_Parameters("LABEL_SIZE")->asDouble()
531 		*	( dc.m_rDC.GetWidth() < dc.m_rDC.GetHeight()
532 			? dc.m_rDC.GetWidth() : dc.m_rDC.GetHeight() )
533 		);
534 
535 		if( Size > 2 )
536 		{
537 			int			Effect, Units	= m_Parameters("LABEL_UNITS")->asInt(), Decimals = m_Parameters("LABEL_DECIMALS")->asInt();
538 			wxColour	Effect_Color	= Get_Color_asWX(m_Parameters("LABEL_EFFCOL")->asInt());
539 			wxFont		Font	= Get_Font(m_Parameters("LABEL_FONT"));
540 
541 			Font.SetPointSize(Size);
542 
543 			dc.dc.SetFont(Font);
544 			dc.dc.SetTextForeground(m_Parameters("LABEL_FONT")->asColor());
545 
546 			switch( m_Parameters("LABEL_EFFECT")->asInt() )
547 			{
548 			default:	Effect	= TEXTEFFECT_NONE       ;	break;
549 			case  1:	Effect	= TEXTEFFECT_FRAME      ;	break;
550 			case  2:	Effect	= TEXTEFFECT_TOP        ;	break;
551 			case  3:	Effect	= TEXTEFFECT_TOPLEFT    ;	break;
552 			case  4:	Effect	= TEXTEFFECT_LEFT       ;	break;
553 			case  5:	Effect	= TEXTEFFECT_BOTTOMLEFT ;	break;
554 			case  6:	Effect	= TEXTEFFECT_BOTTOM     ;	break;
555 			case  7:	Effect	= TEXTEFFECT_BOTTOMRIGHT;	break;
556 			case  8:	Effect	= TEXTEFFECT_RIGHT      ;	break;
557 			case  9:	Effect	= TEXTEFFECT_TOPRIGHT   ;	break;
558 			}
559 
560 			for(int iPoint=0; iPoint<m_Coordinates.Get_Count(); iPoint++)
561 			{
562 				CSG_Shape	*pPoint	= m_Coordinates.Get_Shape(iPoint);
563 
564 				TSG_Point_Int	p(dc.World2DC(pPoint->Get_Point(0)));
565 				wxString		Type(pPoint->asString(0));
566 
567 				int	Align	= !Type.Cmp("LAT_MIN") ? TEXTALIGN_CENTERLEFT
568 							: !Type.Cmp("LAT_MAX") ? TEXTALIGN_CENTERRIGHT
569 							: !Type.Cmp("LON_MIN") ? TEXTALIGN_BOTTOMCENTER
570 							: !Type.Cmp("LON_MAX") ? TEXTALIGN_TOPCENTER
571 							: TEXTALIGN_CENTER;
572 
573 				CSG_String	Coordinate(Get_Unit(pPoint, Units, Decimals, (Align & TEXTALIGN_YCENTER) != 0));
574 
575 				Draw_Text(dc.dc, Align, p.x, p.y, 0.0, Coordinate.c_str(), Effect, Effect_Color);
576 			}
577 		}
578 	}
579 
580 	//-----------------------------------------------------
581 	if( pDC )
582 	{
583 		dc_Map.Draw_DC(dc, m_Parameters("TRANSPARENCY")->asDouble() / 100.0);
584 
585 		delete(pDC);
586 	}
587 
588 	return( true );
589 }
590 
591 
592 //---------------------------------------------------------
Get_Unit(CSG_Shape * pPoint,int Units,int Decimals,bool bLatitude)593 CSG_String CWKSP_Map_Graticule::Get_Unit(CSG_Shape *pPoint, int Units, int Decimals, bool bLatitude)
594 {
595 	double	Value	= pPoint->asDouble(1);
596 
597 	const SG_Char	*D	= SG_T("\xb0");
598 
599 	const SG_Char	*C	= bLatitude
600 		? (Value < 0. ? SG_T("S") : SG_T("N"))
601 		: (Value > 0. ? SG_T("E") : SG_T("W"));
602 
603 	CSG_String	String;
604 
605 	//-----------------------------------------------------
606 	if( Units == 0 )	// decimal degrees
607 	{
608 	//	String.Printf("%s%s", pPoint->asString(1) + (Value < 0 ? 1 : 0), D); // no! label already includes degree symbol
609 		String.Printf("%s", pPoint->asString(1) + (Value < 0 ? 1 : 0));
610 	}
611 
612 	//-----------------------------------------------------
613 	else				// degrees, minutes, seconds
614 	{
615 		if( Value < 0. )
616 		{
617 			Value	= -Value;
618 		}
619 
620 		Value	= fmod(Value, 360.);
621 		int d	= (int)Value;
622 		Value	= (Value - d) * 60.;
623 		int h	= (int)Value;
624 		Value	= (Value - h) * 60.;
625 		int s	= (int)Value;
626 		Value	= (Value - s);
627 
628 		//-------------------------------------------------
629 		if( Value > 0. )	// floating point remainder
630 		{
631 			int	n	= SG_Get_Significant_Decimals(Value, Decimals);
632 
633 			String.Printf("%d%s%02d'%02d.%d''", d, D, h, s, (int)(Value * pow(10, n)));
634 		}
635 		else if( s > 0 || Units == 1 )
636 		{
637 			String.Printf("%d%s%02d'%02d''"   , d, D, h, s);
638 		}
639 		else if( h > 0 )
640 		{
641 			String.Printf("%d%s%02d'"         , d, D, h);
642 		}
643 		else
644 		{
645 			String.Printf("%d%s"              , d, D);
646 		}
647 	}
648 
649 	String	+= C;
650 
651 	return( String );
652 }
653 
654 
655 ///////////////////////////////////////////////////////////
656 //														 //
657 //														 //
658 //														 //
659 ///////////////////////////////////////////////////////////
660 
661 //---------------------------------------------------------
662