#!/usr/bin/perl -w
# $Id: make_small-circle,v 1.5 2004-04-23 09:36:07-06 braup Exp braup $
# Copyright 2004 Bruce Raup  (http://cires.colorado.edu/~braup/)
# This software is distributed under the GNU General Public License.  See
# http://www.gnu.org/licenses/gpl.txt for the text of this license.
# In short:
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program 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 General Public License for more details.
#
($progname = $0)        =~ s!^.*/!!;  # get basename of program

use Getopt::Std;

$version = '$Revision: 1.5 $';
($version) = $version =~ /^\$Revision:\s*(\d+\.\d*)/;

$spacing = 100; # spacing between generated points on the circle, km
$deg_size = 111.195;        # number of km in a degree
$earth_radius = 6371;   # km

$usage = "$progname version $version

This program depends on, and is intended to be used with, GMT (Generic Mapping
Tools (http://gmt.soest.hawaii.edu/)).

This program prints a list of geographic coordinates lying on a (small or
great) circle centered on an input longitude/latitude, with a radius specified
either as an angle or a distance.  The points can then be plotted on a map
using GMT's psxy command.

Usage:
  $progname  -h            (prints this help message and exits)
OR
  $progname  [-v] -x pole_longitude -y pole_latitude [-s point_spacing]
                 [-a circle_size_degrees | -d circle_radius_km]
where
  -x    specifies the longitude of the pole (center of circle)
  -y    specifies the latitude of the pole (center of circle)
  -a    radius of circle as an angle, in degrees (90 for great circle)
  -d    radius of circle as distance, in km (1 degree = $deg_size km is assumed)
  -s    spacing of points on the circle (km) [$spacing]
  -v    specifies verbose mode

Output is printed to stdout.  Note that if an argument to an option is a
negative number, there should be no space between it and the option letter, or
else the negative number will be interpreted as another option.
";

$opt_h = $opt_v = $opt_x = $opt_y = $opt_a = $opt_d = $opt_s = '';   # to keep perl -w quiet
if (! getopts('hvx:y:a:d:s:') ) {
  die "$usage\n";
}

die "$usage\n" if $opt_h;

warn "$progname version $version\n" if $opt_v;

if ($opt_x eq '' || $opt_y eq '') {
  die "Must specify -x and -y.  Use \"$progname -h\" for help.\n";
}
if ($opt_a eq '' && $opt_d eq '') {
  die "Must specify -a or -d.  Use \"$progname -h\" for help.\n";
}

$plon = $opt_x;
$plat = $opt_y;
$circlon = $plon;
$spacing = $opt_s if $opt_s;
$angle = $opt_a if $opt_a;

if ($opt_a) {
  if ($opt_d) {
    die "Must specify -a or -d, not both.  Use \"$progname -h\" for help.\n";
  }
  if ($opt_a < 0 || $opt_a > 90) {
    die "circle_size_degrees needs to be between 0 and 90, inclusive\n";
  }
  $circlat = $plat < 0 ? $plat + $opt_a : $plat - $opt_a;
}

if ($opt_d) {
  if ($opt_a) {
    die "Must specify -a or -d, not both.  Use \"$progname -h\" for help.\n";
  }
  if ($opt_d < 0 || $opt_d > 11000) {
    die "circle_size_km needs to be between 0 and 11000, inclusive\n";
  }
  $angle = $opt_d / $deg_size;
  $circlat = $plat < 0 ? $plat + $angle : $plat - $angle;
}

# calculate perimeter of circle as 2 pi R sin(a)  (a in radians)
$perim = 6.28318530718 * $earth_radius * sin($angle*0.0174532925);

if ($opt_v) {
  warn "Pole longitude, latitude                = $plon, $plat\n";
  warn "Point on circle at zero longitude       = $circlon, $circlat\n";
}

system( "project -T$plon/$plat -C$circlon/$circlat -L0/$perim -G$spacing -Q" ) &&
   die "project had a problem:  $!";
