package org.geotools.filter.function; /* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ //this was autogenerated and then hand modified to implement better support for geometry // transformations in SLD import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.geotools.filter.FunctionExpressionImpl; import org.geotools.filter.capability.FunctionNameImpl; import org.geotools.filter.function.FilterFunction_offset.OffsetOrdinateFilter; import org.geotools.geometry.jts.ReferencedEnvelope; import org.opengis.filter.capability.FunctionName; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryComponentFilter; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Polygon; public class FilterFunction_isometric extends FunctionExpressionImpl implements GeometryTransformation { public static FunctionName NAME = new FunctionNameImpl("isometric", "geometry","extrusion"); public FilterFunction_isometric() { super("isometric"); functionName = NAME; } public int getArgCount() { return 2; } public Object evaluate(Object feature) { Geometry geom = getExpression(0).evaluate(feature, Geometry.class); Double extrusion = getExpression(1).evaluate(feature, Double.class); if (geom != null && extrusion != null) { // build the vertical faces SegmentExtractorFilter extractor = new SegmentExtractorFilter(); geom.apply(extractor); List<Polygon> faces = extractor.getFaces(geom.getFactory(), extrusion); // add the "cap" if(geom instanceof Polygon) { Polygon offseted = (Polygon) geom.clone(); offseted.apply(new OffsetOrdinateFilter(0, extrusion)); faces.add(0, (Polygon) geom); faces.add(offseted); } else if(geom instanceof GeometryCollection){ GeometryCollection gc = (GeometryCollection) geom; for (int i = 0; i < gc.getNumGeometries(); i++) { Geometry g = gc.getGeometryN(i); if(g instanceof Polygon) { Polygon offseted = (Polygon) g.clone(); offseted.apply(new OffsetOrdinateFilter(0, extrusion)); faces.add(0, (Polygon) g); faces.add(offseted); } } } Polygon[] polyArray = (Polygon[]) faces.toArray(new Polygon[faces.size()]); return geom.getFactory().createMultiPolygon(polyArray); } else { return null; } } /** * Returns an translated rendering envelope if the offsets are not using feature attributes. If * the offsets are feature dependent the user will have to expand the rendering area via the * renderer buffer parameter */ public ReferencedEnvelope invert(ReferencedEnvelope renderingEnvelope) { Double offsetX = getExpression(1).evaluate(null, Double.class); Double offsetY = getExpression(2).evaluate(null, Double.class); if (offsetX != null && offsetY != null) { ReferencedEnvelope offseted = new ReferencedEnvelope(renderingEnvelope); offseted.translate(offsetX, offsetY); return offseted; } else { return null; } } /** * Extracts Segment objects out of the Geometry coordinate sequences */ static class SegmentExtractorFilter implements GeometryComponentFilter { List<Segment> segments = new ArrayList<Segment>(); public void filter(Geometry geom) { if(geom instanceof LineString) { extractSegments(((LineString) geom).getCoordinateSequence()); } } private void extractSegments(CoordinateSequence cs) { for(int i = 0; i < cs.size() - 1; i++) { segments.add(new Segment(cs.getX(i), cs.getY(i), cs.getX(i+1), cs.getY(i+1))); } } List<Polygon> getFaces(GeometryFactory gf, double extrude) { // sort the segments from bottom to top Collections.sort(segments); // extrude each segment List<Polygon> result = new ArrayList<Polygon>(); for (Segment segment : segments) { CoordinateSequence cs = gf.getCoordinateSequenceFactory().create(5, 2); cs.setOrdinate(0, 0, segment.x0); cs.setOrdinate(0, 1, segment.y0); cs.setOrdinate(3, 0, segment.x0); cs.setOrdinate(3, 1, segment.y0 + extrude); cs.setOrdinate(2, 0, segment.x1); cs.setOrdinate(2, 1, segment.y1 + extrude); cs.setOrdinate(1, 0, segment.x1); cs.setOrdinate(1, 1, segment.y1); cs.setOrdinate(4, 0, segment.x0); cs.setOrdinate(4, 1, segment.y0); result.add(gf.createPolygon(gf.createLinearRing(cs), null)); } return result; } } static class Segment implements Comparable<Segment> { double x0, y0; double x1, y1; public Segment(double x0, double y0, double x1, double y1) { this.x0 = x0; this.y0 = y0; this.x1 = x1; this.y1 = y1; } public int compareTo(Segment other) { double maxY = Math.max(y0, y1); double otherMaxY = Math.max(other.y0, other.y1); if(maxY > otherMaxY) return -1; if(maxY < otherMaxY) return 1; double maxX = Math.max(x0, x1); double otherMaxX = Math.max(other.x0, other.x1); if(maxX > otherMaxX) return 1; if(maxX < otherMaxX) return -1; return 0; } } }