[Schmitzm-commits] r340 - in branches/1.0-gt2-2.6/src: org/geotools/renderer/shape schmitzm/geotools schmitzm/geotools/gui

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Fri Aug 28 13:13:52 CEST 2009


Author: alfonx
Date: 2009-08-28 13:13:50 +0200 (Fri, 28 Aug 2009)
New Revision: 340

Modified:
   branches/1.0-gt2-2.6/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java
   branches/1.0-gt2-2.6/src/schmitzm/geotools/FilterUtil.java
   branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java
Log:
* Replaced the TransitionShapefileRenderer with the latest 2.6 version (without the hack ATM)

Modified: branches/1.0-gt2-2.6/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java
===================================================================
--- branches/1.0-gt2-2.6/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java	2009-08-28 10:45:01 UTC (rev 339)
+++ branches/1.0-gt2-2.6/src/org/geotools/renderer/shape/TransitionShapefileRenderer.java	2009-08-28 11:13:50 UTC (rev 340)
@@ -1,8 +1,9 @@
 /*
- *    Geotools2 - OpenSource mapping toolkit
+ *    GeoTools - The Open Source Java GIS Toolkit
  *    http://geotools.org
- *    (C) 2002, Geotools Project Managment Committee (PMC)
  *
+ *    (C) 2002-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;
@@ -12,10 +13,13 @@
  *    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.
- *
  */
 package org.geotools.renderer.shape;
 
+import static org.geotools.data.shapefile.ShpFileType.GRX;
+import static org.geotools.data.shapefile.ShpFileType.QIX;
+import static org.geotools.data.shapefile.ShpFileType.SHX;
+
 import java.awt.Graphics2D;
 import java.awt.Rectangle;
 import java.awt.RenderingHints;
@@ -24,19 +28,21 @@
 import java.awt.geom.AffineTransform;
 import java.awt.geom.NoninvertibleTransformException;
 import java.io.IOException;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.media.jai.util.Range;
+import javax.xml.parsers.FactoryConfigurationError;
 
 import org.geotools.data.DataStore;
 import org.geotools.data.DefaultQuery;
@@ -48,15 +54,18 @@
 import org.geotools.data.TransactionStateDiff;
 import org.geotools.data.shapefile.ShapefileDataStore;
 import org.geotools.data.shapefile.ShapefileRendererUtil;
+import org.geotools.data.shapefile.ShpFiles;
 import org.geotools.data.shapefile.dbf.DbaseFileHeader;
 import org.geotools.data.shapefile.dbf.DbaseFileReader;
 import org.geotools.data.shapefile.dbf.IndexedDbaseFileReader;
+import org.geotools.data.shapefile.indexed.IndexType;
 import org.geotools.data.shapefile.shp.ShapeType;
 import org.geotools.data.shapefile.shp.ShapefileReader;
 import org.geotools.data.shapefile.shp.ShapefileReader.Record;
-import org.geotools.feature.FeatureTypeBuilder;
-import org.geotools.feature.GeometryAttributeType;
+import org.geotools.feature.FeatureTypes;
 import org.geotools.feature.SchemaException;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
 import org.geotools.filter.FilterAttributeExtractor;
 import org.geotools.geometry.jts.Decimator;
 import org.geotools.geometry.jts.LiteCoordinateSequenceFactory;
@@ -70,11 +79,12 @@
 import org.geotools.referencing.ReferencingFactoryFinder;
 import org.geotools.referencing.crs.DefaultGeographicCRS;
 import org.geotools.referencing.operation.matrix.GeneralMatrix;
+import org.geotools.referencing.operation.matrix.XAffineTransform;
 import org.geotools.renderer.GTRenderer;
 import org.geotools.renderer.RenderListener;
+import org.geotools.renderer.label.LabelCacheImpl;
 import org.geotools.renderer.lite.LabelCache;
 import org.geotools.renderer.lite.LabelCacheDefault;
-import org.geotools.renderer.lite.ListenerList;
 import org.geotools.renderer.lite.RendererUtilities;
 import org.geotools.renderer.lite.StreamingRenderer;
 import org.geotools.renderer.style.SLDStyleFactory;
@@ -93,6 +103,7 @@
 import org.opengis.feature.simple.SimpleFeature;
 import org.opengis.feature.simple.SimpleFeatureType;
 import org.opengis.feature.type.AttributeDescriptor;
+import org.opengis.feature.type.GeometryDescriptor;
 import org.opengis.filter.Filter;
 import org.opengis.referencing.FactoryException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -100,9 +111,6 @@
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;
 
-import schmitzm.geotools.feature.FeatureOperationTreeFilter;
-import schmitzm.io.IOUtil;
-
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.Envelope;
 import com.vividsolutions.jts.geom.Geometry;
@@ -121,122 +129,112 @@
  * @author jeichar
  * @since 2.1.x
  * @source $URL:
