package net.refractions.udig.community.jody.tile;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import net.refractions.udig.catalog.IGeoResource;
import net.refractions.udig.project.internal.render.impl.RendererImpl;
import net.refractions.udig.project.render.IRenderer;
import net.refractions.udig.project.render.RenderException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.event.GTAdapter;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.renderer.lite.GridCoverageRenderer;
import org.geotools.tile.TileMap;
import org.geotools.tile.ZoomLevel;
import org.geotools.tile.cache.TileRange;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import com.vividsolutions.jts.geom.Envelope;
public class DirectTileRenderer extends RendererImpl implements IRenderer {
private Job load; // no longer used
private Set<String> drawn=new HashSet(); // names of drawn grid coverages
public void render( final Graphics2D destination, IProgressMonitor monitor ) throws RenderException {
if( monitor == null ) monitor = new NullProgressMonitor();
monitor.beginTask("Render TileMap", 100);
setState( STARTING );
IGeoResource handle = getContext().getLayer().findGeoResource(TileMap.class);
try {
TileMap tileMap = handle.resolve( TileMap.class, new SubProgressMonitor(monitor,30) );
Envelope bounds = getRenderBounds();
if( bounds == null ) {
ReferencedEnvelope viewbounds = (ReferencedEnvelope) getContext().getViewportModel().getBounds();
if( getContext().getCRS().equals( viewbounds.getCRS())){
bounds = viewbounds;
}
else {
// TODO: reproject
throw new RenderException("Need to aquire a valid request bounds");
}
}
ZoomLevel zero = (ZoomLevel) tileMap.getInfo().getZoomLevels().iterator().next();
final TileRange range = tileMap.getTileRange(bounds, (int) getContext().getViewportModel().getScaleDenominator());
if (range == TileRange.EMPTY ){
setState(DONE);
return;
}
else {
// load
if(range.isLoaded() ){
drawTiles( destination, range, true ); // instant feedback
setState(DONE);
}
else {
drawTiles( destination, range, true ); // instant feedback
setState(RENDERING);
final IProgressMonitor progress = monitor;
range.load( new IProgressMonitor(){
public void beginTask( String name, int totalWork ) {
progress.beginTask(name, totalWork);
}
public void done() {
drawTiles( destination, range, false );
setState(DONE);
}
public void internalWorked( double work ) {
progress.internalWorked( work );
}
public boolean isCanceled() {
return progress.isCanceled();
}
public void setCanceled( boolean value ) {
progress.setCanceled( value );
setState(CANCELLED);
}
public void setTaskName( String name ) {
progress.setTaskName(name);
}
public void subTask( String name ) {
progress.subTask( name );
}
public void worked( int work ) {
drawTiles( destination, range, false );
setState(RENDERING);
progress.worked(work);
}
});
}
}
}
catch(IOException bad){
throw new RenderException( bad );
}
}
/*
public void renderAttempt1( Graphics2D destination, IProgressMonitor monitor ) throws RenderException {
if( monitor == null ) monitor = new NullProgressMonitor();
monitor.beginTask("Render TileMap", 100);
setState( STARTING );
IGeoResource handle = getContext().getLayer().findGeoResource(TileMap.class);
try {
TileMap tileMap = handle.resolve( TileMap.class, new SubProgressMonitor(monitor,30) );
Envelope bounds = getRenderBounds();
if( bounds == null ) {
ReferencedEnvelope viewbounds = (ReferencedEnvelope) getContext().getViewportModel().getBounds();
if( getContext().getCRS().equals( viewbounds.getCRS())){
bounds = viewbounds;
}
else {
// TODO: reproject
throw new RenderException("Need to aquire a valid request bounds");
}
}
final TileRange range = tileMap.getTileRange(bounds, (int) getContext().getViewportModel().getScaleDenominator());
if( tiles != null && tiles.equals( range )){
// we are already loading this one
System.out.println("Already loading "+tiles);
}
else if ( range.isLoaded()){
tiles = range; // we stayed within the cache!
}
else { // we need to load
tiles = range;
if( load != null ){
load.cancel();
load = null;
}
load = new Job("load"){
protected IStatus run( final IProgressMonitor monitor ) {
range.load( new IProgressMonitor(){
public void beginTask( String name, int totalWork ) {
monitor.beginTask(name, totalWork);
}
public void done() {
monitor.done();
setState( RENDERING );
}
public void internalWorked( double work ) {
monitor.internalWorked( work );
}
public boolean isCanceled() {
return monitor.isCanceled();
}
public void setCanceled( boolean value ) {
monitor.setCanceled( value );
}
public void setTaskName( String name ) {
monitor.setTaskName(name);
}
public void subTask( String name ) {
monitor.subTask( name );
}
public void worked( int work ) {
setState( RENDERING );
monitor.worked(work);
}
});
return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS;
}
};
}
drawTiles( destination, tiles );
}
catch (IOException erp ){
throw new RenderException( erp );
}
finally {
setState( DONE );
}
}
*/
private void drawTiles( Graphics2D graphics, TileRange range, boolean all) {
if( range == TileRange.EMPTY ) return;
if( all ) drawn.clear(); // don't skip
//double scale = getContext().getViewportModel().getScaleDenominator();
//if(scale < state.minScale || scale > state.maxScale) return;
float opacity = 1.0f;
CoordinateReferenceSystem crs = getContext().getViewportModel().getCRS();
Composite oldComposite = graphics.getComposite();
AffineTransform graphicsTransform = graphics.getTransform();
for( Iterator i=range.getTiles().iterator(); i.hasNext(); ){
GridCoverage2D coverage = (GridCoverage2D) i.next();
Envelope2D bounds = coverage.getEnvelope2D();
//Point p = getContext().worldToPixel(
//g.fillOval(p.x, p.y, 10, 10);
if( coverage.getRenderedImage().getWidth() == 512 ){
// real image
String name = coverage.getName().toString();
if( drawn.contains( name ) ){
continue; // skip this image as we have drawn it "last" time
}
else {
drawn.add( name ); // mark this one as drawn for next time
}
}
else {
// placeholder!
if( !all ) continue; // skip if this is not the first draw
}
GridCoverageRenderer paint = new GridCoverageRenderer(coverage, crs);
try {
graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
AffineTransform toScreen = getContext().worldToScreenTransform();
AffineTransform transform = new AffineTransform(graphicsTransform);
transform.concatenate(toScreen);
graphics.setTransform( transform );
paint.paint( graphics );
}
catch ( Throwable t ){
if( coverage != null ){
System.out.println("paint tile:"+coverage.getName());
}
t.printStackTrace();
break; // just one for now
}
finally {
graphics.setTransform(graphicsTransform);
}
}
graphics.setComposite(oldComposite);
}
public void render( IProgressMonitor monitor ) throws RenderException {
Graphics2D g2 = (Graphics2D) context.getImage().getGraphics();
render( g2, monitor );
}
}