skip to main content
Programmer's documentation > Programming with JViews Maps > Creating a map application using the API > Using readers
 
Using readers
Describes the predefined readers, the map loader for supported (predefined) formats, and how to write a new reader.
*Code examples for using readers
*Gives an example for each predefined reader.
*The map loader
*Describes the loader for a map in any supported file format.
*Developing a new reader
*Describes how to write a new reader for map data.
*Optimizing the reader
*Describes how to optimize a new reader to improve performance.
Code examples for using readers
For more information on the predefined readers, see Readers and writers.
The Shapefile reader
The complete source code for this example can be found in the following file:
<installdir> /jviews-maps/codefragments/readers/src/ShapeReader.java.
 
/**
* Simple file reader for ESRI shape file format.
* Attributes are read from the dbf file.
*/
  public void loadFile(String shapeFileName, String dbfFileName)
  throws IOException,
         IlvMapRenderException,
         IlvCoordinateTransformationException {
 
    IlvShapeFileReader reader = null;
    // Instantiate a new reader.
    try {
      reader = new IlvShapeFileReader(shapeFileName, dbfFileName);
    } catch (IOException e) {
      e.printStackTrace();
    }
    // Retrieve the default feature renderer.
    IlvFeatureRenderer renderer = reader.getDefaultFeatureRenderer();
 
     // Coordinate Transformation from IlvGeographicCoordinateSystem.WGS84
    // to IlvGeographicCoordinateSystem.WGS84 (no transformation)
    IlvCoordinateSystem sourceCoordinateSystem =
                           IlvGeographicCoordinateSystem.WGS84;
    IlvCoordinateSystem targetCoordinateSystem =
                           IlvGeographicCoordinateSystem.WGS84;
    IlvCoordinateTransformation transform =
              IlvCoordinateTransformation.CreateTransformation
                (sourceCoordinateSystem, targetCoordinateSystem);
    IlvMapFeature mapFeature;
    // Loop on all map features.
    while ((mapFeature = reader.getNextFeature()) != null) {
      IlvGraphic graphic = renderer.makeGraphic(mapFeature, transform);
      if (mapFeature.getAttributes() != null)
        graphic.setNamedProperty(mapFeature.getAttributes().copy());
      // IlvGraphic has to be stored in an IlvManager.
      manager.addObject(graphic, false);
    }
  }
 
/**
* Create a Shape load-on-demand layer.
*/
  public void loadLOD(String shpFileName,
                      String dbfFileName,
                      String shxFileName,
                      String idxFileName)
  throws IOException {
 
    // Instantiate tile loader.
    IlvShapeFileTileLoader shpTileLoader = new IlvShapeFileTileLoader(
        shpFileName,
        dbfFileName,
        shxFileName,
        idxFileName);
    // instantiate tiled layer.
    IlvTiledLayer tiledLayer =
             new IlvTiledLayer(shpTileLoader.getTileOrigin());
    // Affect tile loader.
    tiledLayer.setTileLoader(shpTileLoader);
    // Add the layer to the IlvManager.
    manager.addLayer(tiledLayer, 0);
    // Fit to tile 0, 0.
    tiledLayer.fitTransformerToTile(view, 0, 0);
  }
The MID/MIF reader
The complete source code for this example can be found in the following file:
<installdir> /jviews-maps/codefragments/readers/src/MIDMIFReader.java.
 
/**
 * Example of how to use the MIDMIF reader package.
 */
public class MIDMIFReader {
  IlvManager manager = new IlvManager();
 