- *         http://svn.geotools.org/geotools/branches/2.2.x/ext/shaperenderer
- *         /src/org/geotools/renderer/shape/ShapefileRenderer.java $
+ *         http://svn.geotools.org/geotools/branches/2.2.x/ext/shaperenderer/src/org/geotools/renderer/shape/ShapefileRenderer.java $
  */
 public class TransitionShapefileRenderer implements GTRenderer {
-	public static final Logger logGt = org.geotools.util.logging.Logging
-			.getLogger("org.geotools.renderer.shape");
+    public static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.renderer.shape");
 
-	org.apache.log4j.Logger LOGGER = org.apache.log4j.Logger
-			.getLogger(TransitionShapefileRenderer.class);
+    /** Tolerance used to compare doubles for equality */
+    private static final double TOLERANCE = 1e-6;
+    private static final GeometryFactory geomFactory = new GeometryFactory(
+            new LiteCoordinateSequenceFactory());
+    private static final Coordinate[] COORDS;
+    private static final MultiPolygon MULTI_POLYGON_GEOM;
+    private static final Polygon POLYGON_GEOM;
+    private static final LinearRing LINE_GEOM;
+    private static final MultiLineString MULTI_LINE_GEOM;
+    private static final Point POINT_GEOM;
+    private static final MultiPoint MULTI_POINT_GEOM;
+    
+    /**
+     * Computes the scale as the ratio between map distances and real world distances,
+     * assuming 90dpi and taking into consideration projection deformations and actual
+     * earth shape. <br>
+     * Use this method only when in need of accurate computation. Will break if the
+     * data extent is outside of the currenct projection definition area. 
+     */
+    public static final String SCALE_ACCURATE = "ACCURATE";
+    
+    /**
+     * Very simple and lenient scale computation method that conforms to the OGC SLD 
+     * specification 1.0, page 26. <br>This method is quite approximative, but should
+     * never break and ensure constant scale even on lat/lon unprojected maps (because
+     * in that case scale is computed as if the area was along the equator no matter
+     * what the real position is).
+     */
+    public static final String SCALE_OGC = "OGC";
+    
+    private String scaleComputationMethodDEFAULT = SCALE_ACCURATE;
+    static {
+        COORDS = new Coordinate[5];
+        COORDS[0] = new Coordinate(0.0, 0.0);
+        COORDS[1] = new Coordinate(5.0, 0.0);
+        COORDS[2] = new Coordinate(5.0, 5.0);
+        COORDS[3] = new Coordinate(0.0, 5.0);
+        COORDS[4] = new Coordinate(0.0, 0.0);
+        LINE_GEOM = geomFactory.createLinearRing(COORDS);
+        MULTI_LINE_GEOM = geomFactory.createMultiLineString(new LineString[]{LINE_GEOM});
+        POLYGON_GEOM = geomFactory.createPolygon(LINE_GEOM, new LinearRing[0]);
+        MULTI_POLYGON_GEOM = geomFactory.createMultiPolygon(new Polygon[]{POLYGON_GEOM});
+        POINT_GEOM = geomFactory.createPoint(COORDS[2]);
+        MULTI_POINT_GEOM = geomFactory.createMultiPoint(COORDS);
+    }
 
-	/** Tolerance used to compare doubles for equality */
-	private static final double TOLERANCE = 1e-6;
-	private static final GeometryFactory geomFactory = new GeometryFactory(
-			new LiteCoordinateSequenceFactory());
-	private static final Coordinate[] COORDS;
-	private static final MultiPolygon MULTI_POLYGON_GEOM;
-	private static final Polygon POLYGON_GEOM;
-	private static final LinearRing LINE_GEOM;
-	private static final MultiLineString MULTI_LINE_GEOM;
-	private static final Point POINT_GEOM;
-	private static final MultiPoint MULTI_POINT_GEOM;
+    /**
+     * This listener is added to the list of listeners automatically. It should be removed if the
+     * default logging is not needed.
+     */
+    public static final DefaultRenderListener DEFAULT_LISTENER = new DefaultRenderListener();
 
-	/**
-	 * Computes the scale as the ratio between map distances and real world
-	 * distances, assuming 90dpi and taking into consideration projection
-	 * deformations and actual earth shape. <br>
-	 * Use this method only when in need of accurate computation. Will break if
-	 * the data extent is outside of the currenct projection definition area.
-	 */
-	public static final String SCALE_ACCURATE = "ACCURATE";
+    private static final IndexInfo STREAMING_RENDERER_INFO = new IndexInfo(IndexType.NONE,null);
+    static int NUM_SAMPLES = 200;
+    private RenderingHints hints;
 
-	/**
-	 * Very simple and lenient scale computation method that conforms to the OGC
-	 * SLD specification 1.0, page 26. <br>
-	 * This method is quite approximative, but should never break and ensure
-	 * constant scale even on lat/lon unprojected maps (because in that case
-	 * scale is computed as if the area was along the equator no matter what the
-	 * real position is).
-	 */
-	public static final String SCALE_OGC = "OGC";
+    /** Factory that will resolve symbolizers into rendered styles */
+    private SLDStyleFactory styleFactory = new SLDStyleFactory();
+    private boolean renderingStopRequested;
+    private boolean concatTransforms;
+    private MapContext context;
+    LabelCache labelCache = new LabelCacheImpl();
+    private List<RenderListener> renderListeners = new CopyOnWriteArrayList<RenderListener>();
+    /** If we are caching styles; by default this is false */
+    boolean caching = false;
+    private double scaleDenominator;
+    DbaseFileHeader dbfheader;
+    private Object defaultGeom;
+    IndexInfo[] layerIndexInfo;
+    StreamingRenderer delegate;
 
-	private final String scaleComputationMethodDEFAULT = SCALE_ACCURATE;
-	static {
-		COORDS = new Coordinate[5];
-		COORDS[0] = new Coordinate(0.0, 0.0);
-		COORDS[1] = new Coordinate(5.0, 0.0);
-		COORDS[2] = new Coordinate(5.0, 5.0);
-		COORDS[3] = new Coordinate(0.0, 5.0);
-		COORDS[4] = new Coordinate(0.0, 0.0);
-		LINE_GEOM = geomFactory.createLinearRing(COORDS);
-		MULTI_LINE_GEOM = geomFactory
-				.createMultiLineString(new LineString[] { LINE_GEOM });
-		POLYGON_GEOM = geomFactory.createPolygon(LINE_GEOM, new LinearRing[0]);
-		MULTI_POLYGON_GEOM = geomFactory
-				.createMultiPolygon(new Polygon[] { POLYGON_GEOM });
-		POINT_GEOM = geomFactory.createPoint(COORDS[2]);
-		MULTI_POINT_GEOM = geomFactory.createMultiPoint(COORDS);
-	}
+    /**
+     * Maps between the AttributeType index of the new generated FeatureType and the real
+     * attributeType
+     */
+    int[] attributeIndexing;
 
-	/**
-	 * This listener is added to the list of listeners automatically. It should
-	 * be removed if the default logging is not needed.
-	 */
-	public static final DefaultRenderListener DEFAULT_LISTENER = new DefaultRenderListener();
-
-	private static final IndexInfo STREAMING_RENDERER_INFO = new IndexInfo(
-			(byte) 0, null, null);
-	static int NUM_SAMPLES = 200;
-	private RenderingHints hints;
-
-	/** Factory that will resolve symbolizers into rendered styles */
-	private final SLDStyleFactory styleFactory = new SLDStyleFactory();
-	private boolean renderingStopRequested;
-	private boolean concatTransforms;
-	private MapContext context;
-	LabelCache labelCache = new LabelCacheDefault();
-	private final ListenerList renderListeners = new ListenerList();
-	boolean caching = false;
-	private double scaleDenominator;
-	DbaseFileHeader dbfheader;
-	private Object defaultGeom;
-	IndexInfo[] layerIndexInfo;
-
-	/**
-	 * Maps between the AttributeDescriptor index of the new generated SimpleFeatureType and
-	 * the real attributeType
-	 */
-	int[] attributeIndexing;
-
-	/** The painter class we use to depict shapes onto the screen */
-	private StyledShapePainter painter = new StyledShapePainter(labelCache);
-	private final Map decimators = new HashMap();
-
-	/**
-	 * Text will be rendered using the usual calls
-	 * gc.drawString/drawGlyphVector. This is a little faster, and more
-	 * consistent with how the platform renders the text in other applications.
-	 * The downside is that on most platform the label and its eventual halo are
-	 * not properly centered.
-	 */
-	public static final String TEXT_RENDERING_STRING = "STRING";
-
-	/**
-	 * Text will be rendered using the associated {@link GlyphVector} outline,
-	 * that is, a {@link Shape}. This ensures perfect centering between the text
-	 * and the halo, but introduces more text aliasing.
-	 */
-	public static final String TEXT_RENDERING_OUTLINE = "OUTLINE";
-
-	/**
-	 * The text rendering method, either TEXT_RENDERING_OUTLINE or
-	 * TEXT_RENDERING_STRING
-	 */
-	public static final String TEXT_RENDERING_KEY = "textRenderingMethod";
-	private final String textRenderingModeDEFAULT = TEXT_RENDERING_STRING;
-
+    /** The painter class we use to depict shapes onto the screen */
+    private StyledShapePainter painter = new StyledShapePainter(labelCache);
+    private Map decimators = new HashMap();
+    
+    /**
+     * Text will be rendered using the usual calls gc.drawString/drawGlyphVector.
+     * This is a little faster, and more consistent with how the platform renders
+     * the text in other applications. The downside is that on most platform the label
+     * and its eventual halo are not properly centered.
+     */
+    public static final String TEXT_RENDERING_STRING = "STRING";
+    
+    /**
+     * Text will be rendered using the associated {@link GlyphVector} outline, that is, a {@link Shape}.
+     * This ensures perfect centering between the text and the halo, but introduces more text aliasing.
+     */
+    public static final String TEXT_RENDERING_OUTLINE = "OUTLINE";
+    
+    /**
+     * The text rendering method, either TEXT_RENDERING_OUTLINE or TEXT_RENDERING_STRING
+     */
+    public static final String TEXT_RENDERING_KEY = "textRenderingMethod";
+    private String textRenderingModeDEFAULT = TEXT_RENDERING_STRING;
+    
 	public static final String LABEL_CACHE_KEY = "labelCache";
 	public static final String FORCE_CRS_KEY = "forceCRS";
 	public static final String DPI_KEY = "dpi";
@@ -244,1404 +242,1311 @@
 	public static final String MEMORY_PRE_LOADING_KEY = "memoryPreloadingEnabled";
 	public static final String OPTIMIZED_DATA_LOADING_KEY = "optimizedDataLoadingEnabled";
 	public static final String SCALE_COMPUTATION_METHOD_KEY = "scaleComputationMethod";
+    
+    /**
+     * "optimizedDataLoadingEnabled" - Boolean  yes/no (see default optimizedDataLoadingEnabledDEFAULT)
+     * "memoryPreloadingEnabled"     - Boolean  yes/no (see default memoryPreloadingEnabledDEFAULT)
+     * "declaredScaleDenominator"    - Double   the value of the scale denominator to use by the renderer.  
+     *                                          by default the value is calculated based on the screen size 
+     *                                          and the displayed area of the map.
+     *  "dpi"                        - Integer  number of dots per inch of the display 90 DPI is the default (as declared by OGC)      
+     *  "forceCRS"                   - CoordinateReferenceSystem declares to the renderer that all layers are of the CRS declared in this hint                               
+     *  "labelCache"                 - Declares the label cache that will be used by the renderer.                               
+     */
+    private Map rendererHints = null;
 
-	/**
-	 * "optimizedDataLoadingEnabled" - Boolean yes/no (see default
-	 * optimizedDataLoadingEnabledDEFAULT) "memoryPreloadingEnabled" - Boolean
-	 * yes/no (see default memoryPreloadingEnabledDEFAULT)
-	 * "declaredScaleDenominator" - Double the value of the scale denominator to
-	 * use by the renderer. by default the value is calculated based on the
-	 * screen size and the displayed area of the map. "dpi" - Integer number of
-	 * dots per inch of the display 90 DPI is the default (as declared by OGC)
-	 * "forceCRS" - CoordinateReferenceSystem declares to the renderer that all
-	 * layers are of the CRS declared in this hint "labelCache" - Declares the
-	 * label cache that will be used by the renderer.
-	 */
-	private Map rendererHints = null;
+    public TransitionShapefileRenderer( MapContext context ) {
+        setContext(context);
+    }
 
-	public TransitionShapefileRenderer(final MapContext context) {
-//		LOGGER.debug("new tr instanciated with context");
-		setContext(context);
-	}
+    public TransitionShapefileRenderer() {
+    }
 
-	public TransitionShapefileRenderer() {
-//		LOGGER.debug("new tr instanciated without context");
-	}
+    public void paint( Graphics2D graphics, Rectangle paintArea, ReferencedEnvelope mapArea ) {
+        if (mapArea == null || paintArea == null) {
+            LOGGER.info("renderer passed null arguments");
+            return;
+        } // Other arguments get checked later
+        paint(graphics, paintArea, mapArea, RendererUtilities.worldToScreenTransform(mapArea,
+                paintArea));
+    }
 
-	public void paint(final Graphics2D graphics, final Rectangle paintArea,
-			final ReferencedEnvelope mapArea) {
-		if (mapArea == null || paintArea == null) {
-			logGt.info("renderer passed null arguments");
-			return;
-		} // Other arguments get checked later
-		paint(graphics, paintArea, mapArea, RendererUtilities
-				.worldToScreenTransform(mapArea, paintArea));
-	}
+    private DbaseFileHeader getDBFHeader( ShapefileDataStore ds ) {
+        DbaseFileReader reader = null;
 
-	private DbaseFileHeader getDBFHeader(final ShapefileDataStore ds) {
-		DbaseFileReader reader = null;
+        try {
+            reader = ShapefileRendererUtil.getDBFReader(ds);
 
-		try {
-			reader = ShapefileRendererUtil.getDBFReader(ds);
+            return reader.getHeader();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            }
+        }
 
-			return reader.getHeader();
-		} catch (final IOException e) {
-			e.printStackTrace();
-		} finally {
-			if (reader != null) {
-				try {
-					reader.close();
-				} catch (final IOException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			}
-		}
+        return null;
+    }
 
-		return null;
-	}
+    private void processStylers( Graphics2D graphics, ShapefileDataStore datastore,
+            Query query, Envelope bbox, Rectangle screenSize, MathTransform mt, Style style, IndexInfo info,
+            Transaction transaction, String layerId) throws IOException {
+        if (LOGGER.isLoggable(Level.FINE)) {
+            LOGGER.fine("processing " + style.getFeatureTypeStyles().length + " stylers");
+        }
 
-	private void processStylers(final Graphics2D graphics,
-			final ShapefileDataStore datastore, final Query query, final Envelope bbox,
-			final Rectangle screenSize, final MathTransform mt, final Style style,
-			final IndexInfo info, final Transaction transaction, final String layerId)
-			throws IOException {
-		if (logGt.isLoggable(Level.FINE)) {
-			logGt.fine("processing " + style.getFeatureTypeStyles().length
-					+ " stylers");
-		}
+        FeatureTypeStyle[] featureStylers = style.getFeatureTypeStyles();
+        SimpleFeatureType type;
 
-		final FeatureTypeStyle[] featureStylers = style.getFeatureTypeStyles();
-		SimpleFeatureType type;
+        try {
+            type = createFeatureType(query, style, datastore);
+        } catch (Exception e) {
+            fireErrorEvent(e);
+            LOGGER.logp(Level.WARNING, "org.geotools.renderer.shape.ShapefileRenderer", "processStylers", "Could not prep style for rendering", e);
+            return;
+        }
 
-		try {
-			type = createFeatureType(query, style, datastore);
-		} catch (final Exception e) {
-			fireErrorEvent(e);
+        for( int i = 0; i < featureStylers.length; i++ ) {
+            if (LOGGER.isLoggable(Level.FINE)) {
+                LOGGER.fine("processing style " + i);
+            }
 
-			return;
-		}
+            FeatureTypeStyle fts = featureStylers[i];
+            String typeName = datastore.getSchema().getTypeName();
 
-		for (int i = 0; i < featureStylers.length; i++) {
-			if (logGt.isLoggable(Level.FINE)) {
-				logGt.fine("processing style " + i);
-			}
+            if ((typeName != null) &&
+                    ( FeatureTypes.isDecendedFrom(datastore.getSchema(), null, fts.getFeatureTypeName()) 
+                    || typeName .equalsIgnoreCase(fts.getFeatureTypeName()))) {
+                // get applicable rules at the current scale
+                Rule[] rules = fts.getRules();
+                List ruleList = new ArrayList();
+                List elseRuleList = new ArrayList();
+                
+                // TODO process filter for geometry expressions and restrict bbox further based on 
+                // the result
+                
+                for( int j = 0; j < rules.length; j++ ) {
+                    if (LOGGER.isLoggable(Level.FINE)) {
+                        LOGGER.fine("processing rule " + j);
+                    }
 
-			final FeatureTypeStyle fts = featureStylers[i];
-			final String typeName = datastore.getSchema().getTypeName();
+                    Rule r = rules[j];
+                    Filter f = r.getFilter();
+                    if(f != null) {
+                    	GeometryFilterChecker checker = new GeometryFilterChecker();
+                        f.accept(checker, null);
+                        // geometry filters are quite unlikely in SLD, but if we have any,
+                        // we need to reproject it to screen space since geometries are
+                        // read directly in screen space
+                        if(checker.isGeometryFilterPresent()) {
+                        	// make copy so we don't modify the style
+                        	DuplicatingStyleVisitor duplicator = new DuplicatingStyleVisitor();
+                            r.accept(duplicator);
+                            r=(Rule) duplicator.getCopy();
+                            
+                            FilterTransformer transformer= new  FilterTransformer(mt);
+                            r.setFilter((Filter) r.getFilter().accept(transformer, null));
+                        }
+                    }
+                    if (isWithInScale(r)) {
+                        if (r.hasElseFilter()) {
+                            elseRuleList.add(r);
+                        } else {
+                            ruleList.add(r);
+                        }
+                    }
+                }
 
-			if ((typeName != null)
-					&& (datastore.getSchema().isDescendedFrom(null,
-							fts.getFeatureTypeName()) || typeName
-							.equalsIgnoreCase(fts.getFeatureTypeName()))) {
-				// get applicable rules at the current scale
-				final Rule[] rules = fts.getRules();
-				final List ruleList = new ArrayList();
-				final List elseRuleList = new ArrayList();
+                // process the features according to the rules
+                // TODO: find a better way to declare the scale ranges so that
+                // we
+                // get style caching also between multiple rendering runs
+                NumberRange scaleRange = new NumberRange(scaleDenominator, scaleDenominator);
 
-				// TODO process filter for geometry expressions and restrict
-				// bbox further based on
-				// the result
+                Set modifiedFIDs = processTransaction(graphics, bbox, mt, datastore, transaction,
+                        typeName, query, ruleList, elseRuleList, scaleRange, layerId);
 
-				for (int j = 0; j < rules.length; j++) {
-					if (logGt.isLoggable(Level.FINE)) {
-						logGt.fine("processing rule " + j);
-					}
+                // don't try to read the shapefile if there is nothing to draw
+                if(ruleList.size() > 0 || elseRuleList.size() > 0)
+                	processShapefile(graphics, datastore, bbox,screenSize, mt, info, type, query, ruleList,
+                        elseRuleList, modifiedFIDs, scaleRange, layerId);
+            }
+        }
+    }
 
-					Rule r = rules[j];
+    private Set processTransaction( Graphics2D graphics, Envelope bbox, MathTransform transform,
+            DataStore ds, Transaction transaction, String typename, Query query, List ruleList,
+            List elseRuleList, NumberRange scaleRange, String layerId ) {
+        if (transaction == Transaction.AUTO_COMMIT) {
+            return Collections.EMPTY_SET;
+        }
 
-					// make copy so I don't accidentally modify style
-					final DuplicatingStyleVisitor duplicator = new DuplicatingStyleVisitor();
-					r.accept(duplicator);
-					r = (Rule) duplicator.getCopy();
-					if (r.getFilter() != null) {
-						// now reproject the geometries in filter because geoms
-						// are retrieved projected to screen space
-						final FilterTransformer transformer = new FilterTransformer(
-								mt);
-						r.setFilter((Filter) r.getFilter().accept(transformer,
-								null));
-					}
-					if (isWithInScale(r)) {
-						if (r.hasElseFilter()) {
-							elseRuleList.add(r);
-						} else {
-							ruleList.add(r);
-						}
-					}
-				}
+        TransactionStateDiff state = (TransactionStateDiff) transaction.getState(ds);
 
-				// process the features according to the rules
-				// TODO: find a better way to declare the scale ranges so that
-				// we
-				// get style caching also between multiple rendering runs
-				final NumberRange scaleRange = new NumberRange(scaleDenominator,
-						scaleDenominator);
+        if (state == null) {
+            return Collections.EMPTY_SET;
+        }
+        // set of fids that has been modified (ie updated or deleted)
+        Set fids = new HashSet();
+        Map modified = null;
+        Map added = null;
+        Diff diff=null;
 
-				final Set modifiedFIDs = processTransaction(graphics, bbox, mt,
-						datastore, transaction, typeName, query, ruleList,
-						elseRuleList, scaleRange, layerId);
+        try {
+            diff = state.diff(typename);
+            modified = diff.modified2;
+            added = diff.added;
+            fids = new HashSet();
+        } catch (IOException e) {
+            fids = Collections.EMPTY_SET;
+            return fids;
+        }
 
-				// don't try to read the shapefile if there is nothing to draw
-				if (ruleList.size() > 0 || elseRuleList.size() > 0)
-					processShapefile(graphics, datastore, bbox, screenSize, mt,
-							info, type, query, ruleList, elseRuleList,
-							modifiedFIDs, scaleRange, layerId);
-			}
-		}
-	}
+        if (!diff.isEmpty()) {
+            SimpleFeature feature;
 
-	private Set processTransaction(final Graphics2D graphics, final Envelope bbox,
-			final MathTransform transform, final DataStore ds, final Transaction transaction,
-			final String typename, final Query query, final List ruleList, final List elseRuleList,
-			final NumberRange scaleRange, final String layerId) {
-		if (transaction == Transaction.AUTO_COMMIT) {
-			return Collections.EMPTY_SET;
-		}
+            for( Iterator modifiedIter = modified.keySet().iterator(), 
+            		addedIter=added.values().iterator(); 
+            	modifiedIter.hasNext() || addedIter.hasNext(); ) {
+                try {
+                    if (renderingStopRequested) {
+                        break;
+                    }
+                    boolean doElse = true;
+                    if( modifiedIter.hasNext() ){
+                    	String fid= (String) modifiedIter.next();
+                    	feature = (SimpleFeature) modified.get(fid);
+                        fids.add(fid);
+                    } else {
+                        feature = (SimpleFeature) addedIter.next();
+                    }
+                    if( feature == TransactionStateDiff.NULL){
+                        continue; // skip this feature as it is removed
+                    }
+                    if (!query.getFilter().evaluate(feature)){
+                        // currently this is failing for TransactionStateDiff.NULL
+                        continue; 
+                    }
+    
+                    // applicable rules
+                    for( Iterator it = ruleList.iterator(); it.hasNext(); ) {
+                        Rule r = (Rule) it.next();
 
-		final TransactionStateDiff state = (TransactionStateDiff) transaction
-				.getState(ds);
+                        if (LOGGER.isLoggable(Level.FINER)) {
+                            LOGGER.finer("applying rule: " + r.toString());
+                        }
 
-		if (state == null) {
-			return Collections.EMPTY_SET;
-		}
+                        if (LOGGER.isLoggable(Level.FINER)) {
+                            LOGGER.finer("this rule applies ...");
+                        }
 
-		Set fids = new HashSet();
-		Map modified = null;
-		Map added = null;
-		Diff diff = null;
+                        Filter filter = r.getFilter();
 
-		try {
-			diff = state.diff(typename);
-			modified = diff.modified2;
-			added = diff.added;
-			fids = new HashSet();
-		} catch (final IOException e) {
-			fids = Collections.EMPTY_SET;
-			return fids;
-		}
+                        if ((filter == null) || filter.evaluate(feature)) {
+                            doElse = false;
 
-		if (!diff.isEmpty()) {
-			SimpleFeature feature;
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("processing Symobolizer ...");
+                            }
 
-			for (Iterator modifiedIter = modified.keySet().iterator(), addedIter = added
-					.values().iterator(); modifiedIter.hasNext()
-					|| addedIter.hasNext();) {
-				if (renderingStopRequested) {
-					break;
-				}
+                            Symbolizer[] symbolizers = r.getSymbolizers();
 
-				boolean doElse = true;
-				if (modifiedIter.hasNext()) {
-					final String fid = (String) modifiedIter.next();
-					feature = (SimpleFeature) modified.get(fid);
-					fids.add(fid);
-				} else {
-					feature = (SimpleFeature) addedIter.next();
-				}
+                            try {
+                                processSymbolizers(graphics, feature, symbolizers, scaleRange,
+                                        transform, layerId);
+                            } catch (Exception e) {
+                                fireErrorEvent(e);
 
-				if (!query.getFilter().evaluate(feature))
-					continue;
+                                continue;
+                            }
 
-				if (feature != TransactionStateDiff.NULL) {
-					// applicable rules
-					for (final Iterator it = ruleList.iterator(); it.hasNext();) {
-						final Rule r = (Rule) it.next();
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("... done!");
+                            }
+                        }
+                    }
 
-						if (logGt.isLoggable(Level.FINER)) {
-							logGt.finer("applying rule: " + r.toString());
-						}
+                    if (doElse) {
+                        // rules with an else filter
+                        if (LOGGER.isLoggable(Level.FINER)) {
+                            LOGGER.finer("rules with an else filter");
+                        }
 
-						if (logGt.isLoggable(Level.FINER)) {
-							logGt.finer("this rule applies ...");
-						}
+                        for( Iterator it = elseRuleList.iterator(); it.hasNext(); ) {
+                            Rule r = (Rule) it.next();
+                            Symbolizer[] symbolizers = r.getSymbolizers();
 
-						final Filter filter = r.getFilter();
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("processing Symobolizer ...");
+                            }
 
-						if ((filter == null) || filter.evaluate(feature)) {
-							doElse = false;
+                            try {
+                                processSymbolizers(graphics, feature, symbolizers, scaleRange,
+                                        transform, layerId);
+                            } catch (Exception e) {
+                                fireErrorEvent(e);
 
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("processing Symobolizer ...");
-							}
+                                continue;
+                            }
 
-							final Symbolizer[] symbolizers = r.getSymbolizers();
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("... done!");
+                            }
+                        }
+                    }
 
-							try {
-								processSymbolizers(graphics, feature,
-										symbolizers, scaleRange, transform,
-										layerId);
-							} catch (final Exception e) {
-								fireErrorEvent(e);
+                    if (LOGGER.isLoggable(Level.FINER)) {
+                        LOGGER.finer("feature rendered event ...");
+                    }
+                }
+                catch (RuntimeException e) {
+                    fireErrorEvent(e);
+                }
+            }
+        }
+        return fids;
+    }
 
-								continue;
-							}
+    private void processShapefile( Graphics2D graphics, ShapefileDataStore datastore,
+            Envelope bbox, Rectangle screenSize, MathTransform mt, IndexInfo info, SimpleFeatureType type, Query query,
+            List ruleList, List elseRuleList, Set modifiedFIDs, NumberRange scaleRange, String layerId )
+            throws IOException {
+        IndexedDbaseFileReader dbfreader = null;
 
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("... done!");
-							}
-						}
-					}
+        // don't waste time processing the dbf file if the only attribute loades is the geometry
+        if(type.getAttributeCount() > 1) {
+            try {
+                dbfreader = ShapefileRendererUtil.getDBFReader(datastore);
+            } catch (Exception e) {
+                fireErrorEvent(e);
+            }
+        }
 
