« メタデータの埋め込み | メイン | SVG Map Toolkitの0.4.0 がリリースされました »

2008年1 月25日 (金)

Shapefile to SVG Map with metadata converter

 メタデータの埋め込み仕様に従ってメタデータが埋め込まれたSVG Mapデータを生成するソフトウェアを、Shape to SVG Map Converterをもとにして作成しました。
 メタデータのネームスペース宣言が適切ではないなどいくつかの問題点がありますが、このソフトウェアで変換したデータを、テキストエディタの正規表現による置換機能やXSLT等を用いて所望の描画スタイルを設定できると思います。

We publish the software which generates a SVG Map data where metadata was embedded according to the embedding specifications for the metadata based on Shape to SVG Map Converter.
It has some problems, such as a namespace declaration sentence of the metadata which cannot be said to be suitable. However, the data which this software generated is useful in order to carry out a rendition style set using XSLT, replacement functions of a text editor, etc.

// =============================================================================
// Meta-embedded SVG Map exporter program
//
// Copyright (C) 2008 by Satoru Takagi All rights reserved.
// 
http://www.svg-map.com/
//
// Usage: java Shape2SvgMapMeta shapefile.shp
//
// This program uses geoTools2.3.0
// =============================================================================
//
// This software is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by  the  Free
// Software Foundation; either version 2.1 of the License, or (at  your  option)
// any later version.
//
// This library is distributed in the hope that it will be  useful,  but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for  more
// details.
//
// You should have received a copy of the  GNU  Lesser  General  Public  License
// along with this library; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// =============================================================================

import java.io.*;
import java.io.IOException;
import java.net.URL;

import org.geotools.data.*;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.*;

import com.vividsolutions.jts.geom.*;

