001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * Created on April 6, 2004, 3:58 PM
017: */
018:
019: package org.geotools.renderer.lite;
020:
021: import java.awt.Color;
022: import java.awt.Graphics2D;
023: import java.awt.image.BufferedImage;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.Set;
028: import java.util.Vector;
029:
030: import org.geotools.feature.Feature;
031: import org.geotools.filter.Expression;
032: import org.geotools.filter.FilterFactory;
033: import org.geotools.filter.FilterFactoryFinder;
034: import org.geotools.styling.ExternalGraphic;
035: import org.geotools.styling.Graphic;
036:
037: /**
038: *
039: * @author jfc173
040: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/render/src/main/java/org/geotools/renderer/lite/CustomGlyphRenderer.java $
041: */
042: public class CustomGlyphRenderer implements GlyphRenderer {
043:
044: private GlyphPropertiesList list = new GlyphPropertiesList();
045: private boolean maxFound = false;
046: private int maxBarHeight = 0;
047:
048: /** Creates a new instance of CustomGlyphRenderer */
049: public CustomGlyphRenderer() {
050: FilterFactory factory = FilterFactoryFinder
051: .createFilterFactory();
052: list.addProperty("radius", Expression.class, factory
053: .createLiteralExpression(50));
054: list.addProperty("circle color", Expression.class, factory
055: .createLiteralExpression("#000066"));
056: list.addProperty("bar height", Expression.class, factory
057: .createLiteralExpression(150));
058: list.addProperty("bar color", Expression.class, factory
059: .createLiteralExpression("#000000"));
060: list.addProperty("bar uncertainty", Expression.class, factory
061: .createLiteralExpression(50));
062: list.addProperty("bar uncertainty width", Expression.class,
063: factory.createLiteralExpression(5));
064: list.addProperty("bar uncertainty color", Expression.class,
065: factory.createLiteralExpression("#999999"));
066: list.addProperty("pointer length", Expression.class, factory
067: .createLiteralExpression(100));
068: list.addProperty("pointer color", Expression.class, factory
069: .createLiteralExpression("#FF0000"));
070: list.addProperty("pointer direction", Expression.class, factory
071: .createLiteralExpression(21));
072: list.addProperty("wedge width", Expression.class, factory
073: .createLiteralExpression(25));
074: list.addProperty("wedge color", Expression.class, factory
075: .createLiteralExpression("#9999FF"));
076: }
077:
078: public boolean canRender(String format) {
079: return format.equalsIgnoreCase("image/hack");
080: }
081:
082: public List getFormats() {
083: Vector ret = new Vector();
084: ret.add("image/hack");
085: return ret;
086: }
087:
088: public String getGlyphName() {
089: return "exploded clock"; //I think Alan called it this once, so here it sticks.
090: }
091:
092: public GlyphPropertiesList getGlyphProperties() {
093: return list;
094: }
095:
096: //Is this really necessary, since the values in the properties list can be set?
097: public void setGlyphProperties(GlyphPropertiesList gpl) {
098: list = gpl;
099: }
100:
101: /**
102: * djb -- addd "height" which is ignored as per API change
103: * @param graphic
104: * @param eg
105: * @param feature
106: * @param height
107: */
108: public BufferedImage render(Graphic graphic, ExternalGraphic eg,
109: Object feature, int height) {
110: Map props = eg.getCustomProperties();
111: Set propNames = props.keySet();
112: Iterator it = propNames.iterator();
113:
114: while (it.hasNext()) {
115: String nextName = (String) it.next();
116:
117: if (list.hasProperty(nextName)) {
118: list.setPropertyValue(nextName, props.get(nextName));
119: } else {
120: //DO I WANT TO THROW AN EXCEPTION OR ADD THE NEW PROPERTY TO THE LIST OR DO NOTHING?
121: System.out
122: .println("Tried to set the property "
123: + nextName
124: + " to a glyph that does not have this property.");
125: }
126: }
127:
128: //Change this to get values from list.
129: int radius = 50;
130: Expression e = (Expression) list.getPropertyValue("radius");
131: if (e != null) {
132: radius = ((Number) e.evaluate(feature)).intValue();
133: }
134:
135: Color circleColor = Color.BLUE.darker();
136: e = (Expression) list.getPropertyValue("circle color");
137: if (e != null) {
138: circleColor = Color.decode((String) e.evaluate(feature));
139: }
140:
141: int barHeight = 150;
142: e = (Expression) list.getPropertyValue("bar height");
143: if (e != null) {
144: barHeight = ((Number) e.evaluate(feature)).intValue();
145: }
146:
147: Color barColor = Color.BLACK;
148: e = (Expression) list.getPropertyValue("bar color");
149: if (e != null) {
150: barColor = Color.decode((String) e.evaluate(feature));
151: }
152:
153: int barUncertainty = 50;
154: e = (Expression) list.getPropertyValue("bar uncertainty");
155: if (e != null) {
156: barUncertainty = ((Number) e.evaluate(feature)).intValue();
157: }
158:
159: int barUncWidth = 5;
160: e = (Expression) list.getPropertyValue("bar uncertainty width");
161: if (e != null) {
162: barUncWidth = ((Number) e.evaluate(feature)).intValue();
163: }
164:
165: Color barUncColor = Color.GRAY;
166: e = (Expression) list.getPropertyValue("bar uncertainty color");
167: if (e != null) {
168: barUncColor = Color.decode((String) e.evaluate(feature));
169: }
170:
171: int pointerDirection = 21;
172: e = (Expression) list.getPropertyValue("pointer direction");
173: if (e != null) {
174: pointerDirection = ((Number) e.evaluate(feature))
175: .intValue();
176: }
177:
178: Color pointerColor = Color.RED;
179: e = (Expression) list.getPropertyValue("pointer color");
180: if (e != null) {
181: pointerColor = Color.decode((String) e.evaluate(feature));
182: }
183:
184: int pointerLength = 100;
185: e = (Expression) list.getPropertyValue("pointer length");
186: if (e != null) {
187: pointerLength = ((Number) e.evaluate(feature)).intValue();
188: }
189:
190: int wedgeWidth = 25;
191: e = (Expression) list.getPropertyValue("wedge width");
192: if (e != null) {
193: wedgeWidth = ((Number) e.evaluate(feature)).intValue();
194: }
195:
196: Color wedgeColor = Color.BLUE;
197: e = (Expression) list.getPropertyValue("wedge color");
198: if (e != null) {
199: wedgeColor = Color.decode((String) e.evaluate(feature));
200: }
201:
202: int circleCenterX, circleCenterY, imageHeight, imageWidth;
203:
204: BufferedImage image;
205: Graphics2D imageGraphic;
206:
207: //calculate maximum value of barHeight + barUncertainty & use that instead of "barHeight + barUncertainty"
208: Expression tempExp = (Expression) list
209: .getPropertyValue("bar height");
210: int temp1 = 0;
211: if (tempExp != null) {
212: temp1 = ((Number) tempExp.evaluate(feature)).intValue();
213: }
214: tempExp = (Expression) list.getPropertyValue("bar uncertainty");
215: int temp2 = 0;
216: if (tempExp != null) {
217: temp2 = ((Number) tempExp.evaluate(feature)).intValue();
218: }
219: if (temp1 + temp2 > maxBarHeight) {
220: maxBarHeight = temp1 + temp2;
221: }
222:
223: //chorner: feature.getParent is no more... is this needed?
224: // if (!maxFound){
225: // maxFound = true;
226: // FeatureCollection fc = feature.getParent();
227: // FeatureIterator features = fc.features();
228: // while (features.hasNext()){
229: // Feature next = features.next();
230: // Expression tempExp = (Expression) list.getPropertyValue("bar height");
231: // int temp1 = 0;
232: // if (tempExp != null){
233: // temp1 = ((Number) tempExp.evaluate(next)).intValue();
234: // }
235: // tempExp = (Expression) list.getPropertyValue("bar uncertainty");
236: // int temp2 = 0;
237: // if (tempExp != null){
238: // temp2 = ((Number) tempExp.evaluate(next)).intValue();
239: // }
240: // if (temp1 + temp2 > maxBarHeight){
241: // maxBarHeight = temp1 + temp2;
242: // }
243: // }
244: // }
245:
246: circleCenterX = Math.max(pointerLength, radius);
247: circleCenterY = Math.max(maxBarHeight, Math.max(pointerLength,
248: radius));
249:
250: imageHeight = Math.max(radius * 2, Math.max(radius
251: + pointerLength, Math.max(radius + maxBarHeight,
252: pointerLength + maxBarHeight)));
253: imageWidth = Math.max(radius * 2, pointerLength * 2);
254: image = new BufferedImage(imageWidth, imageHeight,
255: BufferedImage.TYPE_INT_ARGB);
256: pointerLength = Math.max(pointerLength, radius);
257: imageGraphic = image.createGraphics();
258: imageGraphic.setColor(circleColor);
259: imageGraphic.fillOval(circleCenterX - radius, circleCenterY
260: - radius, radius * 2, radius * 2);
261: imageGraphic.setColor(wedgeColor);
262: imageGraphic.fillArc(circleCenterX - radius, circleCenterY
263: - radius, radius * 2, radius * 2, calculateWedgeAngle(
264: pointerDirection, wedgeWidth), wedgeWidth * 2);
265: imageGraphic.setColor(barUncColor);
266: imageGraphic.fillRect(circleCenterX - barUncWidth,
267: circleCenterY - barHeight - barUncertainty,
268: barUncWidth * 2, barUncertainty * 2);
269: //pointer
270: int[] endPoint = calculateEndOfPointer(circleCenterX,
271: circleCenterY, pointerLength, pointerDirection);
272: imageGraphic.setStroke(new java.awt.BasicStroke(3));
273: imageGraphic.setColor(pointerColor);
274: imageGraphic
275: .draw(new java.awt.geom.Line2D.Double(circleCenterX,
276: circleCenterY, endPoint[0], endPoint[1]));
277: //bar
278: imageGraphic.setStroke(new java.awt.BasicStroke(3));
279: imageGraphic.setColor(barColor);
280: imageGraphic.draw(new java.awt.geom.Line2D.Double(
281: circleCenterX, circleCenterY, circleCenterX,
282: circleCenterY - barHeight));
283:
284: imageGraphic.dispose();
285: return image;
286: }
287:
288: private int calculateWedgeAngle(int pointerDirection, int wedgeWidth) {
289: return 450 - (pointerDirection + wedgeWidth);
290: }
291:
292: private int[] calculateEndOfPointer(int circleCenterX,
293: int circleCenterY, int pointerLength, int pointerDirection) {
294: int x = circleCenterX
295: + (int) Math.round(pointerLength
296: * Math.cos(Math
297: .toRadians(pointerDirection - 90)));
298: int y = circleCenterY
299: + (int) Math.round(pointerLength
300: * Math.sin(Math
301: .toRadians(pointerDirection - 90)));
302: return new int[] { x, y };
303: }
304:
305: }
|