Categorized under: Technical Stuff, Tutorials

Using Open Street Maps in your Netbeans Application

Currently we’re working on the module to support outside plant management in Kuwaiba, so it’s necessary to integrate GIS capabilities into the system. The general architecture would include the following components:

GIS views support: general architecture

GIS views support: general architecture

The new blocks are the tile caching server and the map provider. The bare maps are extracted from the latter and the tiles are cached into the former. The business specific layers  such as pipelines, conduits, poles, distribution frames or cabinets are requested to the webservice interface, which returns an XML document describing the coordinates of those elements as well as other complementary information (labels, areas, etc).

In the present tutorial I will show you a way to place maps on your Netbeans Platform application and to put layers over those maps using the Visual Library.

Requirements

The How-to

JXMapviewer is a component included in the SwingX library (a set of components to extend the Swing API). It’s a subclass of JComponent and can be embedded into any Java Desktop application. It offers many features such as showing waypoints and rendering layers over a map. Having said that, you have to wonder why using the Visual Library if you can do almost everything with JXMapViewer, but the answer is pretty simple: The Visual Library lets you interact naturally with the vector elements in a GIS scenario. This is, you can put nodes and edges over the map and play with lookups and property sheets (for example) or add actions flawlessly to these elements. Accomplishing  this with only JXMapViewer and Java 2D API is significantly harder. The sources for this tutorial can be downloaded  from here.

  1. Download the SwingX core jar from here.
  2. The SwingX-ws binaries seem to be gone, so you can build them by yourself. Just get a subversion client and checkout the code
    svn checkout https://svn.java.net/svn/swingx-ws~svn/trunk
    Create a project from existing sources, pointing to the code you just downloaded (File->New Project->Java->Java project with Existing Sources). Expand the tree and right click on the “Libraries” node. Select “Add JAR/Folder”. Select the jar you downloaded in the previous step. Now you should be ready to compile the project. The resulting binary will be located within the “dist” directory, inside the project folder.
  3. Create a Netbeans Plaform Project (File->New Project->Netbeans Modules->Netbeans Platform Application)
  4. Create a module. In our case, it will be called “MainModule”

    Creating a new module

    Creating a new module

  5. Add a new TopComponent to your module (Right click on the module -> New -> Window) Select the “editor” window mode. Note: Make sure you set its layout to BorderLayout (Thanks, Javier!)

    New TopComponent

  6. Enable de Visual Library. For this, Right click on the MapsProject project, select libraries, scroll down to “platform”, expand that node and check “Visual Libray”

    Enabling the Visual Library

  7. Add the SwingX jars. For this, right click on the MainModule module, select “Properties” and then “Libraries”. Go to the “Wrapped JARs” tab and by pressing the “Add JAR” button, add the libraries obtained through the steps 1 and 2.

    Adding the SwingX libraries

  8. Add the Visual Libray API to the module dependencies:

    Visual Library as module depedency

  9. Now we’re ready to code. What we’re going to do is to add a scene  and put three layers on it: One to contain the map, another to contain the routes and another to hold the  nodes. We will also set a custom overlay painter so the route coordinates are recalculated every time. Take into account that is required to translate the geographic position (polar) to Cartesian coordinates within the scene viewport. It’s important to point out that the ComponentWidget containing the map size can’t match the container size using a layout, so we have to do it manually and that’s what the updateBounds() method is for. Let’s take a look at the scene constructor:

    ...
    //The layers
    mapLayer = new LayerWidget(this);
    routesLayer = new LayerWidget(this);
    nodesLayer = new LayerWidget(this);
    addChild(mapLayer);
    addChild(routesLayer);
    addChild(nodesLayer);
    //The map. We use JXMapKit instead of JXMapViewer because the kit includes the zoom slider, a satellite view and
    //and a JXMapViewer
    myMap = new JXMapKit();
    myMap.setDefaultProvider(JXMapKit.DefaultProviders.OpenStreetMaps);
    myMap.setCenterPosition(mapCenter);
    myMap.getMainMap().setZoom(2);
    mapWidget = new ComponentWidget(this, myMap);
    mapLayer.addChild(mapWidget);//The nodes
    icnw1 = (IconNodeWidget)addNode(“widget1″);
    icnw2 = (IconNodeWidget)addNode(“widget2″);
    icnw1.setImage(ImageUtilities.loadImage(GENERIC_ICON_PATH));
    icnw2.setImage(ImageUtilities.loadImage(GENERIC_ICON_PATH));//The route
    conWidget = (ConnectionWidget)addEdge(“con1″);
    conWidget.setControlPointShape(PointShape.SQUARE_FILLED_BIG);
    conWidget.setLineColor(Color.RED);
    conWidget.setStroke(new BasicStroke(2));myMap.getMainMap().setOverlayPainter(new Painter() {

    @Override
    public void paint(Graphics2D gd, Object t, int i, int i1) {
    Rectangle realViewport = myMap.getMainMap().getViewportBounds();
    Point2D endpointA2D = myMap.getMainMap().getTileFactory().geoToPixel(endpointA, myMap.getMainMap().getZoom());
    Point2D endpointB2D = myMap.getMainMap().getTileFactory().geoToPixel(endpointB, myMap.getMainMap().getZoom());
    icnw1.setPreferredLocation(new Point((int)endpointA2D.getX()-realViewport.x – ICON_RADIUS,(int)endpointA2D.getY()-realViewport.y – ICON_RADIUS));
    icnw2.setPreferredLocation(new Point((int)endpointB2D.getX()-realViewport.x – ICON_RADIUS,(int)endpointB2D.getY()-realViewport.y – ICON_RADIUS));
    List<Point> controlPoints2D = new ArrayList<Point>();
    controlPoints2D.add(new Point((int)endpointA2D.getX()-realViewport.x,(int)endpointA2D.getY()-realViewport.y));
    for (GeoPosition controlPoint : controPoints){
    Point2D controlPoint2D = myMap.getMainMap().getTileFactory().geoToPixel(controlPoint, myMap.getMainMap().getZoom());
    controlPoints2D.add(new Point((int)controlPoint2D.getX()-realViewport.x,(int)controlPoint2D.getY()-realViewport.y ));
    }

    controlPoints2D.add(new Point((int)endpointB2D.getX()-realViewport.x,(int)endpointB2D.getY()-realViewport.y));

    //For some reason, it’s necessary to set the anchors everytime. It’s a rendering issue
    setAnchors();
    conWidget.setControlPoints(controlPoints2D, true);
    validate();
    }
    });

    //If this is not done, an IllegalStateException will be raised when reositioning the conection widget
    routesLayer.bringToFront();
    nodesLayer.bringToFront();

  10. Now we put some code to the TopComponent to include the scene. We have to override the paint(Graphics g) method to update the map bounds.  Let’s take a look at the TopComponent constructor:

    ...
    initComponents();
    setName(NbBundle.getMessage(GISTopComponent.class, "CTL_GISTopComponent"));
    setToolTipText(NbBundle.getMessage(GISTopComponent.class, "HINT_GISTopComponent"));
    myScene = new MapScene();
    add(myScene.createView());
    myScene.updateBounds();
    ...
  11. Click on the image to enlarge.

