Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/netgen/libsrc/csg/spline3d.cpp
3206 views
1
#include <mystdlib.h>
2
3
#include <myadt.hpp>
4
5
#include <linalg.hpp>
6
#include <csg.hpp>
7
8
9
namespace netgen
10
{
11
splinesegment3d :: splinesegment3d (const Point<3> & ap1, const Point<3> & ap2,
12
const Point<3> & ap3)
13
{
14
p1 = ap1;
15
p2 = ap2;
16
p3 = ap3;
17
}
18
19
20
/*
21
todo
22
Tip von Joerg Stiller:
23
setzt Du in
24
void splinesegment3d :: Evaluate
25
Zeilen 54 und 56
26
b2 = 2 * t * (1-t);
27
b2 /= sqrt(2);
28
Das heisst, Du wichtest das zweite Bersteinpolynom mit
29
w2 = 1 / sqrt(2);
30
Das ist aber nur fuer 45-Grad-Segmente korrekt. Fuer den
31
allgemeinen Fall funktioniert
32
w2 = ( e(p3 - p1), e(p2 - p1) ); // also cos(winkel(p3-p1, p2-p1))
33
bzw. schoen symmetrisch
34
w2 = ( e(p3 - p1), e(p2 - p1) )/2 + ( e(p1 - p3), e(p2 - p3) )/2;
35
Das ist natuerlich kein C++ Code sondern symbolisch, wobei
36
e(p3 - p1) ist der von p1 zu p3 zeigende Einheitsvektor und
37
(a, b) steht fuer das Skalarprodukt zweier Vektoren etc.
38
39
Eine vergleichbare Information steht auch irgendwo im Hoscheck & Lasser.
40
Ich habe das Buch aber eben nicht zur Hand.
41
*/
42
43
void splinesegment3d :: Evaluate (double t, Point<3> & p) const
44
{
45
double x, y, z, w;
46
double b1, b2, b3;
47
48
b1 = (1-t)*(1-t);
49
b2 = 2 * t * (1-t);
50
b3 = t * t;
51
52
b2 /= sqrt(double(2));
53
54
x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3;
55
y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3;
56
z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3;
57
w = b1 + b2 + b3;
58
59
p(0) = x / w;
60
p(1) = y / w;
61
p(2) = z / w;
62
}
63
64
void splinesegment3d :: EvaluateTangent (double t, Vec<3> & tang) const
65
{
66
double x, y, z, w, xprime, yprime, zprime, wprime;
67
double b1, b2, b3, b1prime, b2prime, b3prime;
68
69
b1 = (1-t)*(1-t);
70
b2 = 2 * t * (1-t);
71
b3 = t * t;
72
b2 /= sqrt(double(2));
73
74
b1prime = 2 * t - 2;
75
b2prime = - 4 * t + 2;
76
b3prime = 2 * t;
77
b2prime /= sqrt(double(2));
78
79
80
x = p1(0) * b1 + p2(0) * b2 + p3(0) * b3;
81
y = p1(1) * b1 + p2(1) * b2 + p3(1) * b3;
82
z = p1(2) * b1 + p2(2) * b2 + p3(2) * b3;
83
w = b1 + b2 + b3;
84
85
xprime = p1(0) * b1prime + p2(0) * b2prime + p3(0) * b3prime;
86
yprime = p1(1) * b1prime + p2(1) * b2prime + p3(1) * b3prime;
87
zprime = p1(2) * b1prime + p2(2) * b2prime + p3(2) * b3prime;
88
wprime = b1prime + b2prime + b3prime;
89
90
tang(0) = (w * xprime - x * wprime) / (w * w);
91
tang(1) = (w * yprime - y * wprime) / (w * w);
92
tang(2) = (w * zprime - z * wprime) / (w * w);
93
}
94
95
96
void spline3d :: AddSegment (const Point<3> & ap1, const Point<3> & ap2,
97
const Point<3> & ap3)
98
{
99
segments.Append (new splinesegment3d (ap1, ap2, ap3));
100
}
101
102
void spline3d :: Evaluate (double t, Point<3> & p) const
103
{
104
int nr;
105
double loct;
106
static int cnt = 0;
107
108
cnt++;
109
if (cnt % 10000 == 0) (*mycout) << "Evaluate calls: " << cnt << endl;
110
111
while (t < 0) t += GetNumSegments();
112
while (t >= GetNumSegments()) t -= GetNumSegments();
113
nr = 1 + int (t);
114
loct = t - nr + 1;
115
segments.Get(nr)->Evaluate (loct, p);
116
}
117
118
void spline3d :: EvaluateTangent (double t, Vec<3> & tang) const
119
{
120
int nr;
121
double loct;
122
123
while (t < 0) t += GetNumSegments();
124
while (t >= GetNumSegments()) t -= GetNumSegments();
125
nr = 1 + int (t);
126
loct = t - nr + 1;
127
segments.Get(nr)->EvaluateTangent (loct, tang);
128
}
129
130
131
double spline3d :: ProjectToSpline (Point<3> & p) const
132
{
133
double t, tl, tu, dt, dist, mindist, optt(0);
134
Point<3> hp;
135
Vec<3> tanx, px;
136
137
dt = 0.01;
138
mindist = 0;
139
for (t = 0; t <= GetNumSegments() + dt/2; t += dt)
140
{
141
Evaluate (t, hp);
142
dist = Dist (hp, p);
143
if (t == 0 || dist < mindist)
144
{
145
optt = t;
146
mindist = dist;
147
}
148
}
149
150
151
tu = optt + dt;
152
tl = optt - dt;
153
while (tu - tl > 1e-2)
154
{
155
optt = 0.5 * (tu + tl);
156
Evaluate (optt, hp);
157
EvaluateTangent (optt, tanx);
158
if (tanx * (hp - p) > 0)
159
tu = optt;
160
else
161
tl = optt;
162
}
163
164
optt = 0.5 * (tu + tl);
165
166
optt = ProjectToSpline (p, optt);
167
return optt;
168
}
169
170
171
double spline3d :: ProjectToSpline (Point<3> & p, double optt) const
172
{
173
double tl, tu, dt, val, dval, valu, vall;
174
Point<3> hp;
175
Vec<3> tanx, px;
176
int its = 0;
177
int cnt = 1000;
178
do
179
{
180
dt = 1e-8;
181
tl = optt - dt;
182
tu = optt + dt;
183
184
EvaluateTangent (optt, tanx);
185
Evaluate (optt, hp);
186
px = hp - p;
187
val = px * tanx;
188
189
EvaluateTangent (tl, tanx);
190
Evaluate (tl, hp);
191
px = hp - p;
192
vall = px * tanx;
193
194
EvaluateTangent (tu, tanx);
195
Evaluate (tu, hp);
196
px = hp - p;
197
valu = px * tanx;
198
199
dval = (valu - vall) / (2 * dt);
200
201
if (its % 100 == 99)
202
(*testout) << "optt = " << optt
203
<< " val = " << val
204
<< " dval = " << dval << endl;
205
optt -= val / dval;
206
its++;
207
if (fabs(val) < 1e-8 && cnt > 5) cnt = 5;
208
cnt--;
209
}
210
while (cnt > 0);
211
212
Evaluate (optt, p);
213
return optt;
214
}
215
216
217
splinetube :: splinetube (const spline3d & amiddlecurve, double ar)
218
: Surface(), middlecurve (amiddlecurve), r(ar)
219
{
220
(*mycout) << "Splinetube Allocated, r = " << r << endl;
221
222
}
223
224
void splinetube :: DefineTangentialPlane (const Point<3> & ap1,
225
const Point<3> & ap2)
226
{
227
double t;
228
double phi, z;
229
230
p1 = ap1;
231
p2 = ap2;
232
cp = p1;
233
t = middlecurve.ProjectToSpline (cp);
234
ex = p1 - cp;
235
middlecurve.EvaluateTangent (t, ez);
236
ex.Normalize();
237
ez.Normalize();
238
ey = Cross (ez, ex);
239
240
phi = r * atan2 (ey * (p2-cp), ex * (p2-cp));
241
z = ez * (p2 - cp);
242
e2x(0) = phi;
243
e2x(1) = z;
244
e2x.Normalize();
245
e2y(1) = e2x(0);
246
e2y(0) = -e2x(1);
247
248
// (*testout) << "Defineplane: " << endl
249
// << "p1 = " << p1 << " p2 = " << p2 << endl
250
// << "pc = " << cp << endl
251
// << "ex = " << ex << " ey = " << ey << " ez = " << ez << endl
252
// << "phi = " << phi << " z = " << z << endl
253
// << "e2x = " << e2x << " e2y = " << e2y << endl;
254
}
255
256
void splinetube :: ToPlane (const Point<3> & p3d, Point<2> & pplain, double h,
257
int & zone) const
258
{
259
Vec<2> v;
260
v(0) = r * atan2 (ey * (p3d-cp), ex * (p3d-cp));
261
v(1) = ez * (p3d - cp);
262
zone = 0;
263
if (v(0) > r * 2) zone = 1;
264
if (v(0) < r * 2) zone = 2;
265
266
pplain(0) = (v * e2x) / h;
267
pplain(1) = (v * e2y) / h;
268
}
269
270
void splinetube :: FromPlane (const Point<2> & pplain, Point<3> & p3d, double h) const
271
{
272
Vec<2> v;
273
274
v(0) = pplain(0) * h * e2x(0) + pplain(1) * h * e2y(0);
275
v(1) = pplain(0) * h * e2x(1) + pplain(1) * h * e2y(1);
276
277
p3d = p1 + v(0) * ey + v(1) * ez;
278
279
Project (p3d);
280
}
281
282
void splinetube :: Project (Point<3> & p3d) const
283
{
284
Point<3> hp;
285
286
hp = p3d;
287
middlecurve.ProjectToSpline (hp);
288
289
p3d = hp + (r / Dist(p3d, hp)) * (p3d - hp);
290
}
291
292
293
294
double splinetube :: CalcFunctionValue (const Point<3> & point) const
295
{
296
Point<3> hcp;
297
double rad;
298
299
hcp = point;
300
middlecurve.ProjectToSpline (hcp);
301
rad = Dist (hcp, point);
302
return 0.5 * (rad * rad / r - r);
303
}
304
305
void splinetube :: CalcGradient (const Point<3> & point, Vec<3> & grad) const
306
{
307
Point<3> hcp;
308
309
hcp = point;
310
middlecurve.ProjectToSpline (hcp);
311
312
grad = point - hcp;
313
grad /= r;
314
}
315
316
317
318
319
Point<3> splinetube :: GetSurfacePoint () const
320
{
321
Point<3> p;
322
Vec<3> t, n;
323
324
middlecurve.Evaluate (0, p);
325
middlecurve.EvaluateTangent (0, t);
326
n = t.GetNormal ();
327
n *= r;
328
(*mycout) << "p = " << p << " t = " << t << " n = " << n << endl;
329
return p + n;
330
}
331
332
void splinetube :: Print (ostream & str) const
333
{
334
int i;
335
str << "SplineTube, "
336
<< middlecurve.GetNumSegments () << " segments, r = " << r << endl;
337
for (i = 1; i <= middlecurve.GetNumSegments(); i++)
338
str << middlecurve.P1(i) << " - "
339
<< middlecurve.P2(i) << " - "
340
<< middlecurve.P3(i) << endl;
341
}
342
343
344
int splinetube :: BoxInSolid (const BoxSphere<3> & box) const
345
// 0 .. no, 1 .. yes, 2 .. maybe
346
{
347
Point<3> pc = box.Center();
348
middlecurve.ProjectToSpline (pc);
349
double d = Dist (pc, box.Center());
350
351
if (d < r - box.Diam()/2) return 1;
352
if (d > r + box.Diam()/2) return 0;
353
return 2;
354
}
355
}
356
357