Moka kernel
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
geometry.icc
Go to the documentation of this file.
1 /*
2  * lib-gmapkernel : Un noyau de 3-G-cartes et des opérations.
3  * Copyright (C) 2004, Moka Team, Université de Poitiers, Laboratoire SIC
4  * http://www.sic.sp2mi.univ-poitiers.fr/
5  * Copyright (C) 2009, Guillaume Damiand, CNRS, LIRIS,
6  * guillaume.damiand@liris.cnrs.fr, http://liris.cnrs.fr/
7  *
8  * This file is part of lib-gmapkernel
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 //******************************************************************************
25 #include "transformation-matrix.hh"
26 #include <cassert>
27 //******************************************************************************
28 INLINE
30  const CVertex& ALineVertex,
31  const CVertex& ALineDirection)
32 {
33  assert(!ALineDirection.isNull());
34 
35  TCoordinate n2 = ALineDirection.sqrNorm();
36 
37  assert(!isZero(n2));
38 
39  TCoordinate t =
40  ( ( AVertex.getX() - ALineVertex.getX() ) * ALineDirection.getX() +
41  ( AVertex.getY() - ALineVertex.getY() ) * ALineDirection.getY() +
42  ( AVertex.getZ() - ALineVertex.getZ() ) * ALineDirection.getZ() ) / n2;
43 
44  return ALineVertex + t*ALineDirection;
45 }
46 //******************************************************************************
47 INLINE
49  const TCoordinate& AA,
50  const TCoordinate& AB,
51  const TCoordinate& AC,
52  const TCoordinate& AD)
53 {
54  /* Le plan alpha pour équation A*x + B*y + C*z + D = 0.
55  *
56  * Soient X ,Y ,Z les coordonnées du point à projeter (AVertex).
57  * Soient XP,YP,ZP les coordonnées du point projeté sur le plan.
58  * La droite orthogonale au plan et passant par AVertex est définie par
59  * l'équation d'inconnues x y z et de paramètre t:
60  *
61  * (X-x)/A = (Y-y)/B = (Z-z)/C = t
62  *
63  * D'où:
64  *
65  * x = X + A*t
66  * y = Y + B*t
67  * z = Z + C*t
68  *
69  * Or le sommet (XP,YP,ZP) appartient à la droite et au plan. Donc:
70  *
71  * A*(X+A*t) + B*(Y+B*t) + C*(Z+C*t) + D = 0
72  *
73  * Cela permet de déterminer t:
74  *
75  * t = - (A*X + B*Y + C*Z + D) / (A^2 + B^2 + C^2)
76  *
77  * Et donc d'obtenir XP, YP et ZP...
78  */
79 
80 #define X (AVertex.getX())
81 #define Y (AVertex.getY())
82 #define Z (AVertex.getZ())
83 
84  TCoordinate t = - (AA*X + AB*Y + AC*Z + AD) / (sqr(AA) + sqr(AB) + sqr(AC));
85 
86  return CVertex(X + AA*t, Y + AB*t, Z + AC*t);
87 
88 #undef X
89 #undef Y
90 #undef Z
91 }
92 //******************************************************************************
93 INLINE
95  const CVertex& APlaneVertex,
96  const CVertex& APlaneNormal)
97 {
98  assert(!APlaneNormal.isNull());
99 
100  /* Soient X , Y , Z les coordonnées de AVertex.
101  * Soient X0, Y0, Z0 les coordonnées de APlaneVertex.
102  * Soient XN, YN, ZN les composantes de APlaneNormal.
103  *
104  * Le plan alpha pour équation A*x + B*y + C*z + D = 0, avec:
105  *
106  * A = XN
107  * B = YN
108  * C = ZN
109  * D = - (A*X0 + B*Y0 + C*Z0)
110  */
111 
112 #define A (APlaneNormal.getX())
113 #define B (APlaneNormal.getY())
114 #define C (APlaneNormal.getZ())
115 #define D (- (A * APlaneVertex.getX() + \
116  B * APlaneVertex.getY() + \
117  C * APlaneVertex.getZ()))
118 
119  return orthoProjectVertexOnPlane(AVertex, A, B, C, D);
120 
121 #undef A
122 #undef B
123 #undef C
124 #undef D
125 }
126 
127 /* Autre écriture:
128  *
129  * AVertex +
130  * APlaneNormal *
131  * (APlaneVertex.dot(APlaneNormal) - AVertex.dot(APlaneNormal)) /
132  * sqr(APlaneNormal.norm());
133  */
134 //******************************************************************************
135 INLINE
137  const CVertex& ACenter,
138  const TCoordinate& ACoef)
139 {
140  return ACenter + ACoef*(AVertex-ACenter);
141 }
142 //******************************************************************************
143 INLINE
145  const CVertex& ACenter,
146  const CVertex& ACoef)
147 {
148  return ACenter + ACoef.multiply(AVertex-ACenter);
149 }
150 //******************************************************************************
151 INLINE
153  const CVertex& ALineVertex,
154  const CVertex& ALineDirection,
155  const TCoordinate& ACoef)
156 {
157  assert(!ALineDirection.isNull());
158  CVertex center = orthoProjectVertexOnLine(AVertex,
159  ALineVertex, ALineDirection);
160  return center + ACoef*(AVertex-center);
161 }
162 //******************************************************************************
163 INLINE
165  const CVertex& APlaneVertex,
166  const CVertex& APlaneNormal,
167  const TCoordinate& ACoef)
168 {
169  assert(!APlaneNormal.isNull());
170  CVertex center = orthoProjectVertexOnPlane(AVertex,
171  APlaneVertex, APlaneNormal);
172  return center + ACoef*(AVertex-center);
173 }
174 //******************************************************************************
175 INLINE
177  const CVertex& AOtherVertex)
178 {
179  return (AVertex-AOtherVertex).norm();
180 }
181 //******************************************************************************
182 INLINE
184  const CVertex& ALineVertex,
185  const CVertex& ALineDirection)
186 {
187  CVertex proj = orthoProjectVertexOnLine(AVertex, ALineVertex, ALineDirection);
188  return (AVertex-proj).norm();
189 }
190 //******************************************************************************
191 INLINE
193  const CVertex& APlaneVertex,
194  const CVertex& APlaneNormal)
195 {
196  CVertex proj = orthoProjectVertexOnPlane(AVertex, APlaneVertex, APlaneNormal);
197  return (AVertex-proj).norm();
198 }
199 //******************************************************************************
200 INLINE
202  const CVertex& AVector2,
203  const CVertex& ANormal)
204 {
205  assert(!AVector1.isNull());
206  assert(!AVector2.isNull());
207 
208  CVertex V1 = AVector1 / AVector1.norm();
209  CVertex V2 = AVector2 / AVector2.norm();
210 
211  if ((V1+V2).isNull())
212  {
213  if (ANormal.isNull())
214  return getNormalVector(V1);
215  else
216  return V1*ANormal;
217  }
218  else
219  {
220  if (isPositive((AVector1*AVector2).dot(ANormal)))
221  return V1+V2;
222  else
223  return -(V1+V2);
224  }
225 }
226 //******************************************************************************
227 INLINE
229 {
230  assert(!AVector.isNull());
231 
232  if (isZero(AVector.getX()))
233  return AVector.norm()*OX;
234 
235  // if (isZero(AVector.getY())) return OY;
236  // if (isZero(AVector.getZ())) return OZ;
237 
238  CVertex V(-AVector.getY(), AVector.getX(), 0);
239 
240  return (AVector.norm()/V.norm()) * V;
241 }
242 //******************************************************************************
243 INLINE
245  const CVertex& AVector2)
246 {
247  TCoordinate n1 = AVector1.norm();
248  TCoordinate n2 = AVector2.norm();
249 
250  CVertex V = AVector1*AVector2;
251 
252  if (V.isNull())
253  return ORIGIN;
254 
255  assert(!isZero(n1));
256  assert(!isZero(n2));
257 
258  return ((n1+n2)/(2*V.norm()))*V;
259 }
260 //******************************************************************************
261 INLINE
263  const CVertex& AVertex2,
264  const CVertex& AVertex3)
265 { return getNormalVector(AVertex2-AVertex1, AVertex3-AVertex2); }
266 //******************************************************************************
267 INLINE
269  const CVertex& ALine1Vertex2,
270  const CVertex& ALine2Vertex1,
271  const CVertex& ALine2Vertex2)
272 {
273  assert(ALine1Vertex1 != ALine1Vertex2);
274  assert(ALine2Vertex1 != ALine2Vertex2);
275 
276 #define A (ALine1Vertex1)
277 #define B (ALine1Vertex2)
278 #define C (ALine2Vertex1)
279 #define D (ALine2Vertex2)
280 
281  CVertex AB = B - A;
282  CVertex CD = D - C;
283  CVertex AC = C - A;
284 
285  CVertex ABvCD = AB*CD;
286 
287  TCoordinate t = det(AC,CD,ABvCD) / ABvCD.sqrNorm();
288 
289  return A + t*AB;
290 
291 #undef A
292 #undef B
293 #undef C
294 #undef D
295 }
296 //******************************************************************************
297 INLINE
298 bool CGeometry::areColinear(const CVertex& AVector1,
299  const CVertex& AVector2)
300 {
301  return (AVector1*AVector2).isNull();
302 }
303 //******************************************************************************
304 INLINE
306  const CVertex& AVector2,
307  const CVertex& ANormal)
308 {
309  // Formule: V1.V2 = Norm(V1) * Norm(V2) * Cos ( Angle(V1,V2) )
310 
311  CVertex v1 = AVector1;
312  CVertex v2 = AVector2;
313  CVertex n = ANormal;
314 
315  if (!v1.isNull()) v1 /= v1.norm();
316  if (!v2.isNull()) v2 /= v2.norm();
317  if (!n .isNull()) n /= n .norm();
318 
319  TCoordinate cosinus = v1.dot(v2);
320 
321  if (cosinus > +1) cosinus = +1;
322  if (cosinus < -1) cosinus = -1;
323 
324  TCoordinate angle = dAcos(cosinus);
325 
326  return isPositive((v1*v2).dot(n)) ? +angle : -angle;
327 }
328 //******************************************************************************
329 INLINE
331  const CVertex& AVz)
332 {
333  if (AVx.isNull() || AVz.isNull())
334  return ORIGIN;
335 
336  CTransformationMatrix matrix;
337 
338  CVertex Vx(orthoProjectVertexOnPlane(AVx, ORIGIN, AVz));
339  CVertex Vy(AVz*Vx);
340  CVertex Vz(AVz);
341 
342  TCoordinate alpha,beta,gamma;
343 
344  // gamma (pour obtenir: Vy.getX()==0 && Vy.getY()>0)
345  // Après rotation, Vy doit se retrouver sur le vecteur N.
346  // N est tel que: N.Vz==0 et N.getX()==0,
347  // donc N = Vertex(0,Vz.getZ(),-Vz.getY())
348 
349  gamma = getAngle(CVertex(0,+Vz.getZ(),-Vz.getY()),Vy, Vz);
350 
351  matrix.rotate(Vz, -gamma);
352  matrix.applyOn(Vx);
353  matrix.applyOn(Vy);
354 
355  // beta (pour obtenir: Vx.getZ()==0)
356 
357  beta = getAngle(OX,Vx, Vy);
358 
359  matrix.setToIdentity();
360  matrix.rotate(Vy, -beta);
361  matrix.applyOn(Vx);
362  matrix.applyOn(Vz);
363 
364  // alpha (pour obtenir: Vz.getY()==0)
365 
366  alpha = getAngle(OZ,Vz, Vx);
367 
368  return CVertex(alpha,beta,gamma);
369 }
370 //******************************************************************************
371 INLINE
373  const CVertex& ALineVertex,
374  const CVertex& ALineDirection,
375  const CVertex& APlaneNormal)
376 {
377  assert(!ALineDirection.isNull());
378  assert(!APlaneNormal.isNull());
379 
380  CVertex direction = ALineDirection / ALineDirection.norm();
381  CVertex normal = APlaneNormal / APlaneNormal .norm();
382 
383  return sign((direction * normal).dot(AVertex-ALineVertex));
384 }
385 //******************************************************************************
386 INLINE
388  const CVertex& AVertexB,
389  const CVertex& AVertexC,
390  const CVertex& AVertexD,
391  const CVertex& APlaneNormal,
392  int& AIntersection1On,
393  CVertex& AIntersection1,
394  int& AIntersection2On,
395  CVertex& AIntersection2)
396 {
397  assert(!APlaneNormal.isNull());
398 
399  bool nullLength1 = AVertexA == AVertexB;
400  bool nullLength2 = AVertexC == AVertexD;
401 
402  // Cas où un des deux segments au moins est de longueur nulle:
403  if (nullLength1 || nullLength2)
404  {
405  // Les deux segments sont de longueur nulle, pas d'intersection:
406  if (nullLength1 && nullLength2)
407  {
408  AIntersection1On = AIntersection2On = 0;
409  return;
410  }
411 
412  // Un seul segment est de longueur nulle.
413  // Il y alpha au plus un sommet à insérer:
414  AIntersection1On = 0;
415  AIntersection2On = 0;
416 
417  return;
418  }
419 
420  // Les deux segments ne sont pas de longueur nulle:
421  CVertex directionAB = AVertexB - AVertexA;
422  CVertex directionCD = AVertexD - AVertexC;
423 
424  int A = localiseVertexComparedToLine(AVertexA,
425  AVertexC, directionCD,
426  APlaneNormal);
427 
428  int B = localiseVertexComparedToLine(AVertexB,
429  AVertexC, directionCD,
430  APlaneNormal);
431 
432  if (A==0 && B==0)
433  {
434  // Les deux arêtes sont alignées (co-raffinement 1d):
435  // Tri de A, B, C et D:
436  const CVertex * vertices[4] =
437  { & AVertexA, & AVertexB, & AVertexC, & AVertexD };
438 
439  CVertex normal = directionAB * APlaneNormal;
440 
441  assert(!normal.isNull());
442  normal /= normal.norm();
443 
444  int i,j;
445 
446  // Tri à bulle, guère moins efficace qu'un quick-sort vu la taille du
447  // tableau (4 éléments):
448  for (i=0; i<3; ++i)
449  for (j=i+1; j<4; ++j)
450  if (localiseVertexComparedToLine(*vertices[i], *vertices[j],
451  normal, APlaneNormal) == 1)
452  {
453  const CVertex * tmp = vertices[i];
454  vertices[i] = vertices[j];
455  vertices[j] = tmp;
456  }
457 
458  bool firstSegment[4];
459 
460  for (i=0; i<4; ++i)
461  firstSegment[i] = vertices[i]==&AVertexA || vertices[i]==&AVertexB;
462 
463  // Intersections:
464  if (firstSegment[0]==firstSegment[1])
465  {
466  // Les segments sont disjoints:
467  AIntersection1On = AIntersection2On = 0;
468  }
469  else
470  {
471  // Les segments se chevauchent, ou l'un est compris dans l'autre:
472  if (*vertices[0] == *vertices[1])
473  AIntersection1On = 0;
474  else
475  {
476  AIntersection1On = firstSegment[0] ? 1 : 2;
477  AIntersection1 = * vertices[1];
478  }
479 
480  if (*vertices[2] == *vertices[3])
481  AIntersection2On = 0;
482  else
483  {
484  AIntersection2On = firstSegment[3] ? 1 : 2;
485  AIntersection2 = * vertices[2];
486  }
487  }
488  }
489  else
490  {
491  // Les deux arêtes sont disjointes ou se croisent en un point unique:
492  int C = localiseVertexComparedToLine(AVertexC,
493  AVertexA, directionAB,
494  APlaneNormal);
495 
496  int D = localiseVertexComparedToLine(AVertexD,
497  AVertexA, directionAB,
498  APlaneNormal);
499 
500  // assert(C!=0 || D!=0);
501 
502  int combineAB = combineSigns(A,B);
503  int combineCD = combineSigns(C,D);
504 
505  AIntersection1On = (combineAB==-1 && combineCD<=0) ? 1 : 0;
506  AIntersection2On = (combineCD==-1 && combineAB<=0) ? 2 : 0;
507 
508  if (AIntersection1On!=0 || AIntersection2On!=0)
509  {
510  AIntersection1 = AIntersection2 =
511  getLinesIntersection(AVertexA, AVertexB, AVertexC, AVertexD);
512  }
513  }
514 }
515 //******************************************************************************
516 INLINE
518  const CVertex& AVertexB,
519  const CVertex& AVertexC,
520  const CVertex& AVertexD,
521  int& AIntersection1On,
522  CVertex& AIntersection1,
523  int& AIntersection2On,
524  CVertex& AIntersection2)
525 {
526  getSegmentsIntersection(AVertexA, AVertexB, AVertexC, AVertexD,
527  OZ,
528  AIntersection1On, AIntersection1,
529  AIntersection2On, AIntersection2);
530 }
531 //******************************************************************************
532 INLINE
534  const CVertex& AVertex2,
535  const CVertex& AVertex3)
536 {
537 #define A (AVertex1)
538 #define B (AVertex2)
539 #define C (AVertex3)
540 
541  CVertex AB = B - A;
542  CVertex AC = C - A;
543 
544  if (CGeometry::areColinear(AB,AC))
545  return A;
546  else
547  return AC * (AB * AC);
548 
549 #undef A
550 #undef B
551 #undef C
552 }
553 //******************************************************************************