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.Iterator;
032: import java.util.List;
033:
034: import fr.ign.cogit.geoxygene.contrib.geometrie.Distances;
035: import fr.ign.cogit.geoxygene.contrib.geometrie.Operateurs;
036: import fr.ign.cogit.geoxygene.contrib.geometrie.Rectangle;
037: import fr.ign.cogit.geoxygene.feature.Population;
038: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPosition;
039: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPositionList;
040: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_LineString;
041: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Polygon;
042: import fr.ign.cogit.geoxygene.spatial.geomprim.GM_Point;
043:
044: /**
045: * Classe des arcs de la carte topo.
046: * Les arcs ont pour géométrie une GM_LineString, et peuvent être orientés.
047: * Des méthodes sont prévues pour une gestion de réseau, de graphe, et de carte topologique.
048: *
049: * English: arcs of a topological map
050: * @author Mustière/Bonin
051: * @version 1.0
052: */
053:
054: public class Arc extends ElementCarteTopo {
055:
056: public Arc() {
057: }
058:
059: /////////////////////////////////////////////////////////////////////////////////////////////////
060: // Géométrie
061: /////////////////////////////////////////////////////////////////////////////////////////////////
062: /** Renvoie le GM_LineString qui définit la géométrie de self */
063: public GM_LineString getGeometrie() {
064: return (GM_LineString) geom;
065: }
066:
067: /** Définit le GM_LineString qui définit la géométrie de self */
068: public void setGeometrie(GM_LineString geometrie) {
069: this .setGeom(geometrie);
070: }
071:
072: /** Renvoie la liste de DirectPosition qui définit les coordonnées de self */
073: public DirectPositionList getCoord() {
074: return geom.coord();
075: }
076:
077: /** Définit la liste de DirectPosition qui définit les coordonnées de self */
078: public void setCoord(DirectPositionList dpl) {
079: geom = new GM_LineString(dpl);
080: }
081:
082: /////////////////////////////////////////////////////////////////////////////////////////////////
083: // Gestion de la topologie arc / noeuds
084: /////////////////////////////////////////////////////////////////////////////////////////////////
085: private Noeud noeudIni;
086:
087: /** Renvoie le noeud initial de self */
088: public Noeud getNoeudIni() {
089: return this .noeudIni;
090: }
091:
092: /** Définit le noeud initial de self.
093: * NB: met à jour la relation inverse "sortants" de noeud
094: */
095: public void setNoeudIni(Noeud noeud) {
096: if (noeud != null) {
097: this .noeudIni = noeud;
098: if (!noeud.getSortants().contains(this ))
099: noeud.addSortant(this );
100: } else {
101: if (this .getNoeudIni() != null)
102: this .getNoeudIni().getSortants().remove(noeud);
103: noeudIni = null;
104: }
105: }
106:
107: private Noeud noeudFin;
108:
109: /** Renvoie le noeud final de self */
110: public Noeud getNoeudFin() {
111: return this .noeudFin;
112: }
113:
114: /** Définit le noeud final de self.
115: * NB: met à jour la relation inverse "entrants" de noeud
116: */
117: public void setNoeudFin(Noeud noeud) {
118: if (noeud != null) {
119: this .noeudFin = noeud;
120: if (!noeud.getEntrants().contains(this ))
121: noeud.addEntrant(this );
122: } else {
123: if (this .getNoeudFin() != null)
124: this .getNoeudFin().getEntrants().remove(noeud);
125: noeudFin = null;
126: }
127: }
128:
129: /** Renvoie le noeud initial et final de self */
130: public List noeuds() {
131: List noeuds = new ArrayList();
132: if (!(noeudIni == null))
133: noeuds.add(noeudIni);
134: if (!(noeudFin == null))
135: noeuds.add(noeudFin);
136: return noeuds;
137: }
138:
139: /** Projete le point P sur l'arc et découpe l'arc en 2 avec ce point projeté.
140: * NB: si la projection tombe sur une extrémité de l'arc : ne fait rien.
141: */
142: public void projeteEtDecoupe(GM_Point P) {
143: DirectPositionList listePoints = this .getGeometrie().coord();
144: DirectPositionList ptsAvant, ptsApres;
145: Arc arcAvant, arcApres;
146: double d, dmin;
147: DirectPosition pt, ptmin;
148: int positionMin = 0;
149: Noeud nouveauNoeud;
150:
151: if (this .getCarteTopo() == null)
152: return;
153:
154: Population popNoeuds = this .getCarteTopo().getPopNoeuds();
155: Population popArcs = this .getCarteTopo().getPopArcs();
156: int i;
157:
158: if (listePoints.size() < 2)
159: return;
160: ptmin = Operateurs.projection(P.getPosition(), listePoints
161: .get(0), listePoints.get(1));
162: dmin = Distances.distance(P.getPosition(), ptmin);
163: for (i = 1; i < listePoints.size() - 1; i++) {
164: pt = Operateurs.projection(P.getPosition(), listePoints
165: .get(i), listePoints.get(i + 1));
166: d = Distances.distance(P.getPosition(), pt);
167: if (d < dmin) {
168: ptmin = pt;
169: dmin = d;
170: positionMin = i;
171: }
172: }
173: if (Distances.distance(ptmin, listePoints.get(0)) == 0)
174: return;
175: if (Distances.distance(ptmin, listePoints.get(listePoints
176: .size() - 1)) == 0)
177: return;
178:
179: // création du nouveau noeud
180: nouveauNoeud = (Noeud) popNoeuds.nouvelElement();
181: nouveauNoeud.setGeometrie(new GM_Point(ptmin));
182:
183: // création des nouveaux arcs
184: ptsAvant = new DirectPositionList();
185: ptsApres = new DirectPositionList();
186:
187: for (i = 0; i <= positionMin; i++)
188: ptsAvant.add(listePoints.get(i));
189: ptsAvant.add(ptmin);
190: arcAvant = (Arc) popArcs.nouvelElement();
191: arcAvant.setGeometrie(new GM_LineString(ptsAvant));
192:
193: if (Distances.distance(ptmin, listePoints.get(positionMin + 1)) != 0)
194: ptsApres.add(ptmin);
195: for (i = positionMin + 1; i < listePoints.size(); i++)
196: ptsApres.add(listePoints.get(i));
197: arcApres = (Arc) popArcs.nouvelElement();
198: arcApres.setGeometrie(new GM_LineString(ptsApres));
199:
200: // instanciation de la topologie et des attributs
201: this .getNoeudIni().getSortants().remove(this );
202: arcAvant.setNoeudIni(this .getNoeudIni());
203: arcAvant.setNoeudFin(nouveauNoeud);
204: arcAvant.setCorrespondants(this .getCorrespondants());
205: arcAvant.setOrientation(this .getOrientation());
206:
207: arcApres.setNoeudIni(nouveauNoeud);
208: this .getNoeudFin().getEntrants().remove(this );
209: arcApres.setNoeudFin(this .getNoeudFin());
210: arcApres.setCorrespondants(this .getCorrespondants());
211: arcApres.setOrientation(this .getOrientation());
212:
213: //destruction de l'ancien arc
214: this .setNoeudIni(null);
215: this .setNoeudFin(null);
216: popArcs.enleveElement(this );
217: }
218:
219: /////////////////////////////////////////////////////////////////////////////////////////////////
220: // Gestion de la topologie arc / faces
221: /////////////////////////////////////////////////////////////////////////////////////////////////
222: /** Renvoie la face à gauche et à droite de self */
223: public List faces() {
224: List faces = new ArrayList();
225: if (this .getFaceGauche() != null)
226: faces.add(this .getFaceGauche());
227: if (this .getFaceDroite() != null)
228: faces.add(this .getFaceDroite());
229: return faces;
230: }
231:
232: private Face faceGauche;
233:
234: /** Renvoie la face à gauche de self */
235: public Face getFaceGauche() {
236: return this .faceGauche;
237: }
238:
239: /** Définit la face à gauche de self.
240: * NB: met à jour la relation inverse "arsc directs" de face
241: */
242: public void setFaceGauche(Face face) {
243: if (face != null) {
244: this .faceGauche = face;
245: if (!face.getArcsDirects().contains(this ))
246: face.addArcDirect(this );
247: } else {
248: if (this .getFaceGauche() != null)
249: this .getFaceGauche().getArcsDirects().remove(face);
250: faceGauche = null;
251: }
252: }
253:
254: private Face faceDroite;
255:
256: /** Renvoie la face à droite de self */
257: public Face getFaceDroite() {
258: return this .faceDroite;
259: }
260:
261: /** Définit la face à droite de self.
262: * NB: met à jour la relation inverse "arsc indirects" de face
263: */
264: public void setFaceDroite(Face face) {
265: if (face != null) {
266: this .faceDroite = face;
267: if (!face.getArcsIndirects().contains(this ))
268: face.addArcIndirect(this );
269: } else {
270: if (this .getFaceDroite() != null)
271: this .getFaceDroite().getArcsIndirects().remove(face);
272: faceDroite = null;
273: }
274: }
275:
276: /** Recherche du cycle du réseau à droite de l'arc en se basant sur la topologie de RESEAU uniquement.
277: * Renvoie une liste (ArrayList) de 3 éléments :
278: * - get(0): Liste des arcs dans l'ordre de parcours du cycle
279: * Liste classée dans le sens anti-trigonometrique (sauf pour la face exterieure).
280: * (liste de type "ArrayList", contenant elle-même des "Arc").
281: * - get(1): Liste des orientations des arc : true si l'arc à sa face à droite, false sinon
282: * (liste de type "ArrayList", contenant elle-même des objets "Boolean").
283: * - get(2) : La géométrie du polygone faisant le tour du cycle
284: * (de type "GM_Polygon)
285: * NB: la liste retournée est égale à null si on n'a pas trouvé de cycle
286: * (cas pouvant arriver si la topologie arcs/noeuds n'est pas complète.
287: * NB: ne nécessite PAS d'avoir une topologie arcs/faces instanciée.
288: * NB: nécessite d'avoir une topologie arcs/noeuds instanciée.
289: * NB: un cycle passe 2 fois (une fois dans chaque sens) par les cul-de-sac si il y en a.
290: */
291: public List cycleADroite() {
292: Arc arcEnCours;
293: boolean sensEnCours;
294: List arcOriente;
295: GM_LineString contour = new GM_LineString();
296: ;
297: List arcsDuCycle = new ArrayList();
298: List orientationsDuCycle = new ArrayList();
299: List resultat = new ArrayList();
300: int i;
301:
302: // intialisation avec le premier arc du cycle (this) qui est par définition dans le bon sens
303: arcEnCours = this ;
304: sensEnCours = true;
305:
306: // on parcours le cycle dans le sens anti-trigonometrique,
307: // jusqu'à revenir sur this en le parcourant dans le bon sens
308: // (précision utile à la gestion des cul-de-sac).
309: while (true) {
310: // ajout de l'arc en cours au cycle...
311: arcsDuCycle.add(arcEnCours);
312: orientationsDuCycle.add(new Boolean(sensEnCours));
313: if (sensEnCours) { // arc dans le bon sens
314: for (i = 0; i < arcEnCours.getGeometrie()
315: .sizeControlPoint() - 1; i++) {
316: contour.addControlPoint(arcEnCours.getGeometrie()
317: .getControlPoint(i));
318: }
319: arcOriente = arcEnCours.arcSuivantFin();
320: } else { // arc dans le sens inverse
321: for (i = arcEnCours.getGeometrie().sizeControlPoint() - 1; i > 0; i--) {
322: contour.addControlPoint(arcEnCours.getGeometrie()
323: .getControlPoint(i));
324: }
325: arcOriente = arcEnCours.arcSuivantDebut();
326: }
327: if (arcOriente == null) {
328: return null;
329: }
330:
331: // au suivant...
332: arcEnCours = (Arc) arcOriente.get(0); //l'arc
333: sensEnCours = !((Boolean) arcOriente.get(1)).booleanValue(); //le sens de l'arc par rapport au cycle
334:
335: //c'est fini ?
336: if (arcEnCours == this && sensEnCours)
337: break;
338: }
339:
340: // ajout du dernier point pour finir la boucle du polygone
341: contour.addControlPoint(contour.startPoint());
342:
343: resultat.add(arcsDuCycle);
344: resultat.add(orientationsDuCycle);
345: resultat.add(new GM_Polygon(contour));
346: return resultat;
347: }
348:
349: /** Recherche du cycle du réseau à gauche de l'arc en se basant sur la topologie de RESEAU uniquement.
350: * Renvoie une liste (ArrayList) de 3 éléments :
351: * - get(0): Liste des arcs dans l'ordre de parcours du cycle.
352: * Liste classée dans le sens trigonometrique (sauf pour la face exterieure).
353: * (liste de type "ArrayList", contenant elle-même des "Arc").
354: * - get(1): Liste des orientations des arc : true si l'arc à sa face à gauche, false sinon
355: * (liste de type "ArrayList", contenant elle-même des objets "Boolean").
356: * - get(2) : La géométrie du polygone faisant le tour du cycle
357: * (de type "GM_Polygon)
358: * NB: la liste retournée est égale à null si on n'a pas trouvé de cycle
359: * (cas pouvant arriver si la topologie arcs/noeuds n'est pas complète.
360: * NB: ne nécessite PAS d'avoir une topologie arcs/faces instanciée.
361: * NB: nécessite d'avoir une topologie arcs/noeuds instanciée.
362: * NB: un cycle passe 2 fois (une fois dans chaque sens) par les cul-de-sac si il y en a.
363: */
364: public List cycleAGauche() {
365: Arc arcEnCours;
366: boolean sensEnCours;
367: List arcOriente;
368: GM_LineString contour = new GM_LineString();
369: ;
370: List arcsDuCycle = new ArrayList();
371: List orientationsDuCycle = new ArrayList();
372: List resultat = new ArrayList();
373: int i;
374:
375: // intialisation avec le premier arc du cycle (this) qui est par définition dans le bon sens
376: arcEnCours = this ;
377: sensEnCours = true;
378:
379: // on parcours le cycle dans le sens anti-trigonometrique,
380: // jusqu'à revenir sur this en le parcourant dans le bon sens
381: // (précision utile à la gestion des cul-de-sac).
382: while (true) {
383: // ajout de l'arc en cours au cycle...
384: arcsDuCycle.add(arcEnCours);
385: orientationsDuCycle.add(new Boolean(sensEnCours));
386: if (sensEnCours) { // arc dans le bon sens
387: for (i = 0; i < arcEnCours.getGeometrie()
388: .sizeControlPoint() - 1; i++) {
389: contour.addControlPoint(arcEnCours.getGeometrie()
390: .getControlPoint(i));
391: }
392: arcOriente = arcEnCours.arcPrecedentFin();
393: } else { // arc dans le sens inverse
394: for (i = arcEnCours.getGeometrie().sizeControlPoint() - 1; i > 0; i--) {
395: contour.addControlPoint(arcEnCours.getGeometrie()
396: .getControlPoint(i));
397: }
398: arcOriente = arcEnCours.arcPrecedentDebut();
399: }
400: if (arcOriente == null) {
401: return null;
402: }
403:
404: // au suivant...
405: arcEnCours = (Arc) arcOriente.get(0); //l'arc
406: sensEnCours = !((Boolean) arcOriente.get(1)).booleanValue(); //le sens de l'arc par rapport au cycle
407:
408: //c'est fini ?
409: if (arcEnCours == this && sensEnCours)
410: break;
411: }
412:
413: // ajout du dernier point pour finir la boucle du polygone
414: contour.addControlPoint(contour.startPoint());
415:
416: resultat.add(arcsDuCycle);
417: resultat.add(orientationsDuCycle);
418: resultat.add(new GM_Polygon(contour));
419: return resultat;
420: }
421:
422: /////////////////////////////////////////////////////////////////////////////////////////////////
423: // Gestion de type carte topopolgique
424: /////////////////////////////////////////////////////////////////////////////////////////////////
425: // Les arcs sont classés autour d'un noeud en fonction de leur géométrie.
426: // Ceci permet en particulier de parcourir facilement les cycles d'un graphe.
427: /////////////////////////////////////////////////////////////////////////////////////////////////
428:
429: /** Arc suivant self à son noeud final, au sens des cartes topologiques.
430: * L'arc suivant est l'arc incident au noeud final de self,
431: * et suivant self dans l'ordre trigonométrique autour de ce noeud final.
432: *
433: * NB: renvoie une liste de 2 éléments :
434: * element 1, liste.get(0) = l'arc
435: * element 2, liste.get(1) = Boolean, true si entrant, false si sortant
436: * NB: calcul réalisé pour chaque appel de la méthode.
437: * NB : l'arcSuivant peut être self, en cas de cul de sac sur le noeud final.
438: */
439: public List arcSuivantFin() {
440: if (this .getNoeudFin() == null)
441: return null;
442: List arcs = (List) this .getNoeudFin().arcsClasses().get(0);
443: List arcsOrientation = (List) this .getNoeudFin().arcsClasses()
444: .get(1);
445: Iterator itArcs = arcs.iterator();
446: Iterator itArcsOrientation = arcsOrientation.iterator();
447: Boolean orientationEntrant;
448: Arc arc;
449: List resultat = new ArrayList();
450:
451: // On parcours la liste des arcs autour du noeud final
452: // Quand on y rencontre this en tant qu'entrant, on renvoie le suivant dans la liste
453: // NB: cette notion d'entrant est nécesaire pour bien gérer les boucles
454: while (itArcs.hasNext()) {
455: arc = (Arc) itArcs.next();
456: orientationEntrant = (Boolean) itArcsOrientation.next();
457: if ((arc == this ) && orientationEntrant.booleanValue()) {
458: if (itArcs.hasNext()) {
459: resultat.add((Arc) itArcs.next());
460: resultat.add((Boolean) itArcsOrientation.next());
461: } else {
462: resultat.add((Arc) arcs.get(0));
463: resultat.add((Boolean) arcsOrientation.get(0));
464: }
465: return resultat;
466: }
467: }
468: return null;
469: }
470:
471: /** Arc suivant self à son noeud initial, au sens des cartes topologiques.
472: * L'arc suivant est l'arc incident au noeud initial de self,
473: * et suivant self dans l'ordre trigonométrique autour de ce noeud initial.
474: *
475: * NB: renvoie une liste de 2 éléments :
476: * element 1, liste.get(0) = l'arc
477: * element 2, liste.get(1) = Boolean, true si entrant, false si sortant
478: * NB: calcul réalisé pour chaque appel de la méthode.
479: * NB : l'arcSuivant peut être self, en cas de cul de sac sur le noeud initial.
480: */
481: public List arcSuivantDebut() {
482: if (this .getNoeudIni() == null)
483: return null;
484: List arcs = (List) this .getNoeudIni().arcsClasses().get(0);
485: List arcsOrientation = (List) this .getNoeudIni().arcsClasses()
486: .get(1);
487: Iterator itArcs = arcs.iterator();
488: Iterator itArcsOrientation = arcsOrientation.iterator();
489: Boolean orientationEntrant;
490: Arc arc;
491: List resultat = new ArrayList();
492:
493: // On parcours la liste des arcs autour du noeud initial
494: // Quand on y rencontre this en tant que sortant, on renvoie le suivant dans la liste
495: // NB: cette notion de sortant est nécesaire pour bien gérer les boucles.
496: while (itArcs.hasNext()) {
497: arc = (Arc) itArcs.next();
498: orientationEntrant = (Boolean) itArcsOrientation.next();
499: if ((arc == this ) && !orientationEntrant.booleanValue()) {
500: if (itArcs.hasNext()) {
501: resultat.add((Arc) itArcs.next());
502: resultat.add((Boolean) itArcsOrientation.next());
503: } else {
504: resultat.add((Arc) arcs.get(0));
505: resultat.add((Boolean) arcsOrientation.get(0));
506: }
507: return resultat;
508: }
509: }
510: return null;
511: }
512:
513: /** Arc précédant self à son noeud final, au sens des cartes topologiques.
514: * L'arc précédent est l'arc incident au noeud final de self,
515: * et précédant self dans l'ordre trigonométrique autour de ce noeud final.
516: *
517: * NB: renvoie une liste de 2 éléments :
518: * element 1, liste.get(0) = l'arc
519: * element 2, liste.get(1) = Boolean, true si entrant, false si sortant
520: * NB: calcul réalisé pour chaque appel de la méthode.
521: * NB : l'arc précédent peut être self, en cas de cul de sac sur le noeud final.
522: */
523: public List arcPrecedentFin() {
524: if (this .getNoeudFin() == null)
525: return null;
526: List arcs = (List) this .getNoeudFin().arcsClasses().get(0);
527: List arcsOrientation = (List) this .getNoeudFin().arcsClasses()
528: .get(1);
529: Iterator itArcs = arcs.iterator();
530: Iterator itArcsOrientation = arcsOrientation.iterator();
531: Boolean orientationEntrant, orientationPrecedent;
532: Arc arc, arcPrecedent;
533: List resultat = new ArrayList();
534:
535: // On parcours la liste des arcs autour du noeud final
536: // Quand on y rencontre this en tant qu'entrant, on renvoie le précédant dans la liste
537: // NB: cette notion de précédant est nécesaire pour bien gérer les boucles.
538: arc = (Arc) itArcs.next();
539: orientationEntrant = (Boolean) itArcsOrientation.next();
540: if ((arc == this ) && orientationEntrant.booleanValue()) {
541: resultat.add((Arc) arcs.get(arcs.size() - 1));
542: resultat
543: .add((Boolean) arcsOrientation.get(arcs.size() - 1));
544: return resultat;
545: }
546: while (itArcs.hasNext()) {
547: arcPrecedent = arc;
548: orientationPrecedent = orientationEntrant;
549: arc = (Arc) itArcs.next();
550: orientationEntrant = (Boolean) itArcsOrientation.next();
551: if ((arc == this ) && orientationEntrant.booleanValue()) {
552: resultat.add(arcPrecedent);
553: resultat.add(orientationPrecedent);
554: return resultat;
555: }
556: }
557: return null;
558: }
559:
560: /** Arc précédent self à son noeud initial, au sens des cartes topologiques.
561: * L'arc précédent est l'arc incident au noeud initial de self,
562: * et précédent self dans l'ordre trigonométrique autour de ce noeud initial.
563: *
564: * NB: renvoie une liste de 2 éléments :
565: * element 1, liste.get(0) = l'arc
566: * element 2, liste.get(1) = Boolean, true si entrant, false si sortant
567: * NB: calcul réalisé pour chaque appel de la méthode.
568: * NB : l'arc précédent peut être self, en cas de cul de sac sur le noeud initial.
569: */
570: public List arcPrecedentDebut() {
571: if (this .getNoeudIni() == null)
572: return null;
573: List arcs = (List) this .getNoeudIni().arcsClasses().get(0);
574: List arcsOrientation = (List) this .getNoeudIni().arcsClasses()
575: .get(1);
576: Iterator itArcs = arcs.iterator();
577: Iterator itArcsOrientation = arcsOrientation.iterator();
578: Boolean orientationEntrant, orientationPrecedent;
579: Arc arc, arcPrecedent;
580: List resultat = new ArrayList();
581:
582: // On parcours la liste des arcs autour du noeud initial
583: // Quand on y rencontre this en tant que sortant, on renvoie le précédant dans la liste
584: // NB: cette notion de précédant est nécesaire pour bien gérer les boucles.
585: arc = (Arc) itArcs.next();
586: orientationEntrant = (Boolean) itArcsOrientation.next();
587: if ((arc == this ) && !orientationEntrant.booleanValue()) {
588: resultat.add((Arc) arcs.get(arcs.size() - 1));
589: resultat
590: .add((Boolean) arcsOrientation.get(arcs.size() - 1));
591: return resultat;
592: }
593: while (itArcs.hasNext()) {
594: arcPrecedent = arc;
595: orientationPrecedent = orientationEntrant;
596: arc = (Arc) itArcs.next();
597: orientationEntrant = (Boolean) itArcsOrientation.next();
598: if ((arc == this ) && !orientationEntrant.booleanValue()) {
599: resultat.add(arcPrecedent);
600: resultat.add(orientationPrecedent);
601: return resultat;
602: }
603: }
604: return null;
605: }
606:
607: /////////////////////////////////////////////////////////////////////////////////////////////////
608: // Gestion d'un réseau orienté
609: /////////////////////////////////////////////////////////////////////////////////////////////////
610: // NB: ne pas confondre orientation définie par l'attribut "orientation" (traité ici),
611: // et l'orientation définie implicitement par le sens de stockage de la géométrie
612:
613: private int orientation = 2;
614:
615: /** Renvoie l'orientation. L'orientation vaut 2 dans les deux sens, -1 en sens indirect et 1 en sens direct */
616: public int getOrientation() {
617: return this .orientation;
618: }
619:
620: /** Définit l'orientation. L'orientation vaut 2 dans les deux sens, -1 en sens indirect et 1 en sens direct */
621: public void setOrientation(int orientation) {
622: this .orientation = orientation;
623: }
624:
625: /* Noeuds initiaux de l'arc, au sens de son orientation.
626: * Si l'arc est en double sens (orientation = 2), les deux noeuds extrémités sont renvoyés.
627: * Sinon, un seul noeud est renvoyé.
628: * NB: à ne pas confondre avec getNoeudIni, qui renvoie le noeud initial au sens du stockage
629: */
630: public List inisOrientes() {
631: List noeuds = new ArrayList();
632: if ((orientation == 2 || orientation == 1)
633: && !(noeudIni == null))
634: noeuds.add(noeudIni);
635: if ((orientation == 2 || orientation == -1)
636: && !(noeudFin == null))
637: noeuds.add(noeudFin);
638: return noeuds;
639: }
640:
641: /* Noeuds finaux de l'arc, au sens de son orientation.
642: * Si l'arc est en double sens (orientation = 2), les deux noeuds extrémités sont renvoyés.
643: * Sinon, un seul noeud est renvoyé.
644: * NB: à ne pas confondre avec getNoeudFin, qui renvoie le noeud final au sens du stockage
645: */
646: public List finsOrientes() {
647: List noeuds = new ArrayList();
648: if ((orientation == 2 || orientation == -1)
649: && !(noeudIni == null))
650: noeuds.add(noeudIni);
651: if ((orientation == 2 || orientation == 1)
652: && !(noeudFin == null))
653: noeuds.add(noeudFin);
654: return noeuds;
655: }
656:
657: // ///////////////////////////////////////////////////////////////////////////////////////////////
658: // Gestion des poids pour les plus courts chemins
659: // ///////////////////////////////////////////////////////////////////////////////////////////////
660: private double poids = 0;
661:
662: /** Renvoie le poids de l'arc, pour les calculs de plus court chemin */
663: public double getPoids() {
664: return this .poids;
665: }
666:
667: /** Définit le poids de l'arc, pour les calculs de plus court chemin */
668: public void setPoids(double d) {
669: this .poids = d;
670: }
671:
672: /////////////////////////////////////////////////////////////////////////////////////////////////
673: // Gestion des groupes
674: /////////////////////////////////////////////////////////////////////////////////////////////////
675:
676: /* Groupes auquels self appartient */
677: private Collection listeGroupes = new ArrayList();
678:
679: /** Renvoie la liste des groupes de self*/
680: public Collection getListeGroupes() {
681: return this .listeGroupes;
682: }
683:
684: /** Définit la liste des groupes de self*/
685: public void setListegroupes(Collection liste) {
686: this .listeGroupes = liste;
687: }
688:
689: /** Ajoute un groupe à self*/
690: public void addGroupe(Groupe groupe) {
691: if (groupe != null && !listeGroupes.contains(groupe)) {
692: this .listeGroupes.add(groupe);
693: if (!groupe.getListeArcs().contains(this ))
694: groupe.addArc(this );
695: }
696: }
697:
698: /////////////////////////////////////////////////////////////////////////////////////////////////
699: // Pour la gestion des requetes spatiales
700: /////////////////////////////////////////////////////////////////////////////////////////////////
701: private Rectangle rectangleEnglobant = null;
702:
703: /** Rectangle englobant de l'arc, orienté le long des axes des x,y.
704: * NB: le rectangle est calculé au premier appel de cette fonction.
705: * Si l'arc est modifié, la valeur n'est pas mise à jour : il faut le faire explicitement au besoin avec calculeRectangleEnglobant.
706: */
707: public Rectangle getRectangleEnglobant() {
708: if (this .rectangleEnglobant == null)
709: this .calculeRectangleEnglobant();
710: return this .rectangleEnglobant;
711: }
712:
713: /** Calcule le rectangle englobant x,y en fonction de la géométrie */
714: public void calculeRectangleEnglobant() {
715: this .rectangleEnglobant = Rectangle.rectangleEnglobant(this
716: .getGeometrie());
717: }
718:
719: protected boolean proche(Arc arc, double distance) {
720: return arc.getRectangleEnglobant().intersecte(
721: this .getRectangleEnglobant().dilate(distance));
722: }
723:
724: /////////////////////////////////////////////////////////////////////////////////////////////////
725: // Opérateurs de calculs sur les arcs
726: /////////////////////////////////////////////////////////////////////////////////////////////////
727: /** Distance euclidienne entre le noeud et self */
728: public double distance(Noeud noeud) {
729: return (Distances.distance(noeud.getCoord(), this
730: .getGeometrie()));
731: }
732:
733: /** Première composante de la distance de Hausdorff de self vers l'arc.
734: * Elle est calculee comme le maximum des distances d'un point intermediaire
735: * de self à l'arc. Cette approximation peut différer sensiblement
736: * de la definition theorique.
737: * NB : défini en théorie à 3D, mais non vérifié en profondeur */
738: public double premiereComposanteHausdorff(Arc arc) {
739: return (Distances.premiereComposanteHausdorff(this
740: .getGeometrie(), arc.getGeometrie()));
741: }
742:
743: /** Distance de Hausdorff entre self et l'arc.
744: * Elle est calculee comme le maximum des distances d'un point intermediaire
745: * d'une des lignes a l'autre ligne. Dans certains cas cette definition
746: * differe de la definition theorique car la distance de Hausdorff ne se
747: * realise pas necessairement sur un point intermediaire. Mais cela est rare
748: * sur des données réel. Cette implementation est un bon compromis entre
749: * simplicité et précision.
750: * NB : défini en théorie à 3D, mais non vérifié en profondeur */
751: public double hausdorff(Arc arc) {
752: return (Distances.hausdorff(this .getGeometrie(), arc
753: .getGeometrie()));
754: }
755:
756: /** Longueur euclidienne de l'arc. Est calculé en 3D si la géométrie est définie en 3D */
757: public double longueur() {
758: return this.getGeometrie().length();
759: }
760:
761: }
|