/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (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;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.renderer.shape.shapehandler.simple;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
import org.geotools.data.shapefile.shp.ShapeHandler;
import org.geotools.data.shapefile.shp.ShapeType;
import org.geotools.renderer.ScreenMap;
import org.geotools.renderer.shape.GeometryHandlerUtilities;
import org.geotools.renderer.shape.ShapefileRenderer;
import org.geotools.renderer.shape.SimpleGeometry;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import com.vividsolutions.jts.geom.Envelope;
/**
* A ShapeHandler that reads MultiPoint objects from a file. It returns a
* SimpleGeometry and decimates all points that map to the same screen location.
*
* @author jeichar
* @since 2.1.x
*
* @source $URL$
*/
public class MultiPointHandler implements ShapeHandler {
private ShapeType type;
private Envelope bbox;
private MathTransform mt;
private ScreenMap screenMap;
private double spanx;
private double spany;
Logger LOGGER = ShapefileRenderer.LOGGER;
/**
* Create new instance
*
* @param type
* the type of shape.
* @param env
* the area that is visible. If shape is not in area then skip.
* @param mt
* the transform to go from data to the envelope (and that should
* be used to transform the shape coords)
* @param hasOpacity
*/
public MultiPointHandler(ShapeType type, Envelope env,
Rectangle screenSize, MathTransform mt, boolean hasOpacity)
throws TransformException {
if (mt == null) {
throw new NullPointerException();
}
this.type = type;
this.bbox = env;
this.mt = mt;
screenMap = GeometryHandlerUtilities.calculateScreenSize(screenSize,
hasOpacity);
Point2D span = GeometryHandlerUtilities.calculateSpan(mt, 0, 0);
this.spanx = span.getX();
this.spany = span.getY();
}
/**
* @see org.geotools.data.shapefile.shp.ShapeHandler#getShapeType()
*/
public ShapeType getShapeType() {
return type;
}
/*
* (non-Javadoc)
*
* @see org.geotools.data.shapefile.shp.ShapeHandler#read(java.nio.ByteBuffer,
* org.geotools.data.shapefile.shp.ShapeType)
*/
public Object read(ByteBuffer buffer, ShapeType type, boolean flatGeometry) {
if (type == ShapeType.NULL) {
return null;
}
// read bounding box
Envelope geomBBox = GeometryHandlerUtilities.readBounds(buffer);
if (!bbox.intersects(geomBBox)) {
return null;
}
boolean bboxdecimate = geomBBox.getWidth() <= spanx
&& geomBBox.getHeight() <= spany;
int numParts = buffer.getInt();
double[][] coords = new double[numParts][];
double[][] transformed = new double[numParts][];
// if bbox is less than a pixel then decimate the geometry. But
// orientation must
// remain the same so geometry data must be parsed.
if (bboxdecimate) {
coords = new double[1][];
coords[0] = new double[2];
transformed = new double[1][];
transformed[0] = new double[2];
coords[0][0] = buffer.getDouble();
coords[0][1] = buffer.getDouble();
try {
mt.transform(coords[0], 0, transformed[0], 0, 1);
} catch (Exception e) {
ShapefileRenderer.LOGGER
.severe("could not transform coordinates "
+ e.getLocalizedMessage());
transformed[0] = coords[0];
}
if( screenMap.checkAndSet((int)transformed[0][0], (int)transformed[0][1] ) ){
LOGGER.finest("Point already rendered" + transformed[0][0] + " "
+ transformed[0][1]);
return null;
}
} else {
int partsInBBox = 0;
for (int part = 0; part < numParts; part++) {
coords[part] = new double[2];
coords[part][0] = buffer.getDouble();
coords[part][1] = buffer.getDouble();
if (!bbox.contains(coords[part][0], coords[part][1]))
continue;
if (!mt.isIdentity()) {
try {
transformed[partsInBBox] = new double[2];
mt.transform(coords[part], 0, transformed[partsInBBox],
0, 1);
} catch (Exception e) {
ShapefileRenderer.LOGGER
.severe("could not transform coordinates "
+ e.getLocalizedMessage());
transformed[partsInBBox] = coords[part];
}
} else {
transformed[partsInBBox] = new double[2];
System.arraycopy(coords[part], 0, transformed[partsInBBox],
0, 1);
}
if (!screenMap.get((int) transformed[partsInBBox][0],
(int) transformed[partsInBBox][1]))
partsInBBox++;
}
if (partsInBBox == 0)
return null;
if (partsInBBox != numParts) {
double[][] tmp = new double[partsInBBox][];
System.arraycopy(transformed, 0, tmp, 0, partsInBBox);
transformed = tmp;
}
}
return createGeometry(type, geomBBox, transformed);
}
protected Object createGeometry(ShapeType type, Envelope geomBBox, double[][] transformed) {
return new SimpleGeometry(type, transformed, geomBBox);
}
/**
* @see org.geotools.data.shapefile.shp.ShapeHandler#write(java.nio.ByteBuffer,
* java.lang.Object)
*/
public void write(ByteBuffer buffer, Object geometry) {
// This handler doesnt write
throw new UnsupportedOperationException(
"This handler is only for reading");
}
/**
* @see org.geotools.data.shapefile.shp.ShapeHandler#getLength(java.lang.Object)
*/
public int getLength(Object geometry) {
// TODO Auto-generated method stub
return 0;
}
}