This repository has been archived by the owner on Jan 19, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgeom2d.c
209 lines (139 loc) · 5.04 KB
/
geom2d.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
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <assert.h>
#include <math.h>
#include "geom2d.h"
#define DOUBLE_EPSILON 0.0000001
bool egaux_doubles(double d1, double d2) {
return fabs(d1 - d2) < DOUBLE_EPSILON;
}
// Points
Point set_point(double x, double y) {
return (Point) { x, y };
}
Point add_point(Point p1, Point p2) {
return set_point(p1.x + p2.x, p1.y + p2.y);
}
Point mul_reel_point(Point p, double a) {
return set_point(a * p.x, a * p.y);
}
double distance(Point p1, Point p2) {
return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
}
bool egaux_points(Point p1, Point p2) {
return egaux_doubles(p1.x, p2.x) && egaux_doubles(p1.y, p2.y);
}
// Vecteurs
Vecteur set_vecteur(double x, double y) {
return (Vecteur) { x, y };
}
Vecteur add_vecteur(Vecteur v1, Vecteur v2) {
return set_vecteur(v1.x + v2.x, v1.y + v2.y);
}
Vecteur mul_reel_vecteur(Vecteur v, double a) {
return set_vecteur(a * v.x, a * v.y);
}
Vecteur vect_bipoint(Point a, Point b) {
return set_vecteur(b.x - a.x, b.y - a.y);
}
double produit_scalaire(Vecteur v1, Vecteur v2) {
return (v1.x * v2.x) + (v1.y * v2.y);
}
double norme(Vecteur v) {
return sqrt(pow(v.x, 2) + pow(v.y, 2));
}
bool egaux_vecteurs(Vecteur v1, Vecteur v2) {
return egaux_doubles(v1.x, v2.x) && egaux_doubles(v1.y, v2.y);
}
// Distance point-segment
double distance_point_segment(Point a, Point b, Point p) {
if (egaux_points(a, b)) return distance(a, p);
Vecteur ab = vect_bipoint(a, b);
double lambda = produit_scalaire(vect_bipoint(a, p), ab) / produit_scalaire(ab, ab);
if (lambda < 0) {
return distance(a, p);
} else if (lambda > 1) {
return distance(b, p);
} else {
Point q = add_point(a, mul_reel_point(add_point(b, mul_reel_point(a, -1)), lambda));
return distance(q, p);
}
}
// Courbes de bezier
Point bezier2_C(Bezier2* self, double t) {
Point m0 = mul_reel_point(self->c0, pow(1 - t, 2));
Point m1 = mul_reel_point(self->c1, 2 * t * (1 - t));
Point m2 = mul_reel_point(self->c2, t * t);
return add_point(m0, add_point(m1, m2));
}
double distance_point_bezier2(Bezier2* self, Point p, double t) {
return distance(bezier2_C(self, t), p);
}
Point bezier3_C(Bezier3* self, double t) {
Point m0 = mul_reel_point(self->c0, pow(1 - t, 3));
Point m1 = mul_reel_point(self->c1, 3 * t * pow(1 - t, 2));
Point m2 = mul_reel_point(self->c2, 3 * t * t * (1 - t));
Point m3 = mul_reel_point(self->c3, t * t * t);
return add_point(m0, add_point(m1, add_point(m2, m3)));
}
double distance_point_bezier3(Bezier3* self, Point p, double t) {
return distance(bezier3_C(self, t), p);
}
Bezier3 bezier2_to_bezier3(Bezier2* self) {
return (Bezier3) {
self->c0,
mul_reel_point(add_point(self->c0, mul_reel_point(self->c1, 2)), 1./3.),
mul_reel_point(add_point(self->c2, mul_reel_point(self->c1, 2)), 1./3.),
self->c2,
};
}
Bezier2 approx_bezier2(Point *start, unsigned int len) {
assert(len > 1);
Bezier2 curve = {
.c0 = start[0],
};
if (len == 2) {
curve.c1 = mul_reel_point(add_point(start[0], start[1]), .5);
curve.c2 = start[1];
} else {
double n = len - 1;
Point sum = set_point(0, 0);
for (int i = 1; i < (len-1); i++) {
sum = add_point(sum, start[i]);
}
double alpha = (3. * n) / (n*n - 1.);
double beta = (1. - (2. * n)) / (2. * (n + 1.));
curve.c2 = start[len-1];
curve.c1 = add_point(mul_reel_point(sum, alpha), mul_reel_point(add_point(curve.c0, curve.c2), beta));
}
return curve;
}
double approx_bezier3_gamma(double k, double n) {
return (6. * pow(k, 4.)) - (8. * n * pow(k, 3.)) + (6. * k * k) - (4. * n * k) + pow(n, 4.) - (n * n);
}
Bezier3 approx_bezier3(Point* start, unsigned int len) {
assert(len > 1);
if (len <= 3) {
Bezier2 b2 = approx_bezier2(start, len);
return bezier2_to_bezier3(&b2);
} else {
Bezier3 curve = {
.c0 = start[0],
.c3 = start[len-1],
};
double n = len - 1;
Point sum1 = set_point(0, 0);
for (int i = 1; i < (len-1); i++) {
sum1 = add_point(sum1, mul_reel_point(start[i], approx_bezier3_gamma(i, n)));
}
Point sum2 = set_point(0, 0);
for (int i = 1; i < (len-1); i++) {
sum2 = add_point(sum2, mul_reel_point(start[i], approx_bezier3_gamma(n - (double) i, n)));
}
double d = 3. * (n + 2.) * (3. * n * n + 1.);
double alpha = ((-15. * n * n * n) + (5. * n * n) + (2. * n) + 4.) / d;
double beta = ((10. * n * n * n) - (15. * n * n) + n + 2.) / d;
double lambda = (70. * n) / (3. * (n * n - 1.) * (n * n - 4.) * (3. * n * n + 1.));
curve.c1 = add_point(mul_reel_point(curve.c0, alpha), add_point(mul_reel_point(sum1, lambda), mul_reel_point(curve.c3, beta)));
curve.c2 = add_point(mul_reel_point(curve.c0, beta), add_point(mul_reel_point(sum2, lambda), mul_reel_point(curve.c3, alpha)));
return curve;
}
}