Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/netgen/libsrc/csg/polyhedra.cpp
3206 views
1
#include <mystdlib.h>
2
3
#include <linalg.hpp>
4
#include <csg.hpp>
5
6
namespace netgen
7
{
8
9
Polyhedra::Face::Face (int pi1, int pi2, int pi3,
10
const ARRAY<Point<3> > & points,
11
int ainputnr)
12
{
13
inputnr = ainputnr;
14
15
pnums[0] = pi1;
16
pnums[1] = pi2;
17
pnums[2] = pi3;
18
19
20
bbox.Set (points[pi1]);
21
bbox.Add (points[pi2]);
22
bbox.Add (points[pi3]);
23
24
v1 = points[pi2] - points[pi1];
25
v2 = points[pi3] - points[pi1];
26
27
n = Cross (v1, v2);
28
29
nn = n;
30
nn.Normalize();
31
// PseudoInverse (v1, v2, w1, w2);
32
33
Mat<2,3> mat;
34
Mat<3,2> inv;
35
for (int i = 0; i < 3; i++)
36
{
37
mat(0,i) = v1(i);
38
mat(1,i) = v2(i);
39
}
40
CalcInverse (mat, inv);
41
for (int i = 0; i < 3; i++)
42
{
43
w1(i) = inv(i,0);
44
w2(i) = inv(i,1);
45
}
46
}
47
48
49
Polyhedra :: Polyhedra ()
50
{
51
surfaceactive.SetSize(0);
52
surfaceids.SetSize(0);
53
eps_base1 = 1e-8;
54
}
55
56
Polyhedra :: ~Polyhedra ()
57
{
58
;
59
}
60
61
Primitive * Polyhedra :: CreateDefault ()
62
{
63
return new Polyhedra();
64
}
65
66
INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const
67
{
68
/*
69
for (i = 1; i <= faces.Size(); i++)
70
if (FaceBoxIntersection (i, box))
71
return DOES_INTERSECT;
72
*/
73
for (int i = 0; i < faces.Size(); i++)
74
{
75
if (!faces[i].bbox.Intersect (box))
76
continue;
77
//(*testout) << "face " << i << endl;
78
79
const Point<3> & p1 = points[faces[i].pnums[0]];
80
const Point<3> & p2 = points[faces[i].pnums[1]];
81
const Point<3> & p3 = points[faces[i].pnums[2]];
82
83
if (fabs (faces[i].nn * (p1 - box.Center())) > box.Diam()/2)
84
continue;
85
86
//(*testout) << "still in loop" << endl;
87
88
double dist2 = MinDistTP2 (p1, p2, p3, box.Center());
89
//(*testout) << "p1 " << p1 << " p2 " << p2 << " p3 " << p3 << endl
90
// << " box.Center " << box.Center() << " box.Diam() " << box.Diam() << endl
91
// << " dist2 " << dist2 << " sqr(box.Diam()/2) " << sqr(box.Diam()/2) << endl;
92
if (dist2 < sqr (box.Diam()/2))
93
{
94
//(*testout) << "DOES_INTERSECT" << endl;
95
return DOES_INTERSECT;
96
}
97
};
98
99
return PointInSolid (box.Center(), 1e-3 * box.Diam());
100
}
101
102
103
INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p,
104
double eps) const
105
{
106
//(*testout) << "PointInSolid p " << p << " eps " << eps << endl;
107
//(*testout) << "bbox " << poly_bbox << endl;
108
109
if((p(0) > poly_bbox.PMax()(0) + eps) || (p(0) < poly_bbox.PMin()(0) - eps) ||
110
(p(1) > poly_bbox.PMax()(1) + eps) || (p(1) < poly_bbox.PMin()(1) - eps) ||
111
(p(2) > poly_bbox.PMax()(2) + eps) || (p(2) < poly_bbox.PMin()(2) - eps))
112
{
113
//(*testout) << "returning IS_OUTSIDE" << endl;
114
return IS_OUTSIDE;
115
}
116
117
Vec<3> n, v1, v2;
118
119
// random (?) numbers:
120
n(0) = -0.424621;
121
n(1) = 0.15432;
122
n(2) = 0.89212238;
123
124
int cnt = 0;
125
126
for (int i = 0; i < faces.Size(); i++)
127
{
128
const Point<3> & p1 = points[faces[i].pnums[0]];
129
130
Vec<3> v0 = p - p1;
131
132
double lam3 = faces[i].nn * v0;
133
134
if(fabs(lam3) < eps)
135
{
136
double lam1 = (faces[i].w1 * v0);
137
double lam2 = (faces[i].w2 * v0);
138
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
139
{
140
//(*testout) << "returning DOES_INTERSECT" << endl;
141
return DOES_INTERSECT;
142
}
143
}
144
else
145
{
146
lam3 = -(faces[i].n * v0) / (faces[i].n * n);
147
148
if (lam3 < 0) continue;
149
150
Vec<3> rs = v0 + lam3 * n;
151
152
double lam1 = (faces[i].w1 * rs);
153
double lam2 = (faces[i].w2 * rs);
154
if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1)
155
cnt++;
156
}
157
158
}
159
160
//(*testout) << " cnt = " << cnt%2 << endl;
161
return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE;
162
}
163
164
165
166
167
void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p,
168
ARRAY<int> & surfind, double eps) const
169
{
170
for (int i = 0; i < faces.Size(); i++)
171
{
172
const Point<3> & p1 = points[faces[i].pnums[0]];
173
174
Vec<3> v0 = p - p1;
175
double lam3 = -(faces[i].nn * v0); // n->nn
176
177
if (fabs (lam3) > eps) continue;
178
179
double lam1 = (faces[i].w1 * v0);
180
double lam2 = (faces[i].w2 * v0);
181
182
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
183
if (!surfind.Contains (GetSurfaceId(i)))
184
surfind.Append (GetSurfaceId(i));
185
}
186
187
}
188
189
190
191
INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p,
192
const Vec<3> & v,
193
double eps) const
194
{
195
ARRAY<int> point_on_faces;
196
INSOLID_TYPE res(DOES_INTERSECT);
197
198
Vec<3> vn = v;
199
vn.Normalize();
200
for (int i = 0; i < faces.Size(); i++)
201
{
202
const Point<3> & p1 = points[faces[i].pnums[0]];
203
204
Vec<3> v0 = p - p1;
205
double lam3 = -(faces[i].nn * v0); // n->nn
206
207
208
if (fabs (lam3) > eps) continue;
209
//(*testout) << "lam3 <= eps" << endl;
210
211
double lam1 = (faces[i].w1 * v0);
212
double lam2 = (faces[i].w2 * v0);
213
214
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
215
{
216
point_on_faces.Append(i);
217
218
double scal = vn * faces[i].nn; // n->nn
219
220
res = DOES_INTERSECT;
221
if (scal > eps_base1) res = IS_OUTSIDE;
222
if (scal < -eps_base1) res = IS_INSIDE;
223
}
224
}
225
226
//(*testout) << "point_on_faces.Size() " << point_on_faces.Size()
227
// << " res " << res << endl;
228
229
if (point_on_faces.Size() == 0)
230
return PointInSolid (p, 0);
231
if (point_on_faces.Size() == 1)
232
return res;
233
234
235
236
237
double mindist(0);
238
bool first = true;
239
240
for(int i=0; i<point_on_faces.Size(); i++)
241
{
242
for(int j=0; j<3; j++)
243
{
244
double dist = Dist(p,points[faces[point_on_faces[i]].pnums[j]]);
245
if(dist > eps && (first || dist < mindist))
246
{
247
mindist = dist;
248
first = false;
249
}
250
}
251
}
252
253
Point<3> p2 = p + (1e-2*mindist) * vn;
254
res = PointInSolid (p2, eps);
255
256
// (*testout) << "mindist " << mindist << " res " << res << endl;
257
258
return res;
259
260
261
}
262
263
264
/*
265
INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
266
const Vec<3> & v1,
267
const Vec<3> & v2,
268
double eps) const
269
{
270
INSOLID_TYPE res;
271
272
res = VecInSolid(p,v1,eps);
273
if(res != DOES_INTERSECT)
274
return res;
275
276
int point_on_n_faces = 0;
277
278
Vec<3> v1n = v1;
279
v1n.Normalize();
280
Vec<3> v2n = v2;
281
v2n.Normalize();
282
283
284
for (int i = 0; i < faces.Size(); i++)
285
{
286
const Point<3> & p1 = points[faces[i].pnums[0]];
287
288
Vec<3> v0 = p - p1;
289
double lam3 = -(faces[i].n * v0);
290
291
if (fabs (lam3) > eps) continue;
292
293
double lam1 = (faces[i].w1 * v0);
294
double lam2 = (faces[i].w2 * v0);
295
296
if (lam1 >= -eps && lam2 >= -eps && lam1+lam2 <= 1+eps)
297
{
298
double scal1 = v1n * faces[i].n;
299
if (fabs (scal1) > eps) continue;
300
301
302
point_on_n_faces++;
303
304
double scal2 = v2n * faces[i].n;
305
res = DOES_INTERSECT;
306
if (scal2 > eps) res = IS_OUTSIDE;
307
if (scal2 < -eps) res = IS_INSIDE;
308
}
309
}
310
311
if (point_on_n_faces == 1)
312
return res;
313
314
cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
315
316
return Primitive :: VecInSolid2 (p, v1, v2, eps);
317
}
318
*/
319
320
321
322
INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
323
const Vec<3> & v1,
324
const Vec<3> & v2,
325
double eps) const
326
{
327
//(*testout) << "VecInSolid2 eps " << eps << endl;
328
INSOLID_TYPE res = VecInSolid(p,v1,eps);
329
//(*testout) << "VecInSolid = " <<res <<endl;
330
331
if(res != DOES_INTERSECT)
332
return res;
333
334
int point_on_n_faces = 0;
335
336
Vec<3> v1n = v1;
337
v1n.Normalize();
338
Vec<3> v2n = v2 - (v2 * v1n) * v1n;
339
v2n.Normalize();
340
341
double cosv2, cosv2max = -1;
342
343
344
for (int i = 0; i < faces.Size(); i++)
345
{
346
const Point<3> & p1 = points[faces[i].pnums[0]];
347
348
Vec<3> v0 = p - p1;
349
if (fabs (faces[i].nn * v0) > eps) continue; // n->nn
350
if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn
351
352
double lam1 = (faces[i].w1 * v0);
353
double lam2 = (faces[i].w2 * v0);
354
355
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
356
{
357
// v1 is in face
358
359
Point<3> fc = Center (points[faces[i].pnums[0]],
360
points[faces[i].pnums[1]],
361
points[faces[i].pnums[2]]);
362
363
Vec<3> vpfc = fc - p;
364
cosv2 = (v2n * vpfc) / vpfc.Length();
365
if (cosv2 > cosv2max)
366
{
367
cosv2max = cosv2;
368
point_on_n_faces++;
369
370
double scal2 = v2n * faces[i].nn; // n->nn
371
res = DOES_INTERSECT;
372
if (scal2 > eps_base1) res = IS_OUTSIDE;
373
if (scal2 < -eps_base1) res = IS_INSIDE;
374
375
}
376
}
377
}
378
379
if (point_on_n_faces >= 1)
380
return res;
381
382
(*testout) << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
383
cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
384
385
return Primitive :: VecInSolid2 (p, v1, v2, eps);
386
}
387
388
389
390
void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
391
ARRAY<int> & surfind, double eps) const
392
{
393
Vec<3> v1n = v1;
394
v1n.Normalize();
395
Vec<3> v2n = v2; // - (v2 * v1n) * v1n;
396
v2n.Normalize();
397
398
399
for (int i = 0; i < faces.Size(); i++)
400
{
401
const Point<3> & p1 = points[faces[i].pnums[0]];
402
403
Vec<3> v0 = p - p1;
404
if (fabs (v0 * faces[i].nn) > eps) continue; // n->nn
405
if (fabs (v1n * faces[i].nn) > eps_base1) continue; // n->nn
406
if (fabs (v2n * faces[i].nn) > eps_base1) continue; // n->nn
407
408
double lam01 = (faces[i].w1 * v0);
409
double lam02 = (faces[i].w2 * v0);
410
double lam03 = 1-lam01-lam02;
411
double lam11 = (faces[i].w1 * v1);
412
double lam12 = (faces[i].w2 * v1);
413
double lam13 = -lam11-lam12;
414
double lam21 = (faces[i].w1 * v2);
415
double lam22 = (faces[i].w2 * v2);
416
double lam23 = -lam21-lam22;
417
418
bool ok1 = lam01 > eps_base1 ||
419
lam01 > -eps_base1 && lam11 > eps_base1 ||
420
lam01 > -eps_base1 && lam11 > -eps_base1 && lam21 > eps_base1;
421
422
bool ok2 = lam02 > eps_base1 ||
423
lam02 > -eps_base1 && lam12 > eps_base1 ||
424
lam02 > -eps_base1 && lam12 > -eps_base1 && lam22 > eps_base1;
425
426
bool ok3 = lam03 > eps_base1 ||
427
lam03 > -eps_base1 && lam13 > eps_base1 ||
428
lam03 > -eps_base1 && lam13 > -eps_base1 && lam23 > eps_base1;
429
430
if (ok1 && ok2 && ok3)
431
{
432
if (!surfind.Contains (GetSurfaceId(faces[i].planenr)))
433
surfind.Append (GetSurfaceId(faces[i].planenr));
434
}
435
}
436
}
437
438
439
440
441
442
443
444
445
446
447
448
449
void Polyhedra :: GetPrimitiveData (const char *& classname,
450
ARRAY<double> & coeffs) const
451
{
452
classname = "Polyhedra";
453
coeffs.SetSize(0);
454
coeffs.Append (points.Size());
455
coeffs.Append (faces.Size());
456
coeffs.Append (planes.Size());
457
458
/*
459
int i, j;
460
for (i = 1; i <= planes.Size(); i++)
461
{
462
planes.Elem(i)->Print (*testout);
463
}
464
for (i = 1; i <= faces.Size(); i++)
465
{
466
(*testout) << "face " << i << " has plane " << faces.Get(i).planenr << endl;
467
for (j = 1; j <= 3; j++)
468
(*testout) << points.Get(faces.Get(i).pnums[j-1]);
469
(*testout) << endl;
470
}
471
*/
472
}
473
474
void Polyhedra :: SetPrimitiveData (ARRAY<double> & coeffs)
475
{
476
;
477
}
478
479
void Polyhedra :: Reduce (const BoxSphere<3> & box)
480
{
481
for (int i = 0; i < planes.Size(); i++)
482
surfaceactive[i] = 0;
483
484
for (int i = 0; i < faces.Size(); i++)
485
if (FaceBoxIntersection (i, box))
486
surfaceactive[faces[i].planenr] = 1;
487
}
488
489
void Polyhedra :: UnReduce ()
490
{
491
for (int i = 0; i < planes.Size(); i++)
492
surfaceactive[i] = 1;
493
}
494
495
int Polyhedra :: AddPoint (const Point<3> & p)
496
{
497
if(points.Size() == 0)
498
poly_bbox.Set(p);
499
else
500
poly_bbox.Add(p);
501
502
return points.Append (p);
503
}
504
505
int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum)
506
{
507
(*testout) << "polyhedra, add face " << pi1 << ", " << pi2 << ", " << pi3 << endl;
508
509
if(pi1 == pi2 || pi2 == pi3 || pi3 == pi1)
510
{
511
ostringstream msg;
512
msg << "Illegal point numbers for polyhedron face: " << pi1+1 << ", " << pi2+1 << ", " << pi3+1;
513
throw NgException(msg.str());
514
}
515
516
faces.Append (Face (pi1, pi2, pi3, points, inputnum));
517
518
Point<3> p1 = points[pi1];
519
Point<3> p2 = points[pi2];
520
Point<3> p3 = points[pi3];
521
522
Vec<3> v1 = p2 - p1;
523
Vec<3> v2 = p3 - p1;
524
525
Vec<3> n = Cross (v1, v2);
526
n.Normalize();
527
528
Plane pl (p1, n);
529
// int inverse;
530
// int identicto = -1;
531
// for (int i = 0; i < planes.Size(); i++)
532
// if (pl.IsIdentic (*planes[i], inverse, 1e-9*max3(v1.Length(),v2.Length(),Dist(p2,p3))))
533
// {
534
// if (!inverse)
535
// identicto = i;
536
// }
537
// // cout << "is identic = " << identicto << endl;
538
// identicto = -1; // changed April 10, JS
539
540
// if (identicto != -1)
541
// faces.Last().planenr = identicto;
542
// else
543
{
544
planes.Append (new Plane (p1, n));
545
surfaceactive.Append (1);
546
surfaceids.Append (0);
547
faces.Last().planenr = planes.Size()-1;
548
}
549
550
// (*testout) << "is plane nr " << faces.Last().planenr << endl;
551
552
return faces.Size();
553
}
554
555
556
557
int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const
558
{
559
/*
560
(*testout) << "check face box intersection, fnr = " << fnr << endl;
561
(*testout) << "box = " << box << endl;
562
(*testout) << "face-box = " << faces[fnr].bbox << endl;
563
*/
564
565
if (!faces[fnr].bbox.Intersect (box))
566
return 0;
567
568
const Point<3> & p1 = points[faces[fnr].pnums[0]];
569
const Point<3> & p2 = points[faces[fnr].pnums[1]];
570
const Point<3> & p3 = points[faces[fnr].pnums[2]];
571
572
double dist2 = MinDistTP2 (p1, p2, p3, box.Center());
573
/*
574
(*testout) << "p1 = " << p1 << endl;
575
(*testout) << "p2 = " << p2 << endl;
576
(*testout) << "p3 = " << p3 << endl;
577
578
(*testout) << "box.Center() = " << box.Center() << endl;
579
(*testout) << "center = " << box.Center() << endl;
580
(*testout) << "dist2 = " << dist2 << endl;
581
(*testout) << "diam = " << box.Diam() << endl;
582
*/
583
if (dist2 < sqr (box.Diam()/2))
584
{
585
// (*testout) << "intersect" << endl;
586
return 1;
587
}
588
return 0;
589
}
590
591
592
void Polyhedra :: GetPolySurfs(ARRAY < ARRAY<int> * > & polysurfs)
593
{
594
int maxnum = -1;
595
596
for(int i = 0; i<faces.Size(); i++)
597
{
598
if(faces[i].inputnr > maxnum)
599
maxnum = faces[i].inputnr;
600
}
601
602
polysurfs.SetSize(maxnum+1);
603
for(int i=0; i<polysurfs.Size(); i++)
604
polysurfs[i] = new ARRAY<int>;
605
606
for(int i = 0; i<faces.Size(); i++)
607
polysurfs[faces[i].inputnr]->Append(faces[i].planenr);
608
}
609
610
611
void Polyhedra::CalcSpecialPoints (ARRAY<Point<3> > & pts) const
612
{
613
for (int i = 0; i < points.Size(); i++)
614
pts.Append (points[i]);
615
}
616
617
618
void Polyhedra :: AnalyzeSpecialPoint (const Point<3> & pt,
619
ARRAY<Point<3> > & specpts) const
620
{
621
;
622
}
623
624
Vec<3> Polyhedra :: SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const
625
{
626
const double eps = 1e-10*poly_bbox.Diam();
627
628
for (int fi1 = 0; fi1 < faces.Size(); fi1++)
629
for (int fi2 = 0; fi2 < faces.Size(); fi2++)
630
{
631
int si1 = faces[fi1].planenr;
632
int si2 = faces[fi2].planenr;
633
634
if (surfaceids[si1] != s1 || surfaceids[si2] != s2) continue;
635
636
//(*testout) << "check pair fi1/fi2 " << fi1 << "/" << fi2 << endl;
637
638
Vec<3> n1 = GetSurface(si1) . GetNormalVector (p);
639
Vec<3> n2 = GetSurface(si2) . GetNormalVector (p);
640
Vec<3> t = Cross (n1, n2);
641
642
//(*testout) << "t = " << t << endl;
643
644
645
/*
646
int samepts = 0;
647
for (int j = 0; j < 3; j++)
648
for (int k = 0; k < 3; k++)
649
if (Dist(points[faces[fi1].pnums[j]],
650
points[faces[fi2].pnums[k]]) < eps)
651
samepts++;
652
if (samepts < 2) continue;
653
*/
654
655
bool shareedge = false;
656
for(int j = 0; !shareedge && j < 3; j++)
657
{
658
Vec<3> v1 = points[faces[fi1].pnums[(j+1)%3]] - points[faces[fi1].pnums[j]];
659
double smax = v1.Length();
660
v1 *= 1./smax;
661
662
int pospos;
663
if(fabs(v1(0)) > 0.5)
664
pospos = 0;
665
else if(fabs(v1(1)) > 0.5)
666
pospos = 1;
667
else
668
pospos = 2;
669
670
double sp = (p(pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos);
671
if(sp < -eps || sp > smax+eps)
672
continue;
673
674
for (int k = 0; !shareedge && k < 3; k ++)
675
{
676
Vec<3> v2 = points[faces[fi2].pnums[(k+1)%3]] - points[faces[fi2].pnums[k]];
677
v2.Normalize();
678
if(v2 * v1 > 0)
679
v2 -= v1;
680
else
681
v2 += v1;
682
683
//(*testout) << "v2.Length2() " << v2.Length2() << endl;
684
685
if(v2.Length2() > 1e-18)
686
continue;
687
688
double sa,sb;
689
690
sa = (points[faces[fi2].pnums[k]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos);
691
sb = (points[faces[fi2].pnums[(k+1)%3]](pospos) - points[faces[fi1].pnums[j]](pospos)) / v1(pospos);
692
693
694
if(Dist(points[faces[fi1].pnums[j]] + sa*v1, points[faces[fi2].pnums[k]]) > eps)
695
continue;
696
697
if(sa > sb)
698
{
699
double aux = sa; sa = sb; sb = aux;
700
}
701
702
//testout->precision(20);
703
//(*testout) << "sa " << sa << " sb " << sb << " smax " << smax << " sp " << sp << " v1 " << v1 << endl;
704
//testout->precision(8);
705
706
707
shareedge = (sa < -eps && sb > eps) ||
708
(sa < smax-eps && sb > smax+eps) ||
709
(sa > -eps && sb < smax+eps);
710
711
if(!shareedge)
712
continue;
713
714
sa = max2(sa,0.);
715
sb = min2(sb,smax);
716
717
if(sp < sa+eps)
718
shareedge = (t * v1 > 0);
719
else if (sp > sb-eps)
720
shareedge = (t * v1 < 0);
721
722
}
723
}
724
if (!shareedge) continue;
725
726
t.Normalize();
727
728
729
return t;
730
}
731
732
return Vec<3> (0,0,0);
733
}
734
735
736
}
737
738
739
740