001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/model/spatialschema/SurfaceImpl.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstr. 19
030: 53115 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042:
043: ---------------------------------------------------------------------------*/
044: package org.deegree.model.spatialschema;
045:
046: import java.io.Serializable;
047:
048: import org.deegree.framework.log.ILogger;
049: import org.deegree.framework.log.LoggerFactory;
050: import org.deegree.model.crs.CoordinateSystem;
051:
052: /**
053: * default implementation of the Surface interface from package jago.model.
054: * <p>
055: * </p>
056: * for simplicity of the implementation it is assumed that a surface is build from just one surface
057: * patch. this isn't completly confrom to the ISO 19107 and the OGC GAIA specification but
058: * sufficient for most applications.
059: * <p>
060: * </p>
061: * It will be extended to fullfill the complete specs as soon as possible.
062: *
063: * @version 05.04.2002
064: * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
065: */
066:
067: public class SurfaceImpl extends OrientableSurfaceImpl implements
068: Surface, GenericSurface, Serializable {
069: /** Use serialVersionUID for interoperability. */
070: private final static long serialVersionUID = -2148069106391096842L;
071:
072: private static final ILogger LOG = LoggerFactory
073: .getLogger(SurfaceImpl.class);
074:
075: protected SurfacePatch[] patch = null;
076:
077: private double area = 0;
078:
079: /**
080: * initializes the surface with default orientation submitting one surface patch.
081: *
082: * @param surfacePatch
083: * patches of the surface.
084: * @throws GeometryException
085: * will be thrown if orientation is invalid
086: */
087: public SurfaceImpl(SurfacePatch surfacePatch)
088: throws GeometryException {
089: this ('+', surfacePatch);
090: }
091:
092: /**
093: * initializes the surface with default orientation submitting one surface patch.
094: *
095: * @param surfacePatches
096: * patches of the surface.
097: * @throws GeometryException
098: * will be thrown if orientation is invalid
099: */
100: public SurfaceImpl(SurfacePatch[] surfacePatches)
101: throws GeometryException {
102: this ('+', surfacePatches);
103: }
104:
105: /**
106: * initializes the surface with default orientation submitting one surface patch.
107: *
108: * @param surfacePatches
109: * patches of the surface.
110: * @param crs
111: * @throws GeometryException
112: * will be thrown if orientation is invalid
113: */
114: public SurfaceImpl(SurfacePatch[] surfacePatches,
115: CoordinateSystem crs) throws GeometryException {
116: this ('+', surfacePatches);
117: this .crs = crs;
118: }
119:
120: /**
121: * initializes the surface submitting the orientation and one surface patch.
122: *
123: * @param orientation
124: * of the surface
125: *
126: * @param surfacePatch
127: * patches of the surface.
128: * @throws GeometryException
129: * will be thrown if orientation is invalid
130: */
131: public SurfaceImpl(char orientation, SurfacePatch surfacePatch)
132: throws GeometryException {
133: super (surfacePatch.getCoordinateSystem(), orientation);
134:
135: patch = new SurfacePatch[] { surfacePatch };
136:
137: setValid(false);
138: }
139:
140: /**
141: * initializes the surface submitting the orientation and one surface patch.
142: *
143: * @param orientation
144: * of the surface
145: *
146: * @param surfacePatches
147: * patches of the surface.
148: * @throws GeometryException
149: * will be thrown if orientation is invalid
150: */
151: public SurfaceImpl(char orientation, SurfacePatch[] surfacePatches)
152: throws GeometryException {
153: super (surfacePatches[0].getCoordinateSystem(), orientation);
154: patch = surfacePatches;
155: setValid(false);
156: }
157:
158: /**
159: * initializes the surface with default orientation submitting the surfaces boundary
160: *
161: * @param boundary
162: * boundary of the surface
163: * @throws GeometryException
164: * will be thrown if orientation is invalid
165: */
166: public SurfaceImpl(SurfaceBoundary boundary)
167: throws GeometryException {
168: this ('+', boundary);
169: }
170:
171: /**
172: * initializes the surface submitting the orientation and the surfaces boundary.
173: *
174: * @param orientation
175: * of the surface
176: *
177: * @param boundary
178: * boundary of the surface
179: *
180: * @throws GeometryException
181: * will be thrown if orientation is invalid
182: */
183: public SurfaceImpl(char orientation, SurfaceBoundary boundary)
184: throws GeometryException {
185: // todo
186: // extracting surface patches from the boundary
187: super (boundary.getCoordinateSystem(), orientation);
188:
189: this .boundary = boundary;
190: }
191:
192: /**
193: * calculates the centroid and area of the surface
194: */
195: private void calculateCentroidArea() {
196: double x = 0;
197: double y = 0;
198: area = 0;
199: for (int i = 0; i < patch.length; i++) {
200: if (patch[i].getCentroid() != null
201: && patch[i].getArea() > 0) {
202: x += (patch[i].getCentroid().getX() * patch[i]
203: .getArea());
204: y += (patch[i].getCentroid().getY() * patch[i]
205: .getArea());
206: }
207: if (patch[i].getArea() > 0) {
208: area += patch[i].getArea();
209: }
210: }
211: if (area > 0) {
212: centroid = GeometryFactory.createPoint(x / area, y / area,
213: this .crs);
214: } else {
215: // fall back
216: centroid = GeometryFactory.createPoint(0, 0, this .crs);
217: }
218: }
219:
220: /**
221: * calculates the boundary and area of the surface
222: */
223: private void calculateBoundary() {
224: // TODO
225: // consider more than one patch
226: try {
227: Ring ext = new RingImpl(patch[0].getExteriorRing(), crs);
228: Position[][] inn_ = patch[0].getInteriorRings();
229: Ring[] inn = null;
230:
231: if (inn_ != null) {
232: inn = new RingImpl[inn_.length];
233:
234: for (int i = 0; i < inn_.length; i++) {
235: inn[i] = new RingImpl(inn_[i], crs);
236: }
237: }
238: boundary = new SurfaceBoundaryImpl(ext, inn);
239: } catch (Exception e) {
240: LOG.logError(e.getMessage(), e);
241: throw new RuntimeException(e.getMessage(), e);
242: }
243: }
244:
245: /**
246: * calculates area, centroid and the envelope of the surface
247: */
248: @Override
249: protected void calculateParam() {
250: calculateCentroidArea();
251: try {
252: calculateEnvelope();
253: } catch (GeometryException e) {
254: LOG.logError(e.getMessage(), e);
255: }
256: calculateBoundary();
257: setValid(true);
258: }
259:
260: /**
261: * calculates the envelope of the surface
262: */
263: private void calculateEnvelope() throws GeometryException {
264:
265: envelope = patch[0].getEnvelope();
266: for (int i = 1; i < patch.length; i++) {
267: envelope = envelope.merge(patch[i].getEnvelope());
268: }
269: envelope = GeometryFactory.createEnvelope(envelope.getMin(),
270: envelope.getMax(), getCoordinateSystem());
271:
272: }
273:
274: /**
275: * returns the length of all boundaries of the surface in a reference system appropriate for
276: * measuring distances.
277: */
278: public double getPerimeter() {
279: return -1;
280: }
281:
282: /**
283: * The operation "area" shall return the area of this GenericSurface. The area of a 2
284: * dimensional geometric object shall be a numeric measure of its surface area Since area is an
285: * accumulation (integral) of the product of two distances, its return value shall be in a unit
286: * of measure appropriate for measuring distances squared.
287: */
288: public double getArea() {
289: if (!isValid()) {
290: calculateParam();
291: }
292: return area;
293: }
294:
295: public SurfaceBoundary getSurfaceBoundary() {
296: if (!isValid()) {
297: calculateParam();
298: }
299: return (SurfaceBoundary) boundary;
300: }
301:
302: public int getNumberOfSurfacePatches() {
303: return patch.length;
304: }
305:
306: public SurfacePatch getSurfacePatchAt(int index)
307: throws GeometryException {
308: if (index >= patch.length) {
309: throw new GeometryException(
310: "invalid index/position to get a patch!");
311: }
312: return patch[index];
313: }
314:
315: /**
316: * checks if this surface is completly equal to the submitted geometry
317: *
318: * @param other
319: * object to compare to
320: */
321: @Override
322: public boolean equals(Object other) {
323: if (!super .equals(other)) {
324: return false;
325: }
326: if (!(other instanceof SurfaceImpl)) {
327: return false;
328: }
329: if (envelope == null) {
330: try {
331: calculateEnvelope();
332: } catch (GeometryException e1) {
333: return false;
334: }
335: }
336: if (!envelope.equals(((Geometry) other).getEnvelope())) {
337: return false;
338: }
339: try {
340: for (int i = 0; i < patch.length; i++) {
341: if (!patch[i].equals(((Surface) other)
342: .getSurfacePatchAt(i))) {
343: return false;
344: }
345: }
346: } catch (Exception e) {
347: return false;
348: }
349: return true;
350: }
351:
352: /**
353: * The operation "dimension" shall return the inherent dimension of this Geometry, which shall
354: * be less than or equal to the coordinate dimension. The dimension of a collection of geometric
355: * objects shall be the largest dimension of any of its pieces. Points are 0-dimensional, curves
356: * are 1-dimensional, surfaces are 2-dimensional, and solids are 3-dimensional.
357: */
358: public int getDimension() {
359: return 2;
360: }
361:
362: /**
363: * The operation "coordinateDimension" shall return the dimension of the coordinates that define
364: * this Geometry, which must be the same as the coordinate dimension of the coordinate reference
365: * system for this Geometry.
366: */
367: public int getCoordinateDimension() {
368: return patch[0].getExteriorRing()[0].getCoordinateDimension();
369: }
370:
371: /**
372: * @return a shallow copy of the geometry
373: */
374: @Override
375: public Object clone() {
376: Surface s = null;
377: try {
378: s = new SurfaceImpl(getOrientation(), patch);
379: } catch (Exception e) {
380: LOG.logError(e.getMessage(), e);
381: }
382:
383: return s;
384: }
385:
386: /**
387: * translate each point of the surface with the values of the submitted double array.
388: */
389: @Override
390: public void translate(double[] d) {
391: for (int i = 0; i < patch.length; i++) {
392: Position[] ext = patch[i].getExteriorRing();
393: Position[][] inn = patch[i].getInteriorRings();
394: for (int j = 0; j < ext.length; j++) {
395: ext[j].translate(d);
396: }
397: if (inn != null) {
398: for (int j = 0; j < inn.length; j++) {
399: for (int k = 0; k < inn[j].length; k++) {
400: inn[j][k].translate(d);
401: }
402: }
403: }
404: }
405: setValid(false);
406: }
407:
408: /**
409: * The boolean valued operation "intersects" shall return TRUE if this <tt>SurfaceImpl</tt>
410: * intersects with the given <tt>Geometry</t>.
411: * Within a <tt>Complex</tt>, the <tt>Primitives</tt> do not
412: * intersect one another. In general, topologically structured data uses
413: * shared geometric objects to capture intersection information.
414: * @param gmo the <tt>Geometry</tt> to test for intersection
415: * @return true if the <tt>Geometry</tt> intersects with this
416: */
417: @Override
418: public boolean intersects(Geometry gmo) {
419: if (!isValid()) {
420: calculateParam();
421: }
422:
423: for (int i = 0; i < patch.length; i++) {
424: if (patch[i].intersects(gmo)) {
425: return true;
426: }
427: }
428: return false;
429: }
430:
431: /**
432: * The Boolean valued operation "contains" shall return TRUE if this Geometry contains a single
433: * point given by a coordinate.
434: * <p>
435: * </p>
436: */
437: @Override
438: public boolean contains(Position position) {
439: return contains(new PointImpl(position, null));
440: }
441:
442: /**
443: * The Boolean valued operation "contains" shall return TRUE if this Geometry contains another
444: * Geometry.
445: * <p>
446: * </p>
447: */
448: @Override
449: public boolean contains(Geometry gmo) {
450: if (!isValid()) {
451: calculateParam();
452: }
453: return boundary.contains(gmo);
454: }
455:
456: /**
457: *
458: *
459: * @return the Stringrepresenation of this surface.
460: */
461: @Override
462: public String toString() {
463: StringBuffer ret = new StringBuffer(2000);
464: ret.append("\n------------------------------------------\n");
465: ret.append(getClass().getName()).append(":\n");
466: ret.append("envelope = ").append(envelope).append("\n");
467: ret.append("patch = ").append(patch.length).append("\n");
468: for (int i = 0; i < patch.length; i++) {
469: Position[] pos = patch[i].getExteriorRing();
470: ret.append("Exterior Ring: \n");
471: ret.append("length: ").append(pos.length).append("\n");
472: for (int j = 0; j < pos.length; j++) {
473: ret.append(pos[j] + "\n");
474: }
475: }
476: ret.append("\n------------------------------------------\n");
477: return ret.toString();
478: }
479: }
|