001: /*
002: * This file is part of the GeOxygene project source files.
003: *
004: * GeOxygene aims at providing an open framework which implements OGC/ISO specifications for
005: * the development and deployment of geographic (GIS) applications. It is a open source
006: * contribution of the COGIT laboratory at the Institut Géographique National (the French
007: * National Mapping Agency).
008: *
009: * See: http://oxygene-project.sourceforge.net
010: *
011: * Copyright (C) 2005 Institut Géographique National
012: *
013: * This library is free software; you can redistribute it and/or modify it under the terms
014: * of the GNU Lesser General Public License as published by the Free Software Foundation;
015: * either version 2.1 of the License, or any later version.
016: *
017: * This library is distributed in the hope that it will be useful, but WITHOUT ANY
018: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
019: * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser General Public License along with
022: * this library (see file LICENSE if present); if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: *
025: */
026:
027: package fr.ign.cogit.geoxygene.contrib.cartetopo;
028:
029: import fr.ign.cogit.geoxygene.contrib.geometrie.Angle;
030: import fr.ign.cogit.geoxygene.feature.Population;
031:
032: import java.util.ArrayList;
033: import java.util.Iterator;
034: import java.util.List;
035:
036: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPosition;
037:
038: /**
039: * Classe des groupes de la carte topo.
040: * Un groupe est une composition de noeuds, d'arcs et de faces.
041: *
042: * English: a group is a set of nodes/arcs/faces of a topological map
043: * @author Mustière/Bonin
044: * @version 1.0
045: */
046:
047: public class Groupe extends ElementCarteTopo {
048:
049: public Groupe() {
050: }
051:
052: ///////////////////////////////////////////////////
053: // Pour les relations de composition :
054: // - un groupe contient PLUSIEURS noeuds, arcs et faces
055: // - un groupe appartient à UNE carte topo
056: ///////////////////////////////////////////////////
057:
058: /* Noeuds composants du groupe */
059: private List listeNoeuds = new ArrayList();
060:
061: /** Renvoie la liste des noeuds de self*/
062: public List getListeNoeuds() {
063: return this .listeNoeuds;
064: }
065:
066: /** Définit la liste des noeuds de self*/
067: public void setListeNoeuds(List liste) {
068: this .listeNoeuds = liste;
069: }
070:
071: /** Ajoute un noeud à self*/
072: public void addNoeud(Noeud noeud) {
073: if (noeud != null && !listeNoeuds.contains(noeud)) {
074: this .listeNoeuds.add(noeud);
075: if (!noeud.getListeGroupes().contains(this ))
076: noeud.addGroupe(this );
077: }
078: }
079:
080: /** Ajoute une liste de noeuds à self**/
081: public void addAllNoeuds(List liste) {
082: Iterator itObj = liste.iterator();
083: while (itObj.hasNext()) {
084: Noeud objet = (Noeud) itObj.next();
085: this .addNoeud(objet);
086: }
087: }
088:
089: /* Arcs composants du groupe */
090: private List listeArcs = new ArrayList();
091:
092: /** Renvoie la liste des arcs de self*/
093: public List getListeArcs() {
094: return this .listeArcs;
095: }
096:
097: /** Définit la liste des arcs de self*/
098: public void setListeArcs(List liste) {
099: this .listeArcs = liste;
100: }
101:
102: /** Ajoute un arc de self*/
103: public void addArc(Arc arc) {
104: if (arc != null && !listeArcs.contains(arc)) {
105: this .listeArcs.add(arc);
106: if (!arc.getListeGroupes().contains(this ))
107: arc.addGroupe(this );
108: }
109: }
110:
111: /** Ajoute une liste d'arcs à self**/
112: public void addAllArcs(List liste) {
113: Iterator itObj = liste.iterator();
114: while (itObj.hasNext()) {
115: Arc objet = (Arc) itObj.next();
116: this .addArc(objet);
117: }
118: }
119:
120: /* Faces composants du groupe */
121: private List listeFaces = new ArrayList();
122:
123: /** Renvoie la liste des faces de self*/
124: public List getListeFaces() {
125: return this .listeFaces;
126: }
127:
128: /** Définit la liste des faces de self*/
129: public void setListeFaces(List liste) {
130: this .listeFaces = liste;
131: }
132:
133: /** Ajoute une face à self*/
134: public void addFace(Face face) {
135: if (face != null && !listeFaces.contains(face)) {
136: this .listeFaces.add(face);
137: if (!face.getListeGroupes().contains(this ))
138: face.addGroupe(this );
139: }
140: }
141:
142: /** Ajoute une liste de faces à self**/
143: public void addAllFaces(List liste) {
144: Iterator itObj = liste.iterator();
145: while (itObj.hasNext()) {
146: Face objet = (Face) itObj.next();
147: this .addFace(objet);
148: }
149: }
150:
151: ///////////////////////////////////////////////////
152: // Pour les relations topologiques dans une vision Groupe = Hyper Noeud
153: ///////////////////////////////////////////////////
154:
155: /** Arcs entrants dans le groupe, au sens de la géométrie (vision groupe = hyper-noeud) */
156: public List getEntrants() {
157: List arcs = new ArrayList();
158: List arcsDuNoeud = new ArrayList();
159: int i, j;
160:
161: for (i = 0; i < this .getListeNoeuds().size(); i++) {
162: arcsDuNoeud = ((Noeud) this .getListeNoeuds().get(i))
163: .getEntrants();
164: for (j = 0; j < arcsDuNoeud.size(); j++) {
165: if (!this .getListeArcs().contains(arcsDuNoeud.get(j)))
166: arcs.add(arcsDuNoeud.get(j));
167: }
168: }
169: return arcs;
170: }
171:
172: /** Arcs sortants du groupe, au sens de la géométrie (vision groupe = hyper-noeud) */
173: public List getSortants() {
174: List arcs = new ArrayList();
175: List arcsDuNoeud = new ArrayList();
176: int i, j;
177:
178: for (i = 0; i < this .getListeNoeuds().size(); i++) {
179: arcsDuNoeud = ((Noeud) this .getListeNoeuds().get(i))
180: .getSortants();
181: for (j = 0; j < arcsDuNoeud.size(); j++) {
182: if (!this .getListeArcs().contains(arcsDuNoeud.get(j)))
183: arcs.add(arcsDuNoeud.get(j));
184: }
185: }
186: return arcs;
187: }
188:
189: /** Arcs adjacents (entrants et sortants) de self (vision groupe = hyper-noeud).
190: * NB : si un arc est à la fois entrant et sortant (boucle), il est 2 fois dans la liste
191: */
192: public List getAdjacents() {
193: List arcs = new ArrayList();
194: arcs.addAll(this .getSortants());
195: arcs.addAll(this .getEntrants());
196: return arcs;
197: }
198:
199: ///////////////////////////////////////////////////
200: // Pour les relations topologiques dans une vision Groupe = Hyper Noeud,
201: // en tenant compte du sens de circulation
202: ///////////////////////////////////////////////////
203: /** Arcs entrants dans le groupe, au sens de la géométrie (vision groupe = hyper-noeud) */
204: public List entrantsOrientes() {
205: List arcs = new ArrayList();
206: List arcsDuNoeud = new ArrayList();
207: int i, j;
208:
209: for (i = 0; i < this .getListeNoeuds().size(); i++) {
210: arcsDuNoeud = ((Noeud) this .getListeNoeuds().get(i))
211: .entrantsOrientes();
212: for (j = 0; j < arcsDuNoeud.size(); j++) {
213: if (!this .getListeArcs().contains(arcsDuNoeud.get(j)))
214: arcs.add(arcsDuNoeud.get(j));
215: }
216: }
217: return arcs;
218: }
219:
220: /** Arcs sortants du groupe, au sens de la géométrie (vision groupe = hyper-noeud) */
221: public List sortantsOrientes() {
222: List arcs = new ArrayList();
223: List arcsDuNoeud = new ArrayList();
224: int i, j;
225:
226: for (i = 0; i < this .getListeNoeuds().size(); i++) {
227: arcsDuNoeud = ((Noeud) this .getListeNoeuds().get(i))
228: .sortantsOrientes();
229: for (j = 0; j < arcsDuNoeud.size(); j++) {
230: if (!this .getListeArcs().contains(arcsDuNoeud.get(j)))
231: arcs.add(arcsDuNoeud.get(j));
232: }
233: }
234: return arcs;
235: }
236:
237: /** Arcs incidents à un noeuds, classés en tournant autour du noeud dans l'ordre trigonométrique,
238: * et qualifiés d'entrants ou sortants, au sens de la géoémtrie (utile particulièrement à la gestion des boucles).
239: *
240: * NB : renvoie une liste de liste:
241: * Liste.get(0) = liste des arcs (de la classe 'Arc')
242: * Liste.get(1) = liste des orientations de type Boolean,
243: * true = entrant, false = sortant)
244: * NB : Classement effectué sur la direction donnée par le premier point de l'arc après le noeud.
245: * NB : Le premier arc est celui dont la direction est la plus proche de l'axe des X, en tournant dans le sens trigo.
246: * NB : Ce classement est recalculé en fonction de la géométrie à chaque appel de la méthode.
247: */
248: public List arcsClasses() {
249: List arcsClasses = new ArrayList();
250: List arcsClassesOrientation = new ArrayList();
251: List arcsEntrants = new ArrayList(this .getEntrants());
252: List arcsSortants = new ArrayList(this .getSortants());
253: List arcs = new ArrayList();
254: List angles = new ArrayList();
255: List orientations = new ArrayList();
256: List resultat = new ArrayList();
257: Arc arc;
258: Angle angle;
259: double angleMin, angleCourant;
260: int imin;
261: Iterator itArcs;
262: int i;
263:
264: // recherche de l'angle de départ de chaque arc sortant
265: itArcs = arcsSortants.iterator();
266: while (itArcs.hasNext()) {
267: arc = (Arc) itArcs.next();
268: angle = new Angle((DirectPosition) arc.getCoord().get(0),
269: (DirectPosition) arc.getCoord().get(1));
270: arcs.add(arc);
271: angles.add(angle);
272: orientations.add(new Boolean(false));
273: }
274: // recherche de l'angle de départ de chaque arc entrant
275: itArcs = arcsEntrants.iterator();
276: while (itArcs.hasNext()) {
277: arc = (Arc) itArcs.next();
278: angle = new Angle((DirectPosition) arc.getCoord().get(
279: arc.getCoord().size() - 1), (DirectPosition) arc
280: .getCoord().get(arc.getCoord().size() - 2));
281: arcs.add(arc);
282: angles.add(angle);
283: orientations.add(new Boolean(true));
284: }
285: // classement des arcs
286: while (!(arcs.isEmpty())) {
287: angleMin = ((Angle) angles.get(0)).getAngle();
288: imin = 0;
289: for (i = 1; i < arcs.size(); i++) {
290: angleCourant = ((Angle) angles.get(i)).getAngle();
291: if (angleCourant < angleMin) {
292: angleMin = angleCourant;
293: imin = i;
294: }
295: }
296: arcsClasses.add(arcs.get(imin));
297: arcsClassesOrientation.add(orientations.get(imin));
298: arcs.remove(imin);
299: angles.remove(imin);
300: orientations.remove(imin);
301: }
302: //retour du résultat
303: resultat.add(arcsClasses);
304: resultat.add(arcsClassesOrientation);
305: return resultat;
306: }
307:
308: ///////////////////////////////////////////////////
309: // Méthodes de base pour manipuler un groupe
310: ///////////////////////////////////////////////////
311: /** Pour vider un groupe, et mettre à jour les liens des objets simples vers ce groupe.
312: * Vide mais ne détruit pas le groupe: i.e. ne l'enlève pas de la carte topo.
313: */
314: public void vide() {
315: Iterator itArcs = this .getListeArcs().iterator();
316: while (itArcs.hasNext()) {
317: Arc arc = (Arc) itArcs.next();
318: arc.getListeGroupes().remove(this );
319: }
320: Iterator itNoeuds = this .getListeNoeuds().iterator();
321: while (itNoeuds.hasNext()) {
322: Noeud noeud = (Noeud) itNoeuds.next();
323: noeud.getListeGroupes().remove(this );
324: }
325: this .getListeArcs().clear();
326: this .getListeNoeuds().clear();
327: }
328:
329: /** Pour vider un groupe, mettre à jour les liens des objets simples vers ce groupe,
330: * et l'enlever des populations auxquelles il appartient.
331: * NB: ce groupe n'est pas vraiment detruit, il n'est pas rendu null ;
332: * NB: rien n'est géré au niveau de la persistance eventuelle.
333: */
334: public void videEtDetache() {
335: vide();
336: Population groupes = this .getPopulation();
337: if (groupes != null)
338: groupes.remove(this );
339: }
340:
341: /** Pour copier un groupe.
342: * NB 1 : on crée un nouveau groupe pointant
343: * vers les mêmes objets composants.
344: * NB 2 : ce groupe n'est PAS ajouté à la carteTopo
345: */
346: public Groupe copie() {
347: //Groupe copie = new Groupe();
348: Groupe copie = (Groupe) this .getPopulation().nouvelElement();
349: copie.addAllArcs(this .getListeArcs());
350: copie.addAllNoeuds(this .getListeNoeuds());
351: copie.addAllFaces(this .getListeFaces());
352: //copie.setPopulation(this.getPopulation());
353: return copie;
354: }
355:
356: ///////////////////////////////////////////////////
357: ///////////////////////////////////////////////////
358: // Opérateurs de calculs sur les groupes
359: ///////////////////////////////////////////////////
360: ///////////////////////////////////////////////////
361:
362: /** Decompose un groupe en plusieurs groupes connexes, et vide le groupe self.
363: * La liste en sortie contient des Groupes.
364: * ATTENTION : LE GROUPE EN ENTREE EST VIDE AU COURS DE LA METHODE PUIS ENLEVE DE LA CARTE TOPO.
365: */
366: public List decomposeConnexes() {
367: List groupesConnexes = new ArrayList();
368: Groupe groupeConnexe;
369: Noeud amorce;
370: Arc arc;
371: int i;
372:
373: try {
374: if (this .getPopulation() == null) {
375: System.out.println("ATTENTION : le groupe " + this
376: + " n'a pas de population associée");
377: System.out
378: .println(" Impossible de le décomposer en groupes connexes");
379: return null;
380: }
381: if (this .getCarteTopo() == null) {
382: System.out.println("ATTENTION : le groupe " + this
383: + " ne fait pas partie d'une carte topo");
384: System.out
385: .println(" Impossible de le décomposer en groupes connexes");
386: return null;
387: }
388: if (this .getCarteTopo().getPopArcs() == null) {
389: System.out
390: .println("ATTENTION : le groupe "
391: + this
392: + " fait partie d'une carte topo sans population d'arcs");
393: System.out
394: .println(" Impossible de le décomposer en groupes connexes");
395: return null;
396: }
397: if (this .getCarteTopo().getPopNoeuds() == null) {
398: System.out
399: .println("ATTENTION : le groupe "
400: + this
401: + " fait partie d'une carte topo sans population de noeuds");
402: System.out
403: .println(" Impossible de le décomposer en groupes connexes");
404: return null;
405: }
406:
407: while (this .getListeNoeuds().size() != 0) {
408: groupeConnexe = (Groupe) this .getPopulation()
409: .nouvelElement();
410: groupesConnexes.add(groupeConnexe);
411: // le premier noeud de la liste des noeuds, vidée au fur et à mesure, est l'amorce d'un nouveau groupe connexe
412: amorce = (Noeud) this .getListeNoeuds().get(0);
413: groupeConnexe.ajouteVoisins(amorce, this ); //nb: méthode récursive
414: groupeConnexe.arcsDansGroupe(this ); // recherche des arcs du groupe, situés entre 2 noeuds du goupe connexe
415: }
416: // vidage des arcs du groupe, pour faire propre (on a déjà vidé les noeuds au fur et à mesure)
417: for (i = 0; i < this .getListeArcs().size(); i++) {
418: arc = (Arc) this .getListeArcs().get(i);
419: arc.getListeGroupes().remove(this );
420: }
421: this .getListeArcs().clear();
422: this .getPopulation().enleveElement(this );
423:
424: return groupesConnexes;
425: } catch (Exception e) {
426: System.out
427: .println("----- ERREUR dans décomposition en groupes connxes: ");
428: System.out
429: .println("Source possible : Nom de la classe des groupes pas ou mal renseigné dans la carte topo");
430: return null;
431: }
432: }
433:
434: // Methode nécessaire à DecomposeConnexe
435: // ajoute le noeud au groupe connexe, cherche ses voisins, puis l'enlève du goupe total
436: private void ajouteVoisins(Noeud noeud, Groupe groupeTotal) {
437: List noeudsVoisins = new ArrayList();
438: int i;
439:
440: if (this .getListeNoeuds().contains(noeud))
441: return;
442: this .addNoeud(noeud);
443: noeud.addGroupe(this );
444: noeudsVoisins = noeud.voisins(groupeTotal);
445: groupeTotal.getListeNoeuds().remove(noeud);
446: noeud.getListeGroupes().remove(groupeTotal);
447: for (i = 0; i < noeudsVoisins.size(); i++) {
448: this .ajouteVoisins((Noeud) noeudsVoisins.get(i),
449: groupeTotal);
450: }
451: return;
452: }
453:
454: // Methode nécessaire à DecomposeConnexe
455: // Recherche les arcs de groupeTotal ayant pour extrémité des noeuds de this.
456: private void arcsDansGroupe(Groupe groupeTotal) {
457: int i;
458: Arc arc;
459: for (i = 0; i < groupeTotal.getListeArcs().size(); i++) {
460: arc = (Arc) groupeTotal.getListeArcs().get(i);
461: if (this .getListeNoeuds().contains(arc.getNoeudIni())
462: || this .getListeNoeuds()
463: .contains(arc.getNoeudIni())) {
464: this .addArc(arc);
465: arc.addGroupe(this );
466: }
467: }
468: }
469:
470: /** somme des longueurs des arcs du groupe. */
471: public double longueur() {
472: int i;
473: double longueur = 0;
474: for (i = 0; i < this .getListeArcs().size(); i++) {
475: longueur = longueur
476: + ((Arc) this .getListeArcs().get(i)).longueur();
477: }
478: return longueur;
479: }
480:
481: /** Teste si le groupe contient exactement les mêmes arcs qu'un autre groupe.
482: * NB: si des arcs sont en double dans un des groupes et pas dans l'autre, renvoie true quand même
483: */
484: public boolean contientMemesArcs(Groupe groupe) {
485: if (!groupe.getListeArcs().containsAll(this .getListeArcs()))
486: return false;
487: if (!this .getListeArcs().containsAll(groupe.getListeArcs()))
488: return false;
489: return true;
490: }
491:
492: /** Pour un groupe dont on ne connait que les arcs :
493: * ajoute les noeuds ini et fin de ses arcs dans le groupe.
494: * La topologie doit avoir été instanciée.
495: */
496: public void ajouteNoeuds() {
497: int i;
498: Noeud ini, fin;
499: Arc arc;
500:
501: for (i = 0; i < this .getListeArcs().size(); i++) {
502: arc = (Arc) this.getListeArcs().get(i);
503: ini = arc.getNoeudIni();
504: fin = arc.getNoeudFin();
505: if (ini != null) {
506: if (!this.getListeNoeuds().contains(ini)) {
507: this.addNoeud(ini);
508: ini.addGroupe(this);
509: }
510: }
511: if (fin != null) {
512: if (!this.getListeNoeuds().contains(fin)) {
513: this.addNoeud(fin);
514: fin.addGroupe(this);
515: }
516: }
517: }
518: }
519:
520: }
|