-					if (doElse) {
-						// rules with an else filter
-						if (logGt.isLoggable(Level.FINER)) {
-							logGt.finer("rules with an else filter");
-						}
+        OpacityFinder opacityFinder = new OpacityFinder(getAcceptableSymbolizers(type
+                .getGeometryDescriptor()));
 
-						for (final Iterator it = elseRuleList.iterator(); it
-								.hasNext();) {
-							final Rule r = (Rule) it.next();
-							final Symbolizer[] symbolizers = r.getSymbolizers();
+        for( Iterator iter = ruleList.iterator(); iter.hasNext(); ) {
+            Rule rule = (Rule) iter.next();
+            rule.accept(opacityFinder);
+        }
 
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("processing Symobolizer ...");
-							}
+        IndexInfo.Reader shpreader = null;
+        boolean useJTS=true;
+        
+        try {
+            shpreader = new IndexInfo.Reader(info, ShapefileRendererUtil.getShpReader(datastore,
+                    bbox, screenSize, mt, opacityFinder.hasOpacity, useJTS), bbox);
+        } catch (Exception e) {
+            fireErrorEvent(e);
+            return;
+        }
 
-							try {
-								processSymbolizers(graphics, feature,
-										symbolizers, scaleRange, transform,
-										layerId);
-							} catch (final Exception e) {
-								fireErrorEvent(e);
+        FIDReader fidReader = null;
+        try {
+            fidReader = ShapefileRendererUtil.getFidReader(datastore,shpreader);
+        } catch (Exception e) {
+            fireErrorEvent(e);
+            return;
+        }
+        
+        SimpleFeatureBuilder fbuilder = new SimpleFeatureBuilder(type);
+        
+        try {
+            while( true ) {
+                try {
+                    if (renderingStopRequested) {
+                        break;
+                    }
 
-								continue;
-							}
+                    if (!shpreader.hasNext()) {
+                        break;
+                    }
 
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("... done!");
-							}
-						}
-					}
+                    boolean doElse = true;
 
-					if (logGt.isLoggable(Level.FINER)) {
-						logGt.finer("feature rendered event ...");
-					}
-				}
-			}
-		}
+                    String nextFid = null;
+                    if( fidReader.hasNext() ){
+                        try {
+                            nextFid = fidReader.next();
+                        }
+                        catch( NoSuchElementException invalidIndex){
+                            fireErrorEvent(new IllegalStateException("Skipping invalid FID; Please regenerate your index.", invalidIndex));
+                            // TODO: mark index as needing regeneration
+                        }
+                    }
+                    else {
+                        fireErrorEvent(new IllegalStateException("Skipping invalid FID; shape and index are out of sync please regenerate index."));
+                        // TODO: mark index as needing regeneration
+                    }
+                    if(LOGGER.isLoggable(Level.FINER))
+                        LOGGER.finer("trying to read geometry ...");                    
+                    if (nextFid == null || modifiedFIDs.contains(nextFid)) {
+                        // this one is modified we will get it when we processTransaction
+                        shpreader.next();
+                        if( dbfreader != null && !dbfreader.IsRandomAccessEnabled() ){
+                            dbfreader.skip();
+                        }
+                        continue;
+                    }
+                    
+                    if( dbfreader != null && dbfreader.IsRandomAccessEnabled() ){
+                        dbfreader.goTo(shpreader.getRecordNumber());
+                    }
+                    ShapefileReader.Record record = shpreader.next();
 
-		return fids;
-	}
+                    Object geom = record.shape();
+                    if (geom == null) {
+                        if(LOGGER.isLoggable(Level.FINEST))
+                            LOGGER.finest("skipping geometry");
+                        if( dbfreader != null && !dbfreader.IsRandomAccessEnabled() )
+                            dbfreader.skip();
+                        continue;
+                    }
 
-	private void processShapefile(final Graphics2D graphics,
-			final ShapefileDataStore datastore, final Envelope bbox, final Rectangle screenSize,
-			final MathTransform mt, final IndexInfo info, final SimpleFeatureType type, final Query query,
-			final List ruleList, final List elseRuleList, final Set modifiedFIDs,
-			final NumberRange scaleRange, final String layerId) throws IOException {
-		IndexedDbaseFileReader dbfreader = null;
+                    SimpleFeature feature = createFeature(fbuilder, record, dbfreader, nextFid);
+                    if (!query.getFilter().evaluate(feature))
+                        continue;
 
-		// don't waste time processing the dbf file if the only attribute loades
-		// is the geometry
-		if (type.getAttributeCount() > 1) {
-			try {
-				dbfreader = ShapefileRendererUtil.getDBFReader(datastore);
-			} catch (final Exception e) {
-				fireErrorEvent(e);
-			}
-		}
+                    if (renderingStopRequested) {
+                        break;
+                    }
 
-		final OpacityFinder opacityFinder = new OpacityFinder(
-				getAcceptableSymbolizers(type.getDefaultGeometry()));
+                    if (LOGGER.isLoggable(Level.FINEST)) {
+                        LOGGER.finest("... done: " + geom.toString());
+                    }
 
-		for (final Iterator iter = ruleList.iterator(); iter.hasNext();) {
-			final Rule rule = (Rule) iter.next();
-			rule.accept(opacityFinder);
-		}
+                    if (LOGGER.isLoggable(Level.FINER)) {
+                        LOGGER.fine("... done: " + type.getTypeName());
+                    }
 
-		IndexInfo.Reader shpreader = null;
-		final boolean useJTS = true;
+                    // applicable rules
+                    for( Iterator it = ruleList.iterator(); it.hasNext(); ) {
+                        Rule r = (Rule) it.next();
 
-		try {
-			shpreader = new IndexInfo.Reader(info, ShapefileRendererUtil
-					.getShpReader(datastore, bbox, screenSize, mt,
-							opacityFinder.hasOpacity, useJTS), bbox);
-		} catch (final Exception e) {
-			fireErrorEvent(e);
-			return;
-		}
+                        if (LOGGER.isLoggable(Level.FINER)) {
+                            LOGGER.finer("applying rule: " + r.toString());
+                        }
 
-		FIDReader fidReader = null;
-		try {
-			fidReader = ShapefileRendererUtil
-					.getFidReader(datastore, shpreader);
-		} catch (final Exception e) {
-			fireErrorEvent(e);
-			return;
-		}
+                        if (LOGGER.isLoggable(Level.FINER)) {
+                            LOGGER.finer("this rule applies ...");
+                        }
 
-		try {
-			while (true) {
-				try {
-					if (renderingStopRequested) {
-						break;
-					}
+                        Filter filter = r.getFilter();
 
-					if (!shpreader.hasNext()) {
-						break;
-					}
+                        if ((filter == null) || filter.evaluate(feature)) {
+                            doElse = false;
 
-					boolean doElse = true;
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("processing Symobolizer ...");
+                            }
 
-					if (logGt.isLoggable(Level.FINER)) {
-						logGt.fine("trying to read geometry ...");
-					}
+                            Symbolizer[] symbolizers = r.getSymbolizers();
 
-					final String nextFid = fidReader.next();
-					if (modifiedFIDs.contains(nextFid)) {
-						shpreader.next();
-						if (dbfreader != null
-								&& !dbfreader.IsRandomAccessEnabled())
-							dbfreader.skip();
-						continue;
-					}
-					if (dbfreader != null && dbfreader.IsRandomAccessEnabled())
-						dbfreader.goTo(shpreader.getRecordNumber());
-					final ShapefileReader.Record record = shpreader.next();
+                            processSymbolizers(graphics, feature, geom, symbolizers, scaleRange, useJTS, layerId);
 
-					final Object geom = record.shape();
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("... done!");
+                            }
+                        }
+                    }
 
-					if (geom == null) {
-						logGt.finest("skipping geometry");
-						if (dbfreader != null
-								&& !dbfreader.IsRandomAccessEnabled())
-							dbfreader.skip();
-						continue;
-					}
+                    if (doElse) {
+                        // rules with an else filter
+                        if (LOGGER.isLoggable(Level.FINER)) {
+                            LOGGER.finer("rules with an else filter");
+                        }
 
-					final SimpleFeature feature = createFeature(type, record, dbfreader,
-							nextFid);
-					if (!query.getFilter().evaluate(feature))
-						continue;
+                        for( Iterator it = elseRuleList.iterator(); it.hasNext(); ) {
+                            Rule r = (Rule) it.next();
+                            Symbolizer[] symbolizers = r.getSymbolizers();
 
-					if (renderingStopRequested) {
-						break;
-					}
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("processing Symobolizer ...");
+                            }
 
-					if (logGt.isLoggable(Level.FINEST)) {
-						logGt.finest("... done: " + geom.toString());
-					}
+                            processSymbolizers(graphics, feature, geom, symbolizers, scaleRange, useJTS, layerId);
 
-					if (logGt.isLoggable(Level.FINER)) {
-						logGt.fine("... done: " + type.getTypeName());
-					}
+                            if (LOGGER.isLoggable(Level.FINER)) {
+                                LOGGER.finer("... done!");
+                            }
+                        }
+                    }
 
-					// applicable rules
-					for (final Iterator it = ruleList.iterator(); it.hasNext();) {
-						final Rule r = (Rule) it.next();
+                    if (LOGGER.isLoggable(Level.FINER)) {
+                        LOGGER.finer("feature rendered event ...");
+                    }
+                } catch (Exception e) {
+                    fireErrorEvent(e);
+                }
+            }
+        } finally {
+            try {
+                if (dbfreader != null) {
+                    dbfreader.close();
+                }
+            } finally {
+                try {
+                    if (shpreader != null) {
+                        shpreader.close();
+                    }
+                } finally {
+                    if (fidReader != null)
+                        fidReader.close();
+                }
+            }
+        }
+    }
 
