GeographicLib  1.21
Planimeter.cpp
Go to the documentation of this file.
00001 /**
00002  * \file Planimeter.cpp
00003  * \brief Command line utility for measuring the area of geodesic polygons
00004  *
00005  * Copyright (c) Charles Karney (2010-2012) <charles@karney.com> and licensed
00006  * under the MIT/X11 License.  For more information, see
00007  * http://geographiclib.sourceforge.net/
00008  *
00009  * Compile and link with
00010  *   g++ -g -O3 -I../include -I../man -o Planimeter \
00011  *       Planimeter.cpp \
00012  *       ../src/DMS.cpp \
00013  *       ../src/GeoCoords.cpp \
00014  *       ../src/Geodesic.cpp \
00015  *       ../src/GeodesicLine.cpp \
00016  *       ../src/MGRS.cpp \
00017  *       ../src/PolarStereographic.cpp \
00018  *       ../src/PolygonArea.cpp \
00019  *       ../src/TransverseMercator.cpp \
00020  *       ../src/UTMUPS.cpp
00021  *
00022  * See the <a href="Planimeter.1.html">man page</a> for usage
00023  * information.
00024  **********************************************************************/
00025 
00026 #include <iostream>
00027 #include <string>
00028 #include <sstream>
00029 #include <fstream>
00030 #include <GeographicLib/PolygonArea.hpp>
00031 #include <GeographicLib/DMS.hpp>
00032 #include <GeographicLib/Utility.hpp>
00033 #include <GeographicLib/GeoCoords.hpp>
00034 
00035 #include "Planimeter.usage"
00036 
00037 int main(int argc, char* argv[]) {
00038   try {
00039     using namespace GeographicLib;
00040     typedef Math::real real;
00041     real
00042       a = Constants::WGS84_a<real>(),
00043       f = Constants::WGS84_f<real>();
00044     bool reverse = false, sign = true, polyline = false;
00045     std::string istring, ifile, ofile, cdelim;
00046     char lsep = ';';
00047 
00048     for (int m = 1; m < argc; ++m) {
00049       std::string arg(argv[m]);
00050       if (arg == "-r")
00051         reverse = !reverse;
00052       else if (arg == "-s")
00053         sign = !sign;
00054       else if (arg == "-l")
00055         polyline = !polyline;
00056       else if (arg == "-e") {
00057         if (m + 2 >= argc) return usage(1, true);
00058         try {
00059           a = Utility::num<real>(std::string(argv[m + 1]));
00060           f = Utility::fract<real>(std::string(argv[m + 2]));
00061         }
00062         catch (const std::exception& e) {
00063           std::cerr << "Error decoding arguments of -e: " << e.what() << "\n";
00064           return 1;
00065         }
00066         m += 2;
00067       } else if (arg == "--input-string") {
00068         if (++m == argc) return usage(1, true);
00069         istring = argv[m];
00070       } else if (arg == "--input-file") {
00071         if (++m == argc) return usage(1, true);
00072         ifile = argv[m];
00073       } else if (arg == "--output-file") {
00074         if (++m == argc) return usage(1, true);
00075         ofile = argv[m];
00076       } else if (arg == "--line-separator") {
00077         if (++m == argc) return usage(1, true);
00078         if (std::string(argv[m]).size() != 1) {
00079           std::cerr << "Line separator must be a single character\n";
00080           return 1;
00081         }
00082         lsep = argv[m][0];
00083       } else if (arg == "--comment-delimiter") {
00084         if (++m == argc) return usage(1, true);
00085         cdelim = argv[m];
00086       } else if (arg == "--version") {
00087         std::cout
00088           << argv[0]
00089           << ": $Id: dbb8a9a0d79f172256044e72f65ebc667801eeac $\n"
00090           << "GeographicLib version " << GEOGRAPHICLIB_VERSION_STRING << "\n";
00091         return 0;
00092       } else
00093         return usage(!(arg == "-h" || arg == "--help"), arg != "--help");
00094     }
00095 
00096     if (!ifile.empty() && !istring.empty()) {
00097       std::cerr << "Cannot specify --input-string and --input-file together\n";
00098       return 1;
00099     }
00100     if (ifile == "-") ifile.clear();
00101     std::ifstream infile;
00102     std::istringstream instring;
00103     if (!ifile.empty()) {
00104       infile.open(ifile.c_str());
00105       if (!infile.is_open()) {
00106         std::cerr << "Cannot open " << ifile << " for reading\n";
00107         return 1;
00108       }
00109     } else if (!istring.empty()) {
00110       std::string::size_type m = 0;
00111       while (true) {
00112         m = istring.find(lsep, m);
00113         if (m == std::string::npos)
00114           break;
00115         istring[m] = '\n';
00116       }
00117       instring.str(istring);
00118     }
00119     std::istream* input = !ifile.empty() ? &infile :
00120       (!istring.empty() ? &instring : &std::cin);
00121 
00122     std::ofstream outfile;
00123     if (ofile == "-") ofile.clear();
00124     if (!ofile.empty()) {
00125       outfile.open(ofile.c_str());
00126       if (!outfile.is_open()) {
00127         std::cerr << "Cannot open " << ofile << " for writing\n";
00128         return 1;
00129       }
00130     }
00131     std::ostream* output = !ofile.empty() ? &outfile : &std::cout;
00132 
00133     const Geodesic geod(a, f);
00134     PolygonArea poly(geod, polyline);
00135     GeoCoords p;
00136 
00137     std::string s;
00138     real perimeter, area;
00139     unsigned num;
00140     std::string eol("\n");
00141     while (std::getline(*input, s)) {
00142       if (!cdelim.empty()) {
00143         std::string::size_type m = s.find(cdelim);
00144         if (m != std::string::npos) {
00145           eol = " " + s.substr(m) + "\n";
00146           s = s.substr(0, m);
00147         }
00148       }
00149       bool endpoly = s.empty();
00150       if (!endpoly) {
00151         try {
00152           p.Reset(s);
00153           if (Math::isnan(p.Latitude()) || Math::isnan(p.Longitude()))
00154             endpoly = true;
00155         }
00156         catch (const GeographicErr&) {
00157           endpoly = true;
00158         }
00159       }
00160       if (endpoly) {
00161         num = poly.Compute(reverse, sign, perimeter, area);
00162         if (num > 0) {
00163           *output << num << " "
00164                   << Utility::str<real>(perimeter, 8);
00165           if (!polyline)
00166             *output << " " << Utility::str<real>(area, 3);
00167           *output << eol;
00168         }
00169         poly.Clear();
00170         eol = "\n";
00171       } else
00172         poly.AddPoint(p.Latitude(), p.Longitude());
00173     }
00174     num = poly.Compute(reverse, sign, perimeter, area);
00175     if (num > 0) {
00176       *output << num << " "
00177               << Utility::str<real>(perimeter, 8);
00178       if (!polyline)
00179         *output << " " << Utility::str<real>(area, 3);
00180       *output << eol;
00181     }
00182     poly.Clear();
00183     eol = "\n";
00184     return 0;
00185   }
00186   catch (const std::exception& e) {
00187     std::cerr << "Caught exception: " << e.what() << "\n";
00188     return 1;
00189   }
00190   catch (...) {
00191     std::cerr << "Caught unknown exception\n";
00192     return 1;
00193   }
00194 }