public class Shape2SvgMapMeta {
double  boundHeight = 400.0; // SVG Height
double  projCenter;
String fillColor = "green";
String strokeColor = "black";
double strokeWidth = 0.01;
// CRS:84 (WGS84 Long-Lat) This URI(URN) is ambiguous...
String CRS = "
http://purl.org/crs/84";
double[] affineParam = new double[6];
FeatureType readFT;
String metaString;

public static void main(String[] args) {
  Shape2SvgMapMeta s2sm = new Shape2SvgMapMeta();
  try {
   // Prepare an output SVG Map file
   FileOutputStream osFile = new FileOutputStream( args[0] + ".svg" );
   Writer fos = new BufferedWriter(new OutputStreamWriter( osFile , "UTF-8" ));
   
   // Shape file
   URL shapeURL = (new File(args[0])).toURL();
   
   s2sm.parse(  shapeURL , fos );
   fos.close();
   
  }catch(Exception e){
   e.printStackTrace();
  }
}


public void parse( URL shapeURL , Writer out ) throws Exception {
  double maxX, minX, maxY, minY;
 
  // Initialize shape file reader
  ShapefileDataStore readStore = new ShapefileDataStore(shapeURL);
  FeatureSource source = readStore.getFeatureSource();
  readFT = source.getSchema();

 
  // get envelope
  Envelope env = source.getBounds();
  maxX = env.getMaxX();
  minX = env.getMinX();
  maxY = env.getMaxY();
  minY = env.getMinY();
 
  // Make affine parameters for CRS metadata of SVG Map
  // Equirectangular Projection (Standard parallel = Center of map)
  //
  // SVG_X = a * GEO_X + c * GEO_Y + e
  // SVG_Y = b * GEO_X + d * GEO_Y + f
  affineParam[1] = 0.0; // b
  affineParam[2] = 0.0; // c
 
  affineParam[3] = - boundHeight / ( maxY - minY ); // d
 
  projCenter = ( maxY + minY ) / 2.0;
  affineParam[0] = - affineParam[3] * Math.cos( projCenter * Math.PI / 180.0 ); // a
 
  affineParam[4] = -affineParam[0] * minX; // e
  affineParam[5] = -affineParam[3] * maxY; // f
 
  // Make a SVG ViewBox
  double origX , origY , cWidth , cHeight;
  cWidth  = Math.abs( ( maxX - minX ) * affineParam[0] );
  cHeight = Math.abs( ( maxY - minY ) * affineParam[3] );
  origX = affineParam[0] * minX + affineParam[4];
  origY = affineParam[3] * maxY + affineParam[5];
 
  // get FeatureCollection
  FeatureCollection fsShape = source.getFeatures();
 
 
  // Start SVG Map output
  // SVG header etc.
  out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
  out.write("<svg  xmlns=\"
http://www.w3.org/2000/svg\" ");
  out.write("xmlns:xlink=\"
http://www.w3.org/1999/xlink\" ");
  out.write("xmlns:lm=\"
http://www.svg-map.org/svgmap/localmetadata/\" ");
  out.write("viewBox=\"" + origX + " " + origY + " " + cWidth + " " + cHeight + "\" >\n");
 
  // metadata for SVG Map
  out.write("<metadata>\n");
 
  // CRS metadata
  out.write(" <rdf:RDF xmlns:rdf=\"
http://www.w3.org/1999/02/22-rdf-syntax-ns#\" ");
  out.write("xmlns:crs=\"
http://opengis.org/xmldtds/transformations.dtd\" xmlns:svg=\"http://www.w3.org/2000/svg\">\n");
  out.write("  <rdf:Description>\n");
  out.write("   <crs:CoordinateReferenceSystem rdf:resource=\"" + CRS + "\"  ");
  out.write("svg:transform=\"matrix(" + affineParam[0] + "," + affineParam[1] + "," + affineParam[2]
   + "," + affineParam[3] + "," + affineParam[4] + "," + affineParam[5] +")\" />\n");
  out.write("  </rdf:Description>\n");
  out.write(" </rdf:RDF>\n");
  out.write("</metadata>\n");
 
  // Icon for Point
  out.write("<defs>\n");
  out.write(" <g id=\"p0\" >\n");
  out.write("<circle cx=\"0.0\" cy=\"0.0\" r=\"" + (cWidth / 300) + "\" stroke=\"none\" />\n");
  out.write(" </g>\n");
  out.write("</defs>\n");
 
  // Main data body
  FeatureIterator reader = fsShape.features();
  Feature oneFeature;
  Geometry oneGeom;
  Coordinate[] coord;
  while (reader.hasNext()) {
   oneFeature = reader.next();
   metaString = getMetaString( oneFeature );
   isChild = false;
   oneGeom = oneFeature.getDefaultGeometry();
   parseGeometry(oneGeom , out );
  }
  reader.close();
  out.write("</svg>\n");
}

boolean isChild;
private void parseGeometry(Geometry geom , Writer out ) throws Exception {
  Coordinate[] coord;
  Coordinate oneCrd = new Coordinate();
  if (geom instanceof Polygon ){
   out.write("<path ");
   if ( ! isChild ){ out.write(metaString);}
   out.write("fill=\"" + fillColor + "\" fill-rule=\"evenodd\" d=\"M");
   coord = (((Polygon)geom).getExteriorRing()).getCoordinates();
   for ( int i = 0 ; i < coord.length ; i++ ){
    if ( i!= 0 ){
     out.write( "L" );
    }
    oneCrd = transform2D(coord[i] );
    out.write( oneCrd.x + "," + oneCrd.y + " " );
   }
   out.write ("Z ");
   
   for ( int j = 0 ; j < ((Polygon)geom).getNumInteriorRing() ; j++ ){
    coord = (((Polygon)geom).getInteriorRingN(j)).getCoordinates();
    for ( int i = 0 ; i < coord.length ; i++ ){
     if ( i!= 0 ){
      out.write( "L" );
     } else {
      out.write( "M" );
     }
     oneCrd = transform2D(coord[i] );
     out.write( oneCrd.x + "," + oneCrd.y + " " );
    }
    out.write ("Z ");
   }
   
   out.write ("\"/>\n");
  } else if (geom instanceof LineString ){
   out.write("<polyline ");
   if ( ! isChild ){ out.write(metaString);}
   out.write("fill=\"none\" stroke-width=\"" + strokeWidth + "\" stroke=\"" + strokeColor + "\" points=\"");
   coord = ((LineString)geom).getCoordinates();
   for ( int i = 0 ; i < coord.length ; i++ ){
    oneCrd = transform2D(coord[i] );
    out.write( oneCrd.x + "," + oneCrd.y + " " );
   }
   out.write ("\"/>\n");
  } else if (geom instanceof Point ){
   oneCrd = transform2D(((Point)geom).getCoordinate() );
   out.write("<use ");
   if ( ! isChild ){ out.write(metaString);}
   out.write("xlink:href=\"#p0\" fill=\"" + fillColor + "\"");
   out.write(" x=\"" + oneCrd.x + "\"" + " y=\"" + oneCrd.y + "\"/>\n");
  } else if (geom instanceof GeometryCollection ){
//   out.write("<g ");
//   if ( ! isChild ){ out.write(metaString);}
//   out.write(">\n");
//   isChild = true;
   for ( int j = 0 ; j < ((GeometryCollection)geom).getNumGeometries() ; j++){
    Geometry childGeom = ((GeometryCollection)geom).getGeometryN(j);
    parseGeometry(childGeom , out);
   }
//   out.write("</g>\n");
  } else if (geom instanceof Geometry ){
   out.write("<!-- Type: Other Geometry...." + geom + "-->\n");
  } else if (geom instanceof Object){
   out.write("<!-- Type: Other Object...." + geom + "-->\n");
  }
}

private  Coordinate transform2D( Coordinate inCrd ){
  Coordinate outCrd = new Coordinate(
   affineParam[0] * inCrd.x + affineParam[2] * inCrd.y + affineParam[4] ,
   affineParam[1] * inCrd.x + affineParam[3] * inCrd.y + affineParam[5] );
  return (outCrd);
}

private String getMetaString( Feature oneFeature ){
  StringBuffer metaString = new StringBuffer();
  for ( int i = 0 ; i < readFT.getAttributeCount() ; i++){
   if (oneFeature.getAttribute(i) instanceof Geometry == false ){
    metaString.append("lm:");
    metaString.append( readFT.getAttributeType(i).getName());
    metaString.append("=\"");
    metaString.append( oneFeature.getAttribute(i));
    metaString.append( "\" ");
   }
  }
  return ( metaString.toString() );
}

}

トラックバック

この記事のトラックバックURL:
http://www.typepad.com/services/trackback/6a0120a850e7be970b0120a850e9a3970b

Listed below are links to weblogs that reference Shapefile to SVG Map with metadata converter: