/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2009, Johann Sorel * * 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.geotoolkit.display2d.ext.grid; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.Polygon; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.util.ArrayList; import java.util.List; import org.geotoolkit.display.axis.Graduation; import org.geotoolkit.display.axis.NumberGraduation; import org.geotoolkit.display.axis.TickIterator; import org.geotoolkit.display2d.GO2Utilities; import org.geotoolkit.display2d.canvas.RenderingContext2D; import org.geotoolkit.display2d.container.stateless.StatelessContextParams; import org.geotoolkit.display2d.style.labeling.DefaultLabelLayer; import org.geotoolkit.display2d.style.labeling.DefaultLinearLabelDescriptor; import org.geotoolkit.display2d.style.labeling.LabelLayer; import org.geotoolkit.display2d.style.labeling.LabelRenderer; import org.geotoolkit.display2d.style.labeling.LinearLabelDescriptor; import org.apache.sis.geometry.GeneralEnvelope; import org.geotoolkit.display.shape.TransformedShape; import org.geotoolkit.display2d.primitive.ProjectedGeometry; import org.geotoolkit.geometry.jts.JTS; import org.apache.sis.referencing.CRS; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.apache.sis.geometry.Envelopes; /** * Utility class to render grid on J2DCanvas. * * @author Johann Sorel (Geomatys) * @module */ public class J2DGridUtilities { private static final double MIN = 1e-6; private J2DGridUtilities() { } public static void paint(final RenderingContext2D context, final GridTemplate template){ CoordinateReferenceSystem gridCRS = template.getCRS(); //use context crs if gridcrs is not defined if(gridCRS == null) gridCRS = context.getObjectiveCRS(); final Graphics2D g = context.getGraphics(); context.switchToDisplayCRS(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setComposite(GO2Utilities.ALPHA_COMPOSITE_1F); //calculate the cliping zone for texts final float xTextOffset = template.getXTextOffset(); final float yTextOffset = template.getYTextOffset(); final Rectangle clip = new Rectangle(context.getCanvasDisplayBounds()); clip.x += xTextOffset; clip.height -= yTextOffset; final Shape shp = new TransformedShape(clip, context.getDisplayToObjective()); final List<Coordinate> coords = new ArrayList<Coordinate>(); final PathIterator ite = shp.getPathIterator(new AffineTransform()); final double[] vals = new double[3]; while(!ite.isDone()){ ite.currentSegment(vals); coords.add( new Coordinate(vals[0],vals[1])); ite.next(); } final GeometryFactory fact = new GeometryFactory(); final LinearRing ring = fact.createLinearRing(coords.toArray(new Coordinate[coords.size()])); final Polygon bounds = fact.createPolygon(ring, new LinearRing[0]); final LabelRenderer renderer = context.getLabelRenderer(true); final LabelLayer layer = new DefaultLabelLayer(false, true); final RenderingHints tickHint = new RenderingHints(null); tickHint.put(Graduation.VISUAL_AXIS_LENGTH, context.getCanvasDisplayBounds().width); tickHint.put(Graduation.VISUAL_TICK_SPACING, 200); //number of point by line final int nbPoint = 20; final CoordinateReferenceSystem objectiveCRS = context.getObjectiveCRS2D(); try{ //reduce grid bounds to validity area Envelope gridBounds = Envelopes.transform(context.getCanvasObjectiveBounds2D(), gridCRS); if(Math.abs(gridBounds.getSpan(0)) < MIN || Math.abs(gridBounds.getSpan(1)) < MIN ){ return; } Envelope validity = org.geotoolkit.referencing.CRS.getEnvelope(gridCRS); if(validity != null){ GeneralEnvelope env = new GeneralEnvelope(gridBounds); env.intersect(validity); gridBounds = env; } final MathTransform gridToObj = CRS.findOperation(gridCRS, objectiveCRS, null).getMathTransform(); final MathTransform objToGrid = gridToObj.inverse(); //grid on X axis --------------------------------------------------- final NumberGraduation graduationX = new NumberGraduation(null); graduationX.setRange(gridBounds.getMinimum(0), gridBounds.getMaximum(0), gridBounds.getCoordinateReferenceSystem().getCoordinateSystem().getAxis(0).getUnit()); TickIterator tickIte = graduationX.getTickIterator(tickHint, null); while(!tickIte.isDone()){ tickIte.next(); final String label = tickIte.currentLabel(); final double d = tickIte.currentPosition(); if(d>gridBounds.getMaximum(0))continue; final ArrayList<Coordinate> lineCoords = new ArrayList<Coordinate>(); final double maxY = gridBounds.getMaximum(1); final double step = gridBounds.getSpan(1)/nbPoint; for(double k=Math.nextUp(gridBounds.getMinimum(1)); k<maxY; k+=step){ lineCoords.add(new Coordinate(d, k)); } lineCoords.add(new Coordinate(d, Math.nextAfter(maxY,Double.NEGATIVE_INFINITY))); Geometry geom = fact.createLineString(lineCoords.toArray(new Coordinate[lineCoords.size()])); if(geom == null) continue; final StatelessContextParams params = new StatelessContextParams(null, null); final ProjectedGeometry pg = new ProjectedGeometry(params); params.update(context); pg.setDataGeometry(geom, gridCRS); //draw line if(tickIte.isMajorTick()){ g.setPaint(template.getMainLinePaint()); g.setStroke(template.getMainLineStroke()); }else{ g.setPaint(template.getLinePaint()); g.setStroke(template.getLineStroke()); } for(Shape ds : pg.getDisplayShape()) g.draw(ds); //clip geometry to avoid text outside visible area geom = JTS.transform(geom, gridToObj); if(geom == null) continue; geom = geom.intersection(bounds); pg.setDataGeometry(geom, objectiveCRS); //draw text final LinearLabelDescriptor desc; if(tickIte.isMajorTick()){ desc = new DefaultLinearLabelDescriptor( label, template.getMainLabelFont(), template.getMainLabelPaint(), template.getMainHaloWidth(), template.getMainHaloPaint(), 0, 10, 3, false, false, false, pg); }else{ desc = new DefaultLinearLabelDescriptor( label, template.getLabelFont(), template.getLabelPaint(), template.getHaloWidth(), template.getHaloPaint(), 0, 10, 3, false, false, false, pg); } layer.labels().add(desc); } //grid on Y axis --------------------------------------------------- final NumberGraduation graduationY = new NumberGraduation(null); graduationY.setRange(gridBounds.getMinimum(1), gridBounds.getMaximum(1), gridBounds.getCoordinateReferenceSystem().getCoordinateSystem().getAxis(1).getUnit()); tickIte = graduationY.getTickIterator(tickHint, null); while(!tickIte.isDone()){ tickIte.next(); final String label = tickIte.currentLabel(); final double d = tickIte.currentPosition(); if(d>gridBounds.getMaximum(1))continue; final ArrayList<Coordinate> lineCoords = new ArrayList<Coordinate>(); final double maxX = gridBounds.getMaximum(0); final double step = gridBounds.getSpan(0)/nbPoint; for(double k= Math.nextUp(gridBounds.getMinimum(0)); k<maxX; k+=step){ lineCoords.add(new Coordinate(k, d)); } lineCoords.add(new Coordinate(Math.nextAfter(maxX,Double.NEGATIVE_INFINITY), d)); Geometry geom = fact.createLineString(lineCoords.toArray(new Coordinate[lineCoords.size()])); final StatelessContextParams params = new StatelessContextParams(null, null); final ProjectedGeometry pg = new ProjectedGeometry(params); params.update(context); pg.setDataGeometry(geom, gridCRS); //draw line if(tickIte.isMajorTick()){ g.setPaint(template.getMainLinePaint()); g.setStroke(template.getMainLineStroke()); }else{ g.setPaint(template.getLinePaint()); g.setStroke(template.getLineStroke()); } for(Shape ds : pg.getDisplayShape()) g.draw(ds); //clip geometry to avoid text outside visible area geom = JTS.transform(geom, gridToObj); if(geom == null) continue; geom = geom.intersection(bounds); pg.setDataGeometry(geom, objectiveCRS); //draw text final LinearLabelDescriptor desc; if(tickIte.isMajorTick()){ desc = new DefaultLinearLabelDescriptor( label, template.getMainLabelFont(), template.getMainLabelPaint(), template.getMainHaloWidth(), template.getMainHaloPaint(), 0, 10, 3, false, false, false, pg); }else{ desc = new DefaultLinearLabelDescriptor( label, template.getLabelFont(), template.getLabelPaint(), template.getHaloWidth(), template.getHaloPaint(), 0, 10, 3, false, false, false, pg); } layer.labels().add(desc); } }catch(Exception ex){ ex.printStackTrace(); } renderer.portrayImmidiately(layer); } }