001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.wms.responses.map.georss;
006:
007: import com.vividsolutions.jts.geom.Coordinate;
008: import com.vividsolutions.jts.geom.Geometry;
009: import com.vividsolutions.jts.geom.GeometryCollection;
010: import com.vividsolutions.jts.geom.LineString;
011: import com.vividsolutions.jts.geom.Point;
012: import com.vividsolutions.jts.geom.Polygon;
013:
014: import org.geoserver.feature.ReprojectingFeatureCollection;
015: import org.geotools.data.DefaultQuery;
016: import org.geotools.data.FeatureSource;
017: import org.geotools.data.crs.ReprojectFeatureResults;
018: import org.geotools.factory.CommonFactoryFinder;
019: import org.geotools.factory.GeoTools;
020: import org.geotools.feature.Feature;
021: import org.geotools.feature.FeatureCollection;
022: import org.geotools.feature.GeometryAttributeType;
023:
024: import org.geotools.geometry.jts.ReferencedEnvelope;
025: import org.geotools.map.MapLayer;
026: import org.geotools.referencing.CRS;
027: import org.geotools.xml.transform.TransformerBase;
028: import org.geotools.xml.transform.Translator;
029: import org.opengis.filter.Filter;
030: import org.opengis.filter.FilterFactory;
031: import org.opengis.referencing.crs.CoordinateReferenceSystem;
032: import org.vfny.geoserver.wms.WMSMapContext;
033: import org.xml.sax.ContentHandler;
034:
035: import java.io.IOException;
036: import java.util.ArrayList;
037: import java.util.List;
038: import java.util.logging.Level;
039: import java.util.logging.Logger;
040:
041: public abstract class GeoRSSTransformerBase extends TransformerBase {
042: /** logger */
043: protected static Logger LOGGER = org.geotools.util.logging.Logging
044: .getLogger("org.geoserver.georss");
045:
046: /**
047: * Enumeration for geometry encoding.
048: *
049: * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
050: *
051: */
052: public static class GeometryEncoding {
053: private GeometryEncoding() {
054: }
055:
056: public String getPrefix() {
057: return null;
058: }
059:
060: public String getNamespaceURI() {
061: return null;
062: }
063:
064: public void encode(Geometry g,
065: GeoRSSTranslatorSupport translator) {
066: }
067:
068: /**
069: * "simple" encoding:
070: *
071: * ex:
072: * <georss:point>45.256 -71.92</georss:point>,<georss:line>...</georss:line>,...
073: */
074: public static GeometryEncoding SIMPLE = new GeometryEncoding() {
075: public String getPrefix() {
076: return "georss";
077: }
078:
079: public String getNamespaceURI() {
080: return "http://www.georss.org/georss";
081: }
082:
083: public void encode(Geometry g, GeoRSSTranslatorSupport t) {
084: if (g instanceof Point) {
085: Point p = (Point) g;
086: t
087: .element("georss:point", p.getX() + " "
088: + p.getY());
089: }
090:
091: if (g instanceof LineString) {
092: LineString l = (LineString) g;
093:
094: StringBuffer sb = new StringBuffer();
095:
096: for (int i = 0; i < l.getNumPoints(); i++) {
097: Coordinate c = l.getCoordinateN(i);
098: sb.append(c.x).append(" ").append(c.y).append(
099: " ");
100: }
101:
102: sb.setLength(sb.length() - 1);
103:
104: t.element("georss:line", sb.toString());
105: }
106:
107: if (g instanceof Polygon) {
108: Polygon p = (Polygon) g;
109: LineString line = p.getExteriorRing();
110:
111: StringBuffer sb = new StringBuffer();
112:
113: for (int i = 0; i < line.getNumPoints(); i++) {
114: Coordinate c = line.getCoordinateN(i);
115: sb.append(c.x).append(" ").append(c.y).append(
116: " ");
117: }
118:
119: sb.setLength(sb.length() - 1);
120:
121: t.element("georss:polygon", sb.toString());
122: }
123: }
124: };
125:
126: /**
127: * gml encoding:
128: *
129: * ex:
130: * <gml:Point>
131: * <gml:pos>45.256 -71.92</gml:pos>
132: * </gml:Point>
133: */
134: public static GeometryEncoding GML = new GeometryEncoding() {
135: public String getPrefix() {
136: return "gml";
137: }
138:
139: public String getNamespaceURI() {
140: return "http://www.opengis.net/gml";
141: }
142: };
143:
144: /**
145: * lat/long encoding:
146: *
147: * ex:
148: * <geo:lat>45.256</geo:lat>
149: * <geo:long>-71.92</geo:long>
150: *
151: */
152: public static GeometryEncoding LATLONG = new GeometryEncoding() {
153: public String getPrefix() {
154: return "geo";
155: }
156:
157: public String getNamespaceURI() {
158: return "http://www.w3.org/2003/01/geo/wgs84_pos#";
159: }
160:
161: public void encode(Geometry g, GeoRSSTranslatorSupport t) {
162: //encode the centroid
163: Point p = g.getCentroid();
164: t.element("geo:lat", "" + p.getY());
165: t.element("geo:long", "" + p.getX());
166: }
167: };
168: };
169:
170: /**
171: * Geometry encoding to use.
172: */
173: protected GeometryEncoding geometryEncoding = GeometryEncoding.LATLONG;
174:
175: public void setGeometryEncoding(GeometryEncoding geometryEncoding) {
176: this .geometryEncoding = geometryEncoding;
177: }
178:
179: abstract class GeoRSSTranslatorSupport extends TranslatorSupport {
180: public GeoRSSTranslatorSupport(ContentHandler contentHandler,
181: String prefix, String nsURI) {
182: super (contentHandler, prefix, nsURI);
183:
184: nsSupport.declarePrefix(geometryEncoding.getPrefix(),
185: geometryEncoding.getNamespaceURI());
186: }
187:
188: /**
189: * Encodes the geometry of a feature.
190: *
191: */
192: protected void encodeGeometry(Feature feature) {
193: if (feature.getDefaultGeometry() != null) {
194: Geometry g = feature.getDefaultGeometry();
195:
196: //handle case of multi geometry with a single geometry in it
197: if (g instanceof GeometryCollection) {
198: GeometryCollection mg = (GeometryCollection) g;
199:
200: if (mg.getNumGeometries() == 1) {
201: g = mg.getGeometryN(0);
202: }
203: }
204:
205: geometryEncoding.encode(g, this );
206: }
207: }
208:
209: //overrides to increase visiblity
210: public void start(String element) {
211: super .start(element);
212: }
213:
214: public void element(String element, String content) {
215: super .element(element, content);
216: }
217:
218: protected List loadFeatureCollections(WMSMapContext map)
219: throws IOException {
220: ReferencedEnvelope mapArea = map.getAreaOfInterest();
221: CoordinateReferenceSystem wgs84 = null;
222: FilterFactory ff = CommonFactoryFinder
223: .getFilterFactory(GeoTools.getDefaultHints());
224: try {
225: // this should never throw an exception, but we have to deal with it anyways
226: wgs84 = CRS.decode("EPSG:4326");
227: } catch (Exception e) {
228: throw (IOException) (new IOException(
229: "Unable to decode WGS84...").initCause(e));
230: }
231:
232: List featureCollections = new ArrayList();
233: for (int i = 0; i < map.getLayerCount(); i++) {
234: MapLayer layer = map.getLayer(i);
235: DefaultQuery query = new DefaultQuery(layer.getQuery());
236:
237: FeatureCollection features = null;
238: try {
239: FeatureSource source = layer.getFeatureSource();
240:
241: GeometryAttributeType at = source.getSchema()
242: .getDefaultGeometry();
243: if (at == null) {
244: // geometryless layers...
245: features = source.getFeatures(query);
246: } else {
247: // make sure we are querying the source with the bbox in the right CRS, if
248: // not, reproject the bbox
249: ReferencedEnvelope env = new ReferencedEnvelope(
250: mapArea);
251: CoordinateReferenceSystem sourceCRS = at
252: .getCoordinateSystem();
253: if (sourceCRS != null
254: && !CRS
255: .equalsIgnoreMetadata(
256: mapArea
257: .getCoordinateReferenceSystem(),
258: sourceCRS)) {
259: env = env.transform(sourceCRS, true);
260: }
261:
262: // build the mixed query
263: Filter original = query.getFilter();
264: Filter bbox = ff.bbox(at.getLocalName(), env
265: .getMinX(), env.getMinY(), env
266: .getMaxX(), env.getMaxY(), null);
267: query.setFilter(ff.and(original, bbox));
268:
269: // query and eventually reproject
270: features = source.getFeatures(query);
271: if (sourceCRS != null
272: && !CRS.equalsIgnoreMetadata(wgs84,
273: sourceCRS)) {
274: ReprojectingFeatureCollection coll = new ReprojectingFeatureCollection(
275: features, wgs84);
276: coll.setDefaultSource(sourceCRS);
277: features = coll;
278: }
279:
280: if (features == null)
281: throw new NullPointerException();
282:
283: featureCollections.add(features);
284:
285: }
286: } catch (Exception e) {
287: String msg = "Unable to encode map layer: " + layer;
288: LOGGER.log(Level.SEVERE, msg, e);
289: }
290: }
291:
292: return featureCollections;
293: }
294:
295: }
296: }
|