123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- //==============================================================================
- //
- // gpxcoord - the gpx coordinate formatter
- //
- // Copyright (C) 2018 Dick van Oudheusden
- //
- // This library is free software; you can redistribute it and/or
- // modify it under the terms of the GNU Lesser General Public
- // License as published by the Free Software Foundation; either
- // version 3 of the License, or (at your option) any later version.
- //
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public
- // License along with this library; if not, write to the Free
- // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- //
- //==============================================================================
- #include <iostream>
- #include <sstream>
- #include <cstring>
- #include <cctype>
- #include <iomanip>
- #include <cmath>
- #include "Arguments.h"
- // -- Is the next char present in matchers ------------------------------------
- bool isChars(char ch, const std::string &matchers)
- {
- for (auto iter = matchers.begin(); iter != matchers.end(); ++iter)
- {
- if (ch == *iter) return true;
- }
- return false;
- }
- // -- Skip spaces -------------------------------------------------------------
- void skipSpaces(const std::string &input, std::size_t &i)
- {
- const std::size_t length = input.length();
- while (i < length && isspace(input[i]))
- {
- i++;
- }
- }
- // -- Scan a value ------------------------------------------------------------
- bool scanValue(const std::string &input, std::size_t &i, double &value, bool &withPoint)
- {
- const std::size_t length = input.length();
- if (i < length && !isdigit(input[i])) return false;
- std::string text;
- while (i < length && isdigit(input[i]))
- {
- text += input[i++];
- }
- withPoint = (i < length && input[i] == '.');
- if (withPoint)
- {
- text += input[i++];
- while (i < length && isdigit(input[i]))
- {
- text += input[i++];
- }
- }
- try
- {
- value = std::stod(text);
- }
- catch (...)
- {
- std::cerr << "Fail to convert: " << text << std::endl;
- }
- return true;
- }
- // -- Scan the coordinate -----------------------------------------------------
- bool scanCoordinate(const std::string &input, const std::string &positives, const std::string &negatives, double °rees)
- {
- bool negative = false;
- bool withSign = false;
- std::size_t i = 0;
- const
- std::size_t length = input.length();
- degrees = 0.0;
- skipSpaces(input, i);
- if (i < length && isChars(input[i], positives))
- {
- i++;
- withSign = true;
- skipSpaces(input, i);
- }
- else if (i < length && isChars(input[i], negatives))
- {
- i++;
- negative = true;
- withSign = true;
- skipSpaces(input, i);
- }
- else if (i < length && input[i] == '-')
- {
- i++;
- negative = true;
- withSign = true;
- }
- double value = 0.0;
- bool withPoint = false;
- if (!scanValue(input, i, value, withPoint)) return false;
- degrees = value;
- skipSpaces(input, i);
- if (!withPoint && scanValue(input, i, value, withPoint))
- {
- degrees += (value / 60.0);
- }
- skipSpaces(input, i);
- if (!withPoint && scanValue(input, i, value, withPoint))
- {
- degrees += (value / 3600.0);
- }
- skipSpaces(input, i);
- if (!withSign && i < length)
- {
- if (isChars(input[i], positives))
- {
- i++;
- }
- else if (isChars(input[i], negatives))
- {
- i++;
- negative = true;
- }
- }
- skipSpaces(input, i);
- if (i < length)
- {
- if (input[i] != ',' && input[i] != ';') return false;
- i++;
- }
- if (negative) degrees = -degrees;
- return true;
- }
- // -- Output ------------------------------------------------------------------
- void output(double latitude, double longitude, const std::string &browser)
- {
- std::cout << "Results:" << std::endl;
- std::cout << std::setprecision(8) << std::fixed;
- std::cout << " " << latitude << ", " << longitude << std::endl;
- std::string ns = (latitude >= 0 ? "N" : "S");
- std::string ew = (longitude >= 0 ? "E" : "W");
- double degLat, degLon;
- double minLat, minLon;
- minLat = std::modf(std::abs(latitude), °Lat) * 60.0;
- minLon = std::modf(std::abs(longitude), °Lon) * 60.0;
- std::cout << std::setprecision(6) << std::fixed;
- std::cout << " " << ns << " " << int(degLat) << " " << minLat << ", " << ew << " " << int(degLon) << " " << minLon << std::endl;
- double secLat, secLon;
- secLat = std::modf(minLat, &minLat) * 60.0;
- secLon = std::modf(minLon, &minLon) * 60.0;
- std::cout << std::setprecision(4) << std::fixed;
- std::cout << " " << ns << " " << int(degLat) << " " << int(minLat) << " " << secLat << ", " << ew << " " << int(degLon) << " " << int(minLon) << " " << secLon << std::endl;
- if (!browser.empty())
- {
- std::stringstream cmd;
- cmd << std::fixed;
- cmd << browser
- << " \"http://www.openstreetmap.org/?mlat=" << std::setprecision(6) << latitude
- << "&mlon=" << longitude
- << "#map=16/" << std::setprecision(4) << latitude << "/" << longitude << "\"";
- system(cmd.str().c_str());
- }
- }
- // -- Process the input -------------------------------------------------------
- bool process(const std::string &lat, const std::string &lon, const std::string &browser)
- {
- double latitude = 0.0;
- double longitude = 0.0;
- if (!scanCoordinate(lat, "Nn", "Ss", latitude)) return false;
- if (!scanCoordinate(lon, "Ee", "Ww", longitude)) return false;
- if (latitude < -90.0 || latitude > 90.0) return false;
- if (longitude < -180.0 || longitude > 180.0) return false;
- output(latitude, longitude, browser);
- return true;
- }
- // -- Help text ---------------------------------------------------------------
- const std::string HELP =
- "Show all formats for gps coordinates and optional the location in the browser.\n\n"
- "Examples for gps coordinate formats:\n"
- " 51.90540, 4.46660\n"
- " -51.90540, -4.46660\n"
- " N 51 54.324, E 4 27.996\n"
- " 51 54.324 S, 4 27.996 W\n"
- " N 51 54 19.4, E 4 27 59.8\n"
- " 51 54 19.4 S, 4 27 59.8 W";
- // -- Main program ------------------------------------------------------------
- int main(int argc, char *argv[])
- {
- arg::Arguments arguments("gpxcoord [OPTION].. [\"LAT\" \"LON\"]..\nDisplay the LAT LOT gps coordinate in different formats.\n", "gpxcoord v0.1", HELP);
- arg::Argument browser (arguments, true, 'b', "browser", "BROWSER", "set the browser", "");
- std::vector<std::string> coordinates;
- if (arguments.parse(argc, argv, coordinates))
- {
- if (coordinates.empty())
- {
- std::cerr << "Nothing to do ..." << std::endl;
- }
- else if (coordinates.size() % 2 == 1)
- {
- std::cerr << "Missing latitude or longitude coordinate." << std::endl;
- }
- else
- {
- for (std::size_t i = 0; (i + 1) < coordinates.size(); i += 2)
- {
- process(coordinates[i], coordinates[i+1], browser.value());
- }
- }
- }
- return 0;
- }
|