-						if (logGt.isLoggable(Level.FINER)) {
-							logGt.finer("applying rule: " + r.toString());
-						}
+    private Class[] getAcceptableSymbolizers( GeometryDescriptor defaultGeometry ) {
+        Class binding = defaultGeometry.getType().getBinding();
+        if (Polygon.class.isAssignableFrom(binding)
+                || MultiPolygon.class.isAssignableFrom(binding)) {
+            return new Class[]{PointSymbolizer.class, LineSymbolizer.class, PolygonSymbolizer.class};
+        }
 
-						if (logGt.isLoggable(Level.FINER)) {
-							logGt.finer("this rule applies ...");
-						}
+        return new Class[]{PointSymbolizer.class, LineSymbolizer.class};
+    }
 
-						final Filter filter = r.getFilter();
+    SimpleFeature createFeature(SimpleFeatureBuilder builder, Record record, DbaseFileReader dbfreader, String id )
+            throws Exception {
+        SimpleFeatureType type = builder.getFeatureType();
+        if (type.getAttributeCount() == 1) {
+            builder.add(getGeom(record.shape(), type.getGeometryDescriptor()));
+            return builder.buildFeature(id);
+        } else {
+            dbfreader.read();
+            for( int i = 0; i < (type.getAttributeCount() - 1); i++ ) {
+                builder.add(dbfreader.readField(attributeIndexing[i]));
+            }
+            builder.add(getGeom(record.shape(), type.getGeometryDescriptor()));
+            return builder.buildFeature(id);
+        }
+    }
 
-						if ((filter == null) || filter.evaluate(feature)) {
-							doElse = false;
+    /**
+     * Return provided geom; or use a default value if null.
+     * 
+     * @param geom Provided Geometry as read from record.shape()
+     * @param defaultGeometry GeometryDescriptor used to determine default value
+     * @return provided geom or default value if null
+     */
+    private Object getGeom( Object geom, GeometryDescriptor defaultGeometry ) {
+        if( geom instanceof Geometry){
+            return geom;
+        }
+        return getGeom( defaultGeometry );
+    }
 
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("processing Symobolizer ...");
-							}
+    /**
+     * This class keeps a couple of default geometries on hand to use
+     * when making a feature with default values.
+     * 
+     * @param defaultGeometry
+     * @return placeholder to use as a default while waiting for a real geometry.
+     */
+    private Object getGeom(GeometryDescriptor defaultGeometry) {
+        Class binding = defaultGeometry.getType().getBinding();
+        if (MultiPolygon.class.isAssignableFrom(binding)) {
+            return MULTI_POLYGON_GEOM;
+        }
+        else if (MultiLineString.class.isAssignableFrom(binding)) {
+            return MULTI_LINE_GEOM;
+        }
+        else if (Point.class.isAssignableFrom(binding)) {
+            return POINT_GEOM;
+        }
+        else if (MultiPoint.class.isAssignableFrom(binding)) {
+            return MULTI_POINT_GEOM;
+        }
+        return null; // we don't have a good default value - null will need to do
+    }
+    
+    /**
+     * DOCUMENT ME!
+     * 
+     * @param query
+     * @param style
+     * @param schema DOCUMENT ME!
+     * @return
+     * @throws FactoryConfigurationError
+     * @throws SchemaException
+     */
+    SimpleFeatureType createFeatureType( Query query, Style style, ShapefileDataStore ds)
+            throws SchemaException, IOException {
+        SimpleFeatureType schema = ds.getSchema();
+        String[] attributes = findStyleAttributes((query == null) ? Query.ALL : query, style,
+                schema);
+        AttributeDescriptor[] types = new AttributeDescriptor[attributes.length];
+        attributeIndexing = new int[attributes.length];
+        
+        if(attributes.length == 1 && attributes[0].equals(schema.getGeometryDescriptor().getLocalName())) {
+            types[0] = schema.getDescriptor(attributes[0]);
+        } else {
+            dbfheader = getDBFHeader(ds);
+            for( int i = 0; i < types.length; i++ ) {
+                types[i] = schema.getDescriptor(attributes[i]);
+    
+                for( int j = 0; j < dbfheader.getNumFields(); j++ ) {
+                    if (dbfheader.getFieldName(j).equals(attributes[i])) {
+                        attributeIndexing[i] = j;
+    
+                        break;
+                    }
+                }
+            }
+        }
 
-							final Symbolizer[] symbolizers = r.getSymbolizers();
+        SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
+        tb.setName( schema.getName() );
+        tb.addAll( types );
+        tb.setDefaultGeometry( schema.getGeometryDescriptor().getLocalName() );
+        
+        return tb.buildFeatureType();
+    }
 
-							processSymbolizers(graphics, feature, geom,
-									symbolizers, scaleRange, useJTS, layerId);
+    /**
+     * Inspects the <code>MapLayer</code>'s style and retrieves it's needed attribute names,
+     * returning at least the default geometry attribute name.
+     * 
+     * @param query DOCUMENT ME!
+     * @param style the <code>Style</code> to determine the needed attributes from
+     * @param schema the FeatureSource<SimpleFeatureType, SimpleFeature> schema
+     * @return the minimun set of attribute names needed to render <code>layer</code>
+     */
+    private String[] findStyleAttributes( final Query query, Style style, SimpleFeatureType schema ) {
+        StyleAttributeExtractor sae = new StyleAttributeExtractor();
+        sae.visit(style);
 
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("... done!");
-							}
-						}
-					}
-
-					if (doElse) {
-						// rules with an else filter
-						if (logGt.isLoggable(Level.FINER)) {
-							logGt.finer("rules with an else filter");
-						}
-
-						for (final Iterator it = elseRuleList.iterator(); it
-								.hasNext();) {
-							final Rule r = (Rule) it.next();
-							final Symbolizer[] symbolizers = r.getSymbolizers();
-
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("processing Symobolizer ...");
-							}
-
-							processSymbolizers(graphics, feature, geom,
-									symbolizers, scaleRange, useJTS, layerId);
-
-							if (logGt.isLoggable(Level.FINER)) {
-								logGt.finer("... done!");
-							}
-						}
-					}
-
-					if (logGt.isLoggable(Level.FINER)) {
-						logGt.finer("feature rendered event ...");
-					}
-				} catch (final Exception e) {
-					fireErrorEvent(e);
-				}
-			}
-		} finally {
-			try {
-				if (dbfreader != null) {
-					dbfreader.close();
-				}
-			} finally {
-				try {
-					if (shpreader != null) {
-						shpreader.close();
-					}
-				} finally {
-					// if (fidReader != null)
-					// fidReader.close();
-				}
-			}
-		}
-	}
-
-	private Class[] getAcceptableSymbolizers(
-			final GeometryAttributeType defaultGeometry) {
-		if (Polygon.class.isAssignableFrom(defaultGeometry.getType())
-				|| MultiPolygon.class.isAssignableFrom(defaultGeometry
-						.getType())) {
-			return new Class[] { PointSymbolizer.class, LineSymbolizer.class,
-					PolygonSymbolizer.class };
-		}
-
-		return new Class[] { PointSymbolizer.class, LineSymbolizer.class };
-	}
-
-	SimpleFeature createFeature(final SimpleFeatureType type, final Record record,
-			final DbaseFileReader dbfreader, final String id) throws Exception {
-		if (type.getAttributeCount() == 1) {
-			return type.create(new Object[] { getGeom(record.shape(), type
-					.getDefaultGeometry()) }, id);
+        
+        FilterAttributeExtractor qae = new FilterAttributeExtractor();
+        query.getFilter().accept(qae,null);
+        Set ftsAttributes = new LinkedHashSet(sae.getAttributeNameSet());
+        ftsAttributes.addAll(qae.getAttributeNameSet());
+        if (sae.getDefaultGeometryUsed()
+				&& (!ftsAttributes.contains(schema.getGeometryDescriptor().getLocalName()))) {
+        	ftsAttributes.add(schema.getGeometryDescriptor().getLocalName());
 		} else {
-			final DbaseFileHeader header = dbfreader.getHeader();
-
-			final Object[] all = dbfreader.readEntry();
-			final Object[] values = new Object[type.getAttributeCount()];
-
-			for (int i = 0; i < (values.length - 1); i++) {
-				values[i] = all[attributeIndexing[i]];
-
-				if (header.getFieldName(attributeIndexing[i]).equals(
-						type.getAttributeType(i))) {
-					System.out.println("ok");
-				}
-			}
-
-			values[values.length - 1] = getGeom(record.shape(), type
-					.getDefaultGeometry());
-
-			return type.create(values, id);
+	        // the code following assumes the geometry column is the last one
+		    // make sure it's the last for good
+	        ftsAttributes.remove(schema.getGeometryDescriptor().getLocalName());
+	        ftsAttributes.add(schema.getGeometryDescriptor().getLocalName());
 		}
-	}
+        return (String[]) ftsAttributes.toArray(new String[0]);
+    }
 
