1 /* -*-c++-*- */
2 /* osgEarth - Geospatial SDK for OpenSceneGraph
3 * Copyright 2019 Pelican Mapping
4 * http://osgearth.org
5 *
6 * osgEarth is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
17 * IN THE SOFTWARE.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
21 */
22 #include "GeodeticLabelingEngine"
23
24 #define LC "[GeodeticLabelingEngine] "
25
26 using namespace osgEarth;
27 using namespace osgEarth::Util;
28
29 //........................................................................
30
GeodeticLabelingEngine(const SpatialReference * srs)31 GeodeticLabelingEngine::GeodeticLabelingEngine(const SpatialReference* srs) :
32 GraticuleLabelingEngine(srs),
33 _resolution(10.0 / 180.0)
34 {
35 _formatter = new LatLongFormatter(osgEarth::Util::LatLongFormatter::FORMAT_DEGREES_MINUTES_SECONDS_TERSE, LatLongFormatter::USE_SYMBOLS | LatLongFormatter::USE_PREFIXES);
36 }
37
getResolution() const38 double GeodeticLabelingEngine::getResolution() const
39 {
40 return _resolution;
41 }
42
setResolution(double resolution)43 void GeodeticLabelingEngine::setResolution(double resolution)
44 {
45 _resolution = resolution;
46 }
47
48 std::string
getText(const GeoPoint & location,bool lat)49 GeodeticLabelingEngine::getText(const GeoPoint& location, bool lat)
50 {
51 double value = lat ? location.y() : location.x();
52 return _formatter->format(value, lat);
53 }
54
55 bool
updateLabels(const osg::Vec3d & LL_world,osg::Vec3d & UL_world,osg::Vec3d & LR_world,ClipSpace & window,CameraData & data)56 GeodeticLabelingEngine::updateLabels(const osg::Vec3d& LL_world, osg::Vec3d& UL_world, osg::Vec3d& LR_world, ClipSpace& window, CameraData& data)
57 {
58 SpatialReference* wgs84 = SpatialReference::create("wgs84");
59
60 GeoPoint ll, ul, lr;
61 ll.fromWorld(wgs84, LL_world);
62 ul.fromWorld(wgs84, UL_world);
63 lr.fromWorld(wgs84, LR_world);
64
65 double resDegrees = _resolution * 180.0;
66
67 double minLon = osg::minimum(ll.x(), ul.x());
68 double maxLon = lr.x();
69 // Handle the case where the the extent crosses the dateline.
70 if (maxLon < minLon)
71 {
72 maxLon += 360.0;
73 }
74
75 double minLat = osg::minimum(osg::minimum(ll.y(), ul.y()), lr.y());
76 double maxLat = osg::maximum(osg::maximum(ll.y(), ul.y()), lr.y());
77
78 int minLonIndex = floor(((minLon + 180.0) / resDegrees));
79 int maxLonIndex = ceil(((maxLon + 180.0) / resDegrees));
80
81 int minLatIndex = floor(((minLat + 90) / resDegrees));
82 int maxLatIndex = ceil(((maxLat + 90) / resDegrees));
83
84 // Generate horizontal labels
85 unsigned int xi = 0;
86 for (int i = minLonIndex; i <= maxLonIndex; i++)
87 {
88 GeoPoint p(wgs84, -180.0 + (double)i * resDegrees, minLat, 0, ALTMODE_ABSOLUTE);
89 std::string text = getText(p, false);
90 window.clampToBottom(p); // also xforms to geographic
91 data.xLabels[xi]->setPosition(p);
92 data.xLabels[xi]->setText(text);
93 data.xLabels[xi]->setNodeMask(~0);
94 xi++;
95 if (xi >= data.xLabels.size()) break;
96 }
97
98 unsigned int yi = 0;
99 for (int i = minLatIndex; i <= maxLatIndex; i++)
100 {
101 GeoPoint p(wgs84, minLon, -90.0 + (double)i * resDegrees, 0, ALTMODE_ABSOLUTE);
102 std::string text = getText(p, true);
103 window.clampToLeft(p); // also xforms to geographic
104 data.yLabels[yi]->setPosition(p);
105 data.yLabels[yi]->setText(text);
106 data.yLabels[yi]->setNodeMask(~0);
107 yi++;
108 if (yi >= data.yLabels.size()) break;
109 }
110
111 return true;
112 }
113