2 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 // + This file is part of enGrid. +
6 // + Copyright 2008,2009 Oliver Gloth +
8 // + enGrid is free software: you can redistribute it and/or modify +
9 // + it under the terms of the GNU General Public License as published by +
10 // + the Free Software Foundation, either version 3 of the License, or +
11 // + (at your option) any later version. +
13 // + enGrid is distributed in the hope that it will be useful, +
14 // + but WITHOUT ANY WARRANTY; without even the implied warranty of +
15 // + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
16 // + GNU General Public License for more details. +
18 // + You should have received a copy of the GNU General Public License +
19 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
21 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 #include "geometrytools.h"
24 #include "containertricks.h"
26 #include "utilities.h"
28 #include <vtkCellType.h>
31 namespace GeometryTools
{
33 double rad2deg( double rad
)
38 double deg2rad( double deg
)
43 void rotate(vec3_t g1
, vec3_t g2
,vec3_t g3
, vec3_t
&b
, double theta
)
50 mat3_t g
= g_t
.transp();
54 mat3_t rot
= mat3_t::identity();
55 rot
[0][0] = cos(theta
);
56 rot
[0][1] = -sin(theta
);
57 rot
[1][0] = sin(theta
);
58 rot
[1][1] = cos(theta
);
59 //cout << rot << endl;
61 //cout << bbb << endl;
66 vec3_t
rotate(vec3_t v
, vec3_t axis
, double theta
)
70 // transposed base of rotate system
73 // compute projection of v in axis direction
74 vec3_t v_axis
= (axis
*v
)*axis
;
76 // compute first orthogonal vector (first base vector)
79 //In case of points on the rotation axis, do nothing
80 if(g_t
[0].abs()==0) return v
;
84 // second base vector is the normalised axis
87 // compute second orthogonal vector (third base vector)
88 g_t
[2] = g_t
[0].cross(g_t
[1]);
90 // base of rotate system
91 mat3_t g
= g_t
.transp();
93 // matrix for rotation around g_t[1];
94 mat3_t rot
= mat3_t::identity();
95 rot
[0][0] = cos(theta
);
96 rot
[0][2] = sin(theta
);
97 rot
[2][0] = -sin(theta
);
98 rot
[2][2] = cos(theta
);
100 // transfer v to rotate system
103 // rotate the vector and transfer it back
110 vec3_t
orthogonalVector(vec3_t v
)
112 // get absolute values
113 double xx
= v
[0] < 0.0 ? -v
[0] : v
[0];
114 double yy
= v
[1] < 0.0 ? -v
[1] : v
[1];
115 double zz
= v
[2] < 0.0 ? -v
[2] : v
[2];
116 // switch both biggest values and set the other one to zero
119 u
= xx
< zz
? vec3_t(0,v
[2],-v
[1]) : vec3_t(v
[1],-v
[0],0);
121 u
= yy
< zz
? vec3_t(-v
[2],0,v
[0]) : vec3_t(v
[1],-v
[0],0);
128 double intersection(vec3_t x_straight
, vec3_t v_straight
, vec3_t x_plane
, vec3_t u_plane
, vec3_t v_plane
)
130 vec3_t n
= u_plane
.cross(v_plane
);
131 return intersection(x_straight
,v_straight
,x_plane
,n
);
134 double intersection(vec3_t x_straight
, vec3_t v_straight
, vec3_t x_plane
, vec3_t n_plane
)
136 double k
= (x_plane
*n_plane
- x_straight
*n_plane
)/(v_straight
*n_plane
);
140 bool intersection (double &k1
, double &k2
, vec2_t r1
, vec2_t u1
, vec2_t r2
, vec2_t u2
)
142 double ave_length
= .5*(sqrt(u1
[0]*u1
[0]+u1
[1]*u1
[1]) + sqrt(u2
[0]*u2
[0]+u2
[1]*u2
[1]));
143 double DET
= (u1
[0]*u2
[1]-u1
[1]*u2
[0]);
144 if (fabs(DET
) > 1e-6*ave_length
) {
145 k1
= -(u2
[0]*r2
[1]-u2
[0]*r1
[1]-r2
[0]*u2
[1]+r1
[0]*u2
[1])/DET
;
146 k2
= -(-u1
[1]*r2
[0]+u1
[0]*r2
[1]-u1
[0]*r1
[1]+u1
[1]*r1
[0])/DET
;
153 void sliceTriangle(const vector
<vec3_t
> &Tin
, vec3_t x
, vec3_t n
, vector
<vector
<vec3_t
> > &Tout
)
158 double kab
= intersection(a
,b
-a
,x
,n
);
159 double kbc
= intersection(b
,c
-b
,x
,n
);
160 double kca
= intersection(c
,a
-c
,x
,n
);
161 bool ab_cut
= ((kab
>= 0) && (kab
<= 1));
162 bool bc_cut
= ((kbc
>= 0) && (kbc
<= 1));
163 bool ca_cut
= ((kca
>= 0) && (kca
<= 1));
164 if (ab_cut
&& bc_cut
&& ca_cut
) {
165 //cerr << "invalid triangle (SliceTriangle) A" << endl;
166 //exit(EXIT_FAILURE);
167 if ((kab
<= kbc
) && (kab
<= kca
)) ab_cut
= false;
168 else if ((kbc
<= kab
) && (kbc
<= kca
)) bc_cut
= false;
171 if (ab_cut
&& bc_cut
) {
172 vec3_t ab
= a
+ kab
*(b
-a
);
173 vec3_t bc
= b
+ kbc
*(c
-b
);
174 Tout
.resize(3,vector
<vec3_t
>(3));
175 clinit(Tout
[0]) = a
,ab
,bc
;
176 clinit(Tout
[1]) = ab
,b
,bc
;
177 clinit(Tout
[2]) = bc
,c
,a
;
178 } else if (bc_cut
&& ca_cut
) {
179 vec3_t bc
= b
+ kbc
*(c
-b
);
180 vec3_t ca
= c
+ kca
*(a
-c
);
181 Tout
.resize(3,vector
<vec3_t
>(3));
182 clinit(Tout
[0]) = a
,bc
,ca
;
183 clinit(Tout
[1]) = a
,b
,bc
;
184 clinit(Tout
[2]) = bc
,c
,ca
;
185 } else if (ca_cut
&& ab_cut
) {
186 vec3_t ca
= c
+ kca
*(a
-c
);
187 vec3_t ab
= a
+ kab
*(b
-a
);
188 Tout
.resize(3,vector
<vec3_t
>(3));
189 clinit(Tout
[0]) = a
,ab
,ca
;
190 clinit(Tout
[1]) = ab
,b
,ca
;
191 clinit(Tout
[2]) = b
,c
,ca
;
193 Tout
.resize(1,vector
<vec3_t
>(3));
194 clinit(Tout
[0]) = a
,b
,c
;
199 double tetraVol(const vec3_t
& x0
, const vec3_t
& x1
, const vec3_t
& x2
, const vec3_t
& x3
, bool neg
)
201 static double f16
= 1.0/6.0;
202 vec3_t
v1(x1
[0]-x0
[0], x1
[1]-x0
[1], x1
[2]-x0
[2]);
203 vec3_t
v2(x2
[0]-x0
[0], x2
[1]-x0
[1], x2
[2]-x0
[2]);
204 vec3_t
v3(x3
[0]-x0
[0], x3
[1]-x0
[1], x3
[2]-x0
[2]);
205 double V
= v1
[0]*(v2
[1]*v3
[2]-v2
[2]*v3
[1]) + v1
[1]*(v2
[2]*v3
[0]-v2
[0]*v3
[2]) + v1
[2]*(v2
[0]*v3
[1]-v2
[1]*v3
[0]);
207 if (!neg
&& (V
< 0)) {
213 double pyraVol(vec3_t x0
, vec3_t x1
, vec3_t x2
, vec3_t x3
, vec3_t x4
, bool neg
)
215 double V1
= tetraVol(x0
, x1
, x3
, x4
, neg
) + tetraVol(x1
, x2
, x3
, x4
, neg
);
216 double V2
= tetraVol(x0
, x1
, x2
, x4
, neg
) + tetraVol(x2
, x3
, x0
, x4
, neg
);
220 vec3_t m0 = .25*(x0+x1+x2+x3);
221 V += tetraVol(x0, x1, m0, x4, neg);
222 V += tetraVol(x1, x2, m0, x4, neg);
223 V += tetraVol(x2, x3, m0, x4, neg);
224 V += tetraVol(x3, x0, m0, x4, neg);
229 double prismVol(vec3_t x0
, vec3_t x1
, vec3_t x2
, vec3_t x3
, vec3_t x4
, vec3_t x5
, bool neg
)
232 vec3_t p
= 1.0/6.0*(x0
+x1
+x2
+x3
+x4
+x5
);
233 V
+= tetraVol(x0
, x2
, x1
, p
, neg
);
234 V
+= tetraVol(x3
, x4
, x5
, p
, neg
);
235 V
+= pyraVol (x0
, x1
, x4
, x3
, p
, neg
);
236 V
+= pyraVol (x1
, x2
, x5
, x4
, p
, neg
);
237 V
+= pyraVol (x0
, x3
, x5
, x2
, p
, neg
);
241 double hexaVol(vec3_t x0
, vec3_t x1
, vec3_t x2
, vec3_t x3
, vec3_t x4
, vec3_t x5
, vec3_t x6
, vec3_t x7
, bool neg
)
244 vec3_t p
= 1.0/8.0*(x0
+x1
+x2
+x3
+x4
+x5
+x6
+x7
);
245 V
+= pyraVol(x0
, x1
, x3
, x2
, p
, neg
);
246 V
+= pyraVol(x0
, x4
, x5
, x1
, p
, neg
);
247 V
+= pyraVol(x4
, x6
, x7
, x5
, p
, neg
);
248 V
+= pyraVol(x2
, x3
, x7
, x6
, p
, neg
);
249 V
+= pyraVol(x1
, x5
, x7
, x3
, p
, neg
);
250 V
+= pyraVol(x0
, x2
, x6
, x4
, p
, neg
);
254 double triArea(vec3_t x0
, vec3_t x1
, vec3_t x2
)
258 double A
= 0.5*((a
.cross(b
)).abs());
262 double quadArea(vec3_t x0
, vec3_t x1
, vec3_t x2
, vec3_t x3
)
265 vec3_t p
= .25*(x0
+x1
+x2
+x3
);
266 A
+= triArea(x0
,x1
,p
);
267 A
+= triArea(x1
,x2
,p
);
268 A
+= triArea(x2
,x3
,p
);
269 A
+= triArea(x3
,x0
,p
);
273 vec3_t
triNormal(vec3_t x0
, vec3_t x1
, vec3_t x2
)
277 vec3_t n
= 0.5*(a
.cross(b
));
281 vec3_t
quadNormal(vec3_t x0
, vec3_t x1
, vec3_t x2
, vec3_t x3
)
285 vec3_t p
= .25*(x0
+x1
+x2
+x3
);
286 n
+= triNormal(x0
,x1
,p
);
287 n
+= triNormal(x1
,x2
,p
);
288 n
+= triNormal(x2
,x3
,p
);
289 n
+= triNormal(x3
,x0
,p
);
293 vec3_t
triNormal(vtkUnstructuredGrid
*grid
, vtkIdType p1
, vtkIdType p2
, vtkIdType p3
)
296 grid
->GetPoint(p1
,x1
.data());
297 grid
->GetPoint(p2
,x2
.data());
298 grid
->GetPoint(p3
,x3
.data());
299 return triNormal(x1
,x2
,x3
);
302 vec3_t
quadNormal(vtkUnstructuredGrid
*grid
, vtkIdType p1
, vtkIdType p2
, vtkIdType p3
, vtkIdType p4
)
304 vec3_t x1
, x2
, x3
, x4
;
305 grid
->GetPoint(p1
,x1
.data());
306 grid
->GetPoint(p2
,x2
.data());
307 grid
->GetPoint(p3
,x3
.data());
308 grid
->GetPoint(p4
,x4
.data());
309 return quadNormal(x1
,x2
,x3
,x4
);
312 vec3_t
cellNormal(vtkUnstructuredGrid
*grid
, vtkIdType i
)
317 grid
->GetCellPoints(i
, npts
, pts
);
319 return triNormal(grid
,pts
[0],pts
[1],pts
[2]);
320 } else if (npts
== 4) {
321 return quadNormal(grid
,pts
[0],pts
[1],pts
[2],pts
[3]);
328 double cellVA(vtkUnstructuredGrid
*grid
, vtkIdType cellId
, bool neg
)
333 grid
->GetCellPoints(cellId
, Npts
, pts
);
334 for (int i_pts
= 0; i_pts
< Npts
; ++i_pts
) {
335 grid
->GetPoints()->GetPoint(pts
[i_pts
], p
[i_pts
].data());
337 vtkIdType cellType
= grid
->GetCellType(cellId
);
338 if (cellType
== VTK_TRIANGLE
) return triArea (p
[0], p
[1], p
[2]);
339 else if (cellType
== VTK_QUAD
) return quadArea(p
[0], p
[1], p
[2], p
[3]);
340 else if (cellType
== VTK_TETRA
) return tetraVol(p
[0], p
[1], p
[2], p
[3], neg
);
341 else if (cellType
== VTK_PYRAMID
) return pyraVol (p
[0], p
[1], p
[2], p
[3], p
[4], neg
);
342 else if (cellType
== VTK_WEDGE
) return prismVol(p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], neg
);
343 else if (cellType
== VTK_HEXAHEDRON
) return hexaVol (p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7], neg
);
347 double angle(const vec3_t
& u
, const vec3_t
& v
)
349 // return the angle w.r.t. another 3-vector
350 double ptot2
= u
.abs2()*v
.abs2();
354 double arg
= (u
*v
)/sqrt(ptot2
);
355 if(arg
> 1.0) arg
= 1.0;
356 if(arg
< -1.0) arg
= -1.0;
361 double deviation(vtkUnstructuredGrid
*grid
, vtkIdType p1
, vtkIdType p2
, vtkIdType p3
)
364 grid
->GetPoint(p1
,x1
.data());
365 grid
->GetPoint(p2
,x2
.data());
366 grid
->GetPoint(p3
,x3
.data());
372 double angle(vtkUnstructuredGrid
*grid
, vtkIdType p1
, vtkIdType p2
, vtkIdType p3
)
375 grid
->GetPoint(p1
,x1
.data());
376 grid
->GetPoint(p2
,x2
.data());
377 grid
->GetPoint(p3
,x3
.data());
383 double CosAngle(vtkUnstructuredGrid
*grid
, vtkIdType cell1
, vtkIdType cell2
)
385 vec3_t u1
= cellNormal(grid
, cell1
);
386 vec3_t u2
= cellNormal(grid
, cell2
);
392 vec3_t
getCenter(vtkUnstructuredGrid
*grid
, vtkIdType cellId
, double& Rmin
, double& Rmax
)
394 vtkIdType
*pts
, Npts
;
395 grid
->GetCellPoints(cellId
, Npts
, pts
);
397 cout
<<"FATAL ERROR: Npts<=0"<<endl
;
401 //calculate center position
403 for (vtkIdType i
= 0; i
< Npts
; ++i
) {
405 grid
->GetPoints()->GetPoint(pts
[i
], xp
.data());
408 xc
= 1.0/(double)Npts
* xc
;
410 //calculate Rmin+Rmax
412 grid
->GetPoints()->GetPoint(pts
[0], xp
.data());
413 Rmin
= 0.25*(xp
-xc
).abs();
414 Rmax
= 0.25*(xp
-xc
).abs();
415 for (vtkIdType i
= 1; i
< Npts
; ++i
) {
416 grid
->GetPoints()->GetPoint(pts
[i
], xp
.data());
417 Rmin
= min(Rmin
, 0.25*(xp
-xc
).abs());
418 Rmax
= max(Rmax
, 0.25*(xp
-xc
).abs());
424 bool intersectEdgeAndTriangle(const vec3_t
& a
, const vec3_t
& b
, const vec3_t
& c
,
425 const vec3_t
& x1
, const vec3_t
& x2
, vec3_t
& xi
, vec3_t
& ri
, double tol
)
430 vec3_t g3
= g1
.cross(g2
);
433 // direction of the edge
437 if (fabs(g3
*v
) < 1e-6) {
441 // compute intersection between straight and triangular plane
442 double k
= intersection(x1
, v
, a
, g3
);
444 // intersection outside of edge range?
445 if (k
< 0 - tol
*(x1
-x2
).abs()) {
448 if (k
> 1 + tol
*(x1
-x2
).abs()) {
454 // transform xi to triangular base
459 mat3_t GI
= G
.inverse();
463 // intersection outside of triangle?
464 if (ri
[0] + ri
[1] > 1) {
467 if ((ri
[0] < 0 - tol
) || (ri
[0] > 1 + tol
)) {
470 if ((ri
[1] < 0 - tol
) || (ri
[1] > 1 + tol
)) {
477 double distance(vtkUnstructuredGrid
*grid
, vtkIdType id_node1
, vtkIdType id_node2
) {
480 grid
->GetPoints()->GetPoint(id_node1
, A
.data());
481 grid
->GetPoints()->GetPoint(id_node2
, B
.data());
485 double distance2(vtkUnstructuredGrid
*grid
, vtkIdType id_node1
, vtkIdType id_node2
) {
488 grid
->GetPoints()->GetPoint(id_node1
, A
.data());
489 grid
->GetPoints()->GetPoint(id_node2
, B
.data());
490 return((B
-A
).abs2());
493 double areaOfCircumscribedCircle(vtkUnstructuredGrid
*grid
, vtkIdType id_cell
) {
494 vtkIdType N_pts
, *pts
;
495 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
497 grid
->GetPoints()->GetPoint(pts
[0], A
.data());
498 grid
->GetPoints()->GetPoint(pts
[1], B
.data());
499 grid
->GetPoints()->GetPoint(pts
[2], C
.data());
500 double a
=(C
-B
).abs();
501 double alpha
=angle((B
-A
),(C
-A
));
502 double R
=a
/(2*sin(alpha
));
506 vec3_t
getBarycentricCoordinates(double x
, double y
)
516 T
[0][0]=x_1
-x_3
; T
[0][1]=x_2
-x_3
;
517 T
[1][0]=y_1
-y_3
; T
[1][1]=y_2
-y_3
;
520 qWarning()<<"T.det()="<<T
.det();
521 qWarning()<<T
[0][0]<<T
[0][1];
522 qWarning()<<T
[1][0]<<T
[1][1];
523 qWarning()<<"T[0][0]*T[1][1]-T[1][0]*T[0][1]="<<T
[0][0]*T
[1][1]-T
[1][0]*T
[0][1];
527 double lambda_1
= ((y_2
-y_3
)*(x
-x_3
)-(x_2
-x_3
)*(y
-y_3
))/(T
.det());
528 double lambda_2
= (-(y_1
-y_3
)*(x
-x_3
)+(x_1
-x_3
)*(y
-y_3
))/(T
.det());
529 double lambda_3
= 1-lambda_1
-lambda_2
;
531 vec3_t
bary_coords(lambda_1
,lambda_2
,lambda_3
);
556 if(!intersection (k1, k2, t_A, t_M-t_A, t_B, t_C-t_B)) EG_BUG;
557 vec2_t t_I1 = t_A+k1*(t_M-t_A);
558 vec3_t g_nI1 = (1-k2)*g_nB + k2*g_nC;
559 vec2_t pm1_M(1.0/k1,0);
562 double total = t1+t2+t3;
572 // vec3_t bary_coords(t1,t2,t3);
573 // return bary_coords;
576 vec3_t
intersectionOnPlane(vec3_t v
, vec3_t A
, vec3_t nA
, vec3_t B
, vec3_t nB
)
583 //cout<<"u="<<u<<" v="<<v<<endl;
587 vec2_t p_nA
= projectVectorOnPlane(nA
,u
,v
);
588 vec2_t p_nB
= projectVectorOnPlane(nB
,u
,v
);
590 vec2_t p_tA
= turnRight(p_nA
);
591 vec2_t p_tB
= turnRight(p_nB
);
595 if(!intersection(k1
, k2
, p_A
, p_tA
, p_B
, p_tB
)) {
596 //qDebug()<<"WARNING: No intersection found!!!";
597 p_K
= 0.5*(p_A
+ p_B
);
603 //cout<<"nA="<<nA<<endl;
604 //cout<<"p_nA="<<p_nA<<endl;
605 //cout<<"p_tA="<<p_tA<<endl;
606 //cout<<"p_K="<<p_K<<endl;
607 vec3_t K
= A
+ p_K
[0]*u
+ p_K
[1]*v
;
608 //cout<<"K="<<K<<endl;
612 vec2_t
projectVectorOnPlane(vec3_t V
,vec3_t i
,vec3_t j
)
614 double x
= V
*i
/i
.abs2();
615 double y
= V
*j
/j
.abs2();
619 vec3_t
projectPointOnEdge(const vec3_t
& M
,const vec3_t
& A
, const vec3_t
& u
)
622 if(u
.abs2()==0) EG_BUG
;
623 double k
= ((M
-A
)*u
)/u
.abs2();