File: quadtile.h

package info (click to toggle)
monav 0.3-8
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 8,116 kB
  • ctags: 6,239
  • sloc: cpp: 34,354; ansic: 4,103; java: 1,436; sh: 108; xml: 49; makefile: 44
file content (156 lines) | stat: -rw-r--r-- 4,442 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#ifndef QUADTILE_H
#define QUADTILE_H

typedef signed long long quadtile;

// Unseralize a quadtile from 8 bytes
quadtile buf2ll(const unsigned char *s)
{
    quadtile result=0;
    for(int i=0; i<8;i++)
        result = (result << 8LL) | s[i];
    return result;
}

// Unserialize an unsigned long from 4 bytes
unsigned long buf2l(const unsigned char *s)
{
    unsigned long result=0;
    for(int i=0; i<4;i++)
        result = (result << 8UL) | s[i];
    return result;
}

// Take two (<=4bytes) numbers, and alternate their binary digits.
quadtile mux(quadtile x, quadtile y)
{
    long long t=0;

    for(int i=0;i<32;i++) {
        t <<= 1;
        if(x & (1ULL<<31)) t |= 1;
        t <<= 1;
        if(y & (1ULL<<31)) t |= 1;
        x <<= 1; y <<= 1;
    }
    return t;
}

void demux(quadtile tile, quadtile *x, quadtile *y)
{
    *x = 0; *y = 0;
    for(int i=0;i<31;i++) {
    //binary_printf(tile); binary_printf(*x); binary_printf(*y);printf("\n");
        (*y) <<= 1; (*x) <<= 1;
        if(tile & (1ULL<<61)) (*x)|=1;
        tile <<= 1;
        if(tile & (1ULL<<61)) (*y)|=1;
        tile <<= 1;
    }
    //binary_printf(tile); binary_printf(*x); binary_printf(*y);printf("\n");
}

/* Store a pair of doubles in the range (0.0->1.0) as integers with alternating
   binary bits */
quadtile xy2q(double fx, double fy)
{
    return mux((long long) (fx * (1ULL<<31)), (long long) (fy * (1ULL<<31)));
}

#ifdef NEED_QTILE_WRITE
// Below here is only needed in the preprocessor.
#include <math.h>
/* latlon to projected x/y coords */
void ll2pxy(double lat, double lon, unsigned long *x, unsigned long *y)
{
    double fx,fy;
    fx = (lon+180.0) / 360.0;
    fy = (1.0 - log(tan(lat*M_PI/180.0) +
          (1.0/cos(lat*M_PI/180.0)))/M_PI)/2.0;

    *x = (unsigned long) (fx * (1UL<<31));
    *y = (unsigned long) (fy * (1UL<<31));
}

/* Serialise a quadtile to 4 unsigned char bytes, MSB first */
unsigned char *ll2buf(quadtile q)
{
    static unsigned char result[8];
    for(int i=0; i<8;i++) {
        result[7-i] = q & 255;
        q >>= 8;
    }
    return result;
}

unsigned char *l2buf(unsigned long l)
{
    static unsigned char result[4];
    for(int i=0; i<4;i++) {
        result[3-i] = l & 255;
        l >>= 8;
    }
    return result;
}

/* Horrible name! Assume a line drawn between q1 and q2.
    if (q1 & qmask) != (q2 & qmask) then return the quadtile q corresponding
    to the first point along the line q1->q2 where (q & qmask != q1 & qmask) */
quadtile line_edge_intersect(quadtile q1, quadtile q2, quadtile qmask)
{
    quadtile qmin, qmax, xmin, xmax, ymin, ymax, x1, y1, x2, y2;
    if((q1 & qmask) == (q2 & qmask)) {
        printf("Error - q1 and q2 are in the same qtile\n");
        exit(-1);
    }

    //Get the bounds of q1's quadtile.
    qmin = q1 & qmask;
    qmax = q1 | (~qmask);
    demux(qmin, &xmin, &ymin);
    demux(qmax, &xmax, &ymax);

    demux(q1, &x1, &y1);
    demux(q2, &x2, &y2);

    //y = ax + b       x = (y-b)/a
    //First a special case for x1==x2 (a==infinity. Doesn't work.)
    if(x1==x2) {
        if(y2>y1) return mux(x1, ymax+1);
        else return mux(x1, ymin-1);
    }

    double a = ((double)(y2-y1)) / ((double)(x2-x1));
    double b = y1 - a *x1;

    //Find where the line crosses the bounds of this quadtile.
    //FIXME this will fail at the international date line - do roads cross this?
    if(x2 > x1) {
        quadtile y = roundl(a*(xmax) + b);
        if(y>=ymin && y<=ymax) return mux(xmax+1, roundl(a*(xmax+1) + b));
    } else {
        quadtile y = roundl(a*(xmin) + b);
        if(y>=ymin && y<=ymax) return mux(xmin-1, roundl(a*(xmin-1) + b));
    }
    if(y2 > y1) {
        quadtile x = roundl((ymax-b)/a);
        if(x>=xmin && x<=xmax) return mux(roundl((ymax+1-b)/a), ymax+1);
    } else {
        quadtile x = roundl((ymin-b)/a);
        if(x>=xmin && x<=xmax) return mux(roundl((ymin-b-1)/a), ymin-1);
    }

    printf("Error - shouldn't get here in intersect calcs\n");
    //Debugging output.
    printf("q1=%llx q2=%llx qmask=%llx\na=%f, b=%f\n1=%lld,%lld 2=%lld,%lld\n",
            q1, q2, qmask, a, b, x1, y1, x2, y2);
    printf("xmin = %lld xmax = %lld, ymin = %lld, ymax=%lld\n",
            xmin, xmax, ymin, ymax);
    printf("Maxy = %f, Miny=%f\n", a*(xmax+1)+b, a*(ymin-1)+b);
    printf("Maxx = %f, Minx=%f\n", (ymax+1-b)/a, (ymin-1-b)/a);
    exit(-1);
    return 0;
}
#endif /*NEED_QTILE_WRITE*/

#endif /*QUADTILE_H*/