/*
Perform various operations on waypoints.
Copyright (C) 2002-2007 Robert Lipe, robertlipe@usa.net
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
*/
#include <stdio.h>
#include "defs.h"
#include "cet_util.h"
#include "grtcirc.h"
queue waypt_head;
static unsigned int waypt_ct;
static short_handle mkshort_handle;
void
waypt_init(void)
{
mkshort_handle = mkshort_new_handle();
QUEUE_INIT(&waypt_head);
}
waypoint *
waypt_dupe(const waypoint *wpt)
{
/*
* This and waypt_free should be closely synced.
*/
waypoint * tmp;
url_link *url_next;
tmp = waypt_new();
memcpy(tmp, wpt, sizeof(waypoint));
tmp->url_next = NULL;
if (wpt->shortname)
tmp->shortname = xstrdup(wpt->shortname);
if (wpt->description)
tmp->description = xstrdup(wpt->description);
if (wpt->notes)
tmp->notes = xstrdup(wpt->notes);
if (wpt->url)
tmp->url = xstrdup(wpt->url);
if (wpt->url_link_text)
tmp->url_link_text = xstrdup(wpt->url_link_text);
for (url_next = wpt->url_next; url_next; url_next = url_next->url_next) {
waypt_add_url(tmp,
(url_next->url) ? xstrdup(url_next->url) : NULL,
(url_next->url_link_text) ? xstrdup(url_next->url_link_text) : NULL);
}
if (wpt->icon_descr && wpt->wpt_flags.icon_descr_is_dynamic)
tmp->icon_descr = xstrdup(wpt->icon_descr);
if (wpt->gc_data.desc_short.utfstring) {
tmp->gc_data.desc_short.utfstring =
xstrdup(wpt->gc_data.desc_short.utfstring);
}
if (wpt->gc_data.desc_long.utfstring) {
tmp->gc_data.desc_long.utfstring =
xstrdup(wpt->gc_data.desc_long.utfstring);
}
if (wpt->gc_data.placer) {
tmp->gc_data.placer = xstrdup(wpt->gc_data.placer);
}
if (wpt->gc_data.hint) {
tmp->gc_data.hint = xstrdup(wpt->gc_data.hint);
}
/*
* It's important that this duplicated waypoint not appear
* on the master Q.
*/
QUEUE_INIT(&tmp->Q);
tmp->fs = fs_chain_copy( wpt->fs );
return tmp;
}
void
waypt_add(waypoint *wpt)
{
double lat_orig = wpt->latitude;
double lon_orig = wpt->longitude;
ENQUEUE_TAIL(&waypt_head, &wpt->Q);
waypt_ct++;
if (wpt->latitude < -90) wpt->latitude += 180;
else if (wpt->latitude > +90) wpt->latitude -= 180;
if (wpt->longitude < -180) wpt->longitude += 360;
else if (wpt->longitude > +180) wpt->longitude -= 360;
if ((wpt->latitude < -90) || (wpt->latitude > 90.0))
fatal ("Invalid latitude %f in waypoint %s.\n",
lat_orig, wpt->shortname ? wpt->shortname : "");
if ((wpt->longitude < -180) || (wpt->longitude > 180.0))
fatal ("Invalid longitude %f in waypoint %s.\n",
lon_orig, wpt->shortname ? wpt->shortname : "");
/*
* Some input may not have one or more of these types so we
* try to be sure that we have these fields even if just by
* copying them from elsewhere.
*/
if (wpt->shortname == NULL) {
if (wpt->description) {
wpt->shortname = xstrdup(wpt->description);
} else if (wpt->notes) {
wpt->shortname = xstrdup(wpt->notes);
} else {
/* Last ditch: make up a name */
char cbuf[10];
snprintf(cbuf, sizeof(cbuf), "WPT%03d", waypt_ct);
wpt->shortname = xstrdup(cbuf);
}
}
if (wpt->description == NULL || strlen(wpt->description) == 0) {
if (wpt->description)
xfree(wpt->description);
if (wpt->notes != NULL) {
wpt->description = xstrdup(wpt->notes);
} else {
if (wpt->shortname != NULL) {
wpt->description = xstrdup(wpt->shortname);
}
}
}
}
void
waypt_del(waypoint *wpt)
{
dequeue(&wpt->Q);
waypt_ct--;
}
/*
* A constructor for a single waypoint.
*/
waypoint *
waypt_new(void)
{
waypoint *wpt;
wpt = (waypoint *) xcalloc(sizeof (*wpt), 1);
wpt->altitude = unknown_alt;
wpt->fix = fix_unknown;
wpt->sat = -1;
QUEUE_INIT(&wpt->Q);
return wpt;
}
unsigned int
waypt_count(void)
{
return waypt_ct;
}
void
set_waypt_count(unsigned int nc)
{
waypt_ct = nc;
}
void
waypt_disp(const waypoint *wpt)
{
char *tmpdesc = NULL;
if (wpt->creation_time) {
printf("%s ", ctime(&wpt->creation_time));
}
printposn(wpt->latitude,1);
printposn(wpt->longitude,0);
if ( wpt->description ) {
tmpdesc = xstrdup( wpt->description);
printf("%s/%s",
global_opts.synthesize_shortnames ?
mkshort(mkshort_handle, tmpdesc) :
wpt->shortname,
tmpdesc);
if ( tmpdesc )
xfree(tmpdesc);
}
if (wpt->altitude != unknown_alt)
printf(" %f", wpt->altitude);
printf("\n");
}
void
waypt_status_disp(int total_ct, int myct)
{
fprintf(stdout, "%d/%d/%d\r", myct*100/total_ct, myct, total_ct);
fflush(stdout);
}
void
waypt_disp_all(waypt_cb cb)
{
queue *elem, *tmp;
waypoint *waypointp;
int i = 0;
QUEUE_FOR_EACH(&waypt_head, elem, tmp) {
waypointp = (waypoint *) elem;
if (global_opts.verbose_status) {
i++;
waypt_status_disp(waypt_ct, i);
}
(*cb) (waypointp);
}
if (global_opts.verbose_status) {
fprintf(stdout, "\r\n");
}
}
void
waypt_init_bounds(bounds *bounds)
{
/* Set data out of bounds so that even one waypoint will reset */
bounds->max_lat = -9999;
bounds->max_lon = -9999;
bounds->min_lat = 9999;
bounds->min_lon = 9999;
bounds->max_alt = -unknown_alt;
bounds->min_alt = unknown_alt;
}
int
waypt_bounds_valid(bounds *bounds)
{
/* Returns true if bb has any 'real' data in it */
return bounds->max_lat > -9999;
}
/*
* Recompund bounding box based on new position point.
*/
void
waypt_add_to_bounds(bounds *bounds, const waypoint *waypointp)
{
if (waypointp->latitude > bounds->max_lat)
bounds->max_lat = waypointp->latitude;
if (waypointp->longitude > bounds->max_lon)
bounds->max_lon = waypointp->longitude;
if (waypointp->latitude < bounds->min_lat)
bounds->min_lat = waypointp->latitude;
if (waypointp->longitude < bounds->min_lon)
bounds->min_lon = waypointp->longitude;
if (waypointp->altitude != unknown_alt) {
if (waypointp->altitude < bounds->min_alt)
bounds->min_alt = waypointp->altitude;
if (waypointp->altitude > bounds->max_alt)
bounds->max_alt = waypointp->altitude;
}
}
/*
* Makes another pass over the data to compute bounding
* box data and populates bounding box information.
*/
void
waypt_compute_bounds(bounds *bounds)
{
queue *elem, *tmp;
waypoint *waypointp;
waypt_init_bounds(bounds);
QUEUE_FOR_EACH(&waypt_head, elem, tmp) {
waypointp = (waypoint *) elem;
waypt_add_to_bounds(bounds, waypointp);
}
}
waypoint *
find_waypt_by_name(const char *name)
{
queue *elem, *tmp;
waypoint *waypointp;
QUEUE_FOR_EACH(&waypt_head, elem, tmp) {
waypointp = (waypoint *) elem;
if (0 == strcmp(waypointp->shortname, name)) {
return waypointp;
}
}
return NULL;
}
void
waypt_free( waypoint *wpt )
{
/*
* This and waypt_dupe should be closely synced.
*/
if (wpt->shortname) {
xfree(wpt->shortname);
}
if (wpt->description) {
xfree(wpt->description);
}
if (wpt->notes) {
xfree(wpt->notes);
}
if (wpt->url) {
xfree(wpt->url);
}
if (wpt->url_link_text) {
xfree(wpt->url_link_text);
}
if (wpt->url_next) {
url_link *url_next;
for (url_next = wpt->url_next; url_next; ) {
url_link *tonuke = url_next;
if (tonuke->url) {
xfree(tonuke->url);
}
if (tonuke->url_link_text) {
xfree(tonuke->url_link_text);
}
url_next = tonuke->url_next;
xfree(tonuke);
}
}
if (wpt->icon_descr && wpt->wpt_flags.icon_descr_is_dynamic) {
xfree((char *)(void *)wpt->icon_descr);
}
if (wpt->gc_data.desc_short.utfstring) {
xfree(wpt->gc_data.desc_short.utfstring);
}
if (wpt->gc_data.desc_long.utfstring) {
xfree(wpt->gc_data.desc_long.utfstring);
}
if (wpt->gc_data.placer) {
xfree(wpt->gc_data.placer);
}
if (wpt->gc_data.hint) {
xfree (wpt->gc_data.hint);
}
fs_chain_destroy( wpt->fs );
xfree(wpt);
}
void
waypt_flush( queue *head )
{
queue *elem, *tmp;
QUEUE_FOR_EACH(head, elem, tmp) {
waypoint *q = (waypoint *) dequeue(elem);
waypt_free(q);
if (head == &waypt_head) {
waypt_ct--;
}
}
}
void
waypt_flush_all()
{
if ( mkshort_handle ) {
mkshort_del_handle( &mkshort_handle );
}
waypt_flush(&waypt_head);
}
void
waypt_backup(signed int *count, queue **head_bak)
{
queue *elem, *tmp, *qbackup;
waypoint *wpt;
int no = 0;
qbackup = (queue *) xcalloc(1, sizeof(*qbackup));
QUEUE_INIT(qbackup);
QUEUE_MOVE(qbackup, &waypt_head);
QUEUE_INIT(&waypt_head);
waypt_ct = 0;
QUEUE_FOR_EACH(qbackup, elem, tmp)
{
wpt = (waypoint *)elem;
waypt_add(waypt_dupe(wpt));
no++;
}
*head_bak = qbackup;
*count = no;
}
void
waypt_restore(signed int count, queue *head_bak)
{
if (head_bak == NULL) return;
waypt_flush(&waypt_head);
QUEUE_INIT(&waypt_head);
QUEUE_MOVE(&waypt_head, head_bak);
waypt_ct = count;
xfree(head_bak);
}
void
waypt_add_url(waypoint *wpt, char *link, char *url_link_text)
{
if ((link == NULL) && (url_link_text == NULL)) return;
/* Special case first one; it goes right into the waypoint. */
if ((wpt->url == NULL) && (wpt->url_link_text == NULL)) {
wpt->url = link;
wpt->url_link_text = url_link_text;
} else {
url_link *tail;
url_link *new_link = xcalloc(sizeof(url_link), 1);
new_link->url = link;
new_link->url_link_text = url_link_text;
/* Find current end of chain and tack this onto the end.. */
for (tail = wpt->url_next;;tail = tail->url_next) {
if (tail == NULL) {
wpt->url_next = new_link;
break;
}
if (tail->url_next == NULL) {
tail->url_next = new_link;
break;
}
}
}
}
/*
* returns full creation_time with parts of seconds in fractional portion
*/
double
waypt_time(const waypoint *wpt)
{
if (wpt->creation_time <= 0)
return (double) 0;
else
return ((double)wpt->creation_time + ((double)wpt->microseconds / 1000000));
}
/*
* calculates the speed between points "A" and "B"
* the result comes in meters per second and is always positive
*/
double
waypt_speed(const waypoint *A, const waypoint *B)
{
double dist, time;
dist = radtometers(gcdist(
RAD(A->latitude), RAD(A->longitude),
RAD(B->latitude), RAD(B->longitude)));
if (dist < 0.1) dist = 0; /* calc. diffs on 32- and 64-bit hosts */
if (dist == 0) return 0;
time = fabs(waypt_time(A) - waypt_time(B));
if (time > 0)
return (dist / time);
else
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1