#include <xsimple.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <math.h>
#include <geolib/cproj.h>
#include "mapview.h"
#include "wdbii.h"
static POINT *pts;
static int npts = 0;
static int penup = TRUE;
static WDBMAP *map;
static WDBMAPREC *recs, *prevrec;
void drawwdbii(WDBMAP *map)
{
static XPoint p[MAXPOINTS];
WDBMAPREC *rec;
int np;
setlinewidth(map->width);
for (rec = map->recs; rec; rec = rec->next) {
int i;
np = 0;
for (i = 0; i < rec->npts; i++) {
if (rec->pts[i].lat < minlat || rec->pts[i].lat > maxlat ||
rec->pts[i].lon < minlon || rec->pts[i].lon > maxlon) {
if (np) {
if (np > 1)
poly(p, np, map->color);
else
pset(p[0].x, p[0].y, map->color);
}
np = 0;
continue;
}
ll2xy(rec->pts[i].lon, rec->pts[i].lat, &(p[np].x), &(p[np].y));
np++;
}
if (np) {
if (np > 1)
poly(p, np, map->color);
else
pset(p[0].x, p[0].y, map->color);
}
}
}
static void addrec(SEGDICT *sd)
{
WDBMAPREC *rec = (WDBMAPREC *)malloc(sizeof(WDBMAPREC));
rec->rank = (char)sd->rank;
rec->pts = (POINT *)malloc(npts * sizeof(POINT));
rec->npts = npts;
rec->minlat = sd->minlat / 3600.;
rec->maxlat = sd->maxlat / 3600.;
rec->minlon = sd->minlon / 3600.;
rec->maxlon = sd->maxlon / 3600.;
rec->next = NULL;
memcpy(rec->pts, pts, npts * sizeof(POINT));
if (! recs)
recs = rec;
if (prevrec)
prevrec->next = rec;
prevrec = rec;
}
static void pendn(double lon, double lat, SEGDICT *sd)
{
static SEGDICT *prevsd;
if (lat < iminlat || lat > imaxlat || lon < iminlon || lon > imaxlon) {
if (npts)
addrec(prevsd);
npts = 0;
return;
}
if (penup) {
if (npts)
addrec(prevsd);
npts = 0;
penup = FALSE;
}
pts[npts].lat = lat; pts[npts].lon = lon;
if (++npts == MAXPOINTS) {
addrec(sd);
npts = 0;
}
prevsd = sd;
}
WDBMAP *loadwdbii(char *fname, unsigned long color, unsigned long fillcolor,
int width)
{
int fd, segcount, idx, idy, segbufsize, olt, oln, k, stroke, iseg;
char *databuf;
BIT32 i32;
BIT16 *segbuf;
double lastlon = 0.;
double lon, lat;
struct stat st;
int pos;
CBDHEAD *header;
SEGDICT *sd, *sdbuf;
SEGBUF sb;
recs = prevrec = NULL;
if ((fd = open(fname, O_RDONLY)) < 0) {
perror("open");
exit(1);
}
if (fstat(fd, &st) < 0) {
perror("fstat");
exit(1);
}
pts = (POINT *)malloc(MAXPOINTS * sizeof(POINT));
databuf = (char*)malloc(st.st_size);
read(fd, databuf, st.st_size);
close(fd);
/*
* Check the file header for the correct magic number,
* and learn the address of the segment dictionary
*/
header = (CBDHEAD *)databuf;
if (header->magic != CBD_MAGIC) {
fprintf(stderr, "File has bad magic number %X != %X\n",
header->magic, CBD_MAGIC);
exit(1);
}
/* allocate space for the segment buffer */
segbufsize = 2 * header->segmax;
segbuf = (BIT16 *) malloc (50 + segbufsize);
/* allocate space for the segment dictionary */
sdbuf = (SEGDICT *) malloc (100 + (header->segsize));
sd = sdbuf;
sd++;
/* Get the segment dictionary (it's at the end of the file) */
memcpy(sd, databuf + header->dictaddr, header->segsize);
/*
* Now look at each segment and decide if we're
* going to keep it or not
*/
segcount = header->segcount;
npts = 0;
sd = sdbuf;
for (iseg = 1; iseg <= segcount; iseg++) {
sd++; /* does this really work? wow! */
pos = sd->absaddr;
memcpy(&sb, databuf + pos, sizeof(sb));
pos += sizeof(sb);
if (sd->nbytes > segbufsize) {
fprintf(stderr,
"Segment %d needs %d bytes; buffer limit is %d.\n",
iseg, sd->nbytes, segbufsize);
exit(1);
}
memcpy(segbuf, databuf + pos, sd->nbytes);
k = 0;
oln = sb.orgx;
olt = sb.orgy;
lon = oln / 3600.;
lat = olt / 3600.;
penup = TRUE;
pendn(lon, lat, sd);
lastlon = lon;
for (stroke = 1; stroke <= sb.nstrokes; stroke++) {
if (segbuf[k] & SHORTFLAG) {
/* Flag bit on: unpack a 16-bit field into dx and dy */
i32 = segbuf[k++];
if (i32 > 0)
i32 &= ~SHORTFLAG;
idy = i32 & 0xFF;
if (idy & 0x80)
idy |= ~0xFF; /* extend sign */
idx = i32 >> 8;
if (idx & 0x80)
idx |= ~0xBF; /* extend sign */
} else {
/* Flag bit off: take dx and dy from 32-bit fields. */
idx = segbuf[k++];
if (idx < 0)
idx |= SHORTFLAG;
idx = (idx << 16) | (unsigned short) segbuf[k];
k++;
idy = segbuf[k];
k++;
if (idy < 0)
idy |= SHORTFLAG;
idy = (idy << 16) | segbuf[k];
k++;
}
oln = (oln + idx);
olt = (olt + idy);
lon = oln / 3600.;
lat = olt / 3600.;
if (fabs(lastlon - lon) > 180.)
penup = TRUE;
pendn(lon, lat, sd);
lastlon = lon;
}
}
if (npts)
addrec(sd);
free(sdbuf);
free(segbuf);
free(databuf);
free(pts);
map = (WDBMAP *)malloc(sizeof(WDBMAP));
map->type = WDBII;
map->color = color;
map->fillcolor = fillcolor;
map->width = width;
map->recs = recs;
map->next = NULL;
return map;
}