various improvements to speed up surface meshing of BRL-CAD geometries
[engrid.git] / src / libengrid / geometrytools.cpp
blobf914874c701d0b809bedd02fe5d5a3d9170bde56
1 //
2 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 // + +
4 // + This file is part of enGrid. +
5 // + +
6 // + Copyright 2008-2013 enGits GmbH +
7 // + +
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. +
12 // + +
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. +
17 // + +
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/>. +
20 // + +
21 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22 //
23 #include "geometrytools.h"
24 #include "containertricks.h"
25 #include "engrid.h"
26 #include "utilities.h"
27 #include "math/linsolve.h"
29 #include <vtkCellType.h>
30 #include <cmath>
32 namespace GeometryTools {
34 double rad2deg( double rad )
36 return rad/M_PI*180;
39 double deg2rad( double deg )
41 return deg/180*M_PI;
44 void rotate(vec3_t g1, vec3_t g2,vec3_t g3, vec3_t &b, double theta)
46 //cout << b << endl;
47 mat3_t g_t;
48 g_t[0] = g1;
49 g_t[1] = g2;
50 g_t[2] = g3;
51 mat3_t g = g_t.transp();
52 //cout << g << endl;
53 vec3_t bb = g_t*b;
54 //cout << bb << endl;
55 mat3_t rot = mat3_t::identity();
56 rot[0][0] = cos(theta);
57 rot[0][1] = -sin(theta);
58 rot[1][0] = sin(theta);
59 rot[1][1] = cos(theta);
60 //cout << rot << endl;
61 vec3_t bbb = rot*bb;
62 //cout << bbb << endl;
63 b = g*bbb;
64 //cout << b << endl;
67 vec3_t rotate(vec3_t v, vec3_t axis, double theta)
69 axis.normalise();
71 // transposed base of rotate system
72 mat3_t g_t;
74 // compute projection of v in axis direction
75 vec3_t v_axis = (axis*v)*axis;
77 // compute first orthogonal vector (first base vector)
78 g_t[0] = v-v_axis;
80 //In case of points on the rotation axis, do nothing
81 if(g_t[0].abs()==0) return v;
83 g_t[0].normalise();
85 // second base vector is the normalised axis
86 g_t[1] = axis;
88 // compute second orthogonal vector (third base vector)
89 g_t[2] = g_t[0].cross(g_t[1]);
91 // base of rotate system
92 mat3_t g = g_t.transp();
94 // matrix for rotation around g_t[1];
95 mat3_t rot = mat3_t::identity();
96 rot[0][0] = cos(theta);
97 rot[0][2] = sin(theta);
98 rot[2][0] = -sin(theta);
99 rot[2][2] = cos(theta);
101 // transfer v to rotate system
102 vec3_t v_r = g_t*v;
104 // rotate the vector and transfer it back
105 v_r = rot*v_r;
106 v = g*v_r;
108 return v;
111 vec3_t orthogonalVector(vec3_t v)
113 // get absolute values
114 double xx = v[0] < 0.0 ? -v[0] : v[0];
115 double yy = v[1] < 0.0 ? -v[1] : v[1];
116 double zz = v[2] < 0.0 ? -v[2] : v[2];
117 // switch both biggest values and set the other one to zero
118 vec3_t u;
119 if (xx < yy) {
120 u = xx < zz ? vec3_t(0,v[2],-v[1]) : vec3_t(v[1],-v[0],0);
121 } else {
122 u = yy < zz ? vec3_t(-v[2],0,v[0]) : vec3_t(v[1],-v[0],0);
124 u.normalise();
125 return u;
129 double intersection(vec3_t x_straight, vec3_t v_straight, vec3_t x_plane, vec3_t u_plane, vec3_t v_plane)
131 vec3_t n = u_plane.cross(v_plane);
132 return intersection(x_straight,v_straight,x_plane,n);
135 double intersection(vec3_t x_straight, vec3_t v_straight, vec3_t x_plane, vec3_t n_plane)
137 double k = (x_plane*n_plane - x_straight*n_plane)/(v_straight*n_plane);
138 return k;
141 bool intersection (double &k1, double &k2, vec2_t r1, vec2_t u1, vec2_t r2, vec2_t u2)
143 double ave_length = .5*(sqrt(u1[0]*u1[0]+u1[1]*u1[1]) + sqrt(u2[0]*u2[0]+u2[1]*u2[1]));
144 double DET = (u1[0]*u2[1]-u1[1]*u2[0]);
145 if (fabs(DET) > 1e-6*ave_length) {
146 k1 = -(u2[0]*r2[1]-u2[0]*r1[1]-r2[0]*u2[1]+r1[0]*u2[1])/DET;
147 k2 = -(-u1[1]*r2[0]+u1[0]*r2[1]-u1[0]*r1[1]+u1[1]*r1[0])/DET;
148 return true;
149 } else {
150 return false;
154 void sliceTriangle(const vector<vec3_t> &Tin, vec3_t x, vec3_t n, vector<vector<vec3_t> > &Tout)
156 vec3_t a = Tin[0];
157 vec3_t b = Tin[1];
158 vec3_t c = Tin[2];
159 double kab = intersection(a,b-a,x,n);
160 double kbc = intersection(b,c-b,x,n);
161 double kca = intersection(c,a-c,x,n);
162 bool ab_cut = ((kab >= 0) && (kab <= 1));
163 bool bc_cut = ((kbc >= 0) && (kbc <= 1));
164 bool ca_cut = ((kca >= 0) && (kca <= 1));
165 if (ab_cut && bc_cut && ca_cut) {
166 //cerr << "invalid triangle (SliceTriangle) A" << endl;
167 //exit(EXIT_FAILURE);
168 if ((kab <= kbc) && (kab <= kca)) ab_cut = false;
169 else if ((kbc <= kab) && (kbc <= kca)) bc_cut = false;
170 else ca_cut = false;
172 if (ab_cut && bc_cut) {
173 vec3_t ab = a + kab*(b-a);
174 vec3_t bc = b + kbc*(c-b);
175 Tout.resize(3,vector<vec3_t>(3));
176 clinit(Tout[0]) = a,ab,bc;
177 clinit(Tout[1]) = ab,b,bc;
178 clinit(Tout[2]) = bc,c,a;
179 } else if (bc_cut && ca_cut) {
180 vec3_t bc = b + kbc*(c-b);
181 vec3_t ca = c + kca*(a-c);
182 Tout.resize(3,vector<vec3_t>(3));
183 clinit(Tout[0]) = a,bc,ca;
184 clinit(Tout[1]) = a,b,bc;
185 clinit(Tout[2]) = bc,c,ca;
186 } else if (ca_cut && ab_cut) {
187 vec3_t ca = c + kca*(a-c);
188 vec3_t ab = a + kab*(b-a);
189 Tout.resize(3,vector<vec3_t>(3));
190 clinit(Tout[0]) = a,ab,ca;
191 clinit(Tout[1]) = ab,b,ca;
192 clinit(Tout[2]) = b,c,ca;
193 } else {
194 Tout.resize(1,vector<vec3_t>(3));
195 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]);
206 V *= f16;
207 if (!neg && (V < 0)) {
208 V = -1e99;
210 return V; //fabs(V);
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);
217 return min(V1,V2);
219 double V = 0;
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);
225 return V;
229 double prismVol(vec3_t x0, vec3_t x1, vec3_t x2, vec3_t x3, vec3_t x4, vec3_t x5, bool neg)
231 double V = 0;
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);
238 return V;
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)
243 double V = 0;
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);
251 return V;
254 double triArea(vec3_t x0, vec3_t x1, vec3_t x2)
256 vec3_t a = x1-x0;
257 vec3_t b = x2-x0;
258 double A = 0.5*((a.cross(b)).abs());
259 return A;
262 double quadArea(vec3_t x0, vec3_t x1, vec3_t x2, vec3_t x3)
264 double A = 0;
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);
270 return A;
273 vec3_t triNormal(vec3_t x0, vec3_t x1, vec3_t x2)
275 vec3_t a = x1-x0;
276 vec3_t b = x2-x0;
277 vec3_t n = 0.5*(a.cross(b));
278 return n;
281 vec3_t quadNormal(vec3_t x0, vec3_t x1, vec3_t x2, vec3_t x3)
283 vec3_t n;
284 clinit(n) = 0,0,0;
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);
290 return n;
293 vec3_t triNormal(vtkUnstructuredGrid *grid, vtkIdType p1, vtkIdType p2, vtkIdType p3)
295 vec3_t x1, x2, x3;
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)
314 vtkIdType *pts;
315 vtkIdType npts;
316 vec3_t n(0,0,0);
317 grid->GetCellPoints(i, npts, pts);
318 if (npts == 3) {
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]);
322 } else {
323 EG_BUG;
325 return n;
328 double cellVA(vtkUnstructuredGrid *grid, vtkIdType cellId, bool neg)
330 vtkIdType *pts;
331 vtkIdType Npts;
332 vec3_t p[8];
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);
344 return 0.0;
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();
351 if(ptot2 <= 0) {
352 return 0.0;
353 } else {
354 double arg = (u*v)/sqrt(ptot2);
355 if(arg > 1.0) arg = 1.0;
356 if(arg < -1.0) arg = -1.0;
357 return acos(arg);
361 double deviation(vtkUnstructuredGrid *grid, vtkIdType p1, vtkIdType p2, vtkIdType p3)
363 vec3_t x1, x2, x3;
364 grid->GetPoint(p1,x1.data());
365 grid->GetPoint(p2,x2.data());
366 grid->GetPoint(p3,x3.data());
367 vec3_t u=x2-x1;
368 vec3_t v=x3-x2;
369 return angle(u,v);
372 double angle(vtkUnstructuredGrid *grid, vtkIdType p1, vtkIdType p2, vtkIdType p3)
374 vec3_t x1, x2, x3;
375 grid->GetPoint(p1,x1.data());
376 grid->GetPoint(p2,x2.data());
377 grid->GetPoint(p3,x3.data());
378 vec3_t u=x1-x2;
379 vec3_t v=x3-x2;
380 return angle(u,v);
383 double cosAngle(vtkUnstructuredGrid *grid, vtkIdType cell1, vtkIdType cell2)
385 vec3_t u1 = cellNormal(grid, cell1);
386 vec3_t u2 = cellNormal(grid, cell2);
387 u1.normalise();
388 u2.normalise();
389 return(u1*u2);
392 vec3_t getCenter(vtkUnstructuredGrid *grid, vtkIdType cellId, double& Rmin, double& Rmax)
394 vtkIdType *pts, Npts;
395 grid->GetCellPoints(cellId, Npts, pts);
396 if(Npts<=0) {
397 cout<<"FATAL ERROR: Npts<=0"<<endl;
398 abort();
401 //calculate center position
402 vec3_t xc(0,0,0);
403 for (vtkIdType i = 0; i < Npts; ++i) {
404 vec3_t xp;
405 grid->GetPoints()->GetPoint(pts[i], xp.data());
406 xc += xp;
408 xc = 1.0/(double)Npts * xc;
410 //calculate Rmin+Rmax
411 vec3_t xp;
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());
421 return(xc);
424 bool isInsideTriangle(vec2_t r, double tol)
426 if (r[0] < 0-tol || 1+tol < r[0] || r[1] < 0-tol || 1+tol < r[1] || r[0]+r[1] > 1+tol) {
427 return false;
429 return true;
432 bool intersectEdgeAndTriangle(const vec3_t& a, const vec3_t& b, const vec3_t& c,
433 const vec3_t& x1, const vec3_t& x2, vec3_t& xi, vec3_t& ri, double tol)
435 // triangle base
436 vec3_t g1 = b - a;
437 vec3_t g2 = c - a;
438 vec3_t g3 = g1.cross(g2);
439 g3.normalise();
441 // direction of the edge
442 vec3_t v = x2 - x1;
444 // parallel?
445 if (fabs(g3*v) < 1e-6) {
446 return false;
449 // compute intersection between straight and triangular plane
450 double k = intersection(x1, v, a, g3);
451 xi = x1 + k*v;
453 // transform xi to triangular base
454 mat3_t G;
455 G.column(0, g1);
456 G.column(1, g2);
457 G.column(2, g3);
459 mat3_t GI = G.inverse();
460 ri = xi - a;
461 ri = GI*ri;
464 vec3_t b = xi-a;
465 linsolve(G, b, ri);
469 // intersection outside of edge range?
470 if (k < 0 - tol) {
471 return false;
473 if (k > 1 + tol) {
474 return false;
477 // intersection outside of triangle?
478 if (!isInsideTriangle(vec2_t(ri[0],ri[1]),tol)) {
479 return false;
481 return true;
484 double distance(vtkUnstructuredGrid *grid, vtkIdType id_node1, vtkIdType id_node2) {
485 vec3_t A;
486 vec3_t B;
487 grid->GetPoints()->GetPoint(id_node1, A.data());
488 grid->GetPoints()->GetPoint(id_node2, B.data());
489 return((B-A).abs());
492 double distance2(vtkUnstructuredGrid *grid, vtkIdType id_node1, vtkIdType id_node2) {
493 vec3_t A;
494 vec3_t B;
495 grid->GetPoints()->GetPoint(id_node1, A.data());
496 grid->GetPoints()->GetPoint(id_node2, B.data());
497 return((B-A).abs2());
500 double areaOfCircumscribedCircle(vtkUnstructuredGrid *grid, vtkIdType id_cell) {
501 vtkIdType N_pts, *pts;
502 grid->GetCellPoints(id_cell, N_pts, pts);
503 vec3_t A,B,C;
504 grid->GetPoints()->GetPoint(pts[0], A.data());
505 grid->GetPoints()->GetPoint(pts[1], B.data());
506 grid->GetPoints()->GetPoint(pts[2], C.data());
507 double a=(C-B).abs();
508 double alpha=angle((B-A),(C-A));
509 double R=a/(2*sin(alpha));
510 return(M_PI*R*R);
513 void computeCircumscribedCircle(vec3_t a, vec3_t b, vec3_t c, vec3_t &x, double &radius)
515 double la = (b-c).abs();
516 double lb = (a-c).abs();
517 double lc = (a-b).abs();
518 double bca = sqr(la)*(sqr(lb) + sqr(lc) - sqr(la));
519 double bcb = sqr(lb)*(sqr(la) + sqr(lc) - sqr(lb));
520 double bcc = sqr(lc)*(sqr(la) + sqr(lb) - sqr(lc));
521 double sum = bca + bcb + bcc;
522 if (fabs(sum) < 1e-6) {
523 x = (1.0/3.0)*(a + b + c);
524 radius = 1e99;
525 } else {
526 x = bca*a + bcb*b + bcc*c;
527 x *= 1.0/sum;
528 radius = (x-a).abs();
532 vec3_t getBarycentricCoordinates(double x, double y)
534 if(isnan(x) || isinf(x) || isnan(y) || isinf(y)) {
535 qWarning()<<"x="<<x;
536 qWarning()<<"y="<<y;
537 EG_BUG;
540 double x_1=0;
541 double y_1=0;
542 double x_2=1;
543 double y_2=0;
544 double x_3=0;
545 double y_3=1;
547 mat2_t T;
548 T[0][0]=x_1-x_3; T[0][1]=x_2-x_3;
549 T[1][0]=y_1-y_3; T[1][1]=y_2-y_3;
551 if(T.det()==0) {
552 qWarning()<<"T.det()="<<T.det();
553 qWarning()<<T[0][0]<<T[0][1];
554 qWarning()<<T[1][0]<<T[1][1];
555 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];
556 EG_BUG;
559 double lambda_1 = ((y_2-y_3)*(x-x_3)-(x_2-x_3)*(y-y_3))/(T.det());
560 double lambda_2 = (-(y_1-y_3)*(x-x_3)+(x_1-x_3)*(y-y_3))/(T.det());
561 double lambda_3 = 1-lambda_1-lambda_2;
563 vec3_t bary_coords(lambda_1,lambda_2,lambda_3);
564 return bary_coords;
566 // initialize
567 /* double t1=0;
568 double t2=0;
569 double t3=0;*/
571 /* if(x==0) {
572 t3=y;
573 t1=1-y;
574 t2=0;
576 else if(y==0) {
577 t2=x;
578 t1=1-x;
579 t3=0;
581 else if((x+y)==1) {
584 else {
587 double k1,k2;
588 if(!intersection (k1, k2, t_A, t_M-t_A, t_B, t_C-t_B)) EG_BUG;
589 vec2_t t_I1 = t_A+k1*(t_M-t_A);
590 vec3_t g_nI1 = (1-k2)*g_nB + k2*g_nC;
591 vec2_t pm1_M(1.0/k1,0);
593 // normalize
594 double total = t1+t2+t3;
595 t1=t1/total;
596 t2=t2/total;
597 t3=t3/total;*/
599 /* t2 = x;
600 t3 = y;
601 t1 = 1-t2-t3;*/
603 // return value
604 // vec3_t bary_coords(t1,t2,t3);
605 // return bary_coords;
608 vec3_t intersectionOnPlane(vec3_t v, vec3_t A, vec3_t nA, vec3_t B, vec3_t nB)
610 vec3_t u = B-A;
611 // u.normalise();
612 v.normalise();
613 v = u.abs()*v;
615 //cout<<"u="<<u<<" v="<<v<<endl;
617 vec2_t p_A(0,0);
618 vec2_t p_B(1,0);
619 vec2_t p_nA = projectVectorOnPlane(nA,u,v);
620 vec2_t p_nB = projectVectorOnPlane(nB,u,v);
622 vec2_t p_tA = turnRight(p_nA);
623 vec2_t p_tB = turnRight(p_nB);
625 double k1, k2;
626 vec2_t p_K;
627 if(!intersection(k1, k2, p_A, p_tA, p_B, p_tB)) {
628 //qDebug()<<"WARNING: No intersection found!!!";
629 p_K = 0.5*(p_A + p_B);
631 else {
632 p_K = p_A + k1*p_tA;
635 //cout<<"nA="<<nA<<endl;
636 //cout<<"p_nA="<<p_nA<<endl;
637 //cout<<"p_tA="<<p_tA<<endl;
638 //cout<<"p_K="<<p_K<<endl;
639 if(p_K[0]<0) p_K[0] = 0;
640 if(p_K[0]>1) p_K[0] = 1;
641 vec3_t K = A + p_K[0]*u + p_K[1]*v;
642 //cout<<"K="<<K<<endl;
643 return K;
646 vec2_t projectVectorOnPlane(vec3_t V,vec3_t i,vec3_t j)
648 if(i.abs2()==0) EG_BUG;
649 if(j.abs2()==0) EG_BUG;
650 double x = V*i/i.abs2();
651 double y = V*j/j.abs2();
652 return vec2_t(x,y);
655 vec3_t projectPointOnPlane(const vec3_t& M, const vec3_t& A, const vec3_t& N)
657 double k = ((M-A)*N)/N.abs2();
658 return( M - k*N );
661 vec3_t projectPointOnEdge(const vec3_t& M,const vec3_t& A, const vec3_t& u)
663 checkVector(u);
664 if(u.abs2()==0) EG_BUG;
665 double k = ((M-A)*u)/u.abs2();
666 return A + k*u;
669 void cart2spherical(vec3_t x, double &alpha, double &beta, double &r)
671 r = x.abs();
672 static const vec3_t ex(1,0,0);
673 vec3_t xy(x[0],x[1],0);
674 if (x[1] >= 0) {
675 alpha = angle(ex, xy);
676 } else {
677 alpha = 2*M_PI - angle(xy, ex);
679 if (xy.abs2() > 0) {
680 if (x[2] >= 0) {
681 beta = angle(xy, x);
682 } else {
683 beta = -angle(xy, x);
685 } else {
686 beta = 0.5*M_PI;
690 } // namespace