1

I want to plot a line which connects 2 points on a map.

The code I am using:

public class Quickstart {


    public static void main(String[] args) throws Exception {
        // display a data store file chooser dialog for shapefiles
        File file = JFileDataStoreChooser.showOpenFile("shp", null);
        if (file == null) {
            return;
        }

      FileDataStore store = FileDataStoreFinder.getDataStore(file);
      SimpleFeatureSource featureSource = store.getFeatureSource();

      GeometryFactory gf = JTSFactoryFinder.getGeometryFactory();

      // ask for current and destination positions
      double latitude, longitude, latitudeDest, longitudeDest;
      Scanner reader = new Scanner(System.in);
      reader.useLocale(Locale.US);
      System.out.println("Enter reference longitude and latitude:\n");
      longitude = reader.nextDouble();
      latitude = reader.nextDouble();
      System.out.println("Enter destination longitude and latitude:\n");
      longitudeDest = reader.nextDouble();
      latitudeDest = reader.nextDouble();
      reader.close();

        final String EPSG4326 = "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\"," +
                "\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\", " + 
                "0.01745329251994328,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]";

        CoordinateReferenceSystem crs = CRS.parseWKT(EPSG4326);        


        Point start = gf.createPoint(new Coordinate(longitude, latitude));
        Point end = gf.createPoint(new Coordinate(longitudeDest, latitudeDest));

        GeodeticCalculator gc = new GeodeticCalculator(crs);
        gc.setStartingPosition(JTS.toDirectPosition(start.getCoordinate(), crs));
        gc.setDestinationPosition(JTS.toDirectPosition(end.getCoordinate(), crs));

        // Calculate distance between points
        double distance = gc.getOrthodromicDistance();

        int totalmeters = (int) distance;
        int km = totalmeters / 1000;
        int meters = totalmeters - (km * 1000);
        float remaining_cm = (float) (distance - totalmeters) * 10000;
        remaining_cm = Math.round(remaining_cm);
        float cm = remaining_cm / 100;

        System.out.println("Distance = " + km + "km " + meters + "m " + cm + "cm");

        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        builder.setName("TwoDistancesType");
        builder.setCRS(DefaultGeographicCRS.WGS84);
        builder.add("location", Point.class);

        // build the type
        final SimpleFeatureType TYPE = builder.buildFeatureType();

        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);
        featureBuilder.add(start);
        //featureBuilder.add(end);

        SimpleFeature feature = featureBuilder.buildFeature(null);
        DefaultFeatureCollection featureCollection = new DefaultFeatureCollection("internal", TYPE);
        featureCollection.add(feature);

        Style style = SLD.createSimpleStyle(TYPE, Color.red);
        Layer layer = new FeatureLayer(featureCollection, style);

        // Create a map content and add our shapefile to it
        MapContent map = new MapContent();
        map.setTitle("TEST");

        map.addLayer(layer);

        // Now display the map
        JMapFrame.showMap(map);


    }

}

I have 2 problems:

1) I can't add a second feature to featureBuilder.It doesn't allow it.It shows Can handle 1 attributes only, index is 1.

So, how can I plot a line then?

2) With the above code, I am receiving:

org.geotools.renderer.lite.StreamingRenderer fireErrorEvent SEVERE: The scale denominator must be positive
java.lang.IllegalArgumentException: The scale denominator must be positive

------- UPDATE ------------------------

After the solution that @Michael gave for the first question , now I no longer receive the error regarding the denominator, but I am receiving an empty map (white space).

----- UPDATE according to @iant suggestion ----------------

So, I tried this.Created a coordinates which holds the coordinates of the points (start and end) ,then created a linestring with those coordinates and added it to featurebuilder.

        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        builder.setName("TwoDistancesType");
        builder.setCRS(DefaultGeographicCRS.WGS84);

        builder.add("line", LineString.class); //added a linestring class


        final SimpleFeatureType TYPE = builder.buildFeatureType();

        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        Coordinate[] coordinates = {start.getCoordinate(), end.getCoordinate()};       
        LineString line = gf.createLineString(coordinates);
        featureBuilder.add(line);

and even though I am loading a map (countries.shp) it shows me an empty white space with a red line.