Result

Note: You need a working internet connection in order to run the project flawlessly. Otherwise you’ll get and UnknownHostException.

Download the code here.

References

Comments

  1. Great tutorial. I was wondering why it didn’t work when I tried creating the project from scratch. After some hours it turned out to be that the layout of the component needs to be set to BorderLayout or the map won’t show.

    avatar
    Javier Ortiz
    August 8th, 2012
  2. Oh, yeah. I didn’t think it was worth to mention, but I’ll add it to the post. Otherwise, you should specify the size of the scene (the JComponent returned by the call to createView, actually) and use a null layout or something like that. I’m glad you found it useful, I’ll complement it in the next weeks :D

  3. Thanks for a nice tutorial,
    However I don’t know why I cant select or move the widget icone? Please help!

    avatar
    Lee
    November 28th, 2012
  4. No, you can’t select the widget with this version, however we’ve been working on the actual version for Kuwaiba wich lets you connect widgets, move them,select them and make the Property Sheet sensible to such selection. You can find the code here[1]. It still has some rough edges mainly due to the coordinates translation, but might be of help. If you need a cleaner code, just drop me a mail to charles.bedon at neotropic dot co and I’ll prepare a small project for you to get started :)
    [1] http://kuwaiba.svn.sourceforge.net/viewvc/kuwaiba/client/trunk/GISView/src/

    avatar
    Charles Edward Bedon Cortazar
    December 4th, 2012
  5. Many thanks!

    Love to see the solution of how to combine Netbeans Platform Visual-library with swing-x map which is too hard for me.

    avatar
    Lee
    December 5th, 2012


− two = 2