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