-	/**
-	 * Return provided geom; or use a default value if null.
-	 * 
-	 * @param geom
-	 *            Provided Geometry as read from record.shape()
-	 * @param defaultGeometry
-	 *            GeometryAttributeType used to determine default value
-	 * @return provided geom or default value if null
-	 */
-	private Object getGeom(final Object geom, final GeometryAttributeType defaultGeometry) {
-		if (geom instanceof Geometry) {
-			return geom;
-		}
-		return getGeom(defaultGeometry);
-	}
+    /**
+     * DOCUMENT ME!
+     * 
+     * @param graphics
+     * @param feature DOCUMENT ME!
+     * @param geom
+     * @param symbolizers
+     * @param scaleRange
+     * @param layerId 
+     */
+    private void processSymbolizers( Graphics2D graphics, SimpleFeature feature, Object geom,
+            Symbolizer[] symbolizers, NumberRange scaleRange, boolean isJTS, String layerId ) {
+        for( int m = 0; m < symbolizers.length; m++ ) {
+            if (LOGGER.isLoggable(Level.FINER)) {
+                LOGGER.finer("applying symbolizer " + symbolizers[m]);
+            }
 
-	/**
-	 * This class keeps a couple of default geometries on hand to use when
-	 * making a feature with default values.
-	 * 
-	 * @param defaultGeometry
-	 * @return placeholder to use as a default while waiting for a real
-	 *         geometry.
-	 */
-	private Object getGeom(final GeometryAttributeType defaultGeometry) {
-		if (MultiPolygon.class.isAssignableFrom(defaultGeometry.getType())) {
-			return MULTI_POLYGON_GEOM;
-		} else if (MultiLineString.class.isAssignableFrom(defaultGeometry
-				.getType())) {
-			return MULTI_LINE_GEOM;
-		} else if (Point.class.isAssignableFrom(defaultGeometry.getType())) {
-			return POINT_GEOM;
-		} else if (MultiPoint.class.isAssignableFrom(defaultGeometry.getType())) {
-			return MULTI_POINT_GEOM;
-		}
-		return null; // we don't have a good default value - null will need to
-		// do
-	}
+            if (renderingStopRequested) {
+                break;
+            }
 
-	/**
-	 * DOCUMENT ME!
-	 * 
-	 * @param query
-	 * @param style
-	 * @param schema
-	 *            DOCUMENT ME!
-	 * @return
-	 * @throws FactoryConfigurationError
-	 * @throws SchemaException
-	 */
-	SimpleFeatureType createFeatureType(final Query query, final Style style,
-			final ShapefileDataStore ds) throws SchemaException, IOException {
-		final SimpleFeatureType schema = ds.getSchema();
-		final String[] attributes = findStyleAttributes((query == null) ? Query.ALL
-				: query, style, schema);
-		final AttributeDescriptor[] types = new AttributeDescriptor[attributes.length];
-		attributeIndexing = new int[attributes.length];
+            if (symbolizers[m] instanceof TextSymbolizer) {
+                try {
+                    labelCache.put(layerId,(TextSymbolizer) symbolizers[m], 
+                            feature, 
+                            new LiteShape2((Geometry)feature.getDefaultGeometry(), null, null, false, false),
+                            scaleRange);
+                } catch (Exception e) {
+                    fireErrorEvent(e);
+                }
+            } else {
+                Shape shape;
+                try {
+                    Style2D style = styleFactory.createStyle(feature, symbolizers[m], scaleRange);
+                    if( isJTS ){
+                        Geometry g;
+                        if(symbolizers[m] instanceof PointSymbolizer) {
+                            g = RendererUtilities.getCentroid((Geometry) geom);
+                        } else {
+                            g = (Geometry) geom;
+                        }
+                        shape = new LiteShape2(g, null, null, false, false);
+                        painter.paint(graphics, shape, style, scaleDenominator);
+                    }else{
+                        if(symbolizers[m] instanceof PointSymbolizer) {
+                            shape = new LiteShape2(RendererUtilities.getCentroid((Geometry) feature.getDefaultGeometry()), null, null, false, false);
+                        } else {
+                            shape = getShape((SimpleGeometry) geom);
+                        }
+                            
+                        painter.paint(graphics, shape, style, scaleDenominator);
+                    }
+                } catch (Exception e) {
+                    fireErrorEvent(e);
+                }            
+            }
 
-		if (attributes.length == 1
-				&& attributes[0].equals(schema.getDefaultGeometry()
-						.getLocalName())) {
-			types[0] = schema.getAttributeType(attributes[0]);
-		} else {
-			dbfheader = getDBFHeader(ds);
-			for (int i = 0; i < types.length; i++) {
-				types[i] = schema.getAttributeType(attributes[i]);
+        }
+        fireFeatureRenderedEvent(feature);
+    }
 
-				for (int j = 0; j < dbfheader.getNumFields(); j++) {
-					if (dbfheader.getFieldName(j).equals(attributes[i])) {
-						attributeIndexing[i] = j;
+    /**
+     * Applies each of a set of symbolizers in turn to a given feature.
+     * <p>
+     * This is an internal method and should only be called by processStylers.
+     * </p>
+     * 
+     * @param graphics
+     * @param feature The feature to be rendered
+     * @param symbolizers An array of symbolizers which actually perform the rendering.
+     * @param scaleRange The scale range we are working on... provided in order to make the style
+     *        factory happy
+     * @param transform DOCUMENT ME!
+     * @param layerId 
+     * @throws TransformException
+     * @throws FactoryException
+     */
+    private void processSymbolizers( final Graphics2D graphics, final SimpleFeature feature,
+            final Symbolizer[] symbolizers, NumberRange scaleRange, MathTransform transform, String layerId )
+            throws TransformException, FactoryException {
+        LiteShape2 shape;
 
-						break;
-					}
-				}
-			}
-		}
+        for( int m = 0; m < symbolizers.length; m++ ) {
+            if (LOGGER.isLoggable(Level.FINER)) {
+                LOGGER.finer("applying symbolizer " + symbolizers[m]);
+            }
 
-		final SimpleFeatureType type = FeatureTypeBuilder.newFeatureType(types, schema
-				.getTypeName(), schema.getNamespace(), false, null, schema
-				.getDefaultGeometry());
+            Geometry g = (Geometry) feature.getDefaultGeometry();
+            if(symbolizers[m] instanceof PointSymbolizer)
+                g = RendererUtilities.getCentroid(g);
+            shape = new LiteShape2(g, transform, getDecimator(transform), false);
 
-		return type;
-	}
+            if (symbolizers[m] instanceof TextSymbolizer) {
+                labelCache.put(layerId, (TextSymbolizer) symbolizers[m], feature, shape, scaleRange);
+            } else {
+                Style2D style = styleFactory.createStyle(feature, symbolizers[m], scaleRange);
+                painter.paint(graphics, shape, style, scaleDenominator);
+            }
+        }
 
-	/**
-	 * Inspects the <code>MapLayer</code>'s style and retrieves it's needed
-	 * attribute names, returning at least the default geometry attribute name.
-	 * 
-	 * @param query
-	 *            DOCUMENT ME!
-	 * @param style
-	 *            the <code>Style</code> to determine the needed attributes from
-	 * @param schema
-	 *            the featuresource schema
-	 * @return the minimun set of attribute names needed to render
-	 *         <code>layer</code>
-	 */
-	private String[] findStyleAttributes(final Query query, final Style style,
-			final SimpleFeatureType schema) {
-		final StyleAttributeExtractor sae = new StyleAttributeExtractor() {
-			public void visit(final Rule rule) {
+        fireFeatureRenderedEvent(feature);
+    }
 
-				final DuplicatingStyleVisitor dupeStyleVisitor = new DuplicatingStyleVisitor();
-				dupeStyleVisitor.visit(rule);
-				final Rule clone = (Rule) dupeStyleVisitor.getCopy();
+    /**
+     * DOCUMENT ME!
+     * 
+     * @param mathTransform DOCUMENT ME!
+     * @return
+     * @throws org.opengis.referencing.operation.NoninvertibleTransformException
+     */
+    private Decimator getDecimator( MathTransform mathTransform  )
+            throws org.opengis.referencing.operation.NoninvertibleTransformException {
+        Decimator decimator=null;
+        
+        if( mathTransform!=null )
+            decimator = (Decimator) decimators.get(mathTransform);
 
-				super.visit(clone);
-			}
-		};
+        if (decimator == null) {
+            decimator = new Decimator(mathTransform.inverse());
 
-		sae.visit(style);
+            decimators.put(mathTransform, decimator);
+        }
 
-		final FilterAttributeExtractor qae = new FilterAttributeExtractor();
-		query.getFilter().accept(qae, null);
-		final Set ftsAttributes = new HashSet(sae.getAttributeNameSet());
-		ftsAttributes.addAll(qae.getAttributeNameSet());
-		// the code following assumes we won't extract the default geometry, and
-		// that's
-		// most of the time true, but fails if the filter or the style uses it.
-		ftsAttributes.remove(schema.getDefaultGeometry().getLocalName());
-		return (String[]) ftsAttributes.toArray(new String[0]);
-	}
+        return decimator;
+    }
+//
+//    /**
+//     * Creates a JTS shape that is an approximation of the SImpleGeometry. This is ONLY use for
+//     * labelling and is only created if a text symbolizer is part of the current style.
+//     * 
+//     * @param geom the geometry to wrap
+//     * @return
+//     * @throws TransformException
+//     * @throws FactoryException
+//     * @throws RuntimeException DOCUMENT ME!
+//     */
+//    LiteShape2 getLiteShape2( SimpleGeometry geom ) throws TransformException, FactoryException {
+//        Geometry jtsGeom;
+//        if ((geom.type == ShapeType.POLYGON) || (geom.type == ShapeType.POLYGONM)
+//                || (geom.type == ShapeType.POLYGONZ)) {
+//            double[] points = getPointSample(geom, true);
+//            CoordinateSequence seq = new LiteCoordinateSequence(points);
+//            Polygon poly;
+//
+//            try {
+//                poly = geomFactory.createPolygon(geomFactory.createLinearRing(seq),
+//                        new LinearRing[]{});
+//            } catch (Exception e) {
+//                throw new RuntimeException(e);
+//            }
+//
+//            jtsGeom = geomFactory.createMultiPolygon(new Polygon[]{poly});
+//        } else if ((geom.type == ShapeType.ARC) || (geom.type == ShapeType.ARCM)
+//                || (geom.type == ShapeType.ARCZ)) {
+//            double[] points = getPointSample(geom, false);
+//            CoordinateSequence seq = new LiteCoordinateSequence(points);
+//            jtsGeom = geomFactory.createMultiLineString(new LineString[]{geomFactory
+//                    .createLineString(seq)});
+//        } else if ((geom.type == ShapeType.MULTIPOINT) || (geom.type == ShapeType.MULTIPOINTM)
+//                || (geom.type == ShapeType.MULTIPOINTZ)) {
+//            double[] points = getPointSample(geom, false);
+//            CoordinateSequence seq = new LiteCoordinateSequence(points);
+//            jtsGeom = geomFactory.createMultiPoint(seq);
+//        } else {
+//            jtsGeom = geomFactory.createPoint(new Coordinate(geom.coords[0][0], geom.coords[0][1]));
+//        }
+//
+//        LiteShape2 shape = new LiteShape2(jtsGeom, null, null, false);
+//
+//        return shape;
+//    }
 
-	/**
-	 * DOCUMENT ME!
-	 * 
-	 * @param graphics
-	 * @param feature
-	 *            DOCUMENT ME!
-	 * @param geom
-	 * @param symbolizers
-	 * @param scaleRange
-	 * @param layerId
-	 */
-	private void processSymbolizers(final Graphics2D graphics, final SimpleFeature feature,
-			final Object geom, final Symbolizer[] symbolizers, final NumberRange scaleRange,
-			final boolean isJTS, final String layerId) {
-		for (int m = 0; m < symbolizers.length; m++) {
-			if (logGt.isLoggable(Level.FINER)) {
-				logGt.finer("applying symbolizer " + symbolizers[m]);
-			}
+//    /**
+//     * takes a random sampling from the geometry. Only uses the larges part of the geometry.
+//     * 
+//     * @param geom
+//     * @param isPolygon DOCUMENT ME!
+//     * @return
+//     */
+//    private double[] getPointSample( SimpleGeometry geom, boolean isPolygon ) {
+//        int largestPart = 0;
+//
+//        for( int i = 0; i < geom.coords.length; i++ ) {
+//            if (geom.coords[i].length > geom.coords[largestPart].length) {
+//                largestPart = i;
+//            }
+//        }
+//
+//        return geom.coords[largestPart];
+//    }
 
-			if (renderingStopRequested) {
-				break;
-			}
+    /**
+     * DOCUMENT ME!
+     * 
+     * @param geom
+     * @return
+     */
+    private Shape getShape( SimpleGeometry geom ) {
+        if ((geom.type == ShapeType.ARC) || (geom.type == ShapeType.ARCM)
+                || (geom.type == ShapeType.ARCZ)) {
+            return new MultiLineShape(geom);
+        }
 
-			if (symbolizers[m] instanceof TextSymbolizer) {
-				try {
-					labelCache.put(layerId, (TextSymbolizer) symbolizers[m],
-							feature, new LiteShape2(feature
-									.getDefaultGeometry(), null, null, false,
-									false), scaleRange);
-				} catch (final Exception e) {
-					fireErrorEvent(e);
-				}
-			} else {
-				Shape shape;
-				try {
-					final Style2D style = styleFactory.createStyle(feature,
-							symbolizers[m], scaleRange);
-					if (isJTS) {
-						Geometry g;
-						if (symbolizers[m] instanceof PointSymbolizer) {
-							g = RendererUtilities.getCentroid((Geometry) geom);
-						} else {
-							g = (Geometry) geom;
-						}
-						shape = new LiteShape2(g, null, null, false, false);
-						painter.paint(graphics, shape, style, scaleDenominator);
-					} else {
-						if (symbolizers[m] instanceof PointSymbolizer) {
-							shape = new LiteShape2(RendererUtilities
-									.getCentroid(feature.getDefaultGeometry()),
-									null, null, false, false);
-						} else {
-							shape = getShape((SimpleGeometry) geom);
-						}
+        if ((geom.type == ShapeType.POLYGON) || (geom.type == ShapeType.POLYGONM)
+                || (geom.type == ShapeType.POLYGONZ)) {
+            return new PolygonShape(geom);
+        }
 
-						painter.paint(graphics, shape, style, scaleDenominator);
-					}
-				} catch (final Exception e) {
-					fireErrorEvent(e);
-				}
-			}
+        if ((geom.type == ShapeType.POINT) || (geom.type == ShapeType.POINTM)
+                || (geom.type == ShapeType.POINTZ) || (geom.type == ShapeType.MULTIPOINT)
+                || (geom.type == ShapeType.MULTIPOINTM) || (geom.type == ShapeType.MULTIPOINTZ)) {
+            return new MultiPointShape(geom);
+        }
+        
+        
 
-		}
-		fireFeatureRenderedEvent(feature);
-	}
+        return null;
+    }
 
-	/**
-	 * Applies each of a set of symbolizers in turn to a given feature.
-	 * <p>
-	 * This is an internal method and should only be called by processStylers.
-	 * </p>
-	 * 
-	 * @param graphics
-	 * @param feature
-	 *            The feature to be rendered
-	 * @param symbolizers
-	 *            An array of symbolizers which actually perform the rendering.
-	 * @param scaleRange
-	 *            The scale range we are working on... provided in order to make
-	 *            the style factory happy
-	 * @param transform
-	 *            DOCUMENT ME!
-	 * @param layerId
-	 * @throws TransformException
-	 * @throws FactoryException
-	 */
-	private void processSymbolizers(final Graphics2D graphics,
-			final SimpleFeature feature, final Symbolizer[] symbolizers,
-			final Range scaleRange, final MathTransform transform, final String layerId)
-			throws TransformException, FactoryException {
-		LiteShape2 shape;
+    /**
+     * Checks if a rule can be triggered at the current scale level
+     * 
+     * @param r The rule
+     * @return true if the scale is compatible with the rule settings
+     */
+    private boolean isWithInScale( Rule r ) {
+        return ((r.getMinScaleDenominator() - TOLERANCE) <= scaleDenominator)
+                && ((r.getMaxScaleDenominator() + TOLERANCE) > scaleDenominator);
+    }
 
-		for (int m = 0; m < symbolizers.length; m++) {
-			if (logGt.isLoggable(Level.FINER)) {
-				logGt.finer("applying symbolizer " + symbolizers[m]);
-			}
+    /**
+     * adds a listener that responds to error events of feature rendered events.
+     * 
+     * @param listener the listener to add.
+     * @see RenderListener
+     */
+    public void addRenderListener( RenderListener listener ) {
+        renderListeners.add(listener);
+    }
 
-			Geometry g = feature.getDefaultGeometry();
-			if (symbolizers[m] instanceof PointSymbolizer)
-				g = RendererUtilities.getCentroid(g);
-			shape = new LiteShape2(g, transform, getDecimator(transform), false);
+    /**
+     * Removes a render listener.
+     * 
+     * @param listener the listener to remove.
+     * @see RenderListener
+     */
+    public void removeRenderListener( RenderListener listener ) {
+        renderListeners.remove(listener);
+    }
 
-			if (symbolizers[m] instanceof TextSymbolizer) {
-				labelCache.put(layerId, (TextSymbolizer) symbolizers[m],
-						feature, shape, scaleRange);
-			} else {
-				final Style2D style = styleFactory.createStyle(feature,
-						symbolizers[m], scaleRange);
-				painter.paint(graphics, shape, style, scaleDenominator);
-			}
-		}
+    private void fireFeatureRenderedEvent( SimpleFeature feature ) {
+        if (renderListeners.size() > 0) {
+            RenderListener listener;
+            for (int i = 0; i < renderListeners.size(); i++) {
+                listener = renderListeners.get(i);
+                listener.featureRenderer((SimpleFeature) feature);
+            }
+        }
+    }
 
-		fireFeatureRenderedEvent(feature);
-	}
+    private void fireErrorEvent(Exception e) {
+        if (renderListeners.size() > 0) {
+            RenderListener listener;
+            for (int i = 0; i < renderListeners.size(); i++) {
+                try {
+                    listener = renderListeners.get(i);
+                    listener.errorOccurred(e);
+                } catch (RuntimeException ignore) {
+                    LOGGER.fine("Provided RenderListener could not handle error message:" + ignore);
+                    LOGGER.throwing(getClass().getName(), "fireErrorEvent", ignore);
+                }
+            }
+        }
+    }
 
