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 java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.List;
034:
035: import fr.ign.cogit.geoxygene.contrib.geometrie.Operateurs;
036: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPositionList;
037: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_LineString;
038: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Polygon;
039:
040: /**
041: * Classe des faces de la carte topo.
042: * Les arcs ont pour géométrie un GM_Polygon.
043: * @author Mustière/Bonin
044: * @version 1.0
045: */
046:
047: public class Face extends ElementCarteTopo {
048:
049: public Face() {
050: }
051:
052: /////////////////////////////////////////////////////////////////////////////////////////////////
053: // Géométrie
054: /////////////////////////////////////////////////////////////////////////////////////////////////
055:
056: /** Renvoie le GM_Polygon qui définit la géométrie de self */
057: public GM_Polygon getGeometrie() {
058: return (GM_Polygon) this .geom;
059: }
060:
061: /** Définit le GM_Polygon qui définit la géométrie de self */
062: public void setGeometrie(GM_Polygon geometrie) {
063: this .setGeom(geometrie);
064: }
065:
066: /** Renvoie la liste de DirectPosition qui définit les coordonnées de self */
067: public DirectPositionList getCoord() {
068: return this .getGeometrie().exteriorCoord();
069: }
070:
071: // On suppose que exteriorCoordList() donne deux fois le point de départ
072: /** Définit la liste de DirectPosition qui définit les coordonnées de self */
073: public void setCoord(DirectPositionList dpl) {
074: geom = new GM_Polygon(new GM_LineString(dpl));
075: }
076:
077: /////////////////////////////////////////////////////////////////////////////////////////////////
078: // Gestion des groupes
079: /////////////////////////////////////////////////////////////////////////////////////////////////
080:
081: /* Groupes auquels self appartient */
082: private Collection listeGroupes = new ArrayList();
083:
084: /** Renvoie la liste des groupes de self*/
085: public Collection getListeGroupes() {
086: return this .listeGroupes;
087: }
088:
089: /** Définit la liste des groupes de self*/
090: public void setListeGroupes(Collection liste) {
091: this .listeGroupes = liste;
092: }
093:
094: /** Ajoute un groupe à self*/
095: public void addGroupe(Groupe groupe) {
096: if (groupe != null && !listeGroupes.contains(groupe)) {
097: this .listeGroupes.add(groupe);
098: if (!groupe.getListeFaces().contains(this ))
099: groupe.addFace(this );
100: }
101: }
102:
103: /////////////////////////////////////////////////////////////////////////////////////////////////
104: // Gestion de la topologie arcs / faces
105: /////////////////////////////////////////////////////////////////////////////////////////////////
106:
107: private List arcsDirects = new ArrayList();
108:
109: /** Renvoie la liste des arcs directs de self */
110: public List getArcsDirects() {
111: return arcsDirects;
112: }
113:
114: /** Ajoute un arc direct de self */
115: public void addArcDirect(Arc arc) {
116: if (arc != null && !arcsDirects.contains(arc)) {
117: arcsDirects.add(arc);
118: if (arc.getFaceGauche() != this )
119: arc.setFaceGauche(this );
120: }
121: }
122:
123: /** Enlève un arc direct de self */
124: public void enleveArcDirect(Arc arc) {
125: if (arc == null)
126: return;
127: if (!arcsDirects.contains(arc))
128: return;
129: arcsDirects.remove(arc);
130: arc.setFaceGauche(null);
131: }
132:
133: private List arcsIndirects = new ArrayList();
134:
135: /** Renvoie la liste des arcs indirects de self */
136: public List getArcsIndirects() {
137: return arcsIndirects;
138: }
139:
140: /** Ajoute un arc indirect de self */
141: public void addArcIndirect(Arc arc) {
142: if (arc != null && !arcsIndirects.contains(arc)) {
143: arcsIndirects.add(arc);
144: if (arc.getFaceDroite() != this )
145: arc.setFaceDroite(this );
146: }
147: }
148:
149: /** Enlève un arc indirect de self */
150: public void enleveArcIndirect(Arc arc) {
151: if (arc == null)
152: return;
153: if (!arcsIndirects.contains(arc))
154: return;
155: arcsIndirects.remove(arc);
156: arc.setFaceDroite(null);
157: }
158:
159: /** Renvoie la liste (non classée) des arcs entourant self.
160: * NB: cette liste est la concaténation des listes des arcs directs et indirects.
161: * Ce sont ces listes qui doivent être manipulées pour la modification/l'instanciation
162: * des relations topologiques sur les faces.
163: * NB2 codeur : A faire : coder une méthode qui renvoie ces arcs dans le bon ordre de parcours
164: */
165: public List arcs() {
166: List Arcs = new ArrayList();
167: Arcs.addAll(this .getArcsDirects());
168: Arcs.addAll(this .getArcsIndirects());
169: return Arcs;
170: }
171:
172: /** Liste de liste représentant les arcs incidents à une face
173: * (i.e. les arcs des noeuds de la face, sauf les arcs de la face eux-mêmes).
174: * Dans l'esprit de la méthode arcsOrientés d'un noeud, les arcs sont
175: * classés en tournant autour de la face dans l'ordre trigonométrique,
176: * et qualifiés d'entrants ou sortants.
177: *
178: *
179: * ATTENTION : renvoie une liste de liste:
180: * Liste.get(0) = liste des arcs (de la classe 'Arc')
181: * Liste.get(1) = liste des orientations de type Boolean (classe Boolean et non type boolean),
182: * true = entrant, false = sortant)
183: *
184: * NB : Le classement est recalculé en fonction de la géométrie à chaque appel de la méthode.
185: */
186: public List arcsExterieursClasses() {
187: List arcsDeLaFace = this .arcs();
188: Iterator itNoeudsDeLaFace = this .noeudsTrigo().iterator();
189: List arcsDuNoeud;
190: List resultat = new ArrayList();
191: List arcsExterieurs = new ArrayList();
192: List orientations = new ArrayList();
193: Iterator itArcs, itOrientations;
194: Noeud noeud;
195: Arc arc;
196: Boolean orientation;
197:
198: while (itNoeudsDeLaFace.hasNext()) {
199: noeud = (Noeud) itNoeudsDeLaFace.next();
200: arcsDuNoeud = noeud.arcsClasses();
201: itArcs = ((List) arcsDuNoeud.get(0)).iterator();
202: itOrientations = ((List) arcsDuNoeud.get(1)).iterator();
203: ;
204: while (itArcs.hasNext()) {
205: arc = (Arc) itArcs.next();
206: orientation = (Boolean) itOrientations.next();
207: if (arcsDeLaFace.contains(arc))
208: continue;
209: arcsExterieurs.add(arc);
210: orientations.add(orientation);
211: }
212: }
213: resultat.add(arcsExterieurs);
214: resultat.add(orientations);
215: return resultat;
216: }
217:
218: /////////////////////////////////////////////////////////////////////////////////////////////////
219: // Topologie faces / noeuds
220: /////////////////////////////////////////////////////////////////////////////////////////////////
221:
222: /** Renvoie la liste des noeuds entourant self.
223: * NB: cette liste n'est pas modifiable directement. En effet, la topologie face/noeuds n'est pas gérée
224: * directement, elle est déduite par calcul des topologies face/arcs et arcs/noeuds
225: */
226: public List noeuds() {
227: List arcs = this .arcs();
228: HashSet noeuds = new HashSet();
229: Arc arc;
230: Iterator iterarcs = arcs.iterator();
231: while (iterarcs.hasNext()) {
232: arc = (Arc) iterarcs.next();
233: noeuds.addAll(arc.noeuds());
234: }
235: return new ArrayList(noeuds);
236: }
237:
238: /**Renvoie la liste des noeuds entourant self en parcourant la face
239: * dans le sens trigonométrique. Le noeud de départ est choisi au hasard.
240: * NB : La topologie arcs/noeuds ET faces doit avoir été instanciée.
241: * NB : On ne boucle pas : le premier noeud n'est pas égal au dernier noeud
242: * (contrairement aux géométries de polygone).
243: */
244: public List noeudsTrigo() {
245: List arcs;
246: List cycle = new ArrayList();
247: List noeuds = new ArrayList();
248: Arc arc0, arc;
249: Noeud noeud;
250: boolean renverser = true, orientation;
251: Iterator itArcsEntourants, itOrientations;
252:
253: arcs = new ArrayList(this .arcs());
254: if (arcs.size() == 0) {
255: System.out
256: .println("Problème : gestion d'une face avec zéro arc entourant: ");
257: System.out
258: .println(" la topolgie de face a bien été instanciée?");
259: return null;
260: }
261:
262: arc0 = (Arc) arcs.get(0);
263: if (arc0.getFaceDroite() == this ) {
264: cycle = arc0.cycleADroite();
265: renverser = true;
266: } else if (arc0.getFaceGauche() == this ) {
267: cycle = arc0.cycleAGauche();
268: renverser = false;
269: } else
270: System.out
271: .println("Problème : incohérence dans la topologie arcs / faces");
272:
273: itArcsEntourants = ((List) cycle.get(0)).iterator();
274: itOrientations = ((List) cycle.get(1)).iterator();
275: while (itArcsEntourants.hasNext()) {
276: arc = (Arc) itArcsEntourants.next();
277: orientation = ((Boolean) itOrientations.next())
278: .booleanValue();
279: if (orientation)
280: noeud = arc.getNoeudIni();
281: else
282: noeud = arc.getNoeudFin();
283: if (renverser)
284: noeuds.add(0, noeud);
285: else
286: noeuds.add(noeud);
287: }
288: return noeuds;
289: }
290:
291: /////////////////////////////////////////////////////////////////////////////////////////////////
292: // Topologie faces / faces
293: /////////////////////////////////////////////////////////////////////////////////////////////////
294: /** Renvoie la liste des faces voisines de self.
295: * NB: ceci est calculé en passant par la topologie faces/arcs qui doit être instanciée.
296: */
297: public List voisins() {
298: List arcs = this .arcs();
299: HashSet voisins = new HashSet();
300: Arc arc;
301: Iterator iterarcs = arcs.iterator();
302: while (iterarcs.hasNext()) {
303: arc = (Arc) iterarcs.next();
304: voisins.addAll(arc.faces());
305: }
306: voisins.remove(this );
307: return new ArrayList(voisins);
308: }
309:
310: /////////////////////////////////////////////////////////////////////////////////////////////////
311: // Opérateurs de calcul sur les faces
312: /////////////////////////////////////////////////////////////////////////////////////////////////
313: /**Surface d'un polygone. */
314: // Le calcul est effectué dans un repère local centré sur le premier point
315: // de la surface, ce qui est utile pour minimiser les erreurs de calcul
316: // si on manipule de grandes coordonnées).
317: public double surface() {
318: return Operateurs.surface(this.getGeometrie());
319: }
320:
321: }
|