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.spatial.geomprim;
028:
029: import java.util.ArrayList;
030: import java.util.List;
031:
032: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPosition;
033: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPositionList;
034: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_CurveSegment;
035: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_LineString;
036:
037: /**
038: * Courbe. L'orientation vaut nécessairement +1, la primitive est self.
039: * Une courbe est composée de un ou plusieurs segments de courbe.
040: * Chaque segment à l'intérieur d'une courbe peut être défini avec une interpolation différente.
041: * Dans la pratique nous n'utiliserons a priori que des polylignes comme segment(GM_LineString).
042: * <P> Modification de la norme suite au retour d'utilisation : on fait hériter GM_CurveSegment de GM_Curve.
043: * Du coup, on n'implémente plus l'interface GM_GenericCurve.
044: *
045: * @author Thierry Badard & Arnaud Braun
046: * @version 1.0
047: *
048: */
049:
050: public class GM_Curve extends GM_OrientableCurve
051: /*implements GM_GenericCurve*/{
052:
053: //////////////////////////////////////////////////////////////////////////////////
054: // Attribut "segment" et méthodes pour le traiter ////////////////////////////////
055: //////////////////////////////////////////////////////////////////////////////////
056: /** Liste de tous les segment de courbe (GM_CurveSegment) constituant self. */
057: protected List segment;
058:
059: /** Renvoie la liste des segments. */
060: public List getSegment() {
061: return this .segment;
062: }
063:
064: /** Renvoie le segment de rang i */
065: public GM_CurveSegment getSegment(int i) {
066: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
067: if (i != 0) {
068: System.out
069: .println("Recherche d'un segment avec i<>0 alors qu'un GM_CurveSegment ne contient qu'un segment qui est lui-meme");
070: return null;
071: } else
072: return (GM_CurveSegment) this .segment.get(i);
073: else
074: return (GM_CurveSegment) this .segment.get(i);
075: }
076:
077: /** Affecte un segment au i-ème rang de la liste */
078: public void setSegment(int i, GM_CurveSegment value) {
079: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
080: if (i != 0)
081: System.out
082: .println("Affection d'un segment avec i<>0 alors qu'un GM_CurveSegment ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
083: else
084: this .segment.set(i, value);
085: else
086: this .segment.set(i, value);
087: }
088:
089: /** Ajoute un segment en fin de liste sans vérifier la continuité du chaînage.*/
090: public void addSegment(GM_CurveSegment value) {
091: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
092: if (sizeSegment() > 0)
093: System.out
094: .println("Ajout d'un segment alors qu'un GM_CurveSegment ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
095: else
096: this .segment.add(value);
097: else
098: this .segment.add(value);
099: }
100:
101: /** A TESTER.
102: * Ajoute un segment en fin de liste en vérifiant la continuité du chaînage.
103: * Capte une exception en cas de problème. Nécessité de passer une tolérance en paramètre.
104: */
105: public void addSegment(GM_CurveSegment value, double tolerance)
106: throws Exception {
107: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
108: if (sizeSegment() > 0)
109: System.out
110: .println("Ajout d'un segment alors qu'un GM_CurveSegment ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
111: else
112: this .segment.add(value);
113: else {
114: if (this .sizeSegment() == 0)
115: this .segment.add(value);
116: else {
117: int n = this .sizeSegment();
118: GM_CurveSegment lastSegment = this .getSegment(n - 1);
119: if (value.startPoint().equals(lastSegment.endPoint(),
120: tolerance))
121: this .segment.add(value);
122: else
123: throw new Exception(
124: "Rupture de chaînage avec le segment passée en paramètre");
125: }
126: }
127: }
128:
129: /** A TESTER.
130: * Ajoute un segment en fin de liste en vérifiant la continuité du chaînage, et en retournant le segment si necessaire.
131: * Capte une exception en cas de problème. Nécessité de passer une tolérance en paramètre.
132: */
133: public void addSegmentTry(GM_CurveSegment value, double tolerance)
134: throws Exception {
135: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
136: if (sizeSegment() > 0)
137: System.out
138: .println("Ajout d'un segment alors qu'un GM_CurveSegment ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
139: else
140: this .segment.add(value);
141: else {
142: try {
143: this .addSegment(value, tolerance);
144: } catch (Exception e1) {
145: try {
146: this .addSegment(value.reverse(), tolerance);
147: } catch (Exception e2) {
148: throw new Exception(
149: "Rupture de chaînage avec le segment passée en paramètre(après avoir essayé de le retourner).");
150: }
151: }
152: }
153: }
154:
155: /** Ajoute un segment au i-ème rang de la liste, sans vérifier la continuité du chaînage. */
156: public void addSegment(int i, GM_CurveSegment value) {
157: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
158: if (i != 0)
159: System.out
160: .println("Ajout d'un segment avec i<>0 alors qu'un GM_CurveSegment ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
161: else
162: this .segment.add(value);
163: else
164: this .segment.add(i, value);
165: }
166:
167: /** Efface de la liste le (ou les) segment passé en paramètre */
168: public void removeSegment(GM_CurveSegment value) {
169: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
170: System.out
171: .println("removeSegment() : Ne fait rien car un GM_CurveSegment ne contient qu'un segment qui est lui-meme.");
172: else
173: this .segment.remove(value);
174: }
175:
176: /** Efface le i-ème segment de la liste */
177: public void removeSegment(int i) {
178: if ((GM_CurveSegment.class).isAssignableFrom(this .getClass()))
179: System.out
180: .println("removeSegment() : Ne fait rien car un GM_CurveSegment ne contient qu'un segment qui est lui-meme.");
181: else
182: this .segment.remove(i);
183: }
184:
185: /** Renvoie le nombre de segment */
186: public int sizeSegment() {
187: return this .segment.size();
188: }
189:
190: /** A TESTER.
191: * Vérifie le chaînage des segments. renvoie TRUE s'ils sont chaînés, FALSE sinon.
192: * Nécessité de définir une tolérance.
193: */
194: public boolean validate(double tolerance) {
195: if (this .sizeSegment() <= 1)
196: return true;
197: else {
198: int n = this .sizeSegment();
199: for (int i = 0; i < n - 1; i++) {
200: GM_CurveSegment segment1 = this .getSegment(i);
201: GM_CurveSegment segment2 = this .getSegment(i + 1);
202: if (!(segment2.startPoint().equals(segment1.endPoint(),
203: tolerance)))
204: return false;
205: }
206: return true;
207: }
208: }
209:
210: //////////////////////////////////////////////////////////////////////////////////
211: // Constructeurs /////////////////////////////////////////////////////////////////
212: //////////////////////////////////////////////////////////////////////////////////
213: /** Constructeur par défaut */
214: public GM_Curve() {
215: segment = new ArrayList();
216: orientation = +1;
217: primitive = this ;
218: proxy[0] = this ;
219: GM_OrientableCurve proxy1 = new GM_OrientableCurve();
220: proxy1.orientation = -1;
221: proxy1.proxy[0] = this ;
222: proxy1.proxy[1] = proxy1;
223: proxy1.primitive = new GM_Curve(this );
224: proxy[1] = proxy1;
225: }
226:
227: /** Constructeur à partir d'un et d'un seul GM_CurveSegment */
228: public GM_Curve(GM_CurveSegment C) {
229: this ();
230: segment.add(C);
231: }
232:
233: /** Usage interne. Utilisé en interne (dans les constructeurs publics) pour construire la courbe opposé,
234: * qui est la primitive de proxy[1]. On définit ici les références nécessaires. Le but est de retrouver la propriete :
235: * curve.getNegative().getPrimitive().getNegative().getPrimitive() = curve.
236: * Les segment de la courbe sont calcule en dynamique lors de l'appel a la methode getNegative(). */
237: public GM_Curve(GM_Curve curve) {
238: segment = new ArrayList();
239: orientation = +1;
240: primitive = this ;
241: proxy[0] = this ;
242: GM_OrientableCurve proxy1 = new GM_OrientableCurve();
243: proxy1.orientation = -1;
244: proxy1.proxy[0] = this ;
245: proxy1.proxy[1] = proxy1;
246: proxy1.primitive = curve;
247: proxy[1] = proxy1;
248: }
249:
250: //////////////////////////////////////////////////////////////////////////////////
251: // Implémentation de GM_GenericCurve /////////////////////////////////////////////
252: //////////////////////////////////////////////////////////////////////////////////
253: /** Retourne le DirectPosition du premier point.
254: * Différent de l'opérateur "boundary" car renvoie la valeur du point et non pas l'objet géométrique représentatif.
255: * Méthode d'implémentation de l'interface GM_GenericCurve. */
256: public DirectPosition startPoint() {
257: return this .getSegment(0).coord().get(0);
258: }
259:
260: /**Retourne le DirectPosition du dernier point.
261: * Différent de l'opérateur "boundary" car renvoie la valeur du point et non pas l'objet géométrique représentatif.
262: * Méthode d'implémentation de l'interface GM_GenericCurve.*/
263: public DirectPosition endPoint() {
264: GM_CurveSegment lastSegment = this .getSegment(this
265: .sizeSegment() - 1);
266: DirectPositionList pointArray = lastSegment.coord();
267: return pointArray.get(pointArray.size() - 1);
268: }
269:
270: /** NON IMPLEMENTE - A FAIRE.
271: * Renvoie un point à l'abcsisse curviligne s.
272: */
273: /* public DirectPosition param(double s) {
274: return null;
275: }
276: */
277:
278: /** NON IMPLEMENTE.
279: * Vecteur tangent a la courbe, à l'abscisse curviligne passée en paramètre. Le vecteur résultat est normé.
280: */
281: /* public Vecteur tangent(double s) {
282: return null;
283: }
284: */
285:
286: /** NON IMPLEMENTE. Renvoie 0.0 .
287: * Méthode d'implémentation de l'interface GM_GenericCurve.
288: */
289: /* public double startParam() {
290: return 0.0;
291: }
292: */
293:
294: /** NON IMPLEMENTE.
295: * Longueur de la courbe pour une GM_Curve.
296: */
297: /* double endParam() {
298: return 0.0;
299: }
300: */
301:
302: /** NON IMPLEMENTE.
303: * Renvoie le paramètre au point P (le paramètre étant a priori la distance).
304: * Si P n'est pas sur la courbe, on cherche alors pour le calcul le point le plus proche de P sur la courbe (qui est aussi renvoyé en résultat).
305: * On renvoie en général une seule distance, sauf si la courbe n'est pas simple.
306: */
307: /* List paramForPoint(DirectPosition P) {
308: return null;
309: }
310: */
311:
312: /** NON IMPLEMENTE.
313: * Représentation alternative d'une courbe comme l'image continue d'un intervalle de réels, sans imposer que cette paramétrisation représente la longueur de la courbe, et sans imposer de restrictions entre la courbe et ses segments.
314: * Utilité : pour les courbes paramétrées, pour construire une surface paramétrée.
315: */
316: /* DirectPosition constrParam(double cp) {
317: return null;
318: }
319: */
320:
321: /** NON IMPLEMENTE.
322: * Paramètre au startPoint pour une courbe paramétrée, c'est-à-dire : constrParam(startConstrParam())=startPoint().
323: * Méthode d'implémentation de l'interface GM_GenericCurve.
324: * NON IMPLEMENTE
325: */
326: /* double startConstrParam() {
327: return 0.0;
328: }
329: */
330:
331: /** NON IMPLEMENTE.
332: * Paramètre au endPoint pour une courbe paramétrée, c'est-à-dire : constrParam(endConstrParam())=endPoint().
333: */
334: /* double endConstrParam() {
335: return 0.0;
336: }
337: */
338:
339: /**
340: * Longueur totale de la courbe. (code au niveau de GM_Object)
341: */
342: /* public double length() {
343: System.out.println("appel ##");
344: return SpatialQuery.length(this);
345: }*/
346:
347: /** NON IMPLEMENTE.
348: * Longueur entre 2 points.
349: */
350: /* public double length(GM_Position p1, GM_Position p2) {
351: return 0.0;
352: }*/
353:
354: /** NON IMPLEMENTE.
355: * Longueur d'une courbe paramétrée "entre 2 réels".
356: */
357: /* double length(double cparam1, double cparam2) {
358: return 0.0;
359: }
360: */
361:
362: /**
363: * Approximation linéaire d'une courbe avec les points de contrôle. Elimine les points doublons consécutifs
364: * (qui apparaissent quand la courbe est composée de plusieurs segments).
365: * <P> Le paramètre spacing indique la distance maximum entre 2 points de contrôle ;
366: * le paramètre offset indique la distance maximum entre la polyligne générée et la courbe originale.
367: * Si ces 2 paramètres sont à 0, alors aucune contrainte n'est imposée.
368: * Dans l'IMPLEMENTATION ACTUELLE : on impose que ces paramètres soient à 0.
369: * <P> Le paramètre tolérance est nécessaire pour éliminer les doublons. On peut passer 0.0.
370: * <P> Méthode d'implémentation de l'interface GM_GenericCurve.
371: */
372: // Dans la norme, les paramètres spacing et offset sont de type Distance.
373: // Dans la norme, il n'y a pas de paramètre tolérance.
374: public GM_LineString asLineString(double spacing, double offset,
375: double tolerance) {
376: GM_LineString theLineString = null;
377: if ((spacing != 0.0) || (offset != 0.0)) {
378: System.out
379: .println("GM_Curve::asLineString() : Spacing et Offset ne sont pas implémentés. Passer (0.0, 0.0, tolerance) en paramètres");
380: return null;
381: } else {
382: theLineString = new GM_LineString();
383: DirectPositionList aListOfPoints;
384: if (this .sizeSegment() > 0) {
385: for (int i = 0; i < this .sizeSegment(); i++) {
386: aListOfPoints = this .getSegment(i).coord();
387: if (aListOfPoints.size() > 0) {
388: aListOfPoints.initIterator();
389: while (aListOfPoints.hasNext()) {
390: DirectPosition pt1 = aListOfPoints.next();
391: if (theLineString.getControlPoint().size() > 0) {
392: DirectPosition pt2 = theLineString
393: .getControlPoint()
394: .get(
395: theLineString
396: .getControlPoint()
397: .size() - 1);
398: if (!pt1.equals(pt2, tolerance))
399: theLineString.getControlPoint()
400: .add(pt1);
401: } else {
402: theLineString.getControlPoint()
403: .add(pt1);
404: }
405: }
406: }
407: }
408: }
409: return theLineString;
410: }
411: }
412:
413: //////////////////////////////////////////////////////////////////////////////////
414: // Méthodes d'accés aux coordonnées //////////////////////////////////////////////
415: //////////////////////////////////////////////////////////////////////////////////
416: /** Méthode pour afficher les coordonnées d'une courbe. */
417: /*public String toString () {
418: String result = new String();
419: if (sizeSegment() == 0) {
420: result = "GM_Curve : geometrie vide";
421: return result;
422: }
423: for(int i=0; i<this.sizeSegment(); i++) {
424: GM_CurveSegment theSegment = this.getSegment(i);
425: DirectPositionList theList = theSegment.coord();
426: if (theList.size() != 0) {
427: result = result+theList.toString();
428: result = result+"\n";
429: } else result = "GM_CurveSegment vide\n";
430: }
431: return result.substring(0,result.length()-1); // on enleve le dernier "\n";
432: } */
433:
434: /** Renvoie la liste des coordonnées d'une courbe sous forme d'une liste de DirectPosition . */
435: public DirectPositionList coord() {
436: DirectPositionList result = new DirectPositionList();
437: if (sizeSegment() == 0)
438: return result;
439: for (int i = 0; i < this .sizeSegment(); i++) {
440: GM_CurveSegment theSegment = this .getSegment(i);
441: DirectPositionList theList = theSegment.coord();
442: theList.initIterator();
443: while (theList.hasNext()) {
444: DirectPosition thePoint = theList.next();
445: result.add(thePoint);
446: }
447: }
448: return result;
449: }
450:
451: }
|