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