Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <stdio.h>
#include "map.h"
#include "iplot.h"

#define NSYMBOL 20

enum flag { POINT,ENDSEG,ENDSYM };
struct symb {
        double x, y;
        char name[10+1];
        enum flag flag;
} *symbol[NSYMBOL];

static int nsymbol;
static double halfrange = 1;
extern int halfwidth;
extern int vflag;

static int      getrange(FILE *);
static int      getsymbol(FILE *, int);
static void     setrot(struct place *, double, int);
static void     dorot(struct symb *, double *, double *);


void
getsyms(char *file)
{
        FILE *sf = fopen(file,"r");
        if(sf==0)
                filerror("cannot open", file);
        while(nsymbol<NSYMBOL-1 && getsymbol(sf,nsymbol))
                nsymbol++;
        fclose(sf);
}

static int
getsymbol(FILE *sf, int n)
{
        double x,y;
        char s[2];
        int i;
        struct symb *sp;
        for(;;) {
                if(fscanf(sf,"%1s",s)==EOF)
                        return 0;
                switch(s[0]) {
                case ':':
                        break;
                case 'o':
                case 'c':       /* cl */
                        fscanf(sf,"%*[^\n]");
                        continue;
                case 'r':
                        if(getrange(sf))
                                continue;
                default:
                        error("-y file syntax error");
                }
                break;
        }
        sp = (struct symb*)malloc(sizeof(struct symb));
        symbol[n] = sp;
        if(fscanf(sf,"%10s",sp->name)!=1)
                return 0;
        i = 0;
        while(fscanf(sf,"%1s",s)!=EOF) {
                switch(s[0]) {
                case 'r':
                        if(!getrange(sf))
                                break;
                        continue;
                case 'm':
                        if(i>0)
                                symbol[n][i-1].flag = ENDSEG;
                        continue;
                case ':':
                        ungetc(s[0],sf);
                        break;
                default:
                        ungetc(s[0],sf);
                case 'v':
                        if(fscanf(sf,"%lf %lf",&x,&y)!=2)
                                break;
                        sp[i].x = x*halfwidth/halfrange;
                        sp[i].y = y*halfwidth/halfrange;
                        sp[i].flag = POINT;
                        i++;
                        sp = symbol[n] = (struct symb*)realloc(symbol[n],
                                        (i+1)*sizeof(struct symb));
                        continue;
                }
                break;
        }
        if(i>0)
                symbol[n][i-1].flag = ENDSYM;
        else
                symbol[n] = 0;
        return 1;
}

static int
getrange(FILE *sf)
{
        double x,y,xmin,ymin;
        if(fscanf(sf,"%*s %lf %lf %lf %lf",
                &xmin,&ymin,&x,&y)!=4)
                return 0;
        x -= xmin;
        y -= ymin;
        halfrange = (x>y? x: y)/2;
        if(halfrange<=0)
                error("bad ra command in -y file");
        return 1;
}

/* r=0 upright;=1 normal;=-1 reverse*/
int
putsym(struct place *p, char *name, double s, int r)
{
        int x,y,n;
        struct symb *sp;
        double dx,dy;
        int conn = 0;
        for(n=0; symbol[n]; n++)
                if(strcmp(name,symbol[n]->name)==0)
                        break;
        sp = symbol[n];
        if(sp==0)
                return 0;
        if(doproj(p,&x,&y)*vflag <= 0)
                return 1;
        setrot(p,s,r);
        for(;;) {
                dorot(sp,&dx,&dy);
                conn = cpoint(x+(int)dx,y+(int)dy,conn);
                switch(sp->flag) {
                case ENDSEG:
                        conn = 0;
                case POINT:
                        sp++;
                        continue;
                case ENDSYM:
                        break;
                }
                break;
        }
        return 1;
}

static double rot[2][2];

static void
setrot(struct place *p, double s, int r)
{
        double x0,y0,x1,y1;
        struct place up;
        up = *p;
        up.nlat.l += .5*RAD;
        sincos(&up.nlat);
        if(r&&(*projection)(p,&x0,&y0)) {
                if((*projection)(&up,&x1,&y1)<=0) {
                        up.nlat.l -= RAD;
                        sincos(&up.nlat);
                        if((*projection)(&up,&x1,&y1)<=0)
                                goto unit;
                        x1 = x0 - x1;
                        y1 = y0 - y1;
                } else {
                        x1 -= x0;
                        y1 -= y0;
                }
                x1 = r*x1;
                s /= hypot(x1,y1);
                rot[0][0] = y1*s;
                rot[0][1] = x1*s;
                rot[1][0] = -x1*s;
                rot[1][1] = y1*s;
        } else {
unit:
                rot[0][0] = rot[1][1] = s;
                rot[0][1] = rot[1][0] = 0;
        }
}

static void
dorot(struct symb *sp, double *px, double *py)
{
        *px = rot[0][0]*sp->x + rot[0][1]*sp->y;
        *py = rot[1][0]*sp->x + rot[1][1]*sp->y;
}