-
Notifications
You must be signed in to change notification settings - Fork 0
/
walker.c
109 lines (88 loc) · 2.93 KB
/
walker.c
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
#include <math.h>
typedef double angle;
typedef double real;
typedef struct {
real x;
real y;
} point;
typedef real (*landscape)(point);
// the walker struct may as well be private (in this file only, invisible
// outside)
typedef struct {
const point start;
const real height; // walkers try to keep a constant height
const real stride;
const angle delta;
point posn;
angle dirn;
real tot_area;
} walker;
walker walker_construct(landscape H, point start, real stride, real delta) {
walker iter = {
.start = start,
.height = H(start),
.stride = stride,
.delta = delta,
.posn = start,
.dirn = 0,
.tot_area = 0
};
return iter;
}
void revolve(point *edge, point *centre, real step, angle theta) {
// rotate the point "edge" around "centre"
edge->x = centre->x + step * cos(theta);
edge->y = centre->y + step * sin(theta);
}
void walker_step(landscape H, walker* iter) {
// make a note of initial position and angle for the area measurements
point last = iter->posn;
angle theta0 = iter->dirn;
// first seek out a new position to step to
point next = iter->posn;
next.x += iter->stride * cos(iter->dirn);
next.y += iter->stride * sin(iter->dirn);
angle dq = iter->delta;
for(int i=0; i<1; i++) {
while(H(next) > iter->height) {
iter->dirn += dq;
revolve(&next, &last, iter->stride, iter->dirn);
}
dq *= 0.5;
while (H(next) < iter->height) {
iter->dirn -= dq;
revolve(&next, &last, iter->stride, iter->dirn);
}
dq *= 0.5;
}
// now update the area
iter->tot_area += 0.5 * (
+(last.x - iter->start.x) * (next.y - last.y)
-(last.y - iter->start.y) * (next.x - last.x));
// add a small correction for error in height?
iter->tot_area -= 0.5 * iter->delta * iter->stride * iter->stride;
// and a very small correction for path curvature
angle dtheta = iter->dirn - theta0; // curvature = dtheta / ds
iter->tot_area += dtheta * (iter->stride) * (iter->stride) / 6 ;
// finally, move to the next position
iter->posn = next;
}
real distance(point p, point q) {
return sqrt( (p.x - q.x) * (p.x - q.x)
+(p.y - q.y) * (p.y - q.y));
}
real area_inside(landscape H, point start, real ds, real dq) {
// a mountain goat tries to keep its feet level as it navigates a basin:
walker goat = walker_construct(H, start, ds, dq);
// take a couple of steps to get away from the start
while (distance(goat.posn, goat.start) < ds) {
walker_step(H, &goat);
}
// keep going until we loop back to the start
while (distance(goat.posn, goat.start) > ds) {
walker_step(H, &goat);
}
// we don't need to add the last little bit of area on because it is
// guaranteed to be zero.
return goat.tot_area;
}