  /**
    * Load a MIDMIF file by providing the MIF file name and the MID file name.
   */
  public void loadMIDMIF(String mif, String mid)
  throws IlvMapFormatException,
         IOException,
         IlvMapRenderException,
         IlvCoordinateTransformationException {
 
    // Create the MIDMIF reader.
    IlvMapFeatureIterator reader = new IlvMIDMIFReader(mif, mid);
    // Retrieve the default renderer.
    IlvFeatureRenderer renderer = reader.getDefaultFeatureRenderer();
    // Initialize the coordinate transformation.
    IlvCoordinateSystem managerCS =
        IlvCoordinateSystemProperty.GetCoordinateSystem(manager);
    // The MIDMIF file can contain coordinate system information.
    IlvCoordinateSystem fileCS = reader.getCoordinateSystem();
    if ((managerCS == null) && (fileCS != null))
      manager.setNamedProperty(new IlvCoordinateSystemProperty(fileCS));
    // Create the transformation accordingly.
    IlvCoordinateTransformation tr =
           IlvCoordinateTransformation.CreateTransformation(fileCS, managerCS);
    // Retrieve the first feature.
    IlvMapFeature f = reader.getNextFeature();
    int layersCount = manager.getLayersCount();
    manager.setContentsAdjusting(true);
    while (f != null) {
      // Create graphic object.
      IlvGraphic g = renderer.makeGraphic(f, tr);
      if (g != null) {
        // Add it to the manager.
        manager.addObject(g, layersCount, false);
        // Retrieve attributes.
        IlvFeatureAttributeProperty ap = f.getAttributes();
        if (ap != null) {
          // Copy the attributes into the graphic, if any.
          g.setNamedProperty(ap.copy());
        }
      }
      // Loop on all features.
      f = reader.getNextFeature();
    }
  }
The DTED file reader
The complete source code for the DTED® file reader example can be found in the following file:
<installdir> /jviews-maps/codefragments/readers/src/DTEDReader.java.
 
/**
 * Example of how to use the DTED reader package.
 */
public class DTEDReader {
  IlvManager manager = new IlvManager();
  IlvManagerView view = new IlvManagerView(manager);
 
  /**
   * Loads a single DTED tile.
   */
  public IlvGraphic loadSingleFrame(String fileName)
  throws IlvMapFormatException,
         FileNotFoundException,
         IOException,
         IlvMapRenderException,
         IlvCoordinateTransformationException {
    // Instantiate the reader.
    IlvDTEDReader reader = new IlvDTEDReader(fileName);
    // Retrieve the unique feature.
    IlvMapFeature feature = reader.getNextFeature();
    // Retrieve the image renderer.
    IlvFeatureRenderer renderer = reader.getDefaultFeatureRenderer();
    // Transformation.
    IlvGeographicCoordinateSystem gcs = IlvGeographicCoordinateSystem.WGS84;
    IlvCoordinateTransformation tr =
               IlvCoordinateTransformation.CreateTransformation
               (feature.getCoordinateSystem(),gcs);
    // Make the graphic object to be inserted in a IlvManager.
    IlvGraphic graphic = renderer.makeGraphic(feature, tr);
    // Returns it.
    return graphic;
  }
 
  private int level = 0;
 
  /**
   * Create a load-on-demand DTED layer providing the directory name.
   */
  public void makeLODLayer(String dirName) {
    // New DTED layer.
    IlvDTEDLayer layer = new IlvDTEDLayer(dirName, level);
    // Add it to the manager.
    manager.addLayer(layer, -1);
    // Center on tile (0, 0).
    layer.fitTransformerToTile(view, 0, 0);
  }
 
  public static void main(String a[]) {
    javax.swing.SwingUtilities.invokeLater(
     new Runnable() {
      public void run() {
        DTEDReader reader = new DTEDReader();
        try {
          reader.loadSingleFrame(a[0]);
        } catch (IlvMapFormatException e) {
          e.printStackTrace();
        } catch (FileNotFoundException e) {
          e.printStackTrace();
        } catch (IOException e) {
          e.printStackTrace();
        } catch (IlvMapRenderException e) {
          e.printStackTrace();
        } catch (IlvCoordinateTransformationException e) {
          e.printStackTrace();
        }
      }
    }
   );
  }
}
The image file reader
The complete source code for this example can be found in the following file:
<installdir> /jviews-maps/codefragments/readers/src/ImageReader.java.
 
/**
 * Example showing how to use the Image reader package.
 */
public class ImageReader {
  IlvManager manager = new IlvManager();
 
