Moka kernel
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gmv-geometry.cc
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 "g-map-vertex.hh"
26 #include "geometry.hh"
27 using namespace GMap3d;
28 //******************************************************************************
30  int AOrbitMark, int ATreatedMark,
31  int ADirectInfoVertex)
32 {
33  assert(ADart!=NULL);
34  assert(AOrbit==ORBIT_012 || AOrbit==ORBIT_123 || AOrbit==ORBIT_0123);
35  assert(AOrbitMark >=0 && AOrbitMark <NB_MARKS);
36  assert(ATreatedMark>=0 && ATreatedMark<NB_MARKS);
37  assert(ADirectInfoVertex<NB_DIRECT_INFO);
38 
39  CVertex bary(ORIGIN);
40  int n = 0;
41 
42  CCoverage * cov = getBasicDynamicCoverage(ADart, AOrbit, AOrbitMark);
43  assert(cov!=NULL);
44 
45  TOrbit orbit = AND_ORBIT(ORBIT_VERTEX, AOrbit);
46 
47  for (; cov->cont(); ++(*cov))
48  if (!isMarked(**cov, ATreatedMark))
49  {
50  bary +=
51  ADirectInfoVertex>=0
52  ? * getDirectInfoAsAttributeVertex(**cov, ADirectInfoVertex)
53  : * findVertex(**cov);
54 
55  ++n;
56  markOrbit(**cov, orbit, ATreatedMark);
57  }
58 
59  delete cov;
60 
61  return n==0 ? ORIGIN : bary/n;
62 }
63 //******************************************************************************
65  int ADirectInfoVertex)
66 {
67  assert(ADart!=NULL);
68 
69  CVertex bary(ORIGIN);
70  int n = 0;
71  int treated = getNewMark();
72 
73  CCoverage * cov;
74  TOrbit orbit;
75 
76  if (AOrbit>=ORBIT_BORDER_0 && AOrbit<=ORBIT_BORDER_3)
77  {
78  cov = getStaticCoverage(ADart, AOrbit);
79  orbit = ORBIT_VERTEX;
80  }
81  else
82  {
83  cov = getDynamicCoverage(ADart, AOrbit);
84  orbit = AND_ORBIT(AOrbit, ORBIT_VERTEX);
85  }
86 
87  assert(cov!=NULL);
88 
89  for (; cov->cont(); ++(*cov))
90  if (!isMarked(**cov, treated))
91  {
92  bary +=
93  ADirectInfoVertex>=0
94  ? * getDirectInfoAsAttributeVertex(**cov, ADirectInfoVertex)
95  : * findVertex(**cov);
96 
97  ++n;
98  markOrbit(**cov, orbit, treated);
99  }
100 
101  // Démarquage:
102  if (AOrbit>=ORBIT_BORDER_0 && AOrbit<=ORBIT_BORDER_3)
103  {
104  for (cov->reinit(); cov->cont(); ++(*cov))
105  if (isMarked(**cov, treated))
106  unmarkOrbit(**cov, ORBIT_VERTEX, treated);
107  }
108  else
109  unmarkOrbit(ADart, AOrbit, treated);
110 
111  delete cov;
112 
113  freeMark(treated);
114 
115  return n==0 ? ORIGIN : bary/n;
116 }
117 //******************************************************************************
119 {
120  CVertex bary(ORIGIN);
121  int n=0;
122 
123  int treated= getNewMark();
124 
125  for (CDynamicCoverageAll it(this); it.cont(); ++it)
126  {
127  if (!isMarked(*it, treated))
128  {
129  if (isMarked(*it, AMarkNumber))
130  {
131  bary += * findVertex(*it);
132  ++n;
133  markOrbit(*it, ORBIT_VERTEX, treated);
134  }
135  else
136  setMark(*it, treated);
137  }
138  }
139 
140  negateMaskMark(treated);
141  freeMark(treated);
142 
143  return n==0 ? ORIGIN : bary/n;
144 }
145 //******************************************************************************
147 {
148  CVertex bary(ORIGIN);
149  int n=0;
150 
151  for (CDynamicCoverageAll it(this); it.cont(); ++it)
152  if (getDirectInfo(*it, ADirectInfoVertex) != NULL)
153  {
154  bary += * getDirectInfoAsVertex(*it, ADirectInfoVertex);
155  ++n;
156  }
157 
158  return n==0 ? ORIGIN : bary/n;
159 }
160 //******************************************************************************
161 void CGMapVertex::boundingBox(int AMarkNumber, CVertex & AMin, CVertex & AMax)
162 {
163  bool first = true;
164  int treated = getNewMark();
165 
166  for (CDynamicCoverageAll it(this); it.cont(); ++it)
167  if (! isMarked(*it, treated))
168  {
169  if (isMarked(*it, AMarkNumber))
170  {
171  markOrbit(*it, ORBIT_VERTEX, treated);
172 
173  CVertex & vertex = * findVertex(*it);
174 
175  if (first)
176  {
177  first = false;
178  AMin = AMax = vertex;
179  }
180  else
181  {
182  if (vertex.getX() < AMin.getX()) AMin.setX(vertex.getX());
183  if (vertex.getY() < AMin.getY()) AMin.setY(vertex.getY());
184  if (vertex.getZ() < AMin.getZ()) AMin.setZ(vertex.getZ());
185 
186  if (vertex.getX() > AMax.getX()) AMax.setX(vertex.getX());
187  if (vertex.getY() > AMax.getY()) AMax.setY(vertex.getY());
188  if (vertex.getZ() > AMax.getZ()) AMax.setZ(vertex.getZ());
189  }
190  }
191  else
192  setMark(*it, treated);
193  }
194 
195  if (first == true)
196  AMin = AMax = ORIGIN;
197 
198  negateMaskMark(treated);
199  freeMark(treated);
200 }
201 //******************************************************************************
203 {
204  CVertex min, max;
205 
206  boundingBox(AMarkNumber, min, max);
207 
208  return (min + max) / 2;
209 }
210 //******************************************************************************
211 void CGMapVertex::boundingBox(CDart * ADart, TOrbit AOrbit,
212  CVertex & AMin, CVertex & AMax)
213 {
214  assert(ADart != NULL);
215 
216  bool first = true;
217  int treated = getNewMark();
218  CCoverage * cov = getDynamicCoverage(ADart, AOrbit);
219 
220  for (; cov->cont(); ++(*cov))
221  if (! isMarked(**cov, treated))
222  {
223  markOrbit(**cov, AND_ORBIT(AOrbit, ORBIT_VERTEX), treated);
224 
225  CVertex & vertex = * findVertex(**cov);
226 
227  if (first)
228  {
229  first = false;
230  AMin = AMax = vertex;
231  }
232  else
233  {
234  if (vertex.getX() < AMin.getX()) AMin.setX(vertex.getX());
235  if (vertex.getY() < AMin.getY()) AMin.setY(vertex.getY());
236  if (vertex.getZ() < AMin.getZ()) AMin.setZ(vertex.getZ());
237 
238  if (vertex.getX() > AMax.getX()) AMax.setX(vertex.getX());
239  if (vertex.getY() > AMax.getY()) AMax.setY(vertex.getY());
240  if (vertex.getZ() > AMax.getZ()) AMax.setZ(vertex.getZ());
241  }
242  }
243 
244  assert(first == false);
245 
246  unmarkOrbit(ADart, AOrbit, treated);
247  freeMark(treated);
248  delete cov;
249 }
250 //******************************************************************************
252 {
253  assert(ADart != NULL);
254  CVertex min, max;
255 
256  boundingBox(ADart, AOrbit, min, max);
257 
258  return (min + max) / 2;
259 }
260 //******************************************************************************
261 #define PUSH(STACK,V) \
262 ( \
263  (STACK)[1]= (STACK)[0], \
264  (STACK)[0]= (V) \
265 )
266 
267 #define DISTANCE(STACK) \
268 ( \
269  (*(STACK)[0] - *(STACK)[1]).norm() \
270 )
271 //******************************************************************************
272 // Méthode protégée!
274 {
275  assert(ADart!=NULL);
276  assert(AOrbit==ORBIT_0 || AOrbit==ORBIT_BORDER_1 ||
277  AOrbit==ORBIT_01 || AOrbit==ORBIT_BORDER_2);
278 
279  TCoordinate length=0;
280 
281  // Dans le cas d'une orbite ouverte (face ouverte, 2-bord ouvert),
282  // on commence à partir du premier brin 0-cousu.
283  {
284  CCoverage * firstIt = getDynamicCoverage(ADart, AOrbit);
285 
286  while (firstIt->cont() && firstIt->prevOperationType()!=OP_JUMP)
287  ADart= (*firstIt)++;
288 
289  delete firstIt;
290  }
291 
292  {
293  CCoverage * it = getDynamicCoverage(ADart, AOrbit);
294  CVertex * stack[2] = { NULL, NULL };
295 
296  if (isFree0(**it))
297  ++(*it);
298 
299  // On récupère le premier sommet et on avance d'un brin seulement
300  // (pour à la fin du parcours pouvoir récupérer le dernier sommet)
301  PUSH(stack, findVertex((*it)++));
302 
303  // On parcourt le reste de l'orbite en avançant de 2 brins à chaque fois:
304  while (it->cont())
305  {
306  PUSH(stack, findVertex((*it)++));
307  length+= DISTANCE(stack);
308 
309  if (it->cont()) ++(*it);
310  }
311 
312  delete it;
313  }
314 
315  return length;
316 }
317 //******************************************************************************
318 #undef DISTANCE
319 #undef PUSH
320 //******************************************************************************
322 {
323  assert(ADart!=NULL);
324 
325  if (isFree0(ADart))
326  return 0;
327 
328  return (*findVertex(ADart) - *findVertex(alpha0(ADart))).norm();
329 }
330 //******************************************************************************
332 {
333  assert(ADart!=NULL);
334  return orbitLength(ADart, ORBIT_01);
335 }
336 //******************************************************************************
338 {
339  assert(ADart!=NULL);
340  return orbitLength(ADart, ORBIT_BORDER_1);
341 }
342 //******************************************************************************
344 {
345  assert(ADart!=NULL);
346  return orbitLength(ADart, ORBIT_BORDER_2);
347 }
348 //******************************************************************************
349 #define PUSH(STACK,V) \
350 ( \
351  (STACK)[2]=(STACK)[1], \
352  (STACK)[1]=(STACK)[0], \
353  (STACK)[0]=(V) \
354 )
355 
356 #define NORMAL(STACK) \
357 ( \
358  CGeometry::getNormalVector(*(STACK)[0] - *(STACK)[1] , \
359  *(STACK)[2] - *(STACK)[1] ) \
360 )
361 //******************************************************************************
362 // Méthode protégée!
364 {
365  assert(ADart!=NULL);
366  assert(AOrbit==ORBIT_01 || AOrbit==ORBIT_BORDER_2);
367 
368  CVertex normal(ORIGIN);
369  int nbEdges = 0;
370  bool closed;
371 
372  // On teste d'abord si l'orbite est ouverte ou fermée:
373  // (Sensé pour un 2-bord ou une face seulement...)
374  if (isFree1(ADart))
375  {
376  if (isFree0(ADart))
377  return OX;
378 
379  closed = false;
380  }
381  else
382  {
383  // On place ADart sur l'extrémité qui lui est opposée:
384  CVertex * vertex0 = findVertex(ADart);
385  CDart * current=NULL;
386  CCoverage * cov = getDynamicCoverage(ADart, AOrbit);
387 
388  while (cov->cont())
389  current = (*cov)++;
390 
391  closed = vertex0==findVertex(current);
392  ADart = closed ? ADart : current;
393 
394  delete cov;
395  }
396 
397  // Dans le cas d'une orbite ouverte (face ouverte, 2-bord ouvert),
398  // on commence à partir du premier brin 0-cousu.
399  // Si l'orbite est fermée, le brin de départ est quelconque.
400  {
401  CCoverage * it = getDynamicCoverage(ADart, AOrbit);
402  CVertex * stack[3] = { NULL, NULL, NULL };
403  CVertex * second;
404 
405  if (isFree0(**it))
406  ++(*it);
407 
408  // On récupère le premier sommet et on avance d'un brin seulement
409  // (pour à la fin du parcours pouvoir récupérer le dernier sommet)
410  PUSH(stack, findVertex((*it)++));
411 
412  if (!it->cont())
413  {
414  delete it;
415  return OX;
416  }
417 
418  // On récupère le deuxième sommet:
419  // (mémorisé pour le calcul du dernier produit vectoriel)
420  PUSH(stack, second = findVertex((*it)++));
421 
422  if (it->cont())
423  ++(*it);
424 
425  if (!it->cont())
426  {
427  delete it;
428  return CGeometry::getNormalVector(*stack[0] - *stack[1]);
429  }
430 
431  // On parcourt le reste de l'orbite en avançant de 2 brins à chaque fois:
432  while (it->cont())
433  {
434  PUSH(stack, findVertex((*it)++));
435  normal+= NORMAL(stack);
436  ++nbEdges;
437 
438  if (it->cont())
439  ++(*it);
440  }
441 
442  delete it;
443 
444  // Si l'orbite est fermée, il reste à calculer le dernier produit vectoriel:
445  if (closed)
446  {
447  PUSH(stack, second);
448  normal+= NORMAL(stack);
449  ++nbEdges;
450  }
451  }
452 
453  if (normal.isNull())
454  return OZ;
455 
456  assert(nbEdges>0);
457 
458  // Formule telle qu'un carré de côté 1 ait une normale de norme 1:
459  return normal/(2*sqrt(static_cast<double>(nbEdges)));
460 }
461 //******************************************************************************
462 #undef NORMAL
463 #undef PUSH
464 //******************************************************************************
466 {
467  assert(ADart!=NULL);
468 
469  return * findVertex(alpha0(ADart)) - * findVertex(ADart);
470 }
471 //******************************************************************************
473 {
474  assert(ADart!=NULL);
475 
476  CVertex vector = edgeVector(ADart);
477 
478  if (vector.isNull())
479  return OX;
480 
481  return CGeometry::getNormalVector(vector);
482 }
483 //******************************************************************************
485 {
486  assert(ADart!=NULL);
487  return orbitNormalVector(ADart, ORBIT_01);
488 }
489 //******************************************************************************
491 {
492  assert(0<=ADim && ADim<=2);
493 
494  if (ADim==2)
495  return faceNormalVector(ADart);
496 
497  if (ADim==1)
498  return edgeNormalVector(ADart);
499 
500  return OX;
501 }
502 //******************************************************************************
504 {
505  assert(ADart!=NULL);
506  return orbitNormalVector(ADart, ORBIT_BORDER_2);
507 }
508 //******************************************************************************
510 {
511  assert(ADart!=NULL);
512  assert(ADim>=0 && ADim<=2);
513 
514  /* Attention: dans tous les calculs on ne prend pas en compte les faces
515  * 3-cousues car il faudrait comptabiliser un vecteur normal par demi-face, or
516  * ces deux vecteurs sont opposés...
517  */
518 
519  TOrbit orbitCell = AND_ORBIT(ORBIT_CELL[ADim], NEG_ORBIT(ORBIT_3));
520 
521  /* Si ADim==0, orbitCell = ORBIT_12
522  * (Moyenne des vecteurs normaux des faces incidentes au sommet)
523  *
524  * Si ADim==1, orbitCell = ORBIT_02
525  * (Moyenne des vecteurs normaux des faces incidentes à l'arête)
526  *
527  * Si ADim==3, orbtiCell = ORBIT_01
528  * (Moyenne des vecteurs normaux des faces incidentes à la face)
529  */
530 
531  CVertex normal = ORIGIN;
532  int n = 0;
533 
534  int toTreat = getNewMark();
535 
536  halfMarkOrbit(ADart, orbitCell, toTreat);
537 
538  CCoverage * cov = getDynamicCoverage(ADart, orbitCell);
539 
540  for (; cov->cont(); ++(*cov))
541  if (isMarked(**cov, toTreat))
542  {
543  if (ADim==2)
544  {
545  if (!isFree2(**cov))
546  {
547  normal -= faceNormalVector(alpha(**cov, ADim));
548  ++n;
549  }
550  }
551  else
552  {
553  normal += faceNormalVector(**cov);
554  ++n;
555  }
556 
557  unsetMark(**cov, toTreat);
558  }
559 
560  delete cov;
561 
562  freeMark(toTreat);
563 
564  return normal/(n==0 ? 1 : n);
565 }
566 //******************************************************************************
568  int AMarkNumber)
569 {
570  assert(ADart!=NULL);
571  assert(ADim>=0 && ADim<=2);
572  assert(AMarkNumber>=0);
573 
574  CVertex normal = ORIGIN;
575  int n = 0;
576 
577  int toTreat = getNewMark();
578 
579  markCopy(AMarkNumber, toTreat, ADart, ORBIT_CELL[ADim]);
580 
581  CCoverage * cov = getDynamicCoverage(ADart, ORBIT_CELL[ADim]);
582 
583  for (; cov->cont(); ++(*cov))
584  if (isMarked(**cov, toTreat))
585  {
586  if (ADim==2)
587  {
588  if (!isFree2(**cov))
589  {
590  normal -= faceNormalVector(alpha(**cov, ADim));
591  ++n;
592  }
593  }
594  else
595  {
596  normal += faceNormalVector(**cov);
597  ++n;
598  }
599 
600  unsetMark(**cov, toTreat);
601  }
602 
603  delete cov;
604 
605  freeMark(toTreat);
606 
607  return normal/(n==0 ? 1 : n);
608 }
609 //******************************************************************************
611 {
612  assert(ADart!=NULL);
613  assert(3 <= ADim && ADim <= 4);
614 
615  if (!isOrientable(ADart, ORBIT_CELL[ADim]))
616  return ORIGIN;
617 
618  TOrbit pieceOfFace = AND_ORBIT(ORBIT_CELL[2], ORBIT_CELL[ADim]);
619 
620  int treated = getNewMark();
621  int out = getNewMark();
622 
623  halfMarkOrbit(ADart, ORBIT_CELL[ADim], out);
624 
625  CCoverage * cov = getDynamicCoverage(ADart, ORBIT_CELL[ADim]);
626 
627  CVertex normal = ORIGIN;
628  int nbFaces = 0;
629 
630  for (; cov->cont(); ++(*cov))
631  if (!isMarked(**cov, treated) && isMarked(**cov, out))
632  {
633  markOrbit(**cov, pieceOfFace, treated);
634 
635  if (ADim==3 || isFree3(**cov))
636  {
637  normal += faceNormalVector(**cov);
638  ++nbFaces;
639  }
640  }
641 
642  for (cov->reinit(); cov->cont(); ++(*cov))
643  {
644  unsetMark(**cov, treated);
645  unsetMark(**cov, out);
646  }
647 
648  delete cov;
649 
650  freeMark(treated);
651  freeMark(out);
652 
653  if (nbFaces>0)
654  normal /= nbFaces;
655 
656  return normal;
657 }
658 //******************************************************************************