Moka kernel
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
gmg-merge.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-generic.hh"
26 using namespace GMap3d;
27 //******************************************************************************
28 // Fusion de 2 i-cellules incidentes à deux brins donnés.
29 //
30 // dim == 3: fusion de volumes ie 2-décousures et 2-coutures
31 // dim == 2: fusion de faces ie 1-décousures et 1-coutures
32 // dim == 1: fusion d' arêtes ie 0-décousures et 0-coutures
33 //
34 //******************************************************************************
36 {
37  assert(ADart!=NULL);
38 
39  if (!isFree3(ADart)) return 3;
40  if (!isFree2(ADart)) return 2;
41  if (!isFree1(ADart)) return 1;
42  if (!isFree0(ADart)) return 0;
43 
44  return -1;
45 }
46 //******************************************************************************
47 bool CGMapGeneric::canMerge(CDart * ADart1, CDart * ADart2, int ADim)
48 {
49  assert(ADart1!=NULL && ADart2!=NULL);
50  assert(ADim>=1 || ADim<=3);
51 
52  // Il faut que les cellules de dimension ADim-1 incidentes à ADart1 et ADart2
53  // soient de degré 1 ou 2, c'est-à-dire incidentes à 1 ou 2 cellules de
54  // dimension ADim:
55 
56  if (isSameOrbit(ADart1, ADart2, ORBIT_CELL[ADim-1]))
57  {
58  if (degree(ADart1, ADim-1) > 2)
59  return false;
60  }
61  else
62  {
63  if (degree(ADart1, ADim-1) + degree(ADart2, ADim-1) > 2)
64  return false;
65  }
66 
67  // Il faut vérifier que les brins des deux cellules peuvent être fusionnés
68  // deux-à-deux:
69  TOrbit halfCell = SUB_ORBIT(ORBIT_CC, ORBIT_I_IP1[ADim-1]);
70 
71  CCoverage * cov1 = getDynamicCoverage(ADart1, halfCell);
72  CCoverage * cov2 = getDynamicCoverage(ADart2, halfCell);
73 
74  while (cov1->cont() && cov2->cont() &&
75  cov1->prevOperationType()==cov2->prevOperationType())
76  {
77  ++(*cov1);
78  ++(*cov2);
79  }
80 
81  bool ok = !cov1->cont() && !cov2->cont();
82 
83  delete cov1;
84  delete cov2;
85 
86  return ok;
87 }
88 //******************************************************************************
89 void CGMapGeneric::merge(CDart * ADart1, CDart * ADart2, int ADim,
90  bool ADeleteDarts)
91 {
92  assert(ADart1!=NULL && ADart2!=NULL);
93  assert(ADim>=1 && ADim<=3);
94  assert(canMerge(ADart1, ADart2, ADim));
95 
96  TOrbit halfCell = SUB_ORBIT(ORBIT_CC, ORBIT_I_IP1[ADim-1]);
97 
98  CCoverage * it1 = getStaticCoverage(ADart1, halfCell);
99  CCoverage * it2 = getStaticCoverage(ADart2, halfCell);
100 
101  for (; it1->cont(); ++(*it1), ++(*it2))
102  {
103  bool bothLinked = !isFree(**it1,ADim-1) && !isFree(**it2,ADim-1);
104 
105  CDart * t1 = alpha(**it1, ADim-1);
106  CDart * t2 = alpha(**it2, ADim-1);
107 
108  if (!isFree(t1,ADim-1)) unsew(t1,ADim-1);
109  if (!isFree(t2,ADim-1)) unsew(t2,ADim-1);
110 
111  if (bothLinked)
112  sew(t1,t2,ADim-1);
113  }
114 
115  if (ADeleteDarts)
116  for (it1->reinit(), it2->reinit(); it1->cont(); )
117  {
118  delMapDart((*it1)++);
119  delMapDart((*it2)++);
120  }
121 
122  delete it1;
123  delete it2;
124 }
125 //******************************************************************************
126 // Méthode protégée!
127 int CGMapGeneric::isolateMarkedCells(int AMarkNumber, int ADim,
128  bool ADeleteDarts, bool AVerif,
129  int AMarkTreated)
130 {
131  assert(ADim>=0 && ADim<=2);
132  assert(AMarkTreated!=AMarkNumber);
133 
134  int nbIsolated = 0;
135  int treated = getNewMark();
136  int toDelete = 0;
137 
138  if (ADeleteDarts)
139  toDelete = getNewMark();
140 
141  if (AMarkTreated>=0)
142  markCopy(AMarkTreated, treated);
143 
144  CDynamicCoverageAll it(this);
145 
146  for (; it.cont(); ++it)
147  if (!isMarked(*it, treated))
148  {
149  if (isMarked(*it, AMarkNumber))
150  {
151  bool possible =
152  !AVerif ||
153  (!isFree(*it, ADim+1) && canMerge(*it, alpha(*it, ADim+1), ADim+1));
154 
155  markOrbit(*it, ORBIT_CELL[ADim], treated);
156 
157  if (possible)
158  {
159  if (ADeleteDarts)
160  markOrbit(*it, ORBIT_CELL[ADim], toDelete);
161 
162  if (AMarkTreated>=0)
163  for (int i = 0; i<2; ++i)
164  {
165  CDart * dart = i==0 ? *it : alpha(*it, ADim+1);
166 
167  CCoverage * cov =
168  getDynamicCoverage(dart, ORBIT_CELL[ADim+1]);
169 
170  for (; cov->cont(); ++(*cov))
171  if (!isMarked(**cov, AMarkTreated))
172  markOrbit(**cov, ORBIT_CELL[ADim], AMarkTreated);
173 
174  delete cov;
175  }
176 
177  merge(*it, alpha(*it,ADim+1), ADim+1, false);
178  ++nbIsolated;
179  }
180  }
181  else
182  setMark(*it, treated);
183  }
184 
185  negateMaskMark(treated);
186  freeMark(treated);
187 
188  // Suppression des cellules isolées:
189  if (ADeleteDarts)
190  {
191  if (nbIsolated>0)
192  for (it.reinit(); it.cont(); )
193  {
194  CDart * dart = it++;
195 
196  if (isMarked(dart, toDelete))
197  delMapDart(dart);
198  }
199 
200  freeMark(toDelete);
201  }
202 
203  return nbIsolated;
204 }
205 //******************************************************************************
206 int CGMapGeneric::isolateMarkedCells(int AMarkNumber, int ADim,
207  bool ADeleteDarts)
208 {
209  assert(ADim>=0 && ADim<=2);
210  return isolateMarkedCells(AMarkNumber, ADim, ADeleteDarts, true);
211 }
212 //******************************************************************************
214  bool ADeleteDarts)
215 {
216  int treated = getNewMark();
217  int nbIsolated = 0;
218 
219  for (int dim=3; dim>=1; --dim)
220  nbIsolated +=
221  isolateMarkedCells(AMarkNumber, dim, ADeleteDarts, true, treated);
222 
223  unmarkAll(treated);
224  freeMark(treated);
225 
226  return nbIsolated;
227 }
228 //******************************************************************************
229 // Méthode protégée!
230 void CGMapGeneric::markCellsToBeIsolated(int AMarkSource, int ADim,
231  int AMarkDestination, int AMarkTreated)
232 {
233  assert(ADim>=0 && ADim<=2);
234 
235  // Orbite "demi-cellule":
236  // ADim == 0 => Cellules d'orbite 23,
237  // ADim == 1 => Cellules d'orbite 03,
238  // ADim == 2 => Cellules d'orbite 01.
239  TOrbit halfCell = SUB_ORBIT(ORBIT_CC, ORBIT_I_IP1[ADim]);
240 
241  CDynamicCoverageAll it(this);
242 
243  // On sélectionne les demi-cellules de dimension ADim marquées:
244  markIncidentCells(halfCell, AMarkSource, AMarkDestination);
245 
246  // ... qui sont ADim+1-cousues:
247  for (; it.cont(); ++it)
248  if (isMarked(*it, AMarkDestination) && isFree(*it, ADim+1))
249  unsetMark(*it, AMarkDestination);
250 
251  // Lorsque plusieurs cellules adjacentes de dimension ADim+1 sont
252  // sélectionnées, il faut désélectionner le bord de l'objet correspondant à
253  // l'union de ces cellules:
254  int treated = getNewMark();
255 
256  if (AMarkTreated>=0)
257  markCopy(AMarkTreated, treated);
258 
259  for (it.reinit(); it.cont(); ++it)
260  if (!isMarked(*it, treated))
261  // Pour chaque cellule de dimension ADim dont les 2 demi-cellules sont
262  // marquées,
263  if (isMarked( *it , AMarkDestination) &&
264  isMarked(alpha(*it, ADim+1), AMarkDestination))
265  // Traiter les 2 cellules de dimension ADim+1 incidentes à cette cellule
266  // de dimension ADim:
267  for (int i=0; i<=1; ++i)
268  {
269  // Première cellule: incidente à *it,
270  // Deuxième cellule: incidente à alpha(*it, ADim+1).
271  CCoverage * cov = getDynamicCoverage(i==0 ? *it : alpha(*it, ADim+1),
272  ORBIT_CELL[ADim+1]);
273  for (; cov->cont(); ++(*cov))
274  {
275  // Démarquer tous les brins de la cellule qui ne sont pas sur
276  // une cellule de dimension ADim marquée des 2 côtés:
277  setMark(**cov, treated);
278  if (!isFree(**cov, ADim+1) &&
279  !isMarked(alpha(**cov, ADim+1), AMarkDestination))
280  unsetMark(**cov, AMarkDestination);
281 
282  // Si **cov est ADim+1-libre, il alpha déjà été démarqué plus haut.
283 
284  // Si alpha(**cov, ADim+1) est marqué, il ne faut pas marquer **cov
285  // car si alpha(**cov, ADim+1) est traité par l'itérateur it après
286  // **cov, il y aura des démarquages non voulus.
287  }
288 
289  delete cov;
290  }
291 
292  // À ce stade, les cellules de dimension ADim sont soit totalement marquées,
293  // soit totalement démarquées.
294 
295  // Démarquage des cellules impossible à fusionner:
296  if (AMarkTreated>=0)
297  markCopy(AMarkTreated, treated);
298  else
299  unmarkAll(treated);
300 
301  for (it.reinit(); it.cont(); ++it)
302  if (isMarked(*it, AMarkDestination) && !isMarked(*it, treated))
303  {
304  markOrbit(*it, ORBIT_CELL[ADim], treated);
305 
306  if (!canMerge(*it, alpha(*it,ADim+1), ADim+1))
307  unmarkOrbit(*it, ORBIT_CELL[ADim], AMarkDestination);
308  }
309 
310  // Si à ce stade une cellule de dimension ADim+2 (ou ADim+3) est totalement
311  // sélectionnée, il faut désélectionner les cellules de dimension ADim qui la
312  // composent, sinon elle va disparaître par fusions successives :)
313  if (ADim<2)
314  {
315  if (AMarkTreated>=0)
316  markCopy(AMarkTreated, treated);
317  else
318  unmarkAll(treated);
319 
320  for (it.reinit(); it.cont(); ++it)
321  if (isMarked(*it, AMarkDestination) && !isMarked(*it, treated))
322  {
323  bool whole = isWholeCellMarked(*it, ORBIT_CELL[ADim+2],
324  AMarkDestination);
325 
326  CCoverage * cov = getDynamicCoverage(*it, ORBIT_CELL[ADim+2]);
327 
328  for (; cov->cont(); ++(*cov))
329  if (!isMarked(**cov, treated))
330  {
331  markOrbit(**cov, ORBIT_CELL[ADim], treated);
332 
333  if (whole)
334  unmarkOrbit(**cov, ORBIT_CELL[ADim], AMarkDestination);
335 
336  // Remarque: Démarquer les demi-cellules n'est pas suffisant
337  // dans le cas d'un volume dont on alpha bouché le 3-bord...
338  }
339 
340  delete cov;
341  }
342  }
343 
344  unmarkAll(treated);
345  freeMark(treated);
346 }
347 //******************************************************************************
348 int CGMapGeneric::mergeMarkedCells(int AMarkNumber, int ADim,
349  bool ADeleteDarts)
350 {
351  assert(ADim>=1 && ADim<=3);
352 
353  // Sélection des cellules de dimension ADim-1 qui doivent être isolées:
354  int selected = getNewMark();
355 
356  markCellsToBeIsolated(AMarkNumber, ADim-1, selected);
357 
358  // Fusion effective:
359  int nbMerged = isolateMarkedCells(selected, ADim-1, ADeleteDarts, false);
360 
361  unmarkAll(selected);
362  freeMark(selected);
363 
364  return nbMerged;
365 }
366 //******************************************************************************
367 int CGMapGeneric::intuitiveMergeMarkedCells(int AMarkNumber, bool ADeleteDarts)
368 {
369  int nbMerged = 0;
370  int treated = getNewMark();
371 
372  int selected = getNewMark();
373 
374  for (int dim=3; dim>=1; --dim)
375  {
376  // Sélection des cellules qui doivent être isolées:
377  markCellsToBeIsolated(AMarkNumber, dim-1, selected, treated);
378 
379  // Fusion effective:
380  nbMerged +=
381  isolateMarkedCells(selected, dim-1, ADeleteDarts, false, treated);
382 
383  unmarkAll(selected);
384  }
385 
386  freeMark(selected);
387 
388  unmarkAll(treated);
389  freeMark(treated);
390 
391  return nbMerged;
392 }
393 //******************************************************************************