-	/**
-	 * DOCUMENT ME!
-	 * 
-	 * @param mathTransform
-	 *            DOCUMENT ME!
-	 * @return
-	 * @throws org.opengis.referencing.operation.NoninvertibleTransformException
-	 */
-	private Decimator getDecimator(final MathTransform mathTransform)
-			throws org.opengis.referencing.operation.NoninvertibleTransformException {
-		Decimator decimator = null;
+    /**
+     * Setter for property scaleDenominator.
+     * 
+     * @param scaleDenominator New value of property scaleDenominator.
+     */
+    protected void setScaleDenominator( double scaleDenominator ) {
+        this.scaleDenominator = scaleDenominator;
+    }
 
-		if (mathTransform != null)
-			decimator = (Decimator) decimators.get(mathTransform);
+    /**
+     * If you call this method from another thread than the one that called <code>paint</code> or
+     * <code>render</code> the rendering will be forcefully stopped before termination
+     */
+    public void stopRendering() {
+        try {
+            if(delegate != null)
+                delegate.stopRendering();
+        } catch(NullPointerException e) {
+            // Since stopRendering is called by another thread the null check may
+            // pass, and the method call can NPE nevertheless. It's ok, in that
+            // case rendering is done anyways
+        }
+        renderingStopRequested = true;
+        labelCache.stop();
+    }
 
-		if (decimator == null) {
-			decimator = new Decimator(mathTransform.inverse());
+    /**
+     * True if we are caching styles.
+     * 
+     * @return <code>ture </code>if caching
+     */
+    public boolean isCaching() {
+        return caching;
+    }
 
-			decimators.put(mathTransform, decimator);
-		}
+    /**
+     * Set to true to cache styles.
+     * 
+     * @param caching The caching to set.
+     */
+    public void setCaching( boolean caching ) {
+        this.caching = caching;
+    }
 
-		return decimator;
-	}
+    public MapContext getContext() {
+        return context;
+    }
 
-	//
-	// /**
-	// * Creates a JTS shape that is an approximation of the SImpleGeometry.
-	// This is ONLY use for
-	// * labelling and is only created if a text symbolizer is part of the
-	// current style.
-	// *
-	// * @param geom the geometry to wrap
-	// * @return
-	// * @throws TransformException
-	// * @throws FactoryException
-	// * @throws RuntimeException DOCUMENT ME!
-	// */
-	// LiteShape2 getLiteShape2( SimpleGeometry geom ) throws
-	// TransformException, FactoryException {
-	// Geometry jtsGeom;
-	// if ((geom.type == ShapeType.POLYGON) || (geom.type == ShapeType.POLYGONM)
-	// || (geom.type == ShapeType.POLYGONZ)) {
-	// double[] points = getPointSample(geom, true);
-	// CoordinateSequence seq = new LiteCoordinateSequence(points);
-	// Polygon poly;
-	//
-	// try {
-	// poly = geomFactory.createPolygon(geomFactory.createLinearRing(seq),
-	// new LinearRing[]{});
-	// } catch (Exception e) {
-	// throw new RuntimeException(e);
-	// }
-	//
-	// jtsGeom = geomFactory.createMultiPolygon(new Polygon[]{poly});
-	// } else if ((geom.type == ShapeType.ARC) || (geom.type == ShapeType.ARCM)
-	// || (geom.type == ShapeType.ARCZ)) {
-	// double[] points = getPointSample(geom, false);
-	// CoordinateSequence seq = new LiteCoordinateSequence(points);
-	// jtsGeom = geomFactory.createMultiLineString(new LineString[]{geomFactory
-	// .createLineString(seq)});
-	// } else if ((geom.type == ShapeType.MULTIPOINT) || (geom.type ==
-	// ShapeType.MULTIPOINTM)
-	// || (geom.type == ShapeType.MULTIPOINTZ)) {
-	// double[] points = getPointSample(geom, false);
-	// CoordinateSequence seq = new LiteCoordinateSequence(points);
-	// jtsGeom = geomFactory.createMultiPoint(seq);
-	// } else {
-	// jtsGeom = geomFactory.createPoint(new Coordinate(geom.coords[0][0],
-	// geom.coords[0][1]));
-	// }
-	//
-	// LiteShape2 shape = new LiteShape2(jtsGeom, null, null, false);
-	//
-	// return shape;
-	// }
+    public boolean isConcatTransforms() {
+        return concatTransforms;
+    }
 
-	// /**
-	// * takes a random sampling from the geometry. Only uses the larges part of
-	// the geometry.
-	// *
-	// * @param geom
-	// * @param isPolygon DOCUMENT ME!
-	// * @return
-	// */
-	// private double[] getPointSample( SimpleGeometry geom, boolean isPolygon )
-	// {
-	// int largestPart = 0;
-	//
-	// for( int i = 0; i < geom.coords.length; i++ ) {
-	// if (geom.coords[i].length > geom.coords[largestPart].length) {
-	// largestPart = i;
-	// }
-	// }
-	//
-	// return geom.coords[largestPart];
-	// }
+    public void setConcatTransforms( boolean concatTransforms ) {
+        this.concatTransforms = concatTransforms;
+    }
 
-	/**
-	 * DOCUMENT ME!
-	 * 
-	 * @param geom
-	 * @return
-	 */
-	private Shape getShape(final SimpleGeometry geom) {
-		if ((geom.type == ShapeType.ARC) || (geom.type == ShapeType.ARCM)
-				|| (geom.type == ShapeType.ARCZ)) {
-			return new MultiLineShape(geom);
-		}
+    public IndexInfo useIndex( ShapefileDataStore ds ) throws IOException, StoreException {
+        IndexInfo info;
 
-		if ((geom.type == ShapeType.POLYGON)
-				|| (geom.type == ShapeType.POLYGONM)
-				|| (geom.type == ShapeType.POLYGONZ)) {
-			return new PolygonShape(geom);
-		}
+        ShpFiles shpFiles = ShapefileRendererUtil.getShpFiles(ds);
+        if (ds.isLocal()) {
 
-		if ((geom.type == ShapeType.POINT) || (geom.type == ShapeType.POINTM)
-				|| (geom.type == ShapeType.POINTZ)
-				|| (geom.type == ShapeType.MULTIPOINT)
-				|| (geom.type == ShapeType.MULTIPOINTM)
-				|| (geom.type == ShapeType.MULTIPOINTZ)) {
-			return new MultiPointShape(geom);
-		}
+            if (!shpFiles.exists(SHX)) {
+                info = new IndexInfo(IndexType.NONE, shpFiles);
+                LOGGER.fine("No indexing");
+            } else if (shpFiles.exists(QIX)) {
+                info = new IndexInfo(IndexType.QIX, shpFiles);
+                LOGGER.fine("Using quad tree");
+            } else {
+                info = new IndexInfo(IndexType.NONE, shpFiles);
+                LOGGER.fine("No indexing");
+            }
+        } else {
+            info = new IndexInfo(IndexType.NONE, shpFiles);
+            LOGGER.fine("No indexing");
+        }
 
-		return null;
-	}
+        return info;
+    }
 
-	/**
-	 * Checks if a rule can be triggered at the current scale level
-	 * 
-	 * @param r
-	 *            The rule
-	 * @return true if the scale is compatible with the rule settings
-	 */
-	private boolean isWithInScale(final Rule r) {
-		return ((r.getMinScaleDenominator() - TOLERANCE) <= scaleDenominator)
-				&& ((r.getMaxScaleDenominator() + TOLERANCE) > scaleDenominator);
-	}
+    /**
+     * By default ignores all feature renderered events and logs all exceptions as severe.
+     */
+    private static class DefaultRenderListener implements RenderListener {
+        /**
+         * @see org.geotools.renderer.lite.RenderListener#featureRenderer(org.geotools.feature.Feature)
+         */
+        public void featureRenderer( SimpleFeature feature ) {
+            // do nothing.
+        }
 
-	/**
-	 * adds a listener that responds to error events of feature rendered events.
-	 * 
-	 * @param listener
-	 *            the listener to add.
-	 * @see RenderListener
-	 */
-	public void addRenderListener(final RenderListener listener) {
-		renderListeners.add(listener);
-	}
+        /**
+         * @see org.geotools.renderer.lite.RenderListener#errorOccurred(java.lang.Exception)
+         */
+        public void errorOccurred( Exception e ) {
+            LOGGER.log(Level.SEVERE, e.getMessage(), e);
+        }
+    }
 
-	/**
-	 * Removes a render listener.
-	 * 
-	 * @param listener
-	 *            the listener to remove.
-	 * @see RenderListener
-	 */
-	public void removeRenderListener(final RenderListener listener) {
-		renderListeners.remove(listener);
-	}
+    public void setJava2DHints( RenderingHints hints ) {
+        this.hints = hints;
+    }
 
-	private void fireFeatureRenderedEvent(final SimpleFeature feature) {
-		final Object[] objects = renderListeners.getListeners();
+    public RenderingHints getJava2DHints() {
+        return hints;
+    }
 
-		for (int i = 0; i < objects.length; i++) {
-			final RenderListener listener = (RenderListener) objects[i];
-			listener.featureRenderer(feature);
-		}
-	}
+    public void setRendererHints(Map hints) {
+    	if( hints!=null && hints.containsKey(LABEL_CACHE_KEY) ){
+    		LabelCache cache=(LabelCache) hints.get(LABEL_CACHE_KEY);
+    		if( cache==null )
+    			throw new NullPointerException("Label_Cache_Hint has a null value for the labelcache");
+    		
+    		this.labelCache=cache;
+    		this.painter=new StyledShapePainter(cache);
+    	}
+    	if(hints != null && hints.containsKey(StreamingRenderer.LINE_WIDTH_OPTIMIZATION_KEY)) {
+            styleFactory.setLineOptimizationEnabled(Boolean.TRUE.equals(hints.get(StreamingRenderer.LINE_WIDTH_OPTIMIZATION_KEY)));
+        }
+        rendererHints = hints;
+    }
+    
+    public Map getRendererHints() {
+        return rendererHints;
+    }
 
-	private void fireErrorEvent(final Exception e) {
-		final Object[] objects = renderListeners.getListeners();
+    public void setContext( MapContext context ) {
+        if (context == null) {
+            context = new DefaultMapContext(DefaultGeographicCRS.WGS84);
+        }
 
-		for (int i = 0; i < objects.length; i++) {
-			final RenderListener listener = (RenderListener) objects[i];
-			listener.errorOccurred(e);
-		}
-	}
+        // TODO Hack missing!
+        
+        this.context = context;
 
-	/**
-	 * Setter for property scaleDenominator.
-	 * 
-	 * @param scaleDenominator
-	 *            New value of property scaleDenominator.
-	 */
-	protected void setScaleDenominator(final double scaleDenominator) {
-		this.scaleDenominator = scaleDenominator;
-	}
+        MapLayer[] layers = context.getLayers();
+        layerIndexInfo = new IndexInfo[layers.length];
 
-	/**
-	 * If you call this method from another thread than the one that called
-	 * <code>paint</code> or <code>render</code> the rendering will be
-	 * forcefully stopped before termination
-	 */
-	public void stopRendering() {
-		renderingStopRequested = true;
-		labelCache.stop();
-	}
+        int i=0;
+        for(MapLayer layer:layers ) {
+            DataStore ds = (DataStore) layer.getFeatureSource().getDataStore();
+            if( ds instanceof ShapefileDataStore ){
+	            ShapefileDataStore sds = (ShapefileDataStore) ds;
+	            try {
+	                layerIndexInfo[i] = useIndex(sds);
+	            } catch (Exception e) {
+	                layerIndexInfo[i] = new IndexInfo(IndexType.NONE, ShapefileRendererUtil.getShpFiles(sds));
+	                if(LOGGER.isLoggable(Level.FINE))
+	                    LOGGER.fine("Exception while trying to use index" + e.getLocalizedMessage());
+	            }
+	        }else{
+	        	layerIndexInfo[i]=STREAMING_RENDERER_INFO;
+	        }
+            i++;
+        }
+    }
 
-	/**
-	 * DOCUMENT ME!
-	 * 
-	 * @return Returns the caching.
-	 */
-	public boolean isCaching() {
-		return caching;
-	}
+    public void paint( Graphics2D graphics, Rectangle paintArea, AffineTransform worldToScreen ) {
+        if (worldToScreen == null || paintArea == null) {
+            LOGGER.info("renderer passed null arguments");
+            return;
+        } // Other arguments get checked later
+        // First, create the bbox in real world coordinates
+        ReferencedEnvelope mapArea;
+        try {
+            mapArea = RendererUtilities.createMapEnvelope(paintArea, worldToScreen, getContext().getCoordinateReferenceSystem());
+            paint(graphics, paintArea, mapArea, worldToScreen);
+        } catch (NoninvertibleTransformException e) {
+            fireErrorEvent(new Exception("Can't create pixel to world transform", e));
+        }
+    }
 
