0001: /*
0002: * This file is part of the GeOxygene project source files.
0003: *
0004: * GeOxygene aims at providing an open framework which implements OGC/ISO specifications for
0005: * the development and deployment of geographic (GIS) applications. It is a open source
0006: * contribution of the COGIT laboratory at the Institut Géographique National (the French
0007: * National Mapping Agency).
0008: *
0009: * See: http://oxygene-project.sourceforge.net
0010: *
0011: * Copyright (C) 2005 Institut Géographique National
0012: *
0013: * This library is free software; you can redistribute it and/or modify it under the terms
0014: * of the GNU Lesser General Public License as published by the Free Software Foundation;
0015: * either version 2.1 of the License, or any later version.
0016: *
0017: * This library is distributed in the hope that it will be useful, but WITHOUT ANY
0018: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0019: * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
0020: *
0021: * You should have received a copy of the GNU Lesser General Public License along with
0022: * this library (see file LICENSE if present); if not, write to the Free Software
0023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0024: *
0025: */
0026:
0027: package fr.ign.cogit.geoxygene.contrib.cartetopo;
0028:
0029: import java.util.ArrayList;
0030: import java.util.Iterator;
0031: import java.util.List;
0032:
0033: import fr.ign.cogit.geoxygene.contrib.geometrie.Distances;
0034: import fr.ign.cogit.geoxygene.contrib.geometrie.Operateurs;
0035: import fr.ign.cogit.geoxygene.feature.DataSet;
0036: import fr.ign.cogit.geoxygene.feature.FT_Feature;
0037: import fr.ign.cogit.geoxygene.feature.FT_FeatureCollection;
0038: import fr.ign.cogit.geoxygene.feature.Population;
0039: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPosition;
0040: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPositionList;
0041: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Envelope;
0042: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_LineString;
0043: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Polygon;
0044: import fr.ign.cogit.geoxygene.spatial.geomaggr.GM_MultiCurve;
0045: import fr.ign.cogit.geoxygene.spatial.geomaggr.GM_MultiPoint;
0046: import fr.ign.cogit.geoxygene.spatial.geomprim.GM_Point;
0047: import fr.ign.cogit.geoxygene.spatial.geomprim.GM_Ring;
0048: import fr.ign.cogit.geoxygene.spatial.geomroot.GM_Object;
0049: import fr.ign.cogit.geoxygene.util.index.Tiling;
0050:
0051: /**
0052: * Classe racine de la carte topo.
0053: * Une carte topo est une composition d'arcs, de noeuds, de faces et de groupes.
0054: * Une carte topo est vue comme un DataSet particulier.
0055: * Elle a éventuellement une topologie (SPAGHETTI, NETWORK ou MAP).
0056: *
0057: * English: a topological map is an oriented graph, with arcs sorted around the nodes;
0058: * @author Mustière/Bonin
0059: * @version 1.0
0060: */
0061:
0062: public class CarteTopo extends DataSet {
0063:
0064: // Accès aux composants de la carte topo
0065:
0066: /** Population des arcs de la carte topo. */
0067: public Population getPopArcs() {
0068: return this .getPopulation("Arc");
0069: }
0070:
0071: /** Population des noeuds de la carte topo. */
0072: public Population getPopNoeuds() {
0073: return this .getPopulation("Noeud");
0074: }
0075:
0076: /** Population des faces de la carte topo. */
0077: public Population getPopFaces() {
0078: return this .getPopulation("Face");
0079: }
0080:
0081: /** Population des groupes de la carte topo. */
0082: public Population getPopGroupes() {
0083: return this .getPopulation("Groupe");
0084: }
0085:
0086: /** Liste des noeuds de la carte topo. Surcharge de getPopNoeuds().getElements(). */
0087: public List getListeNoeuds() {
0088: return this .getPopNoeuds().getElements();
0089: }
0090:
0091: /** Liste des arcs de la carte topo. Surcharge de getPopArcs().getElements(). */
0092: public List getListeArcs() {
0093: return this .getPopArcs().getElements();
0094: }
0095:
0096: /** Liste des faces de la carte topo. Surcharge de getPopFaces().getElements(). */
0097: public List getListeFaces() {
0098: return this .getPopFaces().getElements();
0099: }
0100:
0101: /** Liste des groupes de la carte topo. Surcharge de getPopGroupes().getElements(). */
0102: public List getListeGroupes() {
0103: return this .getPopGroupes().getElements();
0104: }
0105:
0106: /** Ajoute un noeud à la population des noeuds de la carte topo.
0107: Attention : même si la carte topo est persistante, le noeud n'est pas rendu persistant dans cette méthode */
0108: public void addNoeud(Noeud noeud) {
0109: this .getPopNoeuds().add(noeud);
0110: }
0111:
0112: /** Ajoute un arc à la population des arcs de la carte topo.
0113: Attention : même si la carte topo est persistante, le noeud n'est pas rendu persistant dans cette méthode */
0114: public void addArc(Arc arc) {
0115: this .getPopArcs().add(arc);
0116: }
0117:
0118: /** Ajoute une face à la population des faces de la carte topo.
0119: Attention : même si la carte topo est persistante, le noeud n'est pas rendu persistant dans cette méthode */
0120: public void addFace(Face face) {
0121: this .getPopFaces().add(face);
0122: }
0123:
0124: /** Ajoute un groupe à la population des groupes de la carte topo.
0125: Attention : même si la carte topo est persistante, le noeud n'est pas rendu persistant dans cette méthode */
0126: public void addGroupe(Groupe groupe) {
0127: this .getPopGroupes().add(groupe);
0128: }
0129:
0130: /////////////////////////////////////////////////////////////////////////////////////////////
0131: // Constructeurs
0132: /////////////////////////////////////////////////////////////////////////////////////////////
0133: /** Constructeur par défaut;
0134: * ATTENTION, constructeur à éviter car aucune population n'est créée:
0135: * seule un objet carteTopo est créé */
0136: public CarteTopo() {
0137: }
0138:
0139: /** Constructeur d'une carte topo non persistante.
0140: * Le nom logique peut ête utilisé si la carte topo apparient à un DataSet,
0141: * il peut être une chaîne vide sinon.
0142: *
0143: * Par ce constructeur, la carte topo contient des arcs/noeuds/faces/groupes
0144: * des classes CarteTopo.Arc, CarteTopo.Noeud, CarteTopo.Face, CarteTopo.Groupe.
0145: */
0146: public CarteTopo(String nomLogique) {
0147: this .ojbConcreteClass = this .getClass().getName(); // nécessaire pour ojb
0148: this .setNom(nomLogique);
0149: this .setPersistant(false);
0150: Population arcs = new Population(false, "Arc",
0151: fr.ign.cogit.geoxygene.contrib.cartetopo.Arc.class,
0152: true);
0153: this .addPopulation(arcs);
0154: Population noeuds = new Population(false, "Noeud",
0155: fr.ign.cogit.geoxygene.contrib.cartetopo.Noeud.class,
0156: true);
0157: this .addPopulation(noeuds);
0158: Population faces = new Population(false, "Face",
0159: fr.ign.cogit.geoxygene.contrib.cartetopo.Face.class,
0160: true);
0161: this .addPopulation(faces);
0162: Population groupes = new Population(false, "Groupe",
0163: fr.ign.cogit.geoxygene.contrib.cartetopo.Groupe.class,
0164: false);
0165: this .addPopulation(groupes);
0166: }
0167:
0168: /////////////////////////////////////////////////////////////////////////////////////////////
0169: // Attributs de la carte topo
0170: /////////////////////////////////////////////////////////////////////////////////////////////
0171:
0172: // Description de la structure topologique
0173: /** Spaghetti = pas de relation topologique entre arcs, noeuds et faces */
0174: public static final int SPAGHETTI = 0;
0175: /** Network = topologie arc / noeuds */
0176: public static final int NETWORK = 1;
0177: /** Network = topologie arc / noeuds / faces */
0178: public static final int MAP = 2;
0179: /** Niveau de topologie :
0180: * SPAGHETTI = pas de topologie ; NETWORK = topologie arcs/noeuds ; MAP (par défaut) = topologie arcs/noeuds/faces
0181: * NB : utiliser les constantes SPAGHETTI, NETWORK ou MAP pour remplir cet attribut.
0182: * Remarque codeurs : Le code se sert très peu de l'attribut "type" pour l'instant. A revoir.
0183: */
0184: private int type = MAP;
0185:
0186: public int getType() {
0187: return type;
0188: }
0189:
0190: public void setType(int i) {
0191: type = i;
0192: }
0193:
0194: /////////////////////////////////////////////////////////////////////////////////////////////
0195: // COPIE et VIDAGE de la carte topo
0196: /////////////////////////////////////////////////////////////////////////////////////////////
0197: /** Copie d'une carte topologique avec toutes les relations topologiques.
0198: * Les liens "correspondants" sont aussi dupliqués.
0199: *
0200: * ATTENTION: ne fonctionne bien que pour une carteTopo non spécialisée
0201: * (i.e. avec carteTopo.Arc, carte.Noeud...).
0202: * En effet, les objets copiés appartiendront au package cartetopo.
0203: */
0204: public CarteTopo copie(String nomLogique) {
0205: Noeud noeud, noeudCopie;
0206: Arc arc, arcCopie;
0207: Face face, faceCopie;
0208: Groupe groupe, groupeCopie;
0209: FT_Feature corresp;
0210: Iterator itNoeuds, itArcs, itCorresp, itArcsCopies, itFaces, itGroupes, itGroupesCopies;
0211: ArrayList noeuds, noeudsCopies, arcs, arcsCopies, faces, facesCopies;
0212:
0213: // création d'une nouvelle carte
0214: CarteTopo carte = new CarteTopo(nomLogique);
0215:
0216: // copie des objets, sans relation topologique
0217: itNoeuds = this .getPopNoeuds().getElements().iterator();
0218: while (itNoeuds.hasNext()) {
0219: noeud = (Noeud) itNoeuds.next();
0220: noeudCopie = (Noeud) carte.getPopNoeuds().nouvelElement();
0221: noeudCopie.setGeometrie(noeud.getGeometrie());
0222: itCorresp = noeud.getCorrespondants().iterator();
0223: while (itCorresp.hasNext()) {
0224: corresp = (FT_Feature) itCorresp.next();
0225: noeudCopie.addCorrespondant(corresp);
0226: }
0227: }
0228: itArcs = this .getPopArcs().getElements().iterator();
0229: while (itArcs.hasNext()) {
0230: arc = (Arc) itArcs.next();
0231: arcCopie = (Arc) carte.getPopArcs().nouvelElement();
0232: arcCopie.setGeometrie(arc.getGeometrie());
0233: itCorresp = arc.getCorrespondants().iterator();
0234: while (itCorresp.hasNext()) {
0235: corresp = (FT_Feature) itCorresp.next();
0236: arcCopie.addCorrespondant(corresp);
0237: }
0238: }
0239: itFaces = this .getPopFaces().getElements().iterator();
0240: while (itFaces.hasNext()) {
0241: face = (Face) itFaces.next();
0242: faceCopie = (Face) carte.getPopFaces().nouvelElement();
0243: faceCopie.setGeometrie(face.getGeometrie());
0244: itCorresp = face.getCorrespondants().iterator();
0245: while (itCorresp.hasNext()) {
0246: corresp = (FT_Feature) itCorresp.next();
0247: faceCopie.addCorrespondant(corresp);
0248: }
0249: }
0250: itGroupes = this .getPopGroupes().getElements().iterator();
0251: while (itGroupes.hasNext()) {
0252: groupe = (Groupe) itGroupes.next();
0253: groupeCopie = (Groupe) carte.getPopGroupes()
0254: .nouvelElement();
0255: itCorresp = groupe.getCorrespondants().iterator();
0256: while (itCorresp.hasNext()) {
0257: corresp = (FT_Feature) itCorresp.next();
0258: groupeCopie.addCorrespondant(corresp);
0259: }
0260: }
0261:
0262: if (type == SPAGHETTI)
0263: return carte;
0264:
0265: // copie des relations topologiques
0266: noeuds = new ArrayList(this .getPopNoeuds().getElements());
0267: noeudsCopies = new ArrayList(carte.getPopNoeuds().getElements());
0268: arcs = new ArrayList(this .getPopArcs().getElements());
0269: arcsCopies = new ArrayList(carte.getPopArcs().getElements());
0270: faces = new ArrayList(this .getPopFaces().getElements());
0271: facesCopies = new ArrayList(carte.getPopArcs().getElements());
0272:
0273: itArcs = this .getPopArcs().getElements().iterator();
0274: itArcsCopies = carte.getPopArcs().getElements().iterator();
0275: while (itArcs.hasNext()) {
0276: arc = (Arc) itArcs.next();
0277: arcCopie = (Arc) itArcsCopies.next();
0278: arcCopie.setNoeudIni((Noeud) noeudsCopies.get(noeuds
0279: .indexOf(arc.getNoeudIni())));
0280: arcCopie.setNoeudFin((Noeud) noeudsCopies.get(noeuds
0281: .indexOf(arc.getNoeudFin())));
0282: if (arc.getFaceGauche() != null) {
0283: arcCopie.setFaceGauche((Face) facesCopies.get(faces
0284: .indexOf(arc.getFaceGauche())));
0285: }
0286: if (arc.getFaceDroite() != null) {
0287: arcCopie.setFaceDroite((Face) facesCopies.get(faces
0288: .indexOf(arc.getFaceDroite())));
0289: }
0290: }
0291:
0292: itGroupes = this .getPopGroupes().getElements().iterator();
0293: itGroupesCopies = carte.getPopGroupes().getElements()
0294: .iterator();
0295: while (itGroupes.hasNext()) {
0296: groupe = (Groupe) itGroupes.next();
0297: groupeCopie = (Groupe) itGroupesCopies.next();
0298: itNoeuds = groupeCopie.getListeNoeuds().iterator();
0299: while (itNoeuds.hasNext()) {
0300: noeud = (Noeud) itNoeuds.next();
0301: groupeCopie.addNoeud((Noeud) noeudsCopies.get(noeuds
0302: .indexOf(noeud)));
0303: }
0304: itArcs = groupeCopie.getListeArcs().iterator();
0305: while (itArcs.hasNext()) {
0306: arc = (Arc) itArcs.next();
0307: groupeCopie.addArc((Arc) arcsCopies.get(arcs
0308: .indexOf(arc)));
0309: }
0310: itFaces = groupeCopie.getListeFaces().iterator();
0311: while (itFaces.hasNext()) {
0312: face = (Face) itFaces.next();
0313: groupeCopie.addFace((Face) facesCopies.get(faces
0314: .indexOf(face)));
0315: }
0316: }
0317: return carte;
0318: }
0319:
0320: /** Enlève des arcs de la carteTopo, en enlevant aussi les relations topologiques
0321: * les concernant (avec les faces et noeuds).
0322: */
0323: public void enleveArcs(List arcsAEnlever) {
0324: Iterator itArcs = arcsAEnlever.iterator();
0325: Arc arc;
0326: while (itArcs.hasNext()) {
0327: arc = (Arc) itArcs.next();
0328: this .getPopArcs().remove(arc);
0329: arc.setNoeudFin(null);
0330: arc.setNoeudIni(null);
0331: arc.setFaceDroite(null);
0332: arc.setFaceGauche(null);
0333: }
0334: }
0335:
0336: /** Enlève des noeuds de la carteTopo, en enlevant aussi les relations topologiques
0337: * les concernant (avec les arcs et par conséquent avec les faces).
0338: */
0339: public void enleveNoeuds(List noeudsAEnlever) {
0340: Iterator itNoeuds = noeudsAEnlever.iterator();
0341: Iterator itArcs;
0342: Noeud noeud;
0343: Arc arc;
0344: while (itNoeuds.hasNext()) {
0345: noeud = (Noeud) itNoeuds.next();
0346: this .getPopNoeuds().remove(noeud);
0347: itArcs = noeud.getEntrants().iterator();
0348: while (itArcs.hasNext()) {
0349: arc = (Arc) itArcs.next();
0350: arc.setNoeudFin(null);
0351: }
0352: itArcs = noeud.getSortants().iterator();
0353: while (itArcs.hasNext()) {
0354: arc = (Arc) itArcs.next();
0355: arc.setNoeudIni(null);
0356: }
0357: }
0358: }
0359:
0360: /** Enlève des faces de la carteTopo, en enlevant aussi les relations topologiques
0361: * les concernant (avec les arcs et par conséquent avec les noeuds).
0362: */
0363: public void enleveFaces(List facesAEnlever) {
0364: Iterator itFaces = facesAEnlever.iterator();
0365: Iterator itArcs;
0366: Face face;
0367: Arc arc;
0368: while (itFaces.hasNext()) {
0369: face = (Face) itFaces.next();
0370: this .getPopFaces().remove(face);
0371: itArcs = face.getArcsDirects().iterator();
0372: while (itArcs.hasNext()) {
0373: arc = (Arc) itArcs.next();
0374: arc.setFaceGauche(null);
0375: }
0376: itArcs = face.getArcsIndirects().iterator();
0377: while (itArcs.hasNext()) {
0378: arc = (Arc) itArcs.next();
0379: arc.setFaceDroite(null);
0380: }
0381: }
0382: }
0383:
0384: /////////////////////////////////////////////////////////////////////////////////////////////
0385: // Instanciation ou nettoyage de la topologie de réseau
0386: /////////////////////////////////////////////////////////////////////////////////////////////
0387:
0388: /** Instancie la topologie de réseau d'une Carte Topo,
0389: * en se basant sur la géométrie 2D des arcs et des noeuds.
0390: * Autrement dit: crée les relation "noeud initial" et "noeud final" d'un arc.
0391: *
0392: * ATTENTION: cette méthode ne rajoute pas de noeuds. Si un arc n'a pas de noeud
0393: * localisé à son extrémité, il n'aura pas de noeud initial (ou final).
0394: * DE PLUS si plusieurs noeuds sont trop proches (cf. param tolérance),
0395: * alors un des noeuds est choisi au hasard pour la relation arc/noeud,
0396: * ce qui n'est pas correct.
0397: * IL EST DONC CONSEILLE DE FILTRER LES DOUBLONS AVANT SI NECESSAIRE.
0398: *
0399: * NB: si cela n'avait pas été fait avant,
0400: * la population des noeuds est indexée dans cette méthode
0401: * (dallage, paramètre = 20).
0402: *
0403: * @param tolerance
0404: * Le paramètre "tolerance" spécifie la distance maximale acceptée entre
0405: * la position d'un noeud et la position d'une extrémité de ligne,
0406: * pour considérer ce noeud comme extrémité (la tolérance peut être nulle).
0407: *
0408: */
0409: public void creeTopologieArcsNoeuds(double tolerance) {
0410: Arc arc;
0411: Iterator itArcs;
0412: FT_FeatureCollection selection;
0413:
0414: // initialisation de l'index au besoin
0415: if (!this .getPopNoeuds().hasSpatialIndex())
0416: this .getPopNoeuds()
0417: .initSpatialIndex(Tiling.class, true, 20);
0418:
0419: itArcs = this .getPopArcs().getElements().iterator();
0420: while (itArcs.hasNext()) {
0421: arc = (Arc) itArcs.next();
0422: selection = this .getPopNoeuds().select(
0423: arc.getGeometrie().startPoint(), tolerance);
0424: if (selection.getElements().size() != 0)
0425: arc.setNoeudIni((Noeud) selection.getElements().get(0));
0426: selection = this .getPopNoeuds().select(
0427: arc.getGeometrie().endPoint(), tolerance);
0428: if (selection.getElements().size() != 0)
0429: arc.setNoeudFin((Noeud) selection.getElements().get(0));
0430: }
0431:
0432: }
0433:
0434: /** Crée un nouveau noeud à l'extrémité de chaque arc si il n'y en a pas.
0435: * Les noeuds existants sont tous conservés.
0436: *
0437: * NB: la topologie arcs/noeuds est instanciée au passage.
0438: *
0439: * NB: si cela n'avait pas été fait avant,
0440: * la population des noeuds est indexée dans cette méthode.
0441: * Paramètres de l'index = le même que celui des arcs si il existe,
0442: * sinon Dallage avec à peu près 50 noeuds par dalle.
0443: *
0444: */
0445: public void creeNoeudsManquants(double tolerance) {
0446: Arc arc;
0447: Noeud noeud;
0448: Iterator itArcs;
0449: FT_FeatureCollection selection;
0450:
0451: // initialisation de l'index au besoin
0452: // si on peut, on prend les mêmes paramètres que le dallage des arcs
0453: if (!this .getPopNoeuds().hasSpatialIndex()) {
0454: if (this .getPopArcs().hasSpatialIndex()) {
0455: this .getPopNoeuds().initSpatialIndex(
0456: this .getPopArcs().getSpatialIndex());
0457: this .getPopNoeuds().getSpatialIndex()
0458: .setAutomaticUpdate(true);
0459: } else {
0460: GM_Envelope enveloppe = this .getPopArcs().envelope();
0461: int nb = (int) Math.sqrt(this .getPopArcs().size() / 20);
0462: if (nb == 0)
0463: nb = 1;
0464: this .getPopNoeuds().initSpatialIndex(Tiling.class,
0465: true, enveloppe, nb);
0466: }
0467: }
0468:
0469: itArcs = this .getPopArcs().getElements().iterator();
0470: ;
0471: while (itArcs.hasNext()) {
0472: arc = (Arc) itArcs.next();
0473: //noeud initial
0474: selection = this .getPopNoeuds().select(
0475: arc.getGeometrie().startPoint(), tolerance);
0476: if (selection.getElements().size() == 0) {
0477: noeud = (Noeud) this .getPopNoeuds().nouvelElement(
0478: new GM_Point(arc.getGeometrie().startPoint()));
0479: } else
0480: noeud = (Noeud) selection.getElements().get(0);
0481: arc.setNoeudIni(noeud);
0482:
0483: //noeud final
0484: selection = this .getPopNoeuds().select(
0485: arc.getGeometrie().endPoint(), tolerance);
0486: if (selection.getElements().size() == 0) {
0487: noeud = (Noeud) this .getPopNoeuds().nouvelElement(
0488: new GM_Point(arc.getGeometrie().endPoint()));
0489: } else
0490: noeud = (Noeud) selection.getElements().get(0);
0491: arc.setNoeudFin(noeud);
0492: }
0493: }
0494:
0495: /** Filtrage des noeuds isolés (c'est-à-dire connectés à aucun arc).
0496: * Ceux-ci sont enlevés de la Carte Topo
0497: * IMPORTANT : La topologie de réseau doit avoir été instanciée,
0498: * sinon tous les noeuds sont enlevés.
0499: */
0500: public void filtreNoeudsIsoles() {
0501: Iterator itNoeuds;
0502: List aJeter = new ArrayList();
0503: Noeud noeud;
0504:
0505: itNoeuds = this .getPopNoeuds().getElements().iterator();
0506: while (itNoeuds.hasNext()) {
0507: noeud = (Noeud) itNoeuds.next();
0508: if (noeud.arcs().size() == 0)
0509: aJeter.add(noeud);
0510: }
0511: itNoeuds = aJeter.iterator();
0512: while (itNoeuds.hasNext()) {
0513: noeud = (Noeud) itNoeuds.next();
0514: this .getPopNoeuds().enleveElement(noeud);
0515: }
0516: }
0517:
0518: /** Filtrage des noeuds doublons (plusieurs noeuds localisés au même endroit).
0519: *
0520: * NB: si cela n'avait pas été fait avant,
0521: * la population des noeuds est indexée dans cette méthode
0522: * (dallage, paramètre = 20).
0523: *
0524: * Cette méthode gère les conséquences sur la topologie,
0525: * si celle-ci a été instanciée auparavant.
0526: * Cette méthode gère aussi les conséquences sur les correspondants (un
0527: * noeud gardé a pour correspondants tous les correspondants des doublons).
0528: *
0529: * @param tolerance
0530: * Le paramètre tolérance spécifie la distance maximale pour considérer deux
0531: * noeuds positionnés au même endroit.
0532: */
0533: public void filtreDoublons(double tolerance) {
0534: Iterator itNoeuds, itDoublons, itCorresp, itArcs;
0535: Noeud doublon, noeud;
0536: Arc arc;
0537: FT_Feature corresp;
0538: List aJeter = new ArrayList();
0539: FT_FeatureCollection selection;
0540:
0541: // initialisation de l'index au besoin
0542: if (!this .getPopNoeuds().hasSpatialIndex()) {
0543: this .getPopNoeuds()
0544: .initSpatialIndex(Tiling.class, true, 20);
0545: }
0546: itNoeuds = this .getPopNoeuds().getElements().iterator();
0547: while (itNoeuds.hasNext()) {
0548: noeud = (Noeud) itNoeuds.next();
0549: if (aJeter.contains(noeud))
0550: continue;
0551: selection = this .getPopNoeuds().select(noeud.getCoord(),
0552: tolerance);
0553: itDoublons = selection.getElements().iterator();
0554: while (itDoublons.hasNext()) {
0555: doublon = (Noeud) itDoublons.next();
0556: if (doublon == noeud)
0557: continue;
0558: // on a trouvé un doublon à jeter
0559: // on gère les conséquences sur la topologie et les correspondants
0560: aJeter.add(doublon);
0561: itCorresp = doublon.getCorrespondants().iterator();
0562: while (itCorresp.hasNext()) {
0563: corresp = (FT_Feature) itCorresp.next();
0564: noeud.addCorrespondant(corresp);
0565: }
0566: itArcs = doublon.getEntrants().iterator();
0567: while (itArcs.hasNext()) {
0568: arc = (Arc) itArcs.next();
0569: noeud.addEntrant(arc);
0570: }
0571: itArcs = doublon.getSortants().iterator();
0572: while (itArcs.hasNext()) {
0573: arc = (Arc) itArcs.next();
0574: noeud.addSortant(arc);
0575: }
0576: }
0577: }
0578: itNoeuds = aJeter.iterator();
0579: while (itNoeuds.hasNext()) {
0580: noeud = (Noeud) itNoeuds.next();
0581: this .getPopNoeuds().enleveElement(noeud);
0582: }
0583: }
0584:
0585: /** Filtrage des noeuds "simples", c'est-à-dire avec seulement deux arcs incidents,
0586: * si ils ont des orientations compatibles.
0587: * Ces noeuds sont enlevés et un seul arc est créé à la place des deux arcs incidents.
0588: *
0589: * Cette méthode gère les conséquences sur la topologie arcs/noeuds/faces.
0590: * Cette méthode gère aussi les conséquences sur les correspondants.
0591: * (un nouvel arc a pour correspondants tous les correspondants des deux
0592: * arcs incidents).
0593: * Cette méthode gère les conséquences sur l'orientation
0594: *
0595: * IMPORTANT: la topologie arcs/noeuds doit avoir été instanciée avant
0596: * de lancer cette méthode
0597: */
0598: public void filtreNoeudsSimples() {
0599: Iterator itNoeuds, itCorresp;
0600: List geometries, arcsIncidents;
0601: Noeud noeud, noeudIni1, noeudIni2, noeudFin1, noeudFin2;
0602: Arc arcTotal, arc1, arc2;
0603: Face faceDroite1, faceDroite2, faceGauche1, faceGauche2;
0604: FT_Feature corresp;
0605:
0606: itNoeuds = this .getPopNoeuds().getElements().iterator();
0607: List noeudsElimines = new ArrayList();
0608: while (itNoeuds.hasNext()) {
0609: noeud = (Noeud) itNoeuds.next();
0610: arcsIncidents = noeud.arcs();
0611: if (arcsIncidents.size() != 2)
0612: continue;
0613: if (arcsIncidents.get(0) == arcsIncidents.get(1))
0614: continue; // gestion des boucles
0615: if (noeud.entrantsOrientes().size() == 0)
0616: continue; // incompatibilité d'orientation
0617: if (noeud.sortantsOrientes().size() == 0)
0618: continue; // incompatibilité d'orientation
0619: if ((noeud.entrantsOrientes().size() + noeud
0620: .sortantsOrientes().size()) == 3)
0621: continue; // incompatibilité d'orientation
0622:
0623: arcTotal = (Arc) this .getPopArcs().nouvelElement();
0624: geometries = new ArrayList();
0625: arc1 = (Arc) arcsIncidents.get(0);
0626: arc2 = (Arc) arcsIncidents.get(1);
0627: geometries.add(arc1.getGeometrie());
0628: geometries.add(arc2.getGeometrie());
0629:
0630: //création de la nouvelle géométrie
0631: arcTotal.setGeometrie(Operateurs.compileArcs(geometries));
0632:
0633: //gestion des conséquences sur l'orientation et les correspondants
0634: arcTotal.setOrientation(arc1.getOrientation());
0635: itCorresp = arc1.getCorrespondants().iterator();
0636: while (itCorresp.hasNext()) {
0637: corresp = (FT_Feature) itCorresp.next();
0638: if (!arcTotal.getCorrespondants().contains(corresp))
0639: arcTotal.addCorrespondant(corresp);
0640: }
0641: arc1.setCorrespondants(new ArrayList());
0642:
0643: itCorresp = arc2.getCorrespondants().iterator();
0644: while (itCorresp.hasNext()) {
0645: corresp = (FT_Feature) itCorresp.next();
0646: arcTotal.addCorrespondant(corresp);
0647: }
0648: arc2.setCorrespondants(new ArrayList());
0649:
0650: itCorresp = noeud.getCorrespondants().iterator();
0651: while (itCorresp.hasNext()) {
0652: corresp = (FT_Feature) itCorresp.next();
0653: if (!arcTotal.getCorrespondants().contains(corresp))
0654: arcTotal.addCorrespondant(corresp);
0655: }
0656: noeud.setCorrespondants(new ArrayList());
0657:
0658: //gestion des conséquences sur la topologie
0659: faceDroite1 = arc1.getFaceDroite();
0660: faceGauche1 = arc1.getFaceGauche();
0661: faceDroite2 = arc2.getFaceDroite();
0662: faceGauche2 = arc2.getFaceGauche();
0663: noeudIni1 = arc1.getNoeudIni();
0664: noeudFin1 = arc1.getNoeudFin();
0665: noeudIni2 = arc2.getNoeudIni();
0666: noeudFin2 = arc2.getNoeudFin();
0667:
0668: // conséquences sur le premier arc
0669: if (noeudIni1 == noeud) {
0670: noeudIni1.getSortants().remove(arc1);
0671: if (noeudFin1 != null) {
0672: noeudFin1.getEntrants().remove(arc1);
0673: noeudFin1.addSortant(arcTotal);
0674:
0675: }
0676: if (faceDroite1 != null) {
0677: faceDroite1.getArcsIndirects().remove(arc1);
0678: arcTotal.setFaceGauche(faceDroite1);
0679: }
0680: if (faceGauche1 != null) {
0681: faceGauche1.getArcsDirects().remove(arc1);
0682: arcTotal.setFaceDroite(faceGauche1);
0683: }
0684: } else {
0685: noeudFin1.getEntrants().remove(arc1);
0686: if (noeudIni1 != null) {
0687: noeudIni1.getSortants().remove(arc1);
0688: noeudIni1.addSortant(arcTotal);
0689: }
0690: if (faceDroite1 != null) {
0691: faceDroite1.getArcsIndirects().remove(arc1);
0692: arcTotal.setFaceDroite(faceDroite1);
0693: }
0694: if (faceGauche1 != null) {
0695: faceGauche1.getArcsDirects().remove(arc1);
0696: arcTotal.setFaceGauche(faceGauche1);
0697: }
0698: }
0699:
0700: // conséquences sur le deuxième arc
0701: if (noeudIni2 == noeud) {
0702: noeudIni2.getSortants().remove(arc2);
0703: if (noeudFin2 != null) {
0704: noeudFin2.getEntrants().remove(arc2);
0705: noeudFin2.addEntrant(arcTotal);
0706:
0707: }
0708: if (faceDroite2 != null) {
0709: faceDroite2.getArcsIndirects().remove(arc2);
0710: }
0711: if (faceGauche2 != null) {
0712: faceGauche1.getArcsDirects().remove(arc2);
0713: }
0714: } else {
0715: noeudFin2.getEntrants().remove(arc2);
0716: if (noeudIni2 != null) {
0717: noeudIni2.getSortants().remove(arc2);
0718: noeudIni2.addEntrant(arcTotal);
0719: }
0720: if (faceDroite2 != null) {
0721: faceDroite2.getArcsIndirects().remove(arc2);
0722: }
0723: if (faceGauche2 != null) {
0724: faceGauche2.getArcsDirects().remove(arc2);
0725: }
0726: }
0727:
0728: //Elimination des arcs et du noeud inutile
0729: this .getPopArcs().enleveElement(arc1);
0730: this .getPopArcs().enleveElement(arc2);
0731: noeudsElimines.add(noeud);
0732: }
0733: int i;
0734: for (i = 0; i < noeudsElimines.size(); i++) {
0735: this .getPopNoeuds().enleveElement(
0736: (Noeud) noeudsElimines.get(i));
0737: }
0738: }
0739:
0740: /** Filtre les arcs en double
0741: * (en double = même géométrie et même orientation).
0742: *
0743: * Attention: les conséquences sur la topologie arcs/faces ne sont pas gérées.
0744: */
0745: public void filtreArcsDoublons() {
0746: List arcs = this .getPopArcs().getElements();
0747: List arcsAEnlever = new ArrayList();
0748: for (int i = 0; i < arcs.size(); i++) {
0749: Arc arci = (Arc) arcs.get(i);
0750: if (arcsAEnlever.contains(arci))
0751: continue;
0752: for (int j = i + 1; j < arcs.size(); j++) {
0753: Arc arcj = (Arc) arcs.get(j);
0754: if (!arcj.getGeom().equals(arci.getGeom()))
0755: continue;
0756: if (arcj.getOrientation() != arcj.getOrientation())
0757: continue;
0758: arcsAEnlever.add(arcj);
0759: Iterator itCor = arcj.getCorrespondants().iterator();
0760: while (itCor.hasNext()) {
0761: FT_Feature corresp = (FT_Feature) itCor.next();
0762: arci.addCorrespondant(corresp);
0763: }
0764: arcj.setCorrespondants(new ArrayList());
0765: arcj.setNoeudFin(null);
0766: arcj.setNoeudIni(null);
0767: }
0768: }
0769: this .getPopArcs().removeAll(arcsAEnlever);
0770: }
0771:
0772: /** Transforme la carte topo pour la rendre planaire :
0773: * les arcs sont découpés à chaque intersection d'arcs,
0774: * et un noeud est créé à chaque extrémité d'arc.
0775: *
0776: * NB: la topologie arcs/noeuds de la carte en sortie est instanciée.
0777: *
0778: * NB: les populations d'arcs et de noeuds sont indexées pendant la méthode,
0779: * si cela n'avait pas déjà été fait avant.
0780: * Les paramètres de ces index sont:
0781: * 20x20 cases pour les noeuds, ~50 arcs par case pour les arcs.
0782: * Si cela ne convient pas: instancier les topologies avant.
0783: *
0784: * NB: les "correspondants" des arcs et noeuds suivent le découpage,
0785: * de même que l'attribut orientation.
0786: * MAIS ATTENTION:
0787: * - les liens vers des groupes ne suivent pas.
0788: * - les attributs/liens particuliers (cas où les arcs proviennent
0789: * d'une carteTopo spécialisée) ne suivent pas non plus
0790: * - la topologie des faces est détruite aussi
0791: *
0792: * @param tolerance
0793: * Paramètre de tolérance sur la localisation des noeuds:
0794: * deux extrémités d'arc à moins de cette distance sont considérées superposées
0795: * (utilisé lors de la construction de la topologie arcs/noeuds).
0796: * Ce paramètre peut être nul.
0797: */
0798: public void rendPlanaire(double tolerance) {
0799: Arc arc, arcSel;
0800: FT_FeatureCollection selection;
0801: List listeInter;
0802: GM_Object nodedLineStrings, intersection;
0803: Iterator itSel, itDecoupes;
0804: List dejaTraites = new ArrayList();
0805: List arcsEnleves = new ArrayList();
0806: GM_MultiPoint frontiereArc, frontiereArcSel;
0807: GM_Point ptArcIni, ptArcFin, ptArcSelIni, ptArcSelFin;
0808:
0809: if (this .getPopArcs().size() == 0)
0810: return;
0811: // initialisation de l'index des arcs au besoin
0812: if (!this .getPopArcs().hasSpatialIndex())
0813: this .getPopArcs().initSpatialIndex(Tiling.class, true);
0814:
0815: for (int i = 0; i < this .getPopArcs().size(); i++) {
0816: arc = (Arc) this .getPopArcs().get(i);
0817: if (arcsEnleves.contains(arc))
0818: continue;
0819: if (dejaTraites.contains(arc))
0820: continue;
0821:
0822: //les arcs qui croisent l'arc courant
0823: // Optimisation et blindage pour tous les cas non garanti (Seb)
0824: selection = this .getPopArcs().select(arc.getGeometrie());
0825: selection.remove(arc);
0826: selection.getElements().removeAll(arcsEnleves);
0827:
0828: listeInter = new ArrayList();
0829: itSel = selection.getElements().iterator();
0830: ptArcIni = new GM_Point(arc.getGeometrie().startPoint());
0831: ptArcFin = new GM_Point(arc.getGeometrie().endPoint());
0832: frontiereArc = new GM_MultiPoint();
0833: frontiereArc.add(ptArcIni);
0834: frontiereArc.add(ptArcFin);
0835: while (itSel.hasNext()) {
0836: arcSel = (Arc) itSel.next();
0837:
0838: // if (arcSel == arc) continue;
0839:
0840: ptArcSelIni = new GM_Point(arcSel.getGeometrie()
0841: .startPoint());
0842: ptArcSelFin = new GM_Point(arcSel.getGeometrie()
0843: .endPoint());
0844:
0845: intersection = arcSel.getGeometrie().intersection(
0846: arc.getGeometrie());
0847:
0848: /* //modif Seb: tentative d'accélération : buggé mais je ne trouve pas pourquoi
0849: if (intersection instanceof GM_Point ) {
0850: if ( Operateurs.superposes(ptArcIni, (GM_Point)intersection) ||
0851: Operateurs.superposes(ptArcFin, (GM_Point)intersection) ) {
0852: if ( Operateurs.superposes(ptArcSelIni, (GM_Point)intersection) ||
0853: Operateurs.superposes(ptArcSelFin, (GM_Point)intersection) )
0854: continue;
0855: }
0856: listeInter.add(arcSel);
0857: continue;
0858: }
0859: */
0860: frontiereArcSel = new GM_MultiPoint();
0861: frontiereArcSel.add(ptArcSelIni);
0862: frontiereArcSel.add(ptArcSelFin);
0863: if (frontiereArc.contains(intersection)) {
0864: if (frontiereArcSel.contains(intersection))
0865: continue;
0866: }
0867: listeInter.add(arcSel);
0868: }
0869:
0870: if (listeInter.size() == 0)
0871: continue; //pas d'intersection avec cet arc
0872:
0873: //on découpe tout
0874: itSel = listeInter.iterator();
0875: nodedLineStrings = arc.getGeometrie();
0876: while (itSel.hasNext()) {
0877: arcSel = (Arc) itSel.next();
0878: nodedLineStrings = nodedLineStrings.union(arcSel
0879: .getGeometrie());
0880: }
0881: listeInter.add(arc); // on le rajoute pour la suite
0882: if (nodedLineStrings instanceof GM_LineString) {
0883: System.out
0884: .println("Problème pour rendre le graphe planaire");
0885: System.out
0886: .println(" l'intersection de plusieurs arcs donne un seul arc (pb non résolu, pb JTS?)");
0887: System.out.println(" pb sur l'arc "
0888: + arc.getGeom().coord());
0889: continue;
0890: }
0891: if (nodedLineStrings instanceof GM_MultiCurve) { //cas où il faut découper
0892: //1: on rajoute les morceaux d'arcs découpés
0893: itDecoupes = ((GM_MultiCurve) nodedLineStrings)
0894: .getList().iterator();
0895: while (itDecoupes.hasNext()) {
0896: GM_LineString ligneDecoupe = (GM_LineString) itDecoupes
0897: .next();
0898: Arc arcNouveau = (Arc) this .getPopArcs()
0899: .nouvelElement(ligneDecoupe);
0900: //on recherche à quel(s) arc(s) initial appartient chaque bout découpé
0901: itSel = listeInter.iterator();
0902: while (itSel.hasNext()) {
0903: arcSel = (Arc) itSel.next();
0904: // on devrait mettre ==0 ci-dessous, mais pour gérer les erreurs d'arrondi on met <0.01
0905: if (Distances.premiereComposanteHausdorff(
0906: ligneDecoupe, arcSel.getGeometrie()) < 0.01) {
0907: //on appartient à lui
0908: arcNouveau.getCorrespondants().addAll(
0909: arcSel.getCorrespondants());
0910: arcNouveau.setOrientation(arcSel
0911: .getOrientation());
0912: //si on appartient à l'arc initial, pas la peine de revenir
0913: if (arcSel == arc)
0914: dejaTraites.add(arcNouveau);
0915: }
0916: }
0917: }
0918:
0919: //2: on virera les arcs initiaux qui ont été découpés
0920: itSel = listeInter.iterator();
0921: while (itSel.hasNext()) {
0922: arcSel = (Arc) itSel.next();
0923: arcsEnleves.add(arcSel);
0924: arcSel.setCorrespondants(new ArrayList());
0925: }
0926: continue;
0927: }
0928:
0929: //cas imprévu: OUPS
0930: System.out
0931: .println("Problème pour rendre le graphe planaire");
0932: System.out
0933: .println(" bug non identifié : l'union donne une "
0934: + nodedLineStrings.getClass());
0935: System.out.println(" pb sur l'arc "
0936: + arc.getGeom().coord());
0937: }
0938:
0939: this .enleveArcs(arcsEnleves);
0940: //On construit les nouveaux noeuds éventuels et la topologie arcs/noeuds
0941: this .getPopNoeuds().setElements(new ArrayList());
0942: this .creeNoeudsManquants(tolerance);
0943: }
0944:
0945: /** Fusionne en un seul noeud, tous les noeuds proches de moins de "tolerance"
0946: * Les correspondants suivent, la topologie arcs/noeuds aussi.
0947: * NB: les petits arcs qui n'ont plus de sens sont aussi éliminés.
0948: * Plus précisément ce sont ceux qui partent et arrivent sur un même
0949: * nouveau noeud créé, et restant à moins de "tolerance" de ce nouveau noeud
0950: *
0951: * Un index spatial (dallage) est créé si cela n'avait pas été fait avant,
0952: * mais il est toujours conseillé de le faire en dehors de cette méthode,
0953: * pour controler la taille du dallage.
0954: */
0955: public void fusionNoeuds(double tolerance) {
0956: Iterator itNoeudsProches, itArcs;
0957: Noeud noeud, nouveauNoeud, noeudProche;
0958: Arc arc;
0959: List aEnlever = new ArrayList();
0960: FT_FeatureCollection noeudsProches;
0961: List arcsModifies;
0962:
0963: if (!this .getPopArcs().hasSpatialIndex())
0964: this .getPopArcs().initSpatialIndex(Tiling.class, true);
0965:
0966: for (int i = 0; i < this .getPopNoeuds().size(); i++) {
0967: noeud = (Noeud) this .getPopNoeuds().getElements().get(i);
0968: //On cherche les noeuds voisins
0969: noeudsProches = this .getPopNoeuds().select(
0970: noeud.getGeometrie(), tolerance);
0971: noeudsProches.removeAll(aEnlever);
0972: if (noeudsProches.size() < 2)
0973: continue;
0974:
0975: //Si il y a des voisins, on crée un nouveau noeud
0976: GM_MultiPoint points = new GM_MultiPoint();
0977: itNoeudsProches = noeudsProches.getElements().iterator();
0978: while (itNoeudsProches.hasNext()) {
0979: noeudProche = (Noeud) itNoeudsProches.next();
0980: points.add(noeudProche.getGeometrie());
0981: }
0982: GM_Point centroide = (GM_Point) points.centroid();
0983: nouveauNoeud = (Noeud) this .getPopNoeuds().nouvelElement();
0984: nouveauNoeud.setGeometrie(centroide);
0985:
0986: //On raccroche tous les arcs à ce nouveau noeud
0987: arcsModifies = new ArrayList();
0988: itNoeudsProches = noeudsProches.getElements().iterator();
0989: while (itNoeudsProches.hasNext()) {
0990: noeudProche = (Noeud) itNoeudsProches.next();
0991: nouveauNoeud.getCorrespondants().addAll(
0992: noeudProche.getCorrespondants());
0993: noeudProche.setCorrespondants(new ArrayList());
0994: aEnlever.add(noeudProche);
0995: //modification de chaque arc du noeud proche à bouger
0996: itArcs = noeudProche.arcs().iterator();
0997: while (itArcs.hasNext()) {
0998: arc = (Arc) itArcs.next();
0999: arcsModifies.add(arc);
1000: if (arc.getNoeudIni() == noeudProche) {
1001: arc.setNoeudIni(nouveauNoeud);
1002: arc.getGeometrie().coord().set(
1003: 0,
1004: nouveauNoeud.getGeometrie()
1005: .getPosition());
1006: }
1007: if (arc.getNoeudFin() == noeudProche) {
1008: arc.setNoeudFin(nouveauNoeud);
1009: int fin = arc.getGeometrie().coord().size() - 1;
1010: arc.getGeometrie().coord().set(
1011: fin,
1012: nouveauNoeud.getGeometrie()
1013: .getPosition());
1014: }
1015: }
1016: //On enlève les arcs qui n'ont plus lieu d'être
1017: // (tout petit autour du nouveau noeud)
1018: itArcs = arcsModifies.iterator();
1019: while (itArcs.hasNext()) {
1020: arc = (Arc) itArcs.next();
1021: if (arc.getNoeudIni() == nouveauNoeud
1022: && arc.getNoeudFin() == nouveauNoeud) {
1023: if (Distances.hausdorff(arc.getGeometrie(),
1024: noeudProche.getGeometrie()) <= tolerance) {
1025: nouveauNoeud.getCorrespondants().addAll(
1026: arc.getCorrespondants());
1027: arc.setNoeudIni(null);
1028: arc.setNoeudFin(null);
1029: this .getPopArcs().remove(arc);
1030: }
1031: }
1032: }
1033: }
1034: }
1035: //on enleve tous les anciens noeuds
1036: Iterator itAEnlever = aEnlever.iterator();
1037: while (itAEnlever.hasNext()) {
1038: noeud = (Noeud) itAEnlever.next();
1039: this .getPopNoeuds().remove(noeud);
1040: }
1041: }
1042:
1043: /** Fusionne en un seul noeud, tous les noeuds contenu dans une même
1044: * surface de la population de surfaces passée en paramètre.
1045: *
1046: * Les correspondants suivent, la topologie arcs/noeuds aussi.
1047: *
1048: * NB: les petits arcs qui n'ont plus de sens sont aussi éliminés.
1049: * Plus précisément ce sont ceux qui partent et arrivent sur un même
1050: * nouveau noeud créé, et restant dans la surface de fusion.
1051: *
1052: * Un index spatial (dallage) est créé si cela n'avait pas été fait avant,
1053: * mais il est toujours conseillé de le faire en dehors de cette méthode,
1054: * pour controler la taille du dallage.
1055: */
1056: public void fusionNoeuds(Population popSurfaces) {
1057: Iterator itNoeudsProches, itArcs;
1058: Noeud noeud, nouveauNoeud, noeudProche;
1059: Arc arc;
1060: List aEnlever = new ArrayList();
1061: FT_FeatureCollection noeudsProches;
1062: List arcsModifies;
1063: Iterator itSurf = popSurfaces.getElements().iterator();
1064:
1065: if (!this .getPopNoeuds().hasSpatialIndex())
1066: this .getPopNoeuds().initSpatialIndex(Tiling.class, true);
1067:
1068: while (itSurf.hasNext()) {
1069: FT_Feature surf = (FT_Feature) itSurf.next();
1070: noeudsProches = this .getPopNoeuds().select(surf.getGeom());
1071: noeudsProches.removeAll(aEnlever);
1072: if (noeudsProches.size() < 2)
1073: continue;
1074:
1075: //Si il y a plusieurs noeuds dans la surface, on crée un nouveau noeud
1076: GM_MultiPoint points = new GM_MultiPoint();
1077: itNoeudsProches = noeudsProches.getElements().iterator();
1078: while (itNoeudsProches.hasNext()) {
1079: noeudProche = (Noeud) itNoeudsProches.next();
1080: points.add(noeudProche.getGeometrie());
1081: }
1082: GM_Point centroide = (GM_Point) points.centroid();
1083: nouveauNoeud = (Noeud) this .getPopNoeuds().nouvelElement();
1084: nouveauNoeud.setGeometrie(centroide);
1085:
1086: //On raccroche tous les arcs à ce nouveau noeud
1087: arcsModifies = new ArrayList();
1088: itNoeudsProches = noeudsProches.getElements().iterator();
1089: while (itNoeudsProches.hasNext()) {
1090: noeudProche = (Noeud) itNoeudsProches.next();
1091: nouveauNoeud.getCorrespondants().addAll(
1092: noeudProche.getCorrespondants());
1093: noeudProche.setCorrespondants(new ArrayList());
1094: aEnlever.add(noeudProche);
1095: //modification de chaque arc du noeud proche à bouger
1096: itArcs = noeudProche.arcs().iterator();
1097: while (itArcs.hasNext()) {
1098: arc = (Arc) itArcs.next();
1099: arcsModifies.add(arc);
1100: if (arc.getNoeudIni() == noeudProche) {
1101: arc.setNoeudIni(nouveauNoeud);
1102: arc.getGeometrie().coord().set(
1103: 0,
1104: nouveauNoeud.getGeometrie()
1105: .getPosition());
1106: }
1107: if (arc.getNoeudFin() == noeudProche) {
1108: arc.setNoeudFin(nouveauNoeud);
1109: int fin = arc.getGeometrie().coord().size() - 1;
1110: arc.getGeometrie().coord().set(
1111: fin,
1112: nouveauNoeud.getGeometrie()
1113: .getPosition());
1114: }
1115: }
1116: //On enlève les arcs qui n'ont plus lieu d'être
1117: // (tout petit autour du nouveau noeud)
1118: itArcs = arcsModifies.iterator();
1119: while (itArcs.hasNext()) {
1120: arc = (Arc) itArcs.next();
1121: if (arc.getNoeudIni() == nouveauNoeud
1122: && arc.getNoeudFin() == nouveauNoeud) {
1123: if (surf.getGeom().contains(arc.getGeometrie())) {
1124: nouveauNoeud.getCorrespondants().addAll(
1125: arc.getCorrespondants());
1126: arc.setNoeudIni(null);
1127: arc.setNoeudFin(null);
1128: this .getPopArcs().remove(arc);
1129: }
1130: }
1131: }
1132: }
1133: }
1134: //on enleve tous les anciens noeuds
1135: Iterator itAEnlever = aEnlever.iterator();
1136: while (itAEnlever.hasNext()) {
1137: noeud = (Noeud) itAEnlever.next();
1138: this .getPopNoeuds().remove(noeud);
1139: }
1140: }
1141:
1142: /** Découpe la carte topo this en fonction des noeuds d'une autre carte topo (ct).
1143: * En détail:
1144: * Pour chaque noeud N de la carte topo en entrée,
1145: * on prend chaque arc de this qui en est proche (c'est-à-dire à moins de distanceMaxNoeudArc).
1146: * Si aucune des extrémités de cet arc est à moins de distanceMaxProjectionNoeud du noeud N,
1147: * alors on découpe l'arc en y projetant le noeud N.
1148: *
1149: * Si impassesSeulement = true: seules les noeuds N extrémités d'impasse peuvent être projetées
1150: *
1151: * La topologie arcs/noeuds, l'orientation et les correspondants suivent.
1152: *
1153: * Les arcs de this sont indexés au passage si cela n'avait pas été fait avant.
1154: *
1155: */
1156: public void projete(CarteTopo ct, double distanceMaxNoeudArc,
1157: double distanceMaxProjectionNoeud, boolean impassesSeulement) {
1158: Arc arc;
1159: Noeud noeud;
1160: Iterator itNoeuds = ct.getPopNoeuds().getElements().iterator();
1161: Iterator itArcs;
1162:
1163: if (!this .getPopArcs().hasSpatialIndex()) {
1164: int nb = (int) Math.sqrt(this .getPopArcs().size() / 20);
1165: if (nb == 0)
1166: nb = 1;
1167: this .getPopArcs().initSpatialIndex(Tiling.class, true, nb);
1168: }
1169:
1170: while (itNoeuds.hasNext()) {
1171: noeud = (Noeud) itNoeuds.next();
1172: if (impassesSeulement) {
1173: if (noeud.arcs().size() != 1)
1174: continue;
1175: }
1176: itArcs = this .getPopArcs().select(noeud.getGeom(),
1177: distanceMaxNoeudArc).getElements().iterator();
1178: while (itArcs.hasNext()) {
1179: arc = (Arc) itArcs.next();
1180: if (Distances.distance(arc.getGeometrie().startPoint(),
1181: noeud.getGeometrie().getPosition()) < distanceMaxProjectionNoeud)
1182: continue;
1183: if (Distances.distance(arc.getGeometrie().endPoint(),
1184: noeud.getGeometrie().getPosition()) < distanceMaxProjectionNoeud)
1185: continue;
1186: arc.projeteEtDecoupe(noeud.getGeometrie());
1187: }
1188: }
1189: }
1190:
1191: /** Découpe la carte topo this en fonction de tous les points (noeuds et points intermediaires)
1192: * d'une autre carte topo (ct).
1193: * En détail:
1194: * Pour chaque point P de la carte topo en entrée,
1195: * on prend chaque arc de this qui en est proche (c'est-à-dire à moins de distanceMaxNoeudArc).
1196: * Si aucune des extrémités de cet arc est à moins de distanceMaxProjectionNoeud du noeud P,
1197: * alors on découpe l'arc en y projetant le noeud P.
1198: *
1199: * La topologie arcs/noeuds, l'orientation et les correspondants suivent.
1200: *
1201: * Les arcs de this sont indexés au passage si cela n'avait pas été fait avant.
1202: *
1203: */
1204: public void projeteTousLesPoints(CarteTopo ct,
1205: double distanceMaxNoeudArc,
1206: double distanceMaxProjectionNoeud) {
1207: Arc arc, arcCT;
1208: Iterator itArcsCT = ct.getPopArcs().getElements().iterator();
1209: Iterator itArcs, itPointsCT;
1210:
1211: if (!this .getPopArcs().hasSpatialIndex()) {
1212: int nb = (int) Math.sqrt(this .getPopArcs().size() / 20);
1213: if (nb == 0)
1214: nb = 1;
1215: this .getPopArcs().initSpatialIndex(Tiling.class, true, nb);
1216: }
1217:
1218: while (itArcsCT.hasNext()) {
1219: arcCT = (Arc) itArcsCT.next();
1220: itPointsCT = arcCT.getGeometrie().coord().getList()
1221: .iterator();
1222: while (itPointsCT.hasNext()) {
1223: DirectPosition dp = (DirectPosition) itPointsCT.next();
1224: if (Distances.distance(arcCT.getGeometrie()
1225: .startPoint(), dp) < distanceMaxProjectionNoeud)
1226: continue;
1227: if (Distances.distance(arcCT.getGeometrie().endPoint(),
1228: dp) < distanceMaxProjectionNoeud)
1229: continue;
1230: itArcs = this .getPopArcs().select(dp,
1231: distanceMaxNoeudArc).getElements().iterator();
1232: while (itArcs.hasNext()) {
1233: arc = (Arc) itArcs.next();
1234: if (Distances.distance(arc.getGeometrie()
1235: .startPoint(), dp) < distanceMaxProjectionNoeud)
1236: continue;
1237: if (Distances.distance(arc.getGeometrie()
1238: .endPoint(), dp) < distanceMaxProjectionNoeud)
1239: continue;
1240: arc.projeteEtDecoupe(new GM_Point(dp));
1241: }
1242: }
1243: }
1244: }
1245:
1246: /** Découpe la carte topo this en fonction d'un ensemble de points (GM_Point).
1247: * En détail:
1248: * Pour chaque point en entrée,
1249: * on prend chaque arc de this qui en est proche (c'est-à-dire à moins de distanceMaxNoeudArc).
1250: * Si aucune des extrémités de cet arc est à moins de distanceMaxProjectionNoeud du noeud N,
1251: * alors on découpe l'arc en y projetant le noeud N.
1252: *
1253: * La topologie arcs/noeuds, l'orientation et les correspondants suivent.
1254: *
1255: */
1256: public void projete(List pts, double distanceMaxNoeudArc,
1257: double distanceMaxProjectionNoeud) {
1258: Arc arc;
1259: Iterator itPts = pts.iterator();
1260: Iterator itArcs;
1261: while (itPts.hasNext()) {
1262: GM_Point point = (GM_Point) itPts.next();
1263: itArcs = this .getPopArcs().select(point,
1264: distanceMaxNoeudArc).getElements().iterator();
1265: while (itArcs.hasNext()) {
1266: arc = (Arc) itArcs.next();
1267: if (Distances.distance(arc.getGeometrie().startPoint(),
1268: point.getPosition()) < distanceMaxProjectionNoeud)
1269: continue;
1270: if (Distances.distance(arc.getGeometrie().endPoint(),
1271: point.getPosition()) < distanceMaxProjectionNoeud)
1272: continue;
1273: arc.projeteEtDecoupe(point);
1274: }
1275: }
1276: }
1277:
1278: /////////////////////////////////////////////////////////////////////////////////////////////
1279: // Instanciation de la topologie de faces
1280: /////////////////////////////////////////////////////////////////////////////////////////////
1281: /** Crée les faces à partir d'un graphe planaire et instancie la topologie face / arcs.
1282: * Une face est délimitée par un cycle minimal du graphe.
1283: *
1284: * Le paramètre persistant spécifie si les faces créées, ainsi que la topologie, sont rendus persistants.
1285: * Si oui, il faut appeler cette méthode dans une transaction ouverte.
1286: *
1287: * NB1 : la topologie de réseau arcs/noeuds doit avoir été instanciée.
1288: * NB2 : une face "extérieure" est créée (sa géométrie entoure le "trou" de l'extérieur qu'est le réseau.
1289: * Donc, dans le cas d'une topologie complete arcs/faces, tous les arcs ont une face gauche
1290: * et une face à droite.
1291: * NB3 : ATTENTION : en cas d'un réseau non connexe, une face extérieure différente est crée pour chaque
1292: * partie connexe !
1293: * NB4 : Les culs de sac ont la même face à gauche et à droite, et la face "longe le cul de sac";
1294: * i.e. la géométrie de la face fait un aller/retour sur le cul-de-sac.
1295: * NB5 : Méthode en théorie conçue pour les graphes planaires uniquement (testée dans ce cadre uniquement).
1296: * La méthode est en théorie valable pour les graphes non planaires, mais les faces créées
1297: * seront étranges (on ne recrée pas les intersections manquantes, on les ignore).
1298: * Si il existe des arcs sans noeud initial ou final (topologie de réseau pas complete),
1299: * alors ces arcs n'ont ni face à gauche, ni face à droite
1300: */
1301: public void creeTopologieFaces() {
1302: List arcsDejaTraitesADroite = new ArrayList();
1303: List arcsDejaTraitesAGauche = new ArrayList();
1304: List cycle;
1305: List arcsDuCycle;
1306: List orientationsArcsDuCycle;
1307: Iterator itArcs, itArcsCycle, itOrientations;
1308: Arc arc, arcCycle;
1309: Face face;
1310: GM_Polygon geometrieDuCycle;
1311: boolean orientationOk = true;
1312: Population popFaces = this .getPopFaces();
1313:
1314: // Parcours de tous les arcs du graphe. Puis, pour chaque arc:
1315: // - recherche du cycle à droite et du cycle à gauche
1316: // - creation des faces correspondantes
1317: // - on note les arcs par lesquels on est déjà passé pour ne pas refaire le travail
1318: itArcs = this .getPopArcs().getElements().iterator();
1319: while (itArcs.hasNext()) {
1320: arc = (Arc) itArcs.next();
1321: // a droite
1322: if (!arcsDejaTraitesADroite.contains(arc)) {
1323: cycle = arc.cycleADroite();
1324: if (cycle == null)
1325: continue;
1326: arcsDuCycle = (List) cycle.get(0);
1327: orientationsArcsDuCycle = (List) cycle.get(1);
1328: geometrieDuCycle = (GM_Polygon) cycle.get(2);
1329: face = (Face) popFaces.nouvelElement();
1330: face.setGeometrie(geometrieDuCycle);
1331: //if ( persistant ) JeuDeDonnees.db.makePersistent(face);
1332: itArcsCycle = arcsDuCycle.iterator();
1333: itOrientations = orientationsArcsDuCycle.iterator();
1334: while (itArcsCycle.hasNext()) {
1335: arcCycle = (Arc) itArcsCycle.next();
1336: orientationOk = ((Boolean) itOrientations.next())
1337: .booleanValue();
1338: if (orientationOk) {
1339: arcCycle.setFaceDroite(face);
1340: arcsDejaTraitesADroite.add(arcCycle);
1341: } else {
1342: arcCycle.setFaceGauche(face);
1343: arcsDejaTraitesAGauche.add(arcCycle);
1344: }
1345: }
1346: }
1347: // a gauche
1348: if (!arcsDejaTraitesAGauche.contains(arc)) {
1349: cycle = arc.cycleAGauche();
1350: if (cycle == null)
1351: continue;
1352: arcsDuCycle = (List) cycle.get(0);
1353: orientationsArcsDuCycle = (List) cycle.get(1);
1354: geometrieDuCycle = (GM_Polygon) cycle.get(2);
1355: face = (Face) popFaces.nouvelElement();
1356: face.setGeometrie(geometrieDuCycle);
1357: //if ( persistant ) JeuDeDonnees.db.makePersistent(face);
1358: itArcsCycle = arcsDuCycle.iterator();
1359: itOrientations = orientationsArcsDuCycle.iterator();
1360: while (itArcsCycle.hasNext()) {
1361: arcCycle = (Arc) itArcsCycle.next();
1362: orientationOk = ((Boolean) itOrientations.next())
1363: .booleanValue();
1364: if (orientationOk) {
1365: arcCycle.setFaceGauche(face);
1366: arcsDejaTraitesAGauche.add(arcCycle);
1367: } else {
1368: arcCycle.setFaceDroite(face);
1369: arcsDejaTraitesADroite.add(arcCycle);
1370: }
1371: }
1372: }
1373: }
1374: }
1375:
1376: /** Détruit les relations topologique d'une face avec tous ses arcs entourants */
1377: public void videTopologieFace(Face face) {
1378: Iterator it = face.arcs().iterator();
1379: Arc arc;
1380: while (it.hasNext()) {
1381: arc = (Arc) it.next();
1382: arc.setFaceDroite(null);
1383: arc.setFaceGauche(null);
1384: }
1385: }
1386:
1387: /** Ajoute des arcs et des noeuds à la carteTopo this qui ne contient que des faces.
1388: * Ces arcs sont les arcs entourant les faces.
1389: *
1390: * Les relations topologiques arcs/noeuds/surfaces sont instanciées au passage.
1391: *
1392: * Les trous sont gérés.
1393: * Les faces en entrée peuvent avoir une orientation quelconque (direct), cela est géré.
1394: * Par contre, on ne s'appuie que sur les points intermédiaires existants dans les polygones des faces :
1395: * les relations topologiques sont donc bien gérés uniquement si les polygones ont des géométrie "compatibles".
1396: *
1397: * @param filtrageNoeudsSimples
1398: * Si ce paramètre est égal à false, alors on crée un arc et deux noeuds
1399: * pour chaque segment reliant des points intermédiares des surfaces.
1400: * Si ce paramètre est égal à true, alors on fusionne les arcs et on ne retient
1401: * que les noeuds qui ont 3 arcs incidents ou qui servent de point initial/final à une face.
1402: *
1403: * @author Mustière/Bonin
1404: *
1405: * @date 09/05/2006
1406: *
1407: */
1408: public void ajouteArcsEtNoeudsAuxFaces(boolean filtrageNoeudsSimples) {
1409: DirectPosition pt1, pt2;
1410: Iterator itPts;
1411: boolean sensDirect;
1412:
1413: // On crée un arc pour chaque segment reliant deux points intermédiaires d'une surface
1414: // Pour deux faces adjacentes, on duplique ces arcs. On fait le ménage après.
1415: Iterator itFaces = this .getPopFaces().getElements().iterator();
1416: while (itFaces.hasNext()) {
1417: Face face = (Face) itFaces.next();
1418: GM_Polygon geomFace = face.getGeometrie();
1419: //gestion du contour
1420: DirectPositionList ptsDeLaSurface = geomFace
1421: .exteriorCoord();
1422: sensDirect = Operateurs.sensDirect(ptsDeLaSurface);
1423: itPts = ptsDeLaSurface.getList().iterator();
1424: pt1 = (DirectPosition) itPts.next();
1425: while (itPts.hasNext()) {
1426: pt2 = (DirectPosition) itPts.next();
1427: Arc arc = (Arc) this .getPopArcs().nouvelElement();
1428: GM_LineString segment = new GM_LineString();
1429: segment.addControlPoint(pt1);
1430: segment.addControlPoint(pt2);
1431: arc.setGeom(segment);
1432: if (sensDirect)
1433: arc.setFaceGauche(face);
1434: else
1435: arc.setFaceDroite(face);
1436: pt1 = pt2;
1437: }
1438: //gestion des trous
1439: Iterator itTrous = geomFace.getInterior().iterator();
1440: while (itTrous.hasNext()) {
1441: GM_Ring trou = (GM_Ring) itTrous.next();
1442: DirectPositionList geomTrou = trou.getPrimitive()
1443: .coord();
1444: sensDirect = Operateurs.sensDirect(geomTrou);
1445: itPts = geomTrou.getList().iterator();
1446: pt1 = (DirectPosition) itPts.next();
1447: while (itPts.hasNext()) {
1448: pt2 = (DirectPosition) itPts.next();
1449: Arc arc = (Arc) this .getPopArcs().nouvelElement();
1450: GM_LineString segment = new GM_LineString();
1451: segment.addControlPoint(pt1);
1452: segment.addControlPoint(pt2);
1453: arc.setGeom(segment);
1454: if (sensDirect)
1455: arc.setFaceDroite(face);
1456: else
1457: arc.setFaceGauche(face);
1458: pt1 = pt2;
1459: }
1460: }
1461: }
1462:
1463: //indexation spatiale des arcs crées
1464: //on crée un dallage avec en moyenne 20 objets par case
1465: FT_FeatureCollection arcsNonTraites = new FT_FeatureCollection(
1466: this .getPopArcs().getElements());
1467: int nb = (int) Math.sqrt(arcsNonTraites.size() / 20);
1468: if (nb == 0)
1469: nb = 1;
1470: arcsNonTraites.initSpatialIndex(Tiling.class, true, nb);
1471:
1472: // filtrage des arcs en double dus aux surfaces adjacentes
1473: List arcsAEnlever = new ArrayList();
1474: Iterator itArcs = this .getPopArcs().getElements().iterator();
1475: while (itArcs.hasNext()) {
1476: Arc arc = (Arc) itArcs.next();
1477: if (!arcsNonTraites.contains(arc))
1478: continue;
1479: arcsNonTraites.remove(arc);
1480: FT_FeatureCollection arcsProches = arcsNonTraites.select(
1481: arc.getGeometrie().startPoint(), 0);
1482: Iterator itArcsProches = arcsProches.getElements()
1483: .iterator();
1484: while (itArcsProches.hasNext()) {
1485: Arc arc2 = (Arc) itArcsProches.next();
1486: if (arc2.getGeometrie().startPoint().equals(
1487: arc.getGeometrie().startPoint(), 0)
1488: && arc2.getGeometrie().endPoint().equals(
1489: arc.getGeometrie().endPoint(), 0)) {
1490: arcsAEnlever.add(arc2);
1491: arcsNonTraites.remove(arc2);
1492: if (arc2.getFaceDroite() != null)
1493: arc.setFaceDroite(arc2.getFaceDroite());
1494: if (arc2.getFaceGauche() != null)
1495: arc.setFaceGauche(arc2.getFaceGauche());
1496: }
1497: if (arc2.getGeometrie().startPoint().equals(
1498: arc.getGeometrie().endPoint(), 0)
1499: && arc2.getGeometrie().endPoint().equals(
1500: arc.getGeometrie().startPoint(), 0)) {
1501: arcsAEnlever.add(arc2);
1502: arcsNonTraites.remove(arc2);
1503: if (arc2.getFaceDroite() != null)
1504: arc.setFaceGauche(arc2.getFaceDroite());
1505: if (arc2.getFaceGauche() != null)
1506: arc.setFaceDroite(arc2.getFaceGauche());
1507: }
1508: }
1509: }
1510: this .getPopArcs().removeAll(arcsAEnlever);
1511:
1512: // ajout des noeuds et des relations topologiqes arc/noeud
1513: this .creeNoeudsManquants(0);
1514:
1515: // filtrage de tous les noeuds simples (degré=2)
1516: if (filtrageNoeudsSimples)
1517: this .filtreNoeudsSimples();
1518: }
1519:
1520: /////////////////////////////////////////////////////////////////////////////////////////////
1521: // Pour les calculs de plus court chemin
1522: /////////////////////////////////////////////////////////////////////////////////////////////
1523:
1524: /** Initialise le poids de chaque arc comme étant égal à sa longueur;
1525: * NB: utile uniquement aux plus courts chemins */
1526: public void initialisePoids() {
1527: Arc arc;
1528: Iterator itArcs = this .getPopArcs().getElements().iterator();
1529: while (itArcs.hasNext()) {
1530: arc = (Arc) itArcs.next();
1531: if (arc.getGeometrie() == null)
1532: arc.setPoids(0);
1533: arc.setPoids(arc.longueur());
1534: }
1535: }
1536:
1537: /////////////////////////////////////////////////////////////////////////////////////////////
1538: // IMPORT: remplissage de la carte topo à partir de Features
1539: /////////////////////////////////////////////////////////////////////////////////////////////
1540:
1541: /** Charge en mémoire les élements de la classe 'nomClasseGeo'
1542: * et remplit 'this' avec des correspondants de ces éléments.*/
1543: public void importClasseGeo(String nomClasseGeo) {
1544: Chargeur.importClasseGeo(nomClasseGeo, this );
1545: }
1546:
1547: /** Remplit 'this' avec des correspondants des éléments de 'listeFeature'.*/
1548: public void importClasseGeo(FT_FeatureCollection listeFeatures) {
1549: Chargeur.importClasseGeo(listeFeatures, this);
1550: }
1551: }
|