  /**
   * Load a single image. Upper left and lower right coordinates
   * have to be provided.
   */
  public void loadImage(String imageName, IlvCoordinate ul, IlvCoordinate lr)
  throws IlvMapFormatException,
         FileNotFoundException,
         IOException,
         IlvMapRenderException,
         IlvCoordinateTransformationException {
    // Create image reader.
    IlvImageReader reader = new IlvImageReader(imageName, ul, lr);
    // Retrieve the unique feature.
    IlvMapFeature feature = reader.getNextFeature();
    // Retrieve the default renderer.
    IlvFeatureRenderer renderer = reader.getDefaultFeatureRenderer();
    // No reprojection for images.
    IlvCoordinateTransformation tr =
      new IlvCoordinateTransformation(IlvGeographicCoordinateSystem.WGS84,
                                      IlvGeographicCoordinateSystem.WGS84,
                                      new IlvMapAffineTransform());
    // Create the graphic object.
    IlvGraphic graphic = renderer.makeGraphic(feature, tr);
  }
 
  /**
   * Create a load-on-demand image layer.
    * The pattern, colFmt, rowFmt are used to retrieve the image file name
   * from the tile coordinates
   */
  public void loadLOD(IlvRect tileOrigin,
                      String pattern,
                      String colFmt,
                      String rowFmt)
  {
    // Create the tile loader.
    IlvImageTileLoader tileLoader = new IlvImageTileLoader(pattern,
                                                       colFmt,
                                                       rowFmt);
    // Create the tiled layer.
    IlvTiledLayer tiledLayer = new IlvTiledLayer(tileOrigin);
    // Affect the tile loader to the tiled layer.
    tiledLayer.setTileLoader(tileLoader);
    // Add the layer into the manager.
    manager.addLayer(tiledLayer, -1);
  }
The map loader
The package ilog.views.maps.format provides the class IlvMapLoader that you can use to load in a very simple way any file format for which JViews Maps provides a predefined reader (Shapefile, DTED®, and MID/MIF). These predefined readers are described at length in Readers and writers.
Loading a predefined map format
To load a predefined map format, use the load method. This method first tries to determine the file format according to the naming rules set forth in the specifications of the different formats, and initializes the appropriate reader. The method then loads the map into the manager associated with the map loader.
The following example shows how to import a .shp file (Shapefile format) into a JViews Maps manager using the map loader:
 
IlvMapLoader loader = new IlvMapLoader(manager);
try {
  loader.load("myShapeFile.shp");
} catch (IlvMapFormatException e) {
  // Occurs if there is a format error in the file.
  e.printStackTrace();
} catch (IOException e) {
  // Occurs if there is another IO error.
  e.printStackTrace();
}
A complete example of how to import a file using the map loader and save it in the .ilv format can be found in the following file:
<installdir> /jviews-maps/codefragments/use_map_loader/src/UseMapLoader.java
Loading nongeoreferenced files
When you load a map into a JViews Maps manager using the map loader, this map is automatically displayed in the coordinate system associated with the manager provided that the format of the source data is georeferenced. The IlvMapFeatureIterator interface has an isGeoreferenced method that you can use to know whether a file is georeferenced. Most of the cartographic files are georeferenced. This is the case for files of the DTED format. Some other cartographic formats, such as Shapefile, are not georeferenced.
When loading data from a file that is not georeferenced, and in the absence of any other indications, the map loader is unable to reproject the source data within the target coordinate system (the one associated with the manager).
NOTE If you load several source files of the Shapefile format whose projection is unknown in the same manager, objects are positioned correctly. However, if you try to import data of another format in the manager, the relative position of objects from different source formats are inaccurate.
If you read a file whose format is not georeferenced, but you know the coordinate system in which the data is expressed, you can provide this information to the IlvMapLoader using the setDefaultCoordinateSystem method.
The following example shows how to import a Shapefile whose projection is known to be geographic into a manager that is in a Mercator projected coordinate system:
 
// Initialize the manager for the mercator projection.
IlvProjection p = new IlvMercatorProjection();
IlvProjectedCoordinateSystem pcs =
       new IlvProjectedCoordinateSystem("mercator", p);
IlvCoordinateSystemProperty csProperty =
      new IlvCoordinateSystemProperty(pcs);
manager.setNamedProperty(csProperty);
 
// Create a map loader.
IlvMapLoader mapLoader = new IlvMapLoader(manager);
 
// Load other data.
....
 
// Load a Shapefile expressed in geographic coordinate system. mapLoader.setDefaultCoordinateSystem(IlvGeographicCoordinateSystem.WGS84);
mapLoader.load("myShapeFile.shp");
Specifying a renderer
If you want an IlvMapLoader object to use a specific renderer, specify it as the second argument of its load method, as shown below:
 
IlvFeatureRenderer renderer = new IlvDefaultCurveRenderer();
mapLoader.load(myIterator, renderer);
IlvMapLoader mapLoader = new IlvMapLoader(manager);
The file <installdir> /jviews-maps/codefragments/renderer/src/Viewer.java shows how to use specific renderers with a map loader reading data that has the Shapefile format. For specific renderers, see the examples provided in Creating a colored line renderer and Extending an existing renderer.
Executing this file loads the following two files into the viewer:
*The <installdir>/doc/usermansrc/maps/renderer/HYLINE.SHP file defines contour lines for the region of Manila (Philippines). The HYLNVAL attribute holds the elevation associated with each contour line. Colors are applied to contour lines using the default elevation color model supplied with JViews Maps. See IlvIntervalColorModel.MakeElevationColorModel.
*The <installdir>/doc/usermansrc/maps/renderer/PPPOINT.SHP file defines points representing populated areas in the region of Manila (Philippines). The PPPTNAME attribute holds the name of the town, if it is known. In this case, this name appears next to the IlvMarker object that represents the town.
Attaching attributes to graphic objects
The map loader can automatically attach attributes to the graphic objects that it creates when it loads a map. For this, use the setAttachingAttributes method, as shown in the following example:
 
IlvMapLoader loader = new IlvMapLoader(manager);
loader.setAttachingAttributes(true);
try {
  loader.load("myShapeFile.shp");
} catch (IlvMapFormatException e) {
  // Occurs if there is a format error in the file.
  e.printStackTrace();
} catch (IOException e) {
  // Occurs if there is an other IO error.
  e.printStackTrace();
}
Extending the IlvMapLoader class
This section shows how to subtype the IlvMapLoader class so that it can recognize a file format other than the JViews Maps predefined formats.
The method makeFeatureIterator of this class creates the reader that recognizes the format of the file specified as its parameter. In the following example, the IlvMapLoader class is derived and the method overridden so that it can recognize the format of the polyline file presented in the section Developing a new reader and initialize the appropriate reader. It is assumed that the file has the .pol extension.
 
public class MyMapLoader extends IlvMapLoader
{
  /**
   * Constructor.
   */
  public MyMapLoader(IlvManager manager) {
    super(manager);
  }
  /**
   * Overrides the makeFeatureIterator method from super class.
   */
  public IlvMapFeatureIterator makeFeatureIterator(String fileName)
    throws IOException
   {
    // Does superclass know the format of provided file?
    IlvMapFeatureIterator result = super.makeFeatureIterator(fileName);
    // If not, try with the polygon reader.
    if (result == null) {
      // Test extension.
      int length = fileName.length();
      // .pol are polylines files.
      if (length > 4) {
        String suffix = fileName.substring(length - 4);
        if (suffix.toLowerCase().equals(".pol")) {
          try {
            return new OptimizedPolylineReader(fileName);
          } catch (IlvMapFormatException e) {
            return null;
          }
        }
      }
    }
    return result;
  }
The makeFeatureIterator method first attempts to get an IlvMapFeatureIterator from its superclass. If the file is not recognized, it tries to determine whether the file extension provided (in this example, .pol ) corresponds to that of the file to be read. If the result of the test is true, it creates the appropriate reader, which in this case is the optimized reader created in Optimizing the reader.
If the file does not contain a header, an IlvMapFormatException is thrown and the method returns the null pointer to indicate that it was not able to identify the file format.
The complete source code for this customized map loader can be found in the following file:
<installdir> /jviews-maps/codefragments/readers/src/MyMapLoader.java
Developing a new reader
In addition to the predefined readers available in JViews Maps, you can write your own reader and customize it.
This section contains an example of an IlvMapFeatureIterator that you can use to read polylines that were saved in an ASCII file.
NOTE The classes that implement the IlvMapFeatureIterator interface are not necessarily file readers. They can also iterate, for example, over the result of a query to a map server.
The file to be read
The ASCII file to be read has been created especially for this example. Its format is very simple and its specifications are as follows:
*It has a header specifying its format.
*There is one pair of coordinates (latitude and longitude) per line. These coordinates are expressed in degrees.
*Lines can contain comments. These comments, when they exist, are merged to form an attribute.
*Polylines are separated by a blank line.
*The file has the .pol extension.
The ASCII file is shown below:
 
ascii polylines
-1.0 40.0 A 1x1 degree rectangle centered on the
 1.0 40.0 (0,39) point
 1.0 38.0
-1.0 38.0
-1.0 40.0
 
0.0 90.0 A meridian extending from the North pole to the South pole
0.0 -90.0
The reader
This section shows the reader you can use to read this polyline file.
The complete source code for this example can be found in the following file:
<installdir> /jviews-maps/codefragments/newreader/src/SimplePolylineReader.java
NOTE Only the portions of code that require comments are reproduced here.
As shown below, the SimplePolylineReader implements the IlvMapFeatureIterator interface:
 
class SimplePolygonReader implements IlvMapFeatureIterator
{
 ... member variables ...
 /**
 * Constructor
 */
 public SimplePolygonReader (String fileName) throws FileNotFoundException
 {
 Initializing member variables
 }
 ... methods ...
}
The georeferencing methods
Since latitude and longitude in the polyline file are expressed in degrees, the coordinate system is geographic. This is why the isGeoreferenced method returns true and the getCoordinateSystem method returns IlvGeographicCoordinateSystem.WGS84. The getCoordinateSystem method would return null if the projection of the file to be read was unknown. See the description of the isGeoreferenced method in The IlvMapFeatureIterator interface.
 
public boolean isGeoreferenced()
  {
    return true;
  }
 public IlvCoordinateSystem getCoordinateSystem()
  {
    return IlvGeographicCoordinateSystem.WGS84;
  }
Bounding box methods
Because of the data format, the bounding box of the polyline cannot be retrieved until the data has been read. Here, the methods getUpperLeftCorner and getLowerRightCorner return null to indicate that these points are not known. Another option is to read the data, place it in an array, and then compute the bounding box.
 
public IlvCoordinate getLowerRightCorner()
  {
    return null;
  }
Rendering methods
The getDefaultFeatureRenderer method must return a renderer able to transform into graphic objects all the map features read by this feature iterator. The IlvDefaultCurveRenderer can process map features whose geometry is of type IlvMapLineString.
 
public IlvFeatureRenderer getDefaultFeatureRenderer()
  {
    return new IlvDefaultCurveRenderer();
  }
If the geometries of the returned map features are not predefined but instead are instances of a derived class, or if the map feature attributes store drawing parameters to be used in rendering operations such as color or line width, it is necessary to provide renderers that can process these attributes or derived geometries. See the section Creating a colored line renderer.
The getNextFeature method
The getNextFeature method reads the geometry of a map feature and creates an IlvMapFeature object that will hold all the information required to process the geometry. The geometry read in the code example that follows is an IlvMapLineString, which is the class to define polyline geometries.
 
public IlvMapFeature getNextFeature()
  throws IOException
{
  return readPolyline();
}
The polyline points are read by the private method readPolyline. This method reads each line in the file to extract the coordinates of the points and the related comments, if any.
It is broken up as follows:
1. A geometry of the type IlvMapLineString is created, which will be associated with the map feature.
 
private IlvMapFeature readPolyline()
  throws IOException
{
  // Concatenates all the comment lines.
  StringBuffer buffer = new StringBuffer();
  // Reads the current map feature.
  IlvMapFeature feature = new IlvMapFeature();
  // Reads the current line string geometry.
  IlvMapLineString geometry = new IlvMapLineString();
2. The points making up this line string are read and the related comment is stored as an attribute.
 
// Stores the line of text that is read.
String line;
 
// Reads a line.
while ((line = file.readLine()) != null) {
  [...]
3. The longitude coordinate values are read. Note that an exception of type IlvMapFormatException is thrown if a format error is detected while reading.
 
// Process longitude.
 IlvCoordinate c = new IlvCoordinate();
 
 if (tokenizer.hasMoreElements() == false)
   throw new IlvMapFormatException("Longitude coordinate expected");
 try {
   currentToken = (String)tokenizer.nextElement();
   c.x = decimalParser.parse(currentToken).doubleValue();
 } catch (ParseException e) {
   throw new IlvMapFormatException("Error while parsing longitude");
 }
These comments also apply to latitude coordinates.
4. Each point read from the file is added to the line string geometry.
 
// Add this point to geometry.
   geometry.addPoint(c);
   [...]
5. The following if statement tests whether the end of the file has been reached. In this case, the getNextFeature method should return a null pointer.
 
// End of file.
 if ((line == null) && (geometry.getPointCount() == 0))
   return null;
6. The geometry is associated with the map feature.
 
// Initialize the map feature.
 feature.setGeometry(geometry);
7. The comments are extracted to form attributes, which are associated with the map feature. The attributeInfo object, which is shared by the attributes of the map features, was initialized in the reader’s constructor.
 
// Set attribute.
IlvStringAttribute[] attribute = new IlvStringAttribute[1];
if (buffer.length() > 0) {
  attribute[0] = new IlvStringAttribute();
  attribute[0].setString(buffer.toString());
} else {
  attribute[0] = null;
}
feature.setAttributeInfo(attributeInfo);
feature.setAttributes(new IlvFeatureAttributeProperty(attributeInfo,
                                                          attribute));
8. The read map feature is returned.
 
// Returns the read map feature.
   return feature;
 }
Optimizing the reader
The polyline reader presented in the section Developing a new reader is not the best because it generates a large number of temporary objects. What happens is that each time a polyline is read, a list, and hence memory, is allocated to store its points. If the number of polylines in the file is very high, this might cause memory to become fragmented and also the frequent running of the garbage collector, thus impairing performance.
To improve performance, the simple polyline reader can be optimized so that the IlvMapFeatureIterator always returns the same instance of IlvMapFeature. The list for storing the points will be allocated only once--when these points are read for the first time. During subsequent readings, the list will be reallocated only if necessary. To make this possible, the map feature returned by the getNextFeature method is volatile, meaning that its geometry and attributes must be used before the method is called again. All the readers provided in the JViews Maps library that implement the IlvMapFeatureIterator interface work this way.
The complete source code for this optimized reader example can be found in the following file:
<installdir> /jviews-maps/codefragments/newreader/src/OptimizedPolylineReader.java
The readPolyline method of the class OptimizedPolylineReader resets the points making up the IlvMapLineString geometry to 0. Note that this geometry is now a field of the class.
 
 geometry.removeAll();
The points of each polyline read are stored in a coordinate buffer. New instances of IlvCoordinate are created only if the polyline being read has more points than each of the polylines previously read.
 
if (currentPointNum < oldPointNum) {
  // Use an IlvCoordinate that was already allocated.
  c = (IlvCoordinate)points.elementAt(currentPointNum);
} else {
  c = new IlvCoordinate();
  points.addElement(c);
}
Once the x,y coordinates of a polyline point are read, this point is added to the geometry. Geometries are implemented in such a way that the addPoint method does not reallocate memory if one of the previously read geometries had at least as many points as the current geometry that is being read.
 
  geometry.addPoint(c);
Also, the geometry attributes are stored as fields of the OptimizedPolylineReader class and modified in the readPolyline method.
 
if (buffer.length() > 0) {
  stringAttribute.setString(buffer.toString());
  attributeProperty.setAttribute(0,stringAttribute);
} else {
  attributeProperty.setAttribute(0,null);
}
feature.setAttributes(attributeProperty);

Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.