I wrote a small java class to extract country boundaries from naturalearthdata.com data. My problem is that the coordinates do not match with OSM map, the whole polygon is shifted... e.g. according to the data extracted, the most southern point of Czech Rep. is


and here it is displayed on openstreetmap, about 1km far away from what I expect:


If I understand well, OSM uses wgs84, naturalearth uses wgs84 so I don't need to do any transform ? Is there something that I am missing?

Here is the class:

    import java.io.File;
    import java.io.IOException;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    import javax.imageio.ImageIO;

    import org.apache.log4j.Logger;
    import org.geotools.data.FeatureSource;
    import org.geotools.data.shapefile.ShapefileDataStore;
    import org.geotools.feature.FeatureCollection;
    import org.geotools.feature.GeometryAttributeImpl;
    import org.geotools.geometry.jts.JTS;
    import org.geotools.geometry.jts.JTSFactoryFinder;
    import org.geotools.referencing.CRS;
    import org.geotools.referencing.crs.DefaultGeocentricCRS;
    import org.geotools.referencing.crs.DefaultGeographicCRS;
    import org.opengis.feature.Feature;
    import org.opengis.feature.Property;
    import org.opengis.geometry.MismatchedDimensionException;
    import org.opengis.referencing.FactoryException;
    import org.opengis.referencing.crs.CoordinateReferenceSystem;
    import org.opengis.referencing.operation.MathTransform;
    import org.opengis.referencing.operation.TransformException;

    import com.vividsolutions.jts.geom.Coordinate;
    import com.vividsolutions.jts.geom.CoordinateSequence;
    import com.vividsolutions.jts.geom.Geometry;
    import com.vividsolutions.jts.geom.GeometryFactory;
    import com.vividsolutions.jts.geom.LineString;
    import com.vividsolutions.jts.geom.MultiPolygon;
    import com.vividsolutions.jts.geom.Point;
    import com.vividsolutions.jts.geom.Polygon;
    import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;

    public class Converter {
        static Logger logger = Logger.getLogger(Converter.class);

        static void extract(Feature feature,String iso2) throws Exception{
             logger.info("extract "+iso2);

             GeometryAttributeImpl geometry=(GeometryAttributeImpl)feature.getProperty("the_geom");
             MultiPolygon multiPolygon=(MultiPolygon)geometry.getValue();

             for(int i=0;i<multiPolygon.getNumGeometries();i++){
                  Polygon polygon=(Polygon) multiPolygon.getGeometryN(i);

                  LineString lineString=polygon.getExteriorRing();
                  logger.info("points: "+lineString.getCoordinates().length);

                  System.out.println("points for "+iso2+"-"+i);

                  Coordinate min=lineString.getCoordinates()[0];
                  for(Coordinate coordinate:lineString.getCoordinates()){
                      if (coordinate.y<min.y)


        static void extract(String shapefile,String nameAttr,String nameMatch) throws Exception{
              ShapefileDataStore ds = new ShapefileDataStore(new URL("file://"+shapefile));
              FeatureSource fs = ds.getFeatureSource();
              FeatureCollection fc = fs.getFeatures();

              logger.info("features found:"+fc.size());
              Iterator iterator = fc.iterator();

              while (iterator.hasNext()) {
                  // Extract feature and geometry
                  Feature feature = (Feature) iterator.next();

                 Property propertyName=feature.getProperty(nameAttr);
                 if (propertyName==null){
                     logger.error("property "+nameAttr+" not found. valid properties are:");
                     for(Property property:feature.getProperties()){
                          logger.info("  "+property.getName());  


                 String name=((String)feature.getProperty(nameAttr).getValue());
                 logger.info("found "+nameAttr+"="+name);
                 if (nameMatch.equalsIgnoreCase(name) || name==null)


        static void showProperty(Feature feature,String what) {
            Property propertyNameName=feature.getProperty(what);
             if (propertyNameName!=null)
                 logger.info(what+" not set");

        public static void main(String ... args) throws Exception{


  • For future reference, I ended up using data from here: hiu.state.gov/data/data.aspx (Detailed World Polygons (LSIB) - Eurasia/Africa - March 2013). The precision is good enough for my purposes, less than 100m difference from OSM
    – user34804
    Commented Jul 22, 2014 at 13:34

1 Answer 1


There are several issues here:

  1. OSM uses web mercator (epsg:3857) so that is where your reprojection is going on.
  2. Also you need to consider scale - the Natural Earth data is designed to be viewed and used at near to 1:10Million - at that scale your map looks like this and the dot is in the right place.

map at 1:10M

Finally your code can be improved by using a filter in the request -

FeatureCollection fc = fs.getFeatures(CQL.toFilter(nameAttr + " = '" + nameMatch + "'")); 

to save fetching the whole file each time.

  • Here is an image that shows that the boundaries are shifted west <img src="i57.tinypic.com/vgn4u9.png">
    – user34804
    Commented Jul 21, 2014 at 11:11
  • exactly - the natural Earth borders aren't designed to line up with OSM. You should extract from OSM if you want to map at that scale.
    – Ian Turton
    Commented Jul 21, 2014 at 11:13
  • this is not a projection issue it is a scale issue.
    – Ian Turton
    Commented Jul 21, 2014 at 11:19
  • Ok, thanks I will try to grab the boundaries from OSM data then
    – user34804
    Commented Jul 21, 2014 at 11:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.