------ SOLUTION -------------

Ok, so the solution is (thanks to @iants comments):

Style style = SLD.createLineStyle(Color.red, 2.0f); Layer layer = new FeatureLayer(featureCollection, style);

// Create style for the file
Style shpStyle = SLD.createSimpleStyle(TYPE, Color.blue);
Layer shpLayer = new FeatureLayer(featureSource, shpStyle);

// Create a map content and add our shapefile to it
MapContent map = new MapContent();
map.setTitle("TEST");
map.addLayer(layer);
map.addLayer(shpLayer);

and now you have a red line on a blue map!

George
  • 5,808
  • 15
  • 83
  • 160

2 Answers2

2

Disclaimer: I've never used geotools.

Looking at the source code of SimpleFeatureBuilder, add calls set which throws that error if:

if(index >= values.length)
    throw new ArrayIndexOutOfBoundsException("Can handle "
    + values.length + " attributes only, index is " + index);

values is populated here:

values = new Object[featureType.getAttributeCount()];

so it's obvious that that problem is because your Type only has one property. Change it so it has two:

SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName("TwoDistancesType");
builder.setCRS(DefaultGeographicCRS.WGS84);
builder.add("start", Point.class);
builder.add("end",   Point.class);
Michael
  • 41,989
  • 11
  • 82
  • 128
  • Regarding your second problem, you need to tell us which line that occurs on. Post the full stack trace. – Michael Jul 20 '17 at 12:34
  • Ok, thanks!I missed that.Now, that I have added 2 classes to builder, it no longer gives me the second message.But, it just shows me an empty map (white space).Note, that I want to plot a line which connects the 2 points. (upvoted) – George Jul 20 '17 at 12:45
  • The problem is coming out of the renderer. I wonder whether you need to set a viewport... Try replacing your map with `MapContext map = new DefaultMapContext();` It's deprecated but it'd be good to see if that changes anything – Michael Jul 20 '17 at 12:49
  • `DefaultMapContext();` is depreciated.In geotools quickstart it uses `new MapContent();` and it runs fine (it shows the map).It doesn't change anything though.. – George Jul 20 '17 at 12:52
  • Yes, I know. Hm, the quickstarts I read were using Context but fair enough. The way I would debug this is to remove as much code as possible and gradually reintroduce it until you get the error. Start with a map with no layers, and gradually add the rest back in. – Michael Jul 20 '17 at 12:54
  • If I change `Layer layer = new FeatureLayer(featureCollection, style);` to this `Layer layer = new FeatureLayer(featureSource, style);`, it shows me the map but everything (the whole borders of world) is red.So, something is with the layer. – George Jul 20 '17 at 12:55
2

You need to create a LineString from your points and then store that in your feature.

You should then get a correct scale but you might want to add some other data such as a coast line to the map first. The quick start tutorial can show you how to do that.

Ian Turton
  • 10,018
  • 1
  • 28
  • 47
  • :Hmm, right!I did that but I am receiving an empty map(white) with a red line on it (I updated my post regarding the code).Thanks! – George Jul 21 '17 at 06:47
  • I can't see where you add the country layer to the map. – Ian Turton Jul 21 '17 at 07:11
  • :`File file = JFileDataStoreChooser.showOpenFile("shp", null);`.Herem I am opening the `countries.shp` when I run the application.Like the Quickstart.And then ` Layer layer = new FeatureLayer(featureCollection, style);`, and `map.addLayer(layer);`. – George Jul 21 '17 at 07:12
  • You need a country layer and a line layer, then you can give them different styles to distinguish them – Ian Turton Jul 21 '17 at 07:18
  • OK, can you please provide me an example?How can I create a country layer?And what kind of style?`createSimpleStyle`? `createLineStyle`?And how to add both to the map?Thank you. – George Jul 21 '17 at 07:21
  • I'm on my phone just now, but I can post some code later – Ian Turton Jul 21 '17 at 07:37
  • Ok, I figured!I have some questions though..If you can help [here](https://stackoverflow.com/questions/45235244/show-direction-of-linestring-on-map-auto-zoom-on-map).(upvoted!) – George Jul 21 '17 at 10:27