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 static org.geotools.filter.capability.FunctionNameImpl.parameter;
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;
/**
*
*
* @source $URL$
*/
public class FilterFunction_isometric extends FunctionExpressionImpl implements
GeometryTransformation {
public static FunctionName NAME = new FunctionNameImpl("isometric", Geometry.class,
parameter("geometry", Geometry.class),
parameter("extrusion", Double.class));
public FilterFunction_isometric() {
super(NAME);
}
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 offsetY = getExpression(1).evaluate(null, Double.class);
if (offsetY != null) {
ReferencedEnvelope offseted = new ReferencedEnvelope(renderingEnvelope);
offseted.translate(0, 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;
}
}
}