-	/**
-	 * DOCUMENT ME!
-	 * 
-	 * @param caching
-	 *            The caching to set.
-	 */
-	public void setCaching(final boolean caching) {
-		this.caching = caching;
-	}
+    public void paint( Graphics2D graphics, Rectangle paintArea, ReferencedEnvelope envelope,
+            AffineTransform transform ) {
 
-	public MapContext getContext() {
-		return context;
-	}
+        if (hints != null) {
+            graphics.setRenderingHints(hints);
+        }
 
-	public boolean isConcatTransforms() {
-		return concatTransforms;
-	}
+        if ((graphics == null) || (paintArea == null)) {
+            LOGGER.info("renderer passed null arguments");
 
-	public void setConcatTransforms(final boolean concatTransforms) {
-		this.concatTransforms = concatTransforms;
-	}
+            return;
+        }
 
-	public IndexInfo useIndex(final ShapefileDataStore ds) throws IOException,
-			StoreException {
-		IndexInfo info;
-		String filename = null;
-		final URL url = ShapefileRendererUtil.getshpURL(ds);
+        // reset the abort flag
+        renderingStopRequested = false;
 
-		if (url == null) {
-			throw new NullPointerException("Null URL for ShapefileDataSource");
-		}
+        if (LOGGER.isLoggable(Level.FINE)) {
+            LOGGER.fine("Affine Transform is " + transform);
+        }
 
-		try {
-			filename = java.net.URLDecoder.decode(url.toString(), "US-ASCII");
-		} catch (final java.io.UnsupportedEncodingException use) {
-			throw new java.net.MalformedURLException("Unable to decode " + url
-					+ " cause " + use.getMessage());
-		}
+        /*
+         * If we are rendering to a component which has already set up some form of transformation
+         * then we can concatenate our transformation to it. An example of this is the ZoomPane
+         * component of the swinggui module.
+         */
+        if (concatTransforms) {
+            AffineTransform atg = graphics.getTransform();
 
-		filename = filename.substring(0, filename.length() - 4);
+            // graphics.setTransform(new AffineTransform());
+            atg.concatenate(transform);
+            transform = atg;
+        }
 
-		final String grxext = ".grx";
-		final String qixext = ".qix";
+        try {
+            setScaleDenominator(  
+                    computeScale(
+                            envelope,
+                            context.getCoordinateReferenceSystem(),
+                            paintArea, 
+                            transform,
+                            this.rendererHints));
+        } catch (Exception e) // probably either (1) no CRS (2) error xforming
+        {
+            LOGGER.throwing("RendererUtilities", "calculateScale(envelope, coordinateReferenceSystem, imageWidth, imageHeight, hints)", e);
+            setScaleDenominator(1 / transform.getScaleX()); // DJB old method - the best we can do
+        }
 
-		final boolean local = ds.isLocal();
-		LOGGER.debug("TransitionShapefileRendere is local = " + local
-				+ ".. anyway ignoring it.");
-		// if (local) {
-		final URL shx = IOUtil.changeUrlExt(url, "shx");
-		final URL qixTree = IOUtil.changeUrlExt(url, "qix");
-		final URL grxTree = IOUtil.changeUrlExt(url, "grx");
+        MapLayer[] layers = context.getLayers();
 
-		if (!IOUtil.urlExists(shx)) {
-			LOGGER.debug(shx + " doesn exist => no index");
-			info = new IndexInfo(IndexInfo.TREE_NONE, null, null);
-		} else if (IOUtil.urlExists(qixTree)) {
-			info = new IndexInfo(IndexInfo.QUAD_TREE, qixTree, shx);
-			LOGGER.debug("Using quad tree");
-		} else {
-			LOGGER.debug(qixTree + " doesn exist ");
-			if (IOUtil.urlExists(grxTree)) {
-				info = new IndexInfo(IndexInfo.R_TREE, grxTree, shx);
-				LOGGER.debug("Using r-tree");
-			} else {
-				LOGGER.debug(grxTree + " doesn exist ");
-				info = new IndexInfo(IndexInfo.TREE_NONE, null, null);
-				LOGGER.debug("No indexing");
-			}
-		}
-		// } else {
-		// info = new IndexInfo(IndexInfo.TREE_NONE, null, null);
-		// }
+        // get detstination CRS
+        CoordinateReferenceSystem destinationCrs = context.getCoordinateReferenceSystem();
+        labelCache.start();
+        labelCache.clear();
+        if(labelCache instanceof LabelCacheDefault) {
+            boolean outlineEnabled = TEXT_RENDERING_OUTLINE.equals(getTextRenderingMethod());
+            ((LabelCacheDefault) labelCache).setOutlineRenderingEnabled(outlineEnabled);
+        }
+        for( int i = 0; i < layers.length; i++ ) {
+            MapLayer currLayer = layers[i];
 
-		return info;
-	}
+            if (!currLayer.isVisible()) {
+                // Only render layer when layer is visible
+                continue;
+            }
 
-	/**
-	 * By default ignores all feature renderered events and logs all exceptions
-	 * as severe.
-	 */
-	private static class DefaultRenderListener implements RenderListener {
-		/**
-		 * @see org.geotools.renderer.lite.RenderListener#featureRenderer(org.geotools.feature.SimpleFeature)
-		 */
-		public void featureRenderer(final SimpleFeature feature) {
-			// do nothing.
-		}
+            if (renderingStopRequested) {
+                return;
+            }
+            
+            if( layerIndexInfo[i]==STREAMING_RENDERER_INFO ){
+            	renderWithStreamingRenderer(currLayer, graphics, paintArea, envelope, transform);
+                continue;
+            }
+            labelCache.startLayer(""+i);
 
-		/**
-		 * @see org.geotools.renderer.lite.RenderListener#errorOccurred(java.lang.Exception)
-		 */
-		public void errorOccurred(final Exception e) {
-			logGt.log(Level.SEVERE, e.getMessage(), e);
-		}
-	}
+            ReferencedEnvelope bbox = envelope;
 
-	public void setJava2DHints(final RenderingHints hints) {
-		this.hints = hints;
-	}
+            try {
+                GeometryDescriptor geom = currLayer.getFeatureSource().getSchema().getGeometryDescriptor();
+                
+                CoordinateReferenceSystem dataCRS;
+                if( getForceCRSHint()==null )
+                	dataCRS = geom.getCoordinateReferenceSystem();
+                else
+                	dataCRS=getForceCRSHint();
+                
+                MathTransform mt;
+                CoordinateOperation op;
 
-	public RenderingHints getJava2DHints() {
-		return hints;
-	}
+                try {
+                    op = CRS.getCoordinateOperationFactory(true).createOperation(dataCRS, destinationCrs);
+                    mt = op.getMathTransform();
+                    bbox = bbox.transform(dataCRS, true, 10);
+                } catch (Exception e) {
+                    fireErrorEvent(e);
+                    LOGGER.log(Level.WARNING, "Could not reproject the bounding boxes, proceeding in non reprojecting mode", e);
+                    op = null;
+                    mt = null;
+                }
 
-	public void setRendererHints(final Map hints) {
-		if (hints != null && hints.containsKey(LABEL_CACHE_KEY)) {
-			final LabelCache cache = (LabelCache) hints.get(LABEL_CACHE_KEY);
-			if (cache == null)
-				throw new NullPointerException(
-						"Label_Cache_Hint has a null value for the labelcache");
+                MathTransform at = ReferencingFactoryFinder.getMathTransformFactory(null)
+                        .createAffineTransform(new GeneralMatrix(transform));
 
-			this.labelCache = cache;
-			this.painter = new StyledShapePainter(cache);
-		}
-		rendererHints = hints;
-	}
+                if (mt == null) {
+                    mt = at;
+                } else {
+                    mt = ReferencingFactoryFinder.getMathTransformFactory(null).createConcatenatedTransform(
+                            mt, at);
+                }
 
-	public Map getRendererHints() {
-		return rendererHints;
-	}
+                // dbfheader must be set so that the attributes required for theming can be read in.
+                ShapefileDataStore ds = (ShapefileDataStore) currLayer.getFeatureSource().getDataStore();
 
-	public void setContext(MapContext context) {
-		if (context == null) {
-			context = new DefaultMapContext(DefaultGeographicCRS.WGS84);
-		}
+                // graphics.setTransform(transform);
+                // extract the feature type stylers from the style object
+                // and process them
 
-		this.context = context;
+                Transaction transaction = Transaction.AUTO_COMMIT;
 
-		final MapLayer[] layers = context.getLayers();
-		layerIndexInfo = new IndexInfo[layers.length];
+                if (currLayer.getFeatureSource() instanceof FeatureStore) {
+                    transaction = ((FeatureStore<SimpleFeatureType, SimpleFeature>) currLayer.getFeatureSource()).getTransaction();
+                }
 
-		for (int i = 0; i < layers.length; i++) {
-			final DataStore ds = layers[i].getFeatureSource().getDataStore();
+                DefaultQuery query = new DefaultQuery(currLayer.getQuery());
+                if( query.getFilter() !=null ){
+                    // now reproject the geometries in filter because geoms are retrieved projected to screen space
+                    FilterTransformer transformer= new  FilterTransformer(mt);
+                    Filter transformedFilter = (Filter) query.getFilter().accept(transformer, null);
+                    query.setFilter(transformedFilter);
+                }
+                
+                // by processing the filter we can further restrict the maximum bounds that are
+                // required.  For example if a filter 
+                //BoundsExtractor extractor=new BoundsExtractor(bbox);
+                //if( query.getFilter()!=null )
+                //    query.getFilter().accept(extractor);
+                //
+                //processStylers(graphics, ds, query, extractor.getIntersection(), paintArea,
+                //        mt, currLayer.getStyle(), layerIndexInfo[i], transaction);
+                processStylers(graphics, ds, query, bbox, paintArea,
+                        mt, currLayer.getStyle(), layerIndexInfo[i], transaction, ""+i);
+            } catch (Exception exception) {
+                fireErrorEvent(new Exception("Exception rendering layer " + currLayer, exception));
+            }
 
-			if (ds instanceof ShapefileDataStore) {
-				/**
-				 * Here is the HACK:
-				 */
-				if (layers[i].getQuery() != null
-						&& layers[i].getQuery().getFilter() instanceof FeatureOperationTreeFilter) {
-					layerIndexInfo[i] = STREAMING_RENDERER_INFO;
-					logGt
-							.info("Fallback to StreamingRenderer because Filter is instanceof FeatureOperationTreeFilter!");
-				} else {
+            labelCache.endLayer(""+i, graphics, paintArea);
+        }
 
-					final ShapefileDataStore sds = (ShapefileDataStore) ds;
-
-					try {
-						layerIndexInfo[i] = useIndex(sds);
-					} catch (final Exception e) {
-						layerIndexInfo[i] = new IndexInfo(IndexInfo.TREE_NONE,
-								null, null);
-						logGt.fine("Exception while trying to use index"
-								+ e.getLocalizedMessage());
-					}
-				}
-			} else {
-				layerIndexInfo[i] = STREAMING_RENDERER_INFO;
-			}
-		}
-	}
-
-	public void paint(final Graphics2D graphics, final Rectangle paintArea,
-			final AffineTransform worldToScreen) {
-		if (worldToScreen == null || paintArea == null) {
-			logGt.info("renderer passed null arguments");
-			return;
-		} // Other arguments get checked later
-		// First, create the bbox in real world coordinates
-		ReferencedEnvelope mapArea;
-		try {
-			mapArea = RendererUtilities.createMapEnvelope(paintArea,
-					worldToScreen, getContext().getCoordinateReferenceSystem());
-			paint(graphics, paintArea, mapArea, worldToScreen);
-		} catch (final NoninvertibleTransformException e) {
-			fireErrorEvent(new Exception(
-					"Can't create pixel to world transform", e));
-		}
-	}
-
-	public void paint(final Graphics2D graphics, final Rectangle paintArea,
-			final ReferencedEnvelope envelope, AffineTransform transform) {
-
-		if (hints != null) {
-			graphics.setRenderingHints(hints);
-		}
-
-		if ((graphics == null) || (paintArea == null)) {
-			logGt.info("renderer passed null arguments");
-
-			return;
-		}
-
-		// reset the abort flag
-		renderingStopRequested = false;
-
-		if (logGt.isLoggable(Level.FINE)) {
-			logGt.fine("Affine Transform is " + transform);
-		}
-
-		/*
-		 * If we are rendering to a component which has already set up some form
-		 * of transformation then we can concatenate our transformation to it.
-		 * An example of this is the ZoomPane component of the swinggui module.
-		 */
-		if (concatTransforms) {
-			final AffineTransform atg = graphics.getTransform();
-
-			// graphics.setTransform(new AffineTransform());
-			atg.concatenate(transform);
-			transform = atg;
-		}
-
-		try {
-			setScaleDenominator(computeScale(envelope, context
-					.getCoordinateReferenceSystem(), paintArea,
-					this.rendererHints));
-		} catch (final Exception e) // probably either (1) no CRS (2) error xforming
-		{
-			logGt
-					.throwing(
-							"RendererUtilities",
-							"calculateScale(envelope, coordinateReferenceSystem, imageWidth, imageHeight, hints)",
-							e);
-			setScaleDenominator(1 / transform.getScaleX()); // DJB old method -
-			// the best we can
-			// do
-		}
-
-		final MapLayer[] layers = context.getLayers();
-
-		// get detstination CRS
-		final CoordinateReferenceSystem destinationCrs = context
-				.getCoordinateReferenceSystem();
-		labelCache.start();
-		labelCache.clear();
-		if (labelCache instanceof LabelCacheDefault) {
-			final boolean outlineEnabled = TEXT_RENDERING_OUTLINE
-					.equals(getTextRenderingMethod());
-			((LabelCacheDefault) labelCache)
-					.setOutlineRenderingEnabled(outlineEnabled);
-		}
-		for (int i = 0; i < layers.length; i++) {
-			final MapLayer currLayer = layers[i];
-
-			if (!currLayer.isVisible()) {
-				// Only render layer when layer is visible
-				continue;
-			}
-
-			if (renderingStopRequested) {
-				return;
-			}
-
-			if (layerIndexInfo[i] == STREAMING_RENDERER_INFO) {
-				renderWithStreamingRenderer(currLayer, graphics, paintArea,
-						envelope, transform);
-				continue;
-			}
-			labelCache.startLayer("" + i);
-
-			ReferencedEnvelope bbox = envelope;
-
-			try {
-				final GeometryAttributeType geom = currLayer.getFeatureSource()
-						.getSchema().getDefaultGeometry();
-
-				CoordinateReferenceSystem dataCRS;
-				if (getForceCRSHint() == null)
-					dataCRS = geom.getCoordinateSystem();
-				else
-					dataCRS = getForceCRSHint();
-
-				MathTransform mt;
-				CoordinateOperation op;
-
-				try {
-					op = CRS.getCoordinateOperationFactory(true)
-							.createOperation(dataCRS, destinationCrs);
-					mt = op.getMathTransform();
-					bbox = bbox.transform(dataCRS, true, 10);
-				} catch (final Exception e) {
-					fireErrorEvent(e);
-					logGt
-							.log(
-									Level.WARNING,
-									"Could not reproject the bounding boxes, proceeding in non reprojecting mode",
-									e);
-					op = null;
-					mt = null;
-				}
-
-				final MathTransform at = ReferencingFactoryFinder
-						.getMathTransformFactory(null).createAffineTransform(
-								new GeneralMatrix(transform));
-
-				if (mt == null) {
-					mt = at;
-				} else {
-					mt = ReferencingFactoryFinder.getMathTransformFactory(null)
-							.createConcatenatedTransform(mt, at);
-				}
-
-				// dbfheader must be set so that the attributes required for
-				// theming can be read in.
-				final ShapefileDataStore ds = (ShapefileDataStore) currLayer
-						.getFeatureSource().getDataStore();
-
-				// graphics.setTransform(transform);
-				// extract the feature type stylers from the style object
-				// and process them
-
-				Transaction transaction = Transaction.AUTO_COMMIT;
-
-				if (currLayer.getFeatureSource() instanceof FeatureStore) {
-					transaction = ((FeatureStore) currLayer.getFeatureSource())
-							.getTransaction();
-				}
-
-				final DefaultQuery query = new DefaultQuery(currLayer.getQuery());
-				if (query.getFilter() != null) {
-					// now reproject the geometries in filter because geoms are
-					// retrieved projected to screen space
-					final FilterTransformer transformer = new FilterTransformer(
-							dataCRS, destinationCrs, mt);
-					query.setFilter((Filter) query.getFilter().accept(
-							transformer, null));
-				}
-
-				// by processing the filter we can further restrict the maximum
-				// bounds that are
-				// required. For example if a filter
-				// BoundsExtractor extractor=new BoundsExtractor(bbox);
-				// if( query.getFilter()!=null )
-				// query.getFilter().accept(extractor);
-				//
-				// processStylers(graphics, ds, query,
-				// extractor.getIntersection(), paintArea,
-				// mt, currLayer.getStyle(), layerIndexInfo[i], transaction);
-				processStylers(graphics, ds, query, bbox, paintArea, mt,
-						currLayer.getStyle(), layerIndexInfo[i], transaction,
-						"" + i);
-			} catch (final Exception exception) {
-				fireErrorEvent(new Exception("Exception rendering layer "
-						+ currLayer, exception));
-			}
-
-			labelCache.endLayer("" + i, graphics, paintArea);
-		}
-
-		labelCache.end(graphics, paintArea);
-		logGt.fine("Style cache hit ratio: " + styleFactory.getHitRatio()
-				+ " , hits " + styleFactory.getHits() + ", requests "
-				+ styleFactory.getRequests());
-	}
-
-	/**
-	 * Returns the text rendering method
-	 */
-	private String getTextRenderingMethod() {
-		if (rendererHints == null)
-			return textRenderingModeDEFAULT;
-		final String result = (String) rendererHints.get(TEXT_RENDERING_KEY);
-		if (result == null)
-			return textRenderingModeDEFAULT;
-		return result;
-	}
-
-	/**
-	 * <p>
-	 * Returns scale computation algorithm to be used.
-	 * </p>
-	 */
-	private String getScaleComputationMethod() {
-		if (rendererHints == null)
-			return scaleComputationMethodDEFAULT;
-		final String result = (String) rendererHints
-				.get(SCALE_COMPUTATION_METHOD_KEY);
-		if (result == null)
-			return scaleComputationMethodDEFAULT;
-		return result;
-	}
-
-	private double computeScale(final ReferencedEnvelope envelope,
-			final CoordinateReferenceSystem crs, final Rectangle paintArea, final Map hints) {
-		if (getScaleComputationMethod().equals(SCALE_ACCURATE)) {
-			try {
-				return RendererUtilities.calculateScale(envelope,
-						paintArea.width, paintArea.height, hints);
-			} catch (final Exception e) // probably either (1) no CRS (2) error
-			// xforming
-			{
-				logGt.log(Level.WARNING, e.getLocalizedMessage(), e);
-			}
-		}
-		return RendererUtilities.calculateOGCScale(envelope, paintArea.width,
-				hints);
-	}
-
-	private void renderWithStreamingRenderer(final MapLayer layer,
-			final Graphics2D graphics, final Rectangle paintArea,
-			final ReferencedEnvelope envelope, final AffineTransform transform) {
+        labelCache.end(graphics, paintArea);
+        if(LOGGER.isLoggable(Level.FINE))
+            LOGGER.fine("Style cache hit ratio: " + styleFactory.getHitRatio() + " , hits "
+                + styleFactory.getHits() + ", requests " + styleFactory.getRequests());
+    }
+    
+    /**
+     * Returns the text rendering method
+     */
+    private String getTextRenderingMethod() {
+        if (rendererHints == null)
+            return textRenderingModeDEFAULT;
+        String result = (String) rendererHints.get(TEXT_RENDERING_KEY);
+        if (result == null)
+            return textRenderingModeDEFAULT;
+        return result;
+    }
+    
+    /**
+     * <p>
+     * Returns scale computation algorithm to be used. 
+     * </p>
+     */
+    private String getScaleComputationMethod() {
+        if (rendererHints == null)
+            return scaleComputationMethodDEFAULT;
+        String result = (String) rendererHints.get(SCALE_COMPUTATION_METHOD_KEY);
+        if (result == null)
+            return scaleComputationMethodDEFAULT;
+        return result;
+    }
+    
+    private double computeScale(ReferencedEnvelope envelope, CoordinateReferenceSystem crs, Rectangle paintArea,
+            AffineTransform worldToScreen, Map hints) {
+        if(getScaleComputationMethod().equals(SCALE_ACCURATE)) {
+            try {
+               return RendererUtilities.calculateScale(envelope, paintArea.width, paintArea.height, hints);
+            } catch (Exception e) // probably either (1) no CRS (2) error xforming
+            {
+                LOGGER.log(Level.WARNING, e.getLocalizedMessage(), e);
+            }
+        } 
+        if (XAffineTransform.getRotation(worldToScreen) != 0.0) {
+            return RendererUtilities.calculateOGCScaleAffine(envelope.getCoordinateReferenceSystem(),
+                    worldToScreen, hints);
+        } 
+        return RendererUtilities.calculateOGCScale(envelope, paintArea.width, hints);
+    }
+    
+    private void renderWithStreamingRenderer(MapLayer layer, Graphics2D graphics, Rectangle paintArea, ReferencedEnvelope envelope, AffineTransform transform) {
 		MapContext context = null;
+		RenderListener listener = null;;
 		try {
-			context = new DefaultMapContext(new MapLayer[] { layer }, envelope
-					.getCoordinateReferenceSystem());
-			final StreamingRenderer renderer = new StreamingRenderer();
-			renderer.setContext(context);
-			renderer.setJava2DHints(getJava2DHints());
-			final Map rendererHints2 = new HashMap(
-					getRendererHints() != null ? getRendererHints()
-							: Collections.EMPTY_MAP);
-			rendererHints2.put(LABEL_CACHE_KEY, new IntegratingLabelCache(
-					labelCache));
-			renderer.setRendererHints(rendererHints2);
-			renderer.paint(graphics, paintArea, envelope, transform);
+		    context = new DefaultMapContext(new MapLayer[]{layer}, envelope.getCoordinateReferenceSystem());
+    		delegate = new StreamingRenderer();
+    		delegate.setContext(context);
+    		delegate.setJava2DHints(getJava2DHints());
+    		Map rendererHints2 = new HashMap(getRendererHints() != null ? getRendererHints() : Collections.EMPTY_MAP);
+    		rendererHints2.put(LABEL_CACHE_KEY, new IntegratingLabelCache(labelCache));
+    		delegate.setRendererHints(rendererHints2);
+    		
+    		// cascade events, provided there is anyone listening
+    		listener = new RenderListener() {
+            
+                public void featureRenderer(SimpleFeature feature) {
+                    fireFeatureRenderedEvent(feature);
+                }
+            
+                public void errorOccurred(Exception e) {
+                    fireErrorEvent(e);
+                }
+            };
+            delegate.addRenderListener(listener);
+    		
+    		delegate.paint(graphics, paintArea, envelope, transform);
 		} finally {
-			if (context != null)
-				context.clearLayerList();
+		    // cleanups to avoid circular references
+		    if(context != null)
+		        context.clearLayerList();
+		    if(listener != null && delegate != null)
+		        delegate.removeRenderListener(listener);
+		 
+		    
+		    delegate = null;
 		}
 	}
 
 	/**
-	 * If the forceCRS hint is set then return the value.
-	 * 
-	 * @return the value of the forceCRS hint or null
-	 */
-	private CoordinateReferenceSystem getForceCRSHint() {
-		if (rendererHints == null)
-			return null;
-		final Object crs = this.rendererHints.get("forceCRS");
-		if (crs instanceof CoordinateReferenceSystem)
-			return (CoordinateReferenceSystem) crs;
-
-		return null;
+     * If the forceCRS hint is set then return the value.
+     * @return the value of the forceCRS hint or null
+     */
+    private CoordinateReferenceSystem getForceCRSHint() {
+    	if ( rendererHints==null )
+    		return null;
+    	Object crs=this.rendererHints.get("forceCRS");
+    	if( crs instanceof CoordinateReferenceSystem )
+    		return (CoordinateReferenceSystem) crs;
+    	
+    	return null;
 	}
 
-	/**
-	 * @deprecated
-	 */
-	public void paint(final Graphics2D graphics, final Rectangle paintArea, final Envelope mapArea) {
-		paint(graphics, paintArea, new ReferencedEnvelope(mapArea, context
-				.getCoordinateReferenceSystem()));
-	}
+    /**
+     * @deprecated
+     */
+    public void paint(Graphics2D graphics, Rectangle paintArea, Envelope mapArea) {
+        paint(graphics, paintArea, new ReferencedEnvelope(mapArea, context.getCoordinateReferenceSystem()));
+    }
 
-	/**
-	 * @deprecated
-	 */
-	public void paint(final Graphics2D graphics, final Rectangle paintArea,
-			final Envelope mapArea, final AffineTransform worldToScreen) {
-		paint(graphics, paintArea, new ReferencedEnvelope(mapArea, context
-				.getCoordinateReferenceSystem()), worldToScreen);
-	}
+    /**
+     * @deprecated
+     */
+    public void paint(Graphics2D graphics, Rectangle paintArea, Envelope mapArea, AffineTransform worldToScreen) {
+        paint(graphics, paintArea, new ReferencedEnvelope(mapArea, context.getCoordinateReferenceSystem()), worldToScreen);
+    }
 }

Modified: branches/1.0-gt2-2.6/src/schmitzm/geotools/FilterUtil.java
===================================================================
--- branches/1.0-gt2-2.6/src/schmitzm/geotools/FilterUtil.java	2009-08-28 10:45:01 UTC (rev 339)
+++ branches/1.0-gt2-2.6/src/schmitzm/geotools/FilterUtil.java	2009-08-28 11:13:50 UTC (rev 340)
@@ -38,30 +38,39 @@
 
 import com.vividsolutions.jts.geom.GeometryFactory;
 
-
 /**
  * Diese Klasse enthaelt statische Helper-Methoden fuer die Arbeit mit
  * {@link Filter}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
  * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * 
  * @version 1.01
  * 
  */
 public class FilterUtil {
-  /** Instanz von {@link FilterFactory}. */
-  public static final FilterFactory FILTER_FAC  = CommonFactoryFinder.getFilterFactory(null);
-  /** Globale Instanz von {@link FilterFactory2} **/
-  public static final FilterFactory2 FILTER_FAC2 = CommonFactoryFinder.getFilterFactory2(null);
-  /** Instanz von {@link GeometryFactory}. */
-  public static final GeometryFactory   GEOMETRY_FAC = new GeometryFactory();
-
-  /**
-   * Erzeugt eine Kopie eines Filters
-   * @param filter ein Filter
-   */
-  public static Filter cloneFilter(Filter filter) {
-	DuplicatingFilterVisitor dfv = new DuplicatingFilterVisitor(FILTER_FAC2);
-    Filter newFilter = (Filter) dfv.visit( filter , (Object)null );
-    return newFilter;
-  }
+	/** Instanz von {@link FilterFactory}. */
+	public static final FilterFactoryImpl FILTER_FAC = (FilterFactoryImpl) CommonFactoryFinder
+			.getFilterFactory(null);
+	/** Globale Instanz von {@link FilterFactory2} **/
+	public static final FilterFactory2 FILTER_FAC2 = CommonFactoryFinder
+			.getFilterFactory2(null);
+	/** Instanz von {@link GeometryFactory}. */
+	public static final GeometryFactory GEOMETRY_FAC = new GeometryFactory();
+//
+//	/**
+//	 * Erzeugt eine Kopie eines Filters
+//	 * 
+//	 * @param filter
+//	 *            ein Filter
+//	 * 
+//	 *            TODO GT 26 Das wird in Atlas und Schmitzm nichtbenötig. Wir
+//	 *            können die Methode als theoretisch einfach mal entfernen..
+//	 *            Ansonsten habe ich auch eine Mail auf die gt-user geschickt.
+//	 */
+//	public static Filter cloneFilter(Filter filter) {
+//		DuplicatingFilterVisitor dfv = new DuplicatingFilterVisitor(FILTER_FAC2);
+//		Filter newFilter = (Filter) dfv.visit(filter, (Object) null);
+//		return newFilter;
+//	}
 }

Modified: branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java
===================================================================
--- branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java	2009-08-28 10:45:01 UTC (rev 339)
+++ branches/1.0-gt2-2.6/src/schmitzm/geotools/gui/JMapPane.java	2009-08-28 11:13:50 UTC (rev 340)
@@ -91,6 +91,7 @@
 import org.opengis.feature.simple.SimpleFeatureType;
 import org.opengis.feature.type.GeometryDescriptor;
 import org.opengis.filter.Filter;
+import org.opengis.filter.FilterFactory;
 import org.opengis.filter.expression.Expression;
 import org.opengis.filter.spatial.BinarySpatialOperator;
 import org.opengis.parameter.GeneralParameterValue;
@@ -408,7 +409,7 @@
                                                                                                }
                                                                                              };
 
