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.DirectPositionList;
033: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_LineString;
034: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Polygon;
035: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_SurfacePatch;
036:
037: /**
038: * Surface, composée de morceaux de surface. L'orientation vaut nécessairement +1.
039: *
040: * <P> Modification de la norme suite au retour d'utilisation : on fait hériter GM_SurfacePatch de GM_Surface.
041: * Du coup, on n'implémente plus l'interface GM_GenericSurface.
042: *
043: * @author Thierry Badard & Arnaud Braun
044: * @version 1.0
045: *
046: */
047:
048: public class GM_Surface extends GM_OrientableSurface
049: /*implements GM_GenericSurface*/{
050:
051: //////////////////////////////////////////////////////////////////////////////////
052: // Attribut "patch" et méthodes pour le traiter //////////////////////////////////
053: //////////////////////////////////////////////////////////////////////////////////
054: // A FAIRE : validate : pour que les patch soient contigue ?
055: // pour cela il faut regarder que l'union est du type GM_Surface et non GM_MultiSurface
056:
057: /**Liste des morceaux constituant la surface.*/
058: protected List patch;
059:
060: /** Renvoie la liste des patch. */
061: public List getPatch() {
062: return this .patch;
063: }
064:
065: /** Renvoie le patch de rang i. */
066: public GM_SurfacePatch getPatch(int i) {
067: if ((GM_SurfacePatch.class).isAssignableFrom(this .getClass()))
068: if (i != 0) {
069: System.out
070: .println("Recherche d'un patch avec i<>0 alors qu'un GM_SurfacePatch ne contient qu'un segment qui est lui-meme");
071: return null;
072: } else
073: return (GM_SurfacePatch) this .patch.get(i);
074: else
075: return (GM_SurfacePatch) this .patch.get(i);
076: }
077:
078: /** Affecte un patch au rang i. */
079: public void setPatch(int i, GM_SurfacePatch value) {
080: if ((GM_SurfacePatch.class).isAssignableFrom(this .getClass()))
081: if (i != 0)
082: System.out
083: .println("Affection d'un patch avec i<>0 alors qu'un GM_SurfacePatch ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
084: else
085: this .patch.set(i, value);
086: else
087: this .patch.set(i, value);
088: }
089:
090: /** Ajoute un patch en fin de liste. */
091: public void addPatch(GM_SurfacePatch value) {
092: if ((GM_SurfacePatch.class).isAssignableFrom(this .getClass()))
093: if (sizePatch() > 0)
094: System.out
095: .println("Ajout d'un patch alors qu'un GM_SurfacePatch ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
096: else
097: this .patch.add(value);
098: else
099: this .patch.add(value);
100: }
101:
102: /** Ajoute un patch au rang i. */
103: public void addPatch(int i, GM_SurfacePatch value) {
104: if ((GM_SurfacePatch.class).isAssignableFrom(this .getClass()))
105: if (i != 0)
106: System.out
107: .println("Ajout d'un patch avec i<>0 alors qu'un GM_SurfacePatch ne contient qu'un segment qui est lui-meme. La méthode ne fait rien.");
108: else
109: this .patch.add(value);
110: else
111: this .patch.add(i, value);
112: }
113:
114: /** Efface le patch de valeur value. */
115: public void removePatch(GM_SurfacePatch value) {
116: if ((GM_SurfacePatch.class).isAssignableFrom(this .getClass()))
117: System.out
118: .println("removePatch() : Ne fait rien car un GM_SurfacePatch ne contient qu'un segment qui est lui-meme.");
119: else
120: this .patch.remove(value);
121: }
122:
123: /** Efface le patch de rang i. */
124: public void removePatch(int i) {
125: if ((GM_SurfacePatch.class).isAssignableFrom(this .getClass()))
126: System.out
127: .println("removePatch() : Ne fait rien car un GM_SurfacePatch ne contient qu'un segment qui est lui-meme.");
128: else
129: this .patch.remove(i);
130: }
131:
132: /** Renvoie le nombre de patch. */
133: public int sizePatch() {
134: return this .patch.size();
135: }
136:
137: //////////////////////////////////////////////////////////////////////////////////
138: // Constructeurs /////////////////////////////////////////////////////////////////
139: //////////////////////////////////////////////////////////////////////////////////
140: /** Constructeur par défaut */
141: public GM_Surface() {
142: patch = new ArrayList();
143: orientation = +1;
144: primitive = this ;
145: proxy[0] = this ;
146: GM_OrientableSurface proxy1 = new GM_OrientableSurface();
147: proxy1.orientation = -1;
148: proxy1.proxy[0] = this ;
149: proxy1.proxy[1] = proxy1;
150: proxy1.primitive = new GM_Surface(this );
151: proxy[1] = proxy1;
152: }
153:
154: /** Constructeur à partir d'un et d'un seul surface patch */
155: public GM_Surface(GM_SurfacePatch thePatch) {
156: this ();
157: this .addPatch(thePatch);
158: }
159:
160: /** Utilisé en interne (dans les constructeurs publics) pour construire la surface opposée,
161: * qui est la primitive de proxy[1]. On définit ici les références nécessaires. Le but est de retrouver la propriete :
162: * surface.getNegative().getPrimitive().getNegative().getPrimitive() = surface.
163: * La frontiere de la surface est calculee en dynamique lors de l'appel a la methode getNegative(). */
164: public GM_Surface(GM_Surface surface) {
165: patch = new ArrayList();
166: orientation = +1;
167: primitive = this ;
168: proxy[0] = this ;
169: GM_OrientableSurface proxy1 = new GM_OrientableSurface();
170: proxy1.orientation = -1;
171: proxy1.proxy[0] = this ;
172: proxy1.proxy[1] = proxy1;
173: proxy1.primitive = surface;
174: proxy[1] = proxy1;
175: }
176:
177: //////////////////////////////////////////////////////////////////////////////////
178: // Implémentation de GM_GenericCurve /////////////////////////////////////////////
179: //////////////////////////////////////////////////////////////////////////////////
180: /** NON IMPLEMENTE.
181: * Vecteur normal à self au point passé en paramètre. */
182: /* public Vecteur upNormal(DirectPosition point) {
183: return null;
184: }
185: */
186:
187: /** Périmètre. */
188: public double perimeter() {
189: // return SpatialQuery.perimeter(this); (ancienne methode avec SDOAPI)
190: return this .length();
191: }
192:
193: // code au niveau de GM_Object
194: /** Aire. */
195: /* public double area() {
196: return SpatialQuery.area(this);
197: }*/
198:
199: //////////////////////////////////////////////////////////////////////////////////
200: // Méthodes d'accès aux coordonnées //////////////////////////////////////////////
201: //////////////////////////////////////////////////////////////////////////////////
202: /** Renvoie la frontière extérieure sous forme d'une polyligne (on a linéarisé).
203: * Ne fonctionne que si la surface est composée d'un et d'un seul patch, qui est un polygone. (sinon renvoie null). */
204: public GM_LineString exteriorLineString() {
205: if (this .sizePatch() == 1) {
206: GM_Polygon poly = (GM_Polygon) this .getPatch(0);
207: GM_Ring ext = poly.getExterior();
208: if (ext != null) {
209: GM_Curve c = (GM_Curve) ext.getPrimitive();
210: GM_LineString ls = c.asLineString(0.0, 0.0, 0.0);
211: return ls;
212: } else {
213: System.out
214: .println("GM_Surface::exteriorLineString() : ATTENTION frontiere null");
215: return null;
216: }
217: } else {
218: System.out
219: .println("GM_Surface::exteriorLineString() : cette méthode ne fonctionne que si la surface est composée d'un seul patch.");
220: return null;
221: }
222: }
223:
224: /** Renvoie la frontière extérieure sous forme d'une GM_Curve.
225: * Ne fonctionne que si la surface est composée d'un et d'un seul patch, qui est un polygone. (sinon renvoie null). */
226: public GM_Curve exteriorCurve() {
227: if (this .sizePatch() == 1) {
228: GM_Polygon poly = (GM_Polygon) this .getPatch(0);
229: GM_Ring ext = poly.getExterior();
230: if (ext != null)
231: return (GM_Curve) ext.getPrimitive();
232: else {
233: System.out
234: .println("GM_Surface::exteriorCurve() : ATTENTION frontiere null");
235: return null;
236: }
237: } else {
238: System.out
239: .println("GM_Surface::exteriorCurve() : cette méthode ne fonctionne que si la surface est composée d'un seul patch.");
240: return null;
241: }
242: }
243:
244: /** Renvoie la liste des coordonnées de la frontière EXTERIEURE d'une surface,
245: sous forme d'une DirectPositionList. */
246: public DirectPositionList exteriorCoord() {
247: GM_Curve c = this .exteriorCurve();
248: if (c != null)
249: return c.coord();
250: else
251: return new DirectPositionList();
252: }
253:
254: /** Renvoie la frontière intérieure de rang i sous forme d'une polyligne (on a linéarisé).
255: * Ne fonctionne que si la surface est composée d'un et d'un seul patch, qui est un polygone (sinon renvoie null). */
256: public GM_LineString interiorLineString(int i) {
257: if (this .sizePatch() == 1) {
258: GM_Polygon poly = (GM_Polygon) this .getPatch(0);
259: GM_Ring inte = poly.getInterior(i);
260: if (inte != null) {
261: GM_Curve c = (GM_Curve) inte.getPrimitive();
262: GM_LineString ls = c.asLineString(0.0, 0.0, 0.0);
263: return ls;
264: } else {
265: System.out
266: .println("GM_Surface::interiorLineString() : ATTENTION frontiere null");
267: return null;
268: }
269: } else {
270: System.out
271: .println("GM_Surface::interiorLineString() : cette méthode ne fonctionne que si la surface est composée d'un seul patch");
272: return null;
273: }
274: }
275:
276: /** Renvoie la frontière intérieure de rang i sous forme d'une GM_Curve.
277: * Ne fonctionne que si la surface est composée d'un et d'un seul patch, qui est un polygone (sinon renvoie null). */
278: public GM_Curve interiorCurve(int i) {
279: if (this .sizePatch() == 1) {
280: GM_Polygon poly = (GM_Polygon) this .getPatch(0);
281: GM_Ring inte = poly.getInterior(i);
282: if (inte != null)
283: return (GM_Curve) inte.getPrimitive();
284: else {
285: System.out
286: .println("GM_Surface::interiorCurve() : ATTENTION frontiere null");
287: return null;
288: }
289: } else {
290: System.out
291: .println("GM_Surface::interiorCurve() : cette méthode ne fonctionne que si la surface est composée d'un seul patch");
292: return null;
293: }
294: }
295:
296: /** Renvoie la liste des coordonnées de la frontière intérieure de rang i d'une surface,
297: sous forme d'un GM_PointArray. */
298: public DirectPositionList interiorCoord(int i) {
299: GM_Curve c = this .interiorCurve(i);
300: if (c != null)
301: return c.coord();
302: else
303: return new DirectPositionList();
304: }
305:
306: /** Renvoie la liste des coordonnées d'une surface (exterieure et interieur)
307: sous forme d'une DirectPositionList. Toutes les coordonnees sont concatenees.*/
308: public DirectPositionList coord() {
309: if (this .sizePatch() == 1) {
310: GM_Polygon poly = (GM_Polygon) this .getPatch(0);
311: DirectPositionList dpl = exteriorCurve().coord();
312: for (int i = 0; i < poly.sizeInterior(); i++)
313: dpl.addAll(interiorCurve(i).coord());
314: return dpl;
315: } else {
316: System.out
317: .println("GM_Surface::coord() : cette méthode ne fonctionne que si la surface est composée d'un seul patch");
318: return null;
319: }
320: }
321:
322: /** Affiche la liste des coordonnées (interieures et exterieures) */
323: /*public String toString() {
324: String result = new String();
325: result = result+"exterieur : \n";
326: if (exteriorCurve() != null) result = result+exteriorCurve().toString();
327: else result = result+"vide";
328: if (this.sizePatch() == 1) {
329: GM_Polygon poly = (GM_Polygon)this.getPatch(0);
330: for (int i=0; i<poly.sizeInterior(); i++) {
331: result = "\n"+result+"interieur numero "+i+"\n";
332: if (interiorCurve(i) != null) result = result+interiorCurve(i).toString();
333: else result = result+"vide";
334: }
335: } else {
336: System.out.println("GM_Surface::toString() : cette méthode ne fonctionne que si la surface est composée d'un seul patch");
337: }
338: return result;
339: } */
340:
341: }
|