Hey all,
I'd like to be able to display countries.shp in a Mercator projection. I
think I've created a correct ProjectionCRS but jmappane bails during the
first repaint. The critical issue is that the data go to the poles where
the Mercator is undefined. I thought that
context's areaOfInterest
was the critical element to limit the data to a valid range. The file
attached bails in the first rendering pass.
So who is responsible: me, the jmappane, the renderer, the reprojection
system?
Gerardus Mercator (March 5, 1512 – December 2, 1594)
Geotools at ten years old can't handle this?
--adrian
/*
* GeoTools - OpenSource mapping toolkit
* http://geotools.org
* (C) 2006, GeoTools Project Managment Committee (PMC)
* (C) 2006, Adrian Custer, assigned to the PMC.
*
* This file is hereby placed into the Public Domain. This means anyone is
* free to do whatever they wish with this file. Use it well and enjoy!
*/
package org.geotools.demo.introduction;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JToolBar;
import javax.swing.WindowConstants;
import javax.units.SI;
import org.geotools.TestData;
import org.geotools.data.FeatureSource;
import org.geotools.data.memory.MemoryDataStore;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.demo.mappane.MapViewer;
import org.geotools.feature.AttributeType;
import org.geotools.feature.AttributeTypeFactory;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureTypes;
import org.geotools.feature.GeometryAttributeType;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.SchemaException;
import org.geotools.gui.swing.JMapPane;
import org.geotools.gui.swing.PanAction;
import org.geotools.gui.swing.ResetAction;
import org.geotools.gui.swing.SelectAction;
import org.geotools.gui.swing.ZoomInAction;
import org.geotools.gui.swing.ZoomOutAction;
import org.geotools.map.DefaultMapContext;
import org.geotools.map.MapContext;
import org.geotools.referencing.CRS;
import org.geotools.referencing.FactoryFinder;
import org.geotools.referencing.factory.FactoryGroup;
import org.geotools.referencing.operation.DefaultMathTransformFactory;
import org.geotools.referencing.operation.DefiningConversion;
import org.geotools.renderer.GTRenderer;
import org.geotools.renderer.lite.StreamingRenderer;
import org.geotools.styling.Graphic;
import org.geotools.styling.Mark;
import org.geotools.styling.SLDParser;
import org.geotools.styling.Style;
import org.geotools.styling.StyleBuilder;
import org.geotools.styling.StyleFactory;
import org.geotools.styling.StyleFactoryFinder;
import org.geotools.styling.Symbolizer;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.IdentifiedObject;
import org.opengis.referencing.NoSuchIdentifierException;
import org.opengis.referencing.ReferenceSystem;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CSFactory;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.CoordinateSystemAxis;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
/**
* The QuickStart class, through its main() method, is a quick introductory
* tutorial to each of the major modules of the Geotools library.
*
* WARNING: This is a work in progress and is incomplete.
*
* WARNING: The code is presented as a long sequential series of steps to
* ensure easy legibility instead of seeking programming elegance. The
* code, apart from main(), will run in the order of the methods in the
* file; it can therefore be read from top to bottom.
*
* This tutorial shows the following elements:
*
* (1) FeatureSource creation:
* This creates, through several approaches, the handles which are
* used later for the manipulation of data.
*
* 1.1 - a feature source from scratch
* 1.2 - a feature source from a shapefile
* 1.3 - a feature source from a WMS/WFS (an image)
*
* (.) Catalog creation:
* This creates a resource through which to handle all the features
* used by a complex application.
*
* (.) Coordinate Transform creation:
* This creates a coordinate operation and uses that to transform the
* data in a feature source to a different Coordinate Referencing
* System.
*
* (.) Query creation:
* This creates a Filter/Expression to query a feature for its
* contents and thereby to subset a feature.
*
* ...
*
* (5) Style creation:
* This creates the graphical elements which are used to display
* the data.
*
* (6) Display:
* This creates a GUI MapViewerto display the data.
*
* (7) Image output:
* This renders an image to an image buffer and then dumps the image
* buffer to a file.
*
* ...
*
*
*
* HISTORY:
* This class regroups work from many different tutorials.
* Section 1.1 - "Feature from scratch" was inspired by earlier tutorials.
* Section 1.2 - "Feature from shapefile" was in Ian's MapViewer class.
*
* Section 5 - The style demo came from an email by Tom Howe on user-list.
* Section 6 - The GUI was inspired by Ian Turton's MapViewer demo.
* Section 7 - MakeImage with email advice from David Adler, Aaron B. Parks.
*
* @author Adrian Custer
* @version 0.01
* @since 2.2RC5
*
*/
public class QuickStart {
/* The handles for the ShapeFile and Styled Layer Descriptor (SLD) files. */
/* This is a little confusing due to the use of 3 possible sources of */
/* data, either from the introduction, the mappane or the testdata jars */
/* Use by uncommenting, for *one single* CASE:, the three lines below */
// TODO: Ensure these can be discovered at runtime
static final int DATA_FROM_MAPVIEWER = 1;
static final int DATA_FROM_SAMPLEDATA = 2;
static final int DATA_FROM_INTRODUCTION = 3;
/* CASE: Data from JMapPane, get via Class.getResource() */
static final int dataSource = DATA_FROM_MAPVIEWER;
static final String shpName = "/data/countries.shp";//in mappane
static final String sldName = "/data/countries.sld";//in mappane
/* CASE: Data from TestData, get using TestData.method() for url, file, ... */
// static final int dataSource = DATA_FROM_TESTDATA;
// static final String shpName = "/org/geotools/test-data/shapes/statepop.shp";
// static final String sldName = "/org/geotools/test-data/shapes/statepop.sld";//WARNING: does not exist
/* CASE: Data from File, get using direct reference */
// static final int dataSource = DATA_FROM_INTRODUCTION;
// static final String shpName = "data/world/countries.shp";
// static final String sldName = "data/world/countries.sld";
static File shpFile;
static URL shpURL;
static File sldFile;
static URL sldURL;
// The name of the website.
static final URL webUrl = null;
// The filename for the output image.
static final String imageFileEnd = "image.png";
// FeatureSource variables
static FeatureSource memFS, shpFS, webFS;
// StyledLayerDescriptor variables
static Style memStyl;
static Style shpStyl;
static Style webStyl;
// DataLayer variables
// Cartographic variables
static final Envelope e = new Envelope(-170.0,170.0,-80.0,80.0);
static CoordinateReferenceSystem projCRS = null;
//GUI frame, pane and extras
static JFrame frame;
static JMapPane jmp;
static JToolBar jtb;
static JLabel text;
//Display elements
static MapContext context;
static GTRenderer renderer;
static com.vividsolutions.jts.geom.Envelope worldbounds;
/*
* Create London from scratch! Well, only a FeatureSource for the city.
*
* Create:
* (1) The Geometry
* (2) The CoordinateReferenceSystem
* (3) The Feature starting with AttributeTypes to make the FeatureType
* (4) The MemoryDataStore to get a FeatureSource
*/
public static void createFeatureSourceFromScratch(){
/*
* Make a Geometry using the JTS library
*
* see the Geometry Tutorial for more detail
*/
// Create a com.vividsolutions.jts.geom.Coordinate for a point
// Wikipedia gives London as: 51° 30.4167′ N 0° 7.65′ W
// Gt 2.2 coordinate order is Long/Lat throughout; in 2.3 the CRS rules
Coordinate ptc = new Coordinate(0.1275d,51.507d);
// Create a com.vividsolutions.jts.geom.GeometryFactory
GeometryFactory geomFac = new GeometryFactory();
// Use the factory to make the jts geometries
Point ptG = geomFac.createPoint(ptc);
/*
* Get a CoordinateReferenceSystem
*
* see the Geopositioning Tutorial for more detail
*/
// Grab a premade CRS
CoordinateReferenceSystem ptCRS =
org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;
/*
* Create the Feature
*
* see the Feature Tutorial for more detail
*
* (1) Create the AttributeTypes
* (2) Create the FeatureType
* (3) Create the Feature
*/
//Create the AttributeTypes, starting with the GeometryAttributeType
Class cls = ptG.getClass();
GeometryAttributeType ptGA =
(GeometryAttributeType) AttributeTypeFactory.newAttributeType(
"the_geom", cls, true, 1, null,ptCRS);
AttributeType cityAT =
AttributeTypeFactory.newAttributeType(
"CITYNAME", String.class, true, 48, null);
AttributeType popAT =
AttributeTypeFactory.newAttributeType(
"CITYPOP", Integer.class, true, 48, null);
// Create the FeatureType
AttributeType[] ptATs = new AttributeType[3];
ptATs[0] = ptGA;
ptATs[1] = cityAT;
ptATs[2] = popAT;
org.geotools.feature.FeatureType ptFT = null;
try{
ptFT = FeatureTypes.newFeatureType(ptATs, "Metropolis");
} catch (SchemaException sex){
System.out.println("SchemaException on FeatureType creation: "+sex);
}
// Create the Feature
Object [] ptElems = { ptG, "London", new Integer(7500000)};
org.geotools.feature.Feature ptF = null;
try {
ptF = ptFT.create(ptElems);
} catch (IllegalAttributeException iaex){
System.out.println("IllegalAttributeException on Feature creation: " + iaex);
}
/*
* Create the DataStore and get its FeatureSource
*
* see the DataStore Tutorial for more details
*/
Feature [] ptFetArray = new Feature [] {ptF};
MemoryDataStore memds = new MemoryDataStore();
memds.addFeatures(ptFetArray);
try {
memFS = memds.getFeatureSource("Metropolis");
} catch (IOException ioex) {
System.out.println("IOException on memoryDataStore creation: "+ ioex);
}
}
/*
* Use a Shapefile!
*
* Create a FeatureSource from a Shapefile format file.
*/
public static void createFeatureSourceFromShapefile(){
/* Switch on the source uncommented in the intial declarations */
switch (dataSource){
case DATA_FROM_MAPVIEWER:
shpURL = JMapPane.class.getResource(shpName);
break;
case DATA_FROM_SAMPLEDATA:
try{
shpURL = TestData.url(shpName);
} catch (FileNotFoundException fnfex){
System.out.println("FileNotFoundException on use of TestData.url()"+fnfex);
}
break;
case DATA_FROM_INTRODUCTION:
shpFile = new File(shpName);
try {
shpURL = shpFile.toURL();
} catch (MalformedURLException muex){
System.out.println("MalformedUrlException for shapefile name: "+ muex);
}
break;
}
try {
ShapefileDataStore ds = new ShapefileDataStore(shpURL);
try {
shpFS = ds.getFeatureSource();
}
catch (IOException ioex){
System.out.println("IOException on shapefile read: "+ioex);
}
} catch (MalformedURLException muex){
System.out.println("MalformedUrlException for shpDataStore: "+ muex);
}
}
// TODO:
/*
* Create a FeatureSource from a web resource.
*/
public static void createFeatureSourceFromWeb(){
}
/*
* Create a Mercator ProjectedCRS from Scratch.
*/
public static void createProjectedCRSfromScratch(){
//Make a Merator projectedCRS for the display.
// TODO: move to createProjectedCRSFromScratch().
//Trying to make Mercator
DefaultMathTransformFactory mtf = new DefaultMathTransformFactory();
ParameterValueGroup pvg = null;
try {
pvg = mtf.getDefaultParameters("Mercator_1SP");
} catch (NoSuchIdentifierException nsiex){
System.err.println("On DefaultPrameterGroup creation: "+ nsiex.getMessage());
}
//Start Test Output
// ParameterDescriptorGroup dg = pvg.getDescriptor()
// for (GeneralParameterDescriptor descriptor : dg.descriptors()) {
// System.out.println(descriptor.getName().getCode());
// }
//End Test Output
DefiningConversion dc = new DefiningConversion("A mercator",pvg);
Map props = new HashMap();
props.put(IdentifiedObject.NAME_KEY, "My arbitrary name"); // Mandatory
// props.put(ReferenceSystem.VALID_AREA_KEY,e); // Optional
// Create a collection of axes for the coordinate system.
Map map = new HashMap();
CSFactory csFactory = FactoryFinder.getCSFactory(null);
CoordinateSystemAxis xAxis = null;
CoordinateSystemAxis yAxis = null;
CartesianCS worldCS = null;
try {
map.clear();
map.put("name", "Cartesian X axis");
xAxis = csFactory.createCoordinateSystemAxis(map, "X", AxisDirection.EAST, SI.METER);
map.clear();
map.put("name", "Cartesian Y axis");
yAxis = csFactory.createCoordinateSystemAxis(map, "Y", AxisDirection.NORTH, SI.METER);
map.clear();
map.put("name", "Cartesian CS");
worldCS = csFactory.createCartesianCS(map, xAxis, yAxis);
} catch (FactoryException fex) {
System.err.println("On cartesianCS creation: " + fex.getMessage());
}
// CoordinateReferenceSystem projCRS = null;
FactoryGroup fg = new FactoryGroup(null);
try{
projCRS = fg.createProjectedCRS(props,
org.geotools.referencing.crs.DefaultGeographicCRS.WGS84,
dc,
worldCS);
} catch (FactoryException fex) {
System.err.println("On projectedCRS creation: " + fex.getMessage());
}
// System.out.println(projCRS.toWKT());
// An older attempt
// CRSFactory crsFactory = FactoryFinder.getCRSFactory(null);
// String wkt = "PROJCS[\"Mercator Attempt\", "
// + "GEOGCS[\"WGS84\", "
// + "DATUM[\"WGS84\", "
// + "SPHEROID[\"WGS84\", 6378137.0, 298.257223563]], "
// + "PRIMEM[\"Greenwich\", 0.0], "
// + "UNIT[\"degree\",0.017453292519943295], "
// + "AXIS[\"Longitude\",EAST], "
// + "AXIS[\"Latitude\",NORTH]], "
// + "PROJECTION[\"Mercator_1SP\"], "
// + "PARAMETER[\"semi_major\", 6378137.0], "
// + "PARAMETER[\"semi_minor\", 6356752.314245179], "
// + "PARAMETER[\"central_meridian\", 0.0], "
// + "PARAMETER[\"scale_factor\", 1.0], "
// + "PARAMETER[\"false_easting\", 0.0], "
// + "PARAMETER[\"false_northing\", 0.0], "
// + "UNIT[\"metre\",1.0], "
// + "AXIS[\"x\",EAST], "
// + "AXIS[\"y\",NORTH]]";
// CoordinateReferenceSystem prjCRS=null;
// try{
// prjCRS = crsFactory.createFromWKT(wkt);
// } catch (FactoryException fe){
// System.err.println("On prjCRS creation a FactoryException :"+fe.getMessage());
// }
// Envelope e = new Envelope(-170.0,170.0,-80.0,80.0);
// context.setAreaOfInterest(e, prjCRS);
}
/*
* Create the styles that will be used for the creation of the MapLayers.
*/
public static void createStyles(){
// Make a simple point style, uses a StyleBuilder
StyleBuilder builder = new StyleBuilder();
Mark mark = builder.createMark("circle", Color.RED);
Graphic g = builder.createGraphic(null,mark,null);
Symbolizer s = builder.createPointSymbolizer(g);
memStyl = builder.createStyle(s);
// Make the sldURL from the sldName
/* Switch on the source uncommented in the intial declarations */
switch (dataSource){
case DATA_FROM_MAPVIEWER:
sldURL = MapViewer.class.getResource(sldName);
break;
case DATA_FROM_SAMPLEDATA:
try{
sldURL = TestData.url(sldName);
} catch (FileNotFoundException fnfex){
System.out.println("FileNotFoundException on use of TestData.url()"+fnfex);
}
break;
case DATA_FROM_INTRODUCTION:
sldFile = new File(sldName);
try {
sldURL = sldFile.toURL();
} catch (MalformedURLException muex){
System.out.println("MalformedUrlException for shapefile name: "+ muex);
}
break;
}
// Create the shapefile Style, uses StyleFactory and an SLD URL.
StyleFactory sf = StyleFactoryFinder.createStyleFactory();
SLDParser stylereader = null;
try {
stylereader = new SLDParser(sf,sldURL);
} catch (IOException ioex){
System.out.println("IOException on SLDfile read: " + ioex);
}
org.geotools.styling.Style[] shpStylArr = stylereader.readXML();
shpStyl = shpStylArr[0];
}
/*
* Create a GUI map displayer.
*
* This is all Swing stuff for the JMapPane.
*
*/
public static void initGUI(){
frame=new JFrame("My Map Viewer");
// frame.setBounds(20,20,500,310);
frame.setBounds(20,20,1080,600);
frame.setBackground(Color.cyan);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Container content = frame.getContentPane();
content.setBackground(Color.magenta);
content.setLayout(new BorderLayout());
// content.setLayout(new GridLayout(1,2 ));
// jmpp = new JMapPane();
jmp = new JMapPane();
jmp.setBackground(Color.white);
// jmp.setSize(20,100);
//jmp.addZoomChangeListener(this);
/* TODO: Fix this TOOLBAR STUFF BELOW: */
content.setLayout(new BorderLayout());
jtb = new JToolBar();
Action zoomIn = new ZoomInAction(jmp);
Action zoomOut = new ZoomOutAction(jmp);
Action pan = new PanAction(jmp);
Action select = new SelectAction(jmp);
Action reset = new ResetAction(jmp);
jtb.add(zoomIn);
jtb.add(zoomOut);
jtb.add(pan);
jtb.addSeparator();
jtb.add(reset);
jtb.addSeparator();
jtb.add(select);
final JButton button= new JButton();
button.setText("CRS");
button.setToolTipText("Change map prjection");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String code = JOptionPane.showInputDialog( button, "Coordinate Reference System:", "EPSG:4326" );
try{
CoordinateReferenceSystem crs = CRS.decode( code );
jmp.getContext().setAreaOfInterest(jmp.getContext().getAreaOfInterest(),crs);
jmp.setReset(true);
jmp.repaint();
}
catch(FactoryException fe){
JOptionPane.showMessageDialog( button, fe.getMessage(), fe.getClass().toString(), JOptionPane.ERROR_MESSAGE );
return;
}
}
});
jtb.add(button);
content.add(jtb,BorderLayout.NORTH);
/* TOOLBAR STUFF ABOVE */
content.add(jmp,BorderLayout.CENTER);
// content.add(jmp);
content.doLayout();
frame.setVisible(true);
}
/*
* Display features onto the screen.
*
* This is a very crude example, showing only how do display a map. The
* core class, JMapPane, also has a toolbar which is not shown here. See
* the demo/gui for more details.
*/
public static void loadGUI()throws Exception{
//Setup the context and renderer within the jmappane
context = new DefaultMapContext(); //WGS84 by default //TODO: make mercator
context.setAreaOfInterest(e, projCRS);
renderer = new StreamingRenderer();
jmp.setRenderer(renderer);
jmp.setContext(context);
//Add the data directly to the context (which makes the MapLayers)
context.addLayer(memFS,memStyl);
context.addLayer(shpFS,shpStyl);
// context.addLayer(webFS,webStyl);
//Set boundary to all that's visible
// jmp.setMapArea(context.getLayerBounds());
jmp.setMapArea(e);
jmp.setHighlightLayer(context.getLayer(0));
// jmp.setSize(200,600);
frame.repaint();
frame.doLayout();
// Thread.sleep(5000);
// jmp.setSize(200,600);
// frame.repaint();
// frame.doLayout();
}
/*
* Make graphical image files, one from scratch and the other from the
* jmappane contents.
* TODO: add to catalog---great for pre/post transform comparisons
* TODO: clean this up, isolate resolution and size
*
*/
public static void makeImages(){
/*
* 1. Create an image from scratch
*/
//Size of the final image, will be too big for the input
int w = 1800;
int h = 800;
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, w, h);
//TODO: HACK HACK HACK need a real pixel to world transform
AffineTransform trsf = new AffineTransform(new double[]{1.0,1.0,1.0,1.0});
// DefaultMathTransformFactory dmtf = new DefaultMathTransformFactory();
// try{
// trsf = dmtf.createAffineTransform(new Matrix2(1,1,1,1));
// } catch (Exception e){
// ;
// }
// transform =
// renderer.worldToScreenTransform(
// g,
// new Rectangle(0, 0, w, h),
// worldbounds);
renderer.paint(g, new Rectangle(0, 0, w, h), trsf);
try{
ImageIO.write(image, "png", new File("workspace/gtdemo-new-"+imageFileEnd));
} catch (IOException ioex) {
System.err.println("IO Exception on image file write: "+ ioex);
}
g.dispose();
/*
* 2. Create an image from the jmappane contents
*/
//spit the image out to a file
int ww = jmp.getWidth()+40;
int hh = jmp.getHeight()+40;
BufferedImage imageOut = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = imageOut.createGraphics();
g2.setColor(Color.gray);
g2.fillRect(0, 0, ww, hh);
jmp.paint(g2);
try{
ImageIO.write(imageOut, "png", new File("workspace/gtdemo-jmp-"+imageFileEnd));
} catch (IOException ioex) {
System.err.println("IO Exception on image file write: "+ ioex);
}
g2.dispose();
}
/**
* This is main() the only real function in this QuickStart tutorial.
* The class works sequentially through every step
* @param args
*/
public static void main(String[] args) throws Exception {
System.out.println("QuickStart: Tutorial Start...");
System.out.println("\tStart: Create FeatureSource from scratch.");
createFeatureSourceFromScratch();
System.out.println("\t End: Created FeatureSource from scratch.");
System.out.println("\tStart: Create FeatureSource from shapefile.");
createFeatureSourceFromShapefile();
System.out.println("\t End: Created FeatureSource from shapefile.");
System.out.println("\tStart: Create FeatureSource from web server.");
createFeatureSourceFromWeb();
System.out.println("\t End: Created FeatureSource from web server.");
System.out.println("\tStart: Create the Styled Layer Descriptors.");
createStyles();
System.out.println("\t End: Created the Styled Layer Descriptors.");
System.out.println("\tStart: Create ProjectedCRS from scratch.");
createProjectedCRSfromScratch();
System.out.println("\t End: Created ProjectedCRS from scratch.");
System.out.println("\tStart: Initialize the GUI.");
initGUI();
System.out.println("\t End: Initialized the GUI.");
System.out.println("\tStart: Load the map.");
loadGUI();
System.out.println("\t End: Loaded the map.");
// System.out.println("\tStart: Make an image.");
// makeImages();
// System.out.println("\t End: Made the image.");
System.out.println("QuickStart: Tutorial End.");
}
}
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Geotools-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/geotools-devel