-  private static final FilterFactoryImpl                           ff                        = FilterUtil.FILTER_FAC;
+  private static final FilterFactory                           ff                        = FilterUtil.FILTER_FAC;
   private static final GeometryFactory                             gf                        = FilterUtil.GEOMETRY_FAC;
 
   /**
@@ -2598,7 +2599,7 @@
         filter = prepareFilter(fsCRS);
         filterCache.put(fsCRS, filter);
       }
-      Expression geometry = ff.createAttributeExpression(geomDescr
+      Expression geometry = ff.property(geomDescr
           .getLocalName());
       filter.setExpression1(geometry);
       return filter;
@@ -2739,11 +2740,13 @@
       }
       // Filter fuer Point zusammenstellen
       final Geometry geometry = FilterUtil.GEOMETRY_FAC.createPoint(nearPoint);
+      
       final DWithinImpl dwithinFilter = (DWithinImpl) FilterUtil.FILTER_FAC
           .createGeometryDistanceFilter(DWithinImpl.GEOMETRY_DWITHIN);
       dwithinFilter.setDistance(nearDist);
       dwithinFilter.setExpression2(FilterUtil.FILTER_FAC
           .createLiteralExpression(geometry));
+      
 
       return dwithinFilter;
     }



More information about the Schmitzm-commits mailing list