User:Tatata/ksj2osm-admin.pl

From OpenStreetMap Wiki
Jump to navigation Jump to search
参考
作業の概要についてはこちらも参照して下さい。


This perl script convert KSJ2 administrative district data xml file to osm xml file.

(ja)このperlスクリプトは国土数値情報(行政区域データ)のxmlファイルをosmのxmlファイルに変換します。

Preparation

(ja)準備

  • Installation of JOSM (a java program; needs J2SE SDK or JRE). (ja)JOSMの導入(javaプログラムなので実行にはJ2SE SDK或いはJREが必要。)
  • Installation of perl. You can download ActivePerl from ActiveState site (free of charge). (ja)perlの導入。ActiveStateのサイトからActivePerlをでダウンロードできる(無料)。
  • Save the code below as a file with proper name. (e.g. ksj2osm-admin.pl) (ja)適切なファイル名を付けて下のソースコードを保存する。(例えばksj2osm-admin.plなど。)

How to convert the data

(ja)変換手順

  • Download a file of KSJ2 administrative district data (i.e. choose one prefecture which you want to import) and decompress it from zip file to xml file. (ja)国土数値情報(行政区域データ)からインポートしたい都道府県のファイルを一つダウンロードし、zipファイルを解凍してxmlファイルにする。
  • Put the xml file on the same directory of the script. (ja)xmlファイルをスクリプトと同じディレクトリに置く。
  • Open the perl script by editor program, edit the initial values of variables; see table below. And then save the script. (ja)このperlスクリプトをエディタープログラムで開き、変数の初期値を編集し(下の表を参照)、スクリプトを保存する。
  • Open command prompt window and run the script on the directory where you put the script and xml file. Output files (ksj2osm-admin-place-0.osm, ksj2osm-admin-inner-*.osm, ksj2osm-admin-outer-*.osm, ksj2osm-admin.log) will be created on the same directory. (ja)コマンドプロンプトを開いて、スクリプトとxmlファイルを置いたディレクトリでスクリプトを実行する。出力ファイル (ksj2osm-admin-place-0.osm, ksj2osm-admin-inner-*.osm, ksj2osm-admin-outer-*.osm, ksj2osm-admin.log) は同じディレクトリに作成される。
  • Open output files (ksj2osm-admin-place-0.osm, ksj2osm-admin-inner-*.osm, ksj2osm-admin-outer-*.osm) by JOSM, check and edit the data (see notes below), and then upload to server. (ja)JOSMで出力ファイル (ksj2osm-admin-place-0.osm, ksj2osm-admin-inner-*.osm, ksj2osm-admin-outer-*.osm)を開いてデータの確認や編集を行い(下の注意を参照)、それからサーバーにアップロードする。


variable
変数
description of initial value 初期値の説明
$switch_place 0 : no output of places.
1 : output a file "ksj2osm-admin-place-0.osm".
0 : 都道府県・支庁・郡・市区町村を出力しない。
1 : ファイル "ksj2osm-admin-place-0.osm" を出力する。
$switch_inner 0 : no output of municipality boundary.
1 : output files "ksj2osm-admin-inner-*.osm".
0 : 市区町村界を出力しない。
1 : ファイル "ksj2osm-admin-inner-*.osm" を出力する。
$switch_outer 0 : no output of prefecture boundary (including coastlines).
1 : output files "ksj2osm-admin-outer-*.osm". You need to remove coastlines by using JOSM.
0 : 都府県界(海岸線を含む)を出力しない。
1 : ファイル "ksj2osm-admin-outer-*.osm" を出力する。JOSMを使って海岸線を削除する必要があります。
$max_ways_inner number : limit of the number of ways outputted into each "ksj2osm-admin-inner-*.osm" file.
Please adjust this number to reduce the size of each output file; a rough estimate is a half of the file size which you can open by JOSM. In the case of Tatata's PC, a rough estimate is 5MB since JOSM can open a 10MB file.
数値 : 各 "ksj2osm-admin-inner-*.osm" ファイルに出力するwayの数の上限。
個々の出力ファイルのサイズを小さくする為に、この数値を調整して下さい。目安はあなたのPC上のJOSMで開けるファイルの半分のサイズです。TatataのPCの場合は10MBのファイルなら開けるので、各出力ファイルが5MB以下になるようにしています。
$max_ways_outer number : limit of the number of ways outputted into each "ksj2osm-admin-outer-*.osm" file.
Please adjust this number to reduce the size of each output file; a rough estimate, see description above.
数値 : 各 "ksj2osm-admin-outer-*.osm" ファイルに出力するwayの数の上限。
個々の出力ファイルのサイズを小さくする為に、この数値を調整して下さい。目安は前述の説明を参照。
$file_in filename : the name of input file without an extension (i.e. without ".xml"). ファイル名 : 入力ファイルの名前。拡張子 (".xml") は付けない。
$file_name unnecessary to edit; this is the prefix of output file name. 編集不要。これは出力ファイル名の接頭語です。

Notes

(ja)注意

  • Please remove coastlines from output files of prefecture boundary (i.e. "ksj2osm-admin-outer-*.osm") by using JOSM. (ja)JOSMを使って、都府県界の出力ファイル ("ksj2osm-admin-outer-*.osm") から海岸線を削除して下さい。
  • The coordinate of the node which is tagged with "place=*", is calculated values as the middle between the maximum latitude of the area and the minimum latitude and the middle between the maximum longitude and the minimum longitude. So you may need to adjust its position. (ja)"place=*"タグが付けられたノードの座標は、そのエリアの最大の緯度と最小の緯度の中間点及び最大の経度と最小の経度の中間点として計算された値です。このため、位置の調整を行う必要があるかも知れません。
  • In case of there is one municipality in one county, this script make two nodes tagged with "place=*" for them with the same coordinate. So please adjust their positions. (ja)1つの郡の中に1つの自治体しかない場合、"place=*"タグが付いた郡のノードと自治体のノードは同じ座標になり重なってしまいますので、位置を調整して下さい。
  • For the place where its belonging has not been decided, "place=locality" will be tagged. This script can make one node for each prefecture. In case of more than one such place, please make nodes manually. (ja)所属未定地には"place=locality"タグが付けられます。所属未定地が都道府県内に複数有ってもこのスクリプトが作成できるノードは1つだけです。所属未定地が複数有る場合には修正を行って下さい。
  • For enclaves, municipality boundaries will be created but nodes tagged with "place=*" will not. When you tag enclaves with their names, please use " place_name=*" for those areas. (ja)飛地の境界線は作成されますが、飛地に対する"place=*"タグが付いたノードは作成されません。手入力で飛地に名称をつける場合にはクローズドウェイに対して" place_name=*"タグを使って付けて下さい。
  • In case of there are enclaves of other prefectures, this script make nodes tagged with "place=*" for them. So please remove them manually. (ja)隣接都府県の飛地が有る場合、飛地とそれらが属する都府県に対する"place=*"タグが付いたノードが作成されますので、削除して下さい。
  • KSJ2 administrative district data doesn't have information below, so you need to input them manually into the node which is tagged with "place=*". See also Japan tagging#Names. (ja)国土数値情報の行政区域データには以下の情報が無いので、"place=*"タグが付けられたノードについてはそれらを手入力する必要があります。Japan tagging#Namesも参照してください。
    • place name in Japanese; "is_in:state=". (ja)日本語の地名 ("is_in:state=")。
    • place name in English; "name=" (in round brackets), "name:en=", "is_in:state=" (in round brackets), "is_in:region=" (in round brackets), "is_in:county=" (in round brackets). (ja)英語の地名 ("name="(丸括弧内), "name:en=", "is_in:state="(丸括弧内), "is_in:region="(丸括弧内), "is_in:county="(丸括弧内))。
    • place name in romanization of Japanese; "name:ja_rm=". (ja)ローマ字表記の地名 ("name:ja_rm=")。

Code

As of 2013-02-24.



#!/usr/bin/perl

use strict;
use warnings;
# use encoding "utf8"; 
use encoding "utf8", STDOUT => "shiftjis", STDERR => "shiftjis"; # for Windows
use Encode;
use open IO => "utf8";
use XML::Parser;

#####
#
# KSJ2 Administrative area
#
# National-Land Numerical Information (Administrative area) 2010, MLIT Japan
# 国土数値情報(行政区域データ)平成22年 国土交通省
#
# Files
#   Input
#     XML file : N03-070401_*.xml
#   Output
#     Osm file : ksj2osm-admin-place-0.osm (places)
#     Osm file : ksj2osm-admin-inner-*.osm (municipality boundary)
#     Osm file : ksj2osm-admin-outer-*.osm (prefecture boundary w/coastline)
#     Log file : ksj2osm-admin.log
#
#####

our $switch_place = 1; # 0 : no output, 1 : output ksj2osm-admin-place-0.osm
our $switch_inner = 1; # 0 : no output, 1 : output ksj2osm-admin-inner-*.osm
our $switch_outer = 1; # 0 : no output, 1 : output ksj2osm-admin-outer-*.osm
our $max_ways_inner = 27; # for splitting output inner files. (27 for Chiba inner)
our $max_ways_outer = 90; # for splitting output outer files. (90 for Chiba outer)
our $file_in = "N03-070401_14";
our $file_name = "ksj2osm-admin";

our $east = 160.00000000;
our $west = 110.00000000;
our $south = 10.00000000;
our $north = 60.00000000;

our %centerHash;
our $count_place_files = 0;
our $count_inner_files = 0;
our $count_outer_files = 0;
our $count_ways = 0;
our %curveHash;
our $negative_id = 0;
our $node_ref;
our %nodes = ();
our $num_error = 0;
our $num_nodes = 0;
our $num_places = 0;
our $num_ways = 0;
our %ocHash;
our %placeHash;
our %surfaceHash;
our @workArray;
our %workHash;
our $workString;
# our $x = 0; #####DEBUG


sub main() {

  my $parser = new XML::Parser(ErrorContext => 3,
                               Handlers => {Init => \&handle_init,
                                            Start => \&handle_start,
                                            Char => \&handle_char,
                                            End => \&handle_end,
                                            Final => \&handle_final});

  $parser->parsefile("$file_in.xml");

}


sub handle_init() {

  open_log();

}


sub handle_start() {

 my ($expat, $element, %hash) = @_;
 if ($element eq "ksj:EC01"
    || $element eq "ksj:ARE"
    || $element eq "jps:GM_Surface"
    || $element eq "jps:GM_CompositeCurve.generator"
    || $element eq "jps:GM_OrientableCurve"
    || $element eq "jps:GM_OrientablePrimitive.primitive"
    || $element eq "jps:GM_Curve"
    || $element eq "GM_PointRef.point"
    || $element eq "jps:GM_Point") {get_id(@_);}
  $workString = "";                              # add 2009-05-26

}


sub handle_char () {

  my ($expat, $string) = @_;
#  $workString = $string;
#  $workString .= "";                             # mod 2009-05-26
  $workString .= $string;                         # mod 2009-10-16

}


sub handle_end() {

  my ($expat, $element) = @_;
  if ($element eq "ksj:PRN"
    || $element eq "ksj:SUN"
    || $element eq "ksj:CON"
    || $element eq "ksj:CN2"
    || $element eq "ksj:AAC"
    || $element eq "DirectPosition.coordinate") {get_element(@_);}
  elsif ($element eq "ksj:EC01") {add_place();}
  elsif ($element eq "jps:GM_SurfaceBoundary.exterior") {add_exterior();}
  elsif ($element eq "jps:GM_SurfaceBoundary.interior") {add_interior();}
  elsif ($element eq "jps:GM_Surface") {add_surface();}
  elsif ($element eq "jps:GM_OrientableCurve") {add_oc();}
  elsif ($element eq "jps:GM_Curve") {add_curve();}
  elsif ($element eq "jps:GM_Point") {replace_point();}


}


sub handle_final() {

  update_hash();

  my $time = localtime(time);
  print LOG "***** End of processing $file_in.xml : $time\n";
  print "***** End of processing $file_in.xml : $time\n";

  print LOG "*****\n";
  print LOG "***** Dump of placeHash\n";
  foreach my $item(keys %placeHash) {
    print LOG "* 1st key: $item\n";
    foreach my $item2(keys %{$placeHash{$item}}) {
      print LOG "** 2nd key: $item2\n";
      foreach my $item3(keys %{$placeHash{$item}{$item2}}) {
        print LOG "*** 3rd key: $item3\n";
        foreach my $item4(keys %{$placeHash{$item}{$item2}{$item3}}) {
          print LOG "**** 4th key: $item4\n";
          foreach my $item5(keys %{$placeHash{$item}{$item2}{$item3}{$item4}}) {
            print LOG "***** 5th key: $item5, value: $placeHash{$item}{$item2}{$item3}{$item4}{$item5}\n";
          }
        }
      }
    }
    print LOG "*****\n";
  }

  print LOG "***** Dump of centerHash\n";
  foreach my $item(keys %centerHash) {
    print LOG "* 1st key: $item\n";
    foreach my $item2(keys %{$centerHash{$item}}) {
      print LOG "** 2nd key: $item2, value: $centerHash{$item}{$item2}\n";
    }
  }
  print LOG "*****\n";

#####DEBUG
#  print LOG "***** Dump of surfaceHash\n";
#  foreach my $item(keys %surfaceHash) {
#    print LOG "* 1st key: $item\n";
#    foreach my $item2(keys %{$surfaceHash{$item}}) {
#      print LOG "** 2nd key: $item2, value: $surfaceHash{$item}{$item2}\n";
#    }
#  }
#  print LOG "*****\n";
#
#  print LOG "***** Dump of curveHash\n";
#  foreach my $item(keys %curveHash) {
#    print LOG "* 1st key: $item\n";
#    foreach my $item2(keys %{$curveHash{$item}}) {
#      print LOG "** 2nd key: $item2, value: $curveHash{$item}{$item2}\n";
#    }
#  }
#  print LOG "*****\n";
#####

  create_osm();

  close_log();

}


sub open_log() {

  my $time = localtime(time);
  open(LOG, ">$file_name.log");
  print LOG "***** KSJ2 Administrative area Data 2007 : Start $time\n";
  print "***** KSJ2 Administrative area 2007 : Start $time\n";
  print LOG "***** Switch : place = $switch_place, inner = $switch_inner, outer = $switch_outer.\n";
  print "***** Switch : place = $switch_place, inner = $switch_inner, outer = $switch_outer.\n";
  print LOG "***** Max ways : inner = $max_ways_inner, outer = $max_ways_outer.\n";
  print "***** Max ways : inner = $max_ways_inner, outer = $max_ways_outer.\n";
  print LOG "***** Extracting from $file_in.xml\n";
  print "***** Extracting from $file_in.xml\n";

}


sub close_log() {

  my $time = localtime(time);
  print LOG "***** Done!: End $time\n";
  close LOG;
  print "***** Done!: End $time\n";

}


sub get_id() {

  my ($expat, $element, %hash) = @_;
  if ($element eq "ksj:ARE" ) {
    if (exists($hash{"idref"})) {
      $workHash{"ARE"} = $hash{"idref"};
    }
    else {
      print LOG "* idref not found in element ksj:ARE.\n";
      print "* idref not found in element ksj:ARE.\n";
      while (my ($key, $value) = each(%hash)) {
        print LOG "key: $key , value: $value \n";
        print "key: $key , value: $value \n";
      }
      die "idref not found in element ksj:ARE.";
    }
  }
  elsif ($element eq "jps:GM_CompositeCurve.generator" ) {
    if (exists($hash{"idref"})) {
      if (exists($workHash{"CompositeCurve"})) {
        $workHash{"CompositeCurve"} .= ",";
      }
      $workHash{"CompositeCurve"} .= $hash{"idref"};
    }
    else {
      print LOG "* idref not found in element jps:GM_CompositeCurve.generator.\n";
      print "* idref not found in element jps:GM_CompositeCurve.generator.\n";
      while (my ($key, $value) = each(%hash)) {
        print LOG "key: $key , value: $value \n";
        print "key: $key , value: $value \n";
      }
      die "idref not found in element jps:GM_CompositeCurve.generator.";
    }
  }
  elsif ($element eq "jps:GM_OrientableCurve" ) {
    if (exists($hash{"id"})) {
      $workHash{"id"} = $hash{"id"};
      $workHash{"element"} = $hash{"jps:GM_OrientableCurve"};
    }
    else {
      print LOG "* id not found in element jps:GM_Curve.\n";
      print "* id not found in element jps:GM_Curve.\n";
      while (my ($key, $value) = each(%hash)) {
        print LOG "key: $key , value: $value \n";
        print "key: $key , value: $value \n";
      }
      die "id not found in element jps:GM_Curve.";
    }
  }
  elsif ($element eq "jps:GM_OrientablePrimitive.primitive" ) {
    if (exists($workHash{"element"})) {
      if (exists($hash{"idref"})) {
        $workHash{"primitive"} = $hash{"idref"};
      }
      else {
        print LOG "* idref not found in element jps:GM_OrientablePrimitive.primitive.\n";
        print "* idref not found in element jps:GM_OrientablePrimitive.primitive.\n";
        while (my ($key, $value) = each(%hash)) {
          print LOG "key: $key , value: $value \n";
          print "key: $key , value: $value \n";
        }
        die "idref not found in element jps:GM_OrientablePrimitive.primitive.";
      }
    }
  }
  elsif ($element eq "GM_PointRef.point") {
    if (exists($hash{"idref"})) {
      if (exists($workHash{"points"})) {
        $workHash{"points"} .= ",";
      }
      $workHash{"points"} .= $hash{"idref"};
    }
    else {
      print LOG "* id not found in element GM_PointRef.point.\n";
      print "* id not found in element GM_PointRef.point.\n";
      while (my ($key, $value) = each(%hash)) {
        print LOG "key: $key , value: $value \n";
        print "key: $key , value: $value \n";
      }
      die "id not found in element GM_PointRef.point.";
    }
  }
  else {
    if (exists($hash{"id"})) {
      $workHash{"id"} = $hash{"id"};
    }
    else {
      print LOG "* id not found in element $element.\n";
      print "* id not found in element $element.\n";
      while (my ($key, $value) = each(%hash)) {
        print LOG "key: $key , value: $value \n";
        print "key: $key , value: $value \n";
      }
      die "id not found in element $element";
    }
  }
}


sub get_element() {

  my ($expat, $element) = @_;
  if ($element eq "ksj:PRN" ) {$workHash{"PRN"} = $workString;}
  elsif ($element eq "ksj:SUN" ) {$workHash{"SUN"} = $workString;}
  elsif ($element eq "ksj:CON" ) {$workHash{"CON"} = $workString;}
  elsif ($element eq "ksj:CN2" ) {$workHash{"CN2"} = $workString;}
  elsif ($element eq "ksj:AAC" ) {$workHash{"AAC"} = $workString;}
  elsif ($element eq "DirectPosition.coordinate" ) {
    if (exists($workHash{"points"})) {
      $workHash{"points"} .= ",";
    }
    $workHash{"points"} .= $workString;
  }
  $workString = "";                              # add 2009-05-26
}

# set tag data for writing OSM file
sub write_osm_constant_tag(){

  my $tags;

  my %hash = (
    "created_by" => "National-Land-Numerical-Information_MLIT_Japan",
    "note:en" => "National-Land Numerical Information (Administrative area) 2010, MLIT Japan",
    "note:ja" => "国土数値情報(行政区域データ)平成22年 国土交通省",
    "source" => "KSJ2",
    "source_ref" => "http://nlftp.mlit.go.jp/ksj/jpgis/datalist/KsjTmplt-N03.html",
    "KSJ2:filename" => $file_in . ".xml",
  );

  foreach my $key ( keys( %hash ) ){

    $tags .= "<tag k=\"$key\" v=\"$hash{$key}\"/>\n";

  }

  return $tags;

}  # end sub write_osm_constant_tag()

sub add_place() {

  unless (exists($workHash{"SUN"})) {$workHash{"SUN"} = "*";}
  unless (exists($workHash{"CON"})) {$workHash{"CON"} = "*";}
  unless (exists($workHash{"CN2"})) {$workHash{"CN2"} = "*";}
  $placeHash{$workHash{"PRN"}}{$workHash{"SUN"}}{$workHash{"CON"}}{$workHash{"CN2"}}{"AAC"} = $workHash{"AAC"};
  if (exists($placeHash{$workHash{"PRN"}}{$workHash{"SUN"}}{$workHash{"CON"}}{$workHash{"CN2"}}{"EC01"})) {
    $placeHash{$workHash{"PRN"}}{$workHash{"SUN"}}{$workHash{"CON"}}{$workHash{"CN2"}}{"EC01"} .= ",";
  }
  $placeHash{$workHash{"PRN"}}{$workHash{"SUN"}}{$workHash{"CON"}}{$workHash{"CN2"}}{"EC01"} .= $workHash{"id"};
  if (exists($placeHash{$workHash{"PRN"}}{$workHash{"SUN"}}{$workHash{"CON"}}{$workHash{"CN2"}}{"ARE"})) {
    $placeHash{$workHash{"PRN"}}{$workHash{"SUN"}}{$workHash{"CON"}}{$workHash{"CN2"}}{"ARE"} .= ",";
  }
  $placeHash{$workHash{"PRN"}}{$workHash{"SUN"}}{$workHash{"CON"}}{$workHash{"CN2"}}{"ARE"} .= $workHash{"ARE"};
  %workHash = ();
}


sub add_exterior() {
  if (exists($workHash{"exterior"})) {
    $workHash{"exterior"} .= ",";
  }
  $workHash{"exterior"} .= $workHash{"CompositeCurve"};
  delete $workHash{"CompositeCurve"};
}


sub add_interior() {
  if (exists($workHash{"interior"})) {
    $workHash{"interior"} .= ",";
  }
  $workHash{"interior"} .= $workHash{"CompositeCurve"};
  delete $workHash{"CompositeCurve"};
}


sub add_surface() {

  if (exists($workHash{"exterior"})) {
    $surfaceHash{$workHash{"id"}}{"exterior"} = $workHash{"exterior"};
  }
  if (exists($workHash{"interior"})) {
    $surfaceHash{$workHash{"id"}}{"interior"} = $workHash{"interior"};
  }
  %workHash = ();
}


sub add_oc() {
  $ocHash{$workHash{"id"}} = $workHash{"primitive"};
  %workHash = ();
}


sub add_curve() {
  $curveHash{$workHash{"id"}}{"points"} = $workHash{"points"};
  %workHash = ();

#  $x++; #####DEBUG
#  print "add_curve $x\n"; #####DEBUG
}


sub replace_point() {

  my $string;

  foreach my $item(keys %curveHash) {
    if (exists($curveHash{$item}{"points"})) {
      $curveHash{$item}{"points"} =~ s/$workHash{"id"}/$workHash{"points"}/g;
    }
  }
  %workHash = ();

#  $x++; #####DEBUG
#  print "replace_point $x\n"; #####DEBUG
}


sub update_hash() {

  my @surfaceArray;
  my @curveArray;

  %workHash = ();

  foreach my $item(keys %placeHash) {
    foreach my $item2(keys %{$placeHash{$item}}) {
      foreach my $item3(keys %{$placeHash{$item}{$item2}}) {
        foreach my $item4(keys %{$placeHash{$item}{$item2}{$item3}}) {
          @surfaceArray = split(/,/, $placeHash{$item}{$item2}{$item3}{$item4}{"ARE"});
          foreach my $surface(@surfaceArray) {
            if (exists($surfaceHash{$surface}{"exterior"})) {
              @curveArray = split(/,/, $surfaceHash{$surface}{"exterior"});
              foreach my $curve(@curveArray) {update_curvehash($curve);}
            }
            if (exists($surfaceHash{$surface}{"interior"})) {
              @curveArray = split(/,/, $surfaceHash{$surface}{"interior"});
              foreach my $curve(@curveArray) {update_curvehash($curve);}
            }
          }
          maxmin_latlong($item, $item2, $item3, $item4);
          %workHash = ();
        }
      }
    }
  }

  update_centerhash();

#  $x++; #####DEBUG
#  print "update_hash $x\n"; #####DEBUG
}


sub update_curvehash() {

  my ($curve) = @_;

  if (exists($ocHash{$curve})) {$curve = $ocHash{$curve};}

  @workArray = split(/,/, $curveHash{$curve}{"points"});
  foreach my $coordinate(@workArray) {
    my ($lat, $long) = split(/\s/, $coordinate);
    if (defined($lat) && defined($long)) {
      unless (($lat eq "") || ($long eq "")) {
        unless (($lat > $north) || ($lat < $south)
        || ($long > $east) || ($long < $west)) {
          if (exists($workHash{"maxlat"})) {
            if ($lat > $workHash{"maxlat"}) {$workHash{"maxlat"} = $lat;}
          } else {$workHash{"maxlat"} = $lat;}
          if (exists($workHash{"maxlong"})) {
            if ($long > $workHash{"maxlong"}) {$workHash{"maxlong"} = $long;}
          } else {$workHash{"maxlong"} = $long;}
          if (exists($workHash{"minlat"})) {
            if ($lat < $workHash{"minlat"}) {$workHash{"minlat"} = $lat;}
          } else {$workHash{"minlat"} = $lat;}
          if (exists($workHash{"minlong"})) {
            if ($long < $workHash{"minlong"}) {$workHash{"minlong"} = $long;}
          } else {$workHash{"minlong"} = $long;}
        }
      }
    }
  }

  if (exists($curveHash{$curve}{"num"})) {$curveHash{$curve}{"num"}++;}
  else {$curveHash{$curve}{"num"} = 0;}

}


sub maxmin_latlong(){

  my ($item, $item2, $item3, $item4) = @_;

  $centerHash{$item.$item2.$item3.$item4}{"maxlat"} = $workHash{"maxlat"};
  $centerHash{$item.$item2.$item3.$item4}{"maxlong"} = $workHash{"maxlong"};
  $centerHash{$item.$item2.$item3.$item4}{"minlat"} = $workHash{"minlat"};
  $centerHash{$item.$item2.$item3.$item4}{"minlong"} = $workHash{"minlong"};

  if (exists($centerHash{$item.$item2.$item3}{"maxlat"})) {
    if ($centerHash{$item.$item2.$item3}{"maxlat"} < $workHash{"maxlat"}) {
      $centerHash{$item.$item2.$item3}{"maxlat"} = $workHash{"maxlat"};
    }
  }
  else {
    $centerHash{$item.$item2.$item3}{"maxlat"} = $workHash{"maxlat"};
  }
  if (exists($centerHash{$item.$item2.$item3}{"maxlong"})) {
    if ($centerHash{$item.$item2.$item3}{"maxlong"} < $workHash{"maxlong"}) {
      $centerHash{$item.$item2.$item3}{"maxlong"} = $workHash{"maxlong"};
    }
  }
  else {
    $centerHash{$item.$item2.$item3}{"maxlong"} = $workHash{"maxlong"};
  }
  if (exists($centerHash{$item.$item2.$item3}{"minlat"})) {
    if ($centerHash{$item.$item2.$item3}{"minlat"} > $workHash{"minlat"}) {
      $centerHash{$item.$item2.$item3}{"minlat"} = $workHash{"minlat"};
    }
  }
  else {
    $centerHash{$item.$item2.$item3}{"minlat"} = $workHash{"minlat"};
  }
  if (exists($centerHash{$item.$item2.$item3}{"minlong"})) {
    if ($centerHash{$item.$item2.$item3}{"minlong"} > $workHash{"minlong"}) {
      $centerHash{$item.$item2.$item3}{"minlong"} = $workHash{"minlong"};
    }
  }
  else {
    $centerHash{$item.$item2.$item3}{"minlong"} = $workHash{"minlong"};
  }

  if (exists($centerHash{$item.$item2}{"maxlat"})) {
    if ($centerHash{$item.$item2}{"maxlat"} < $workHash{"maxlat"}) {
      $centerHash{$item.$item2}{"maxlat"} = $workHash{"maxlat"};
    }
  }
  else {
    $centerHash{$item.$item2}{"maxlat"} = $workHash{"maxlat"};
  }
  if (exists($centerHash{$item.$item2}{"maxlong"})) {
    if ($centerHash{$item.$item2}{"maxlong"} < $workHash{"maxlong"}) {
      $centerHash{$item.$item2}{"maxlong"} = $workHash{"maxlong"};
    }
  }
  else {
    $centerHash{$item.$item2}{"maxlong"} = $workHash{"maxlong"};
  }
  if (exists($centerHash{$item.$item2}{"minlat"})) {
    if ($centerHash{$item.$item2}{"minlat"} > $workHash{"minlat"}) {
      $centerHash{$item.$item2}{"minlat"} = $workHash{"minlat"};
    }
  }
  else {
    $centerHash{$item.$item2}{"minlat"} = $workHash{"minlat"};
  }
  if (exists($centerHash{$item.$item2}{"minlong"})) {
    if ($centerHash{$item.$item2}{"minlong"} > $workHash{"minlong"}) {
      $centerHash{$item.$item2}{"minlong"} = $workHash{"minlong"};
    }
  }
  else {
    $centerHash{$item.$item2}{"minlong"} = $workHash{"minlong"};
  }

  if (exists($centerHash{$item}{"maxlat"})) {
    if ($centerHash{$item}{"maxlat"} < $workHash{"maxlat"}) {
      $centerHash{$item}{"maxlat"} = $workHash{"maxlat"};
    }
  }
  else {
    $centerHash{$item}{"maxlat"} = $workHash{"maxlat"};
  }
  if (exists($centerHash{$item}{"maxlong"})) {
    if ($centerHash{$item}{"maxlong"} < $workHash{"maxlong"}) {
      $centerHash{$item}{"maxlong"} = $workHash{"maxlong"};
    }
  }
  else {
    $centerHash{$item}{"maxlong"} = $workHash{"maxlong"};
  }
  if (exists($centerHash{$item}{"minlat"})) {
    if ($centerHash{$item}{"minlat"} > $workHash{"minlat"}) {
      $centerHash{$item}{"minlat"} = $workHash{"minlat"};
    }
  }
  else {
    $centerHash{$item}{"minlat"} = $workHash{"minlat"};
  }
  if (exists($centerHash{$item}{"minlong"})) {
    if ($centerHash{$item}{"minlong"} > $workHash{"minlong"}) {
      $centerHash{$item}{"minlong"} = $workHash{"minlong"};
    }
  }
  else {
    $centerHash{$item}{"minlong"} = $workHash{"minlong"};
  }

}


sub update_centerhash(){

  foreach my $item(keys %centerHash) {
    $centerHash{$item}{"lat"} = $centerHash{$item}{"maxlat"};
    $centerHash{$item}{"long"} = $centerHash{$item}{"maxlong"};
    $centerHash{$item}{"lat"} += $centerHash{$item}{"minlat"};
    $centerHash{$item}{"long"} += $centerHash{$item}{"minlong"};
    $centerHash{$item}{"lat"} /= 2;
    $centerHash{$item}{"long"} /= 2;
  }
}


sub create_osm(){

  my $i = 0;
  my ($item, $item2, $item3, $item4) = "";

  if ($switch_place == 1) {
    open(OSM, ">$file_name-place-$count_place_files.osm");
    printf LOG "***** open %s-place-%s.osm\n", $file_name, $count_place_files;
    print OSM "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    print OSM "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";
    foreach $item(keys %placeHash) {
      write_place(1, $item, $item2, $item3, $item4);
      foreach $item2(keys %{$placeHash{$item}}) {
        unless ($item2 eq "*") {write_place(2, $item, $item2, $item3, $item4);}
        foreach $item3(keys %{$placeHash{$item}{$item2}}) {
          unless ($item3 eq "*") {write_place(3, $item, $item2, $item3, $item4);}
          foreach $item4(keys %{$placeHash{$item}{$item2}{$item3}}) {
            unless ($item4 eq "*") {write_place(4, $item, $item2, $item3, $item4);}
          }
        }
      }
    }
    print OSM "</osm>";
    close OSM;
    printf LOG "***** close %s-place-%s.osm\n", $file_name, $count_place_files;
    $count_place_files++;
  }

  if ($switch_inner == 1) {
    open(OSM, ">$file_name-inner-$count_inner_files.osm");
    printf LOG "***** open %s-inner-%s.osm\n", $file_name, $count_inner_files;
    print OSM "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    print OSM "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";
    foreach $item(keys %curveHash) {
      if ($curveHash{$item}{"num"} >= 1) {
        @workArray = split(/,/, $curveHash{$item}{"points"});
        foreach my $coordinate(@workArray) {
          $i = write_node($i, $item, $coordinate);
        }
        $count_ways++;
        write_way("inner", $i, $item);
        $i = 0;
        if ($count_ways == $max_ways_inner) {
          print OSM "</osm>";
          close OSM;
          printf LOG "***** close %s-inner-%s.osm\n", $file_name, $count_inner_files;
          %nodes = ();
          $count_ways = 0;
          $count_inner_files++;
          open(OSM, ">$file_name-inner-$count_inner_files.osm");
          printf LOG "***** open %s-inner-%s.osm\n", $file_name, $count_inner_files;
          print OSM "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
          print OSM "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";
        }
      }
    }
    print OSM "</osm>";
    close OSM;
    printf LOG "***** close %s-inner-%s.osm\n", $file_name, $count_inner_files;
    $count_inner_files++;
  }

  if ($switch_outer == 1) {
    open(OSM, ">$file_name-outer-$count_outer_files.osm");
    printf LOG "***** open %s-outer-%s.osm\n", $file_name, $count_outer_files;
    print OSM "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
    print OSM "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";
    foreach $item(keys %curveHash) {
      if ($curveHash{$item}{"num"} == 0) {
        @workArray = split(/,/, $curveHash{$item}{"points"});
        foreach my $coordinate(@workArray) {
          $i = write_node($i, $item, $coordinate);
        }
        $count_ways++;
        write_way("outer", $i, $item);
        $i = 0;
        if ($count_ways == $max_ways_outer) {
          print OSM "</osm>";
          close OSM;
          printf LOG "***** close %s-outer-%s.osm\n", $file_name, $count_outer_files;
          %nodes = ();
          $count_ways = 0;
          $count_outer_files++;
          open(OSM, ">$file_name-outer-$count_outer_files.osm");
          printf LOG "***** open %s-outer-%s.osm\n", $file_name, $count_outer_files;
          print OSM "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
          print OSM "<osm version=\"0.5\" generator=\"KSJ2OSM\">\n";
        }
      }
    }
    print OSM "</osm>";
    close OSM;
    printf LOG "***** close %s-outer-%s.osm\n", $file_name, $count_outer_files;
    $count_outer_files++;
  }

  printf LOG 
    "***** Administrative area : skipped %d error coordinates\n"
    , $num_error;
  printf LOG 
    "***** Administrative area : %d nodes on %d ways\n"
    , $num_nodes, $num_ways;
  printf LOG 
    "***** Administrative area : %d nodes tagged as place\n"
    , $num_places;
  printf LOG 
    "***** Administrative area : output place files = %d\n"
    , $count_place_files;
  printf LOG 
    "***** Administrative area : output inner files = %d\n"
    , $count_inner_files;
  printf LOG 
    "***** Administrative area : output outer files = %d\n"
    , $count_outer_files;
  printf 
    "***** Administrative area : skipped %d error coordinates\n"
    , $num_error;
  printf 
    "***** Administrative area : %d nodes on %d ways\n"
    , $num_nodes, $num_ways;
  printf 
    "***** Administrative area : %d nodes tagged as place\n"
    , $num_places;
  printf 
    "***** Administrative area : output place files = %d\n"
    , $count_place_files;
  printf 
    "***** Administrative area : output inner files = %d\n"
    , $count_inner_files;
  printf 
    "***** Administrative area : output outer files = %d\n"
    , $count_outer_files;

}


sub write_place() {

  my ($flag, $item, $item2, $item3, $item4) = @_;
  my $name;
  my $string;
  my $place_tag;
  my $tmp_tags;
  $negative_id--;

  my $tags = &write_osm_constant_tag();

  if ($flag == 1) {
    $name = $item;
    $string = $item;
    $tags .= "<tag k=\"KSJ2:PRN\" v=\"$item\"/>";
    if ($item eq "北海道") {
      $tags .= "<tag k=\"is_in\" v=\"日本 (Japan)\"/>";
      $tags .= "<tag k=\"is_in:country\" v=\"日本 (Japan)\"/>";
      $place_tag = "state";
    }
    else {
      $tags .= "<tag k=\"is_in\" v=\"日本 (Japan)\"/>";
      $tags .= "<tag k=\"is_in:country\" v=\"日本 (Japan)\"/>";
      $tags .= "<tag k=\"is_in:state\" v=\" ()\"/>";
      $place_tag = "region";
    }
  }
  elsif ($flag == 2) {
    $name = $item2;
    $string = $item.$item2;
    $tags .= "<tag k=\"KSJ2:PRN\" v=\"$item\"/>";
    $tags .= "<tag k=\"KSJ2:SUN\" v=\"$item2\"/>";
    $tags .= "<tag k=\"is_in\" v=\"$item ()\"/>";
    $tags .= "<tag k=\"is_in:state\" v=\"$item ()\"/>";
    $place_tag = "region";
  }
  elsif ($flag == 3) {
    $name = $item3;
    $string = $item.$item2.$item3;
    $tags .= "<tag k=\"KSJ2:PRN\" v=\"$item\"/>";
    unless ($item2 eq "*") {
      $tags .= "<tag k=\"KSJ2:SUN\" v=\"$item2\"/>";
      $tags .= "<tag k=\"is_in\" v=\"$item2 ()\"/>";
      $tags .= "<tag k=\"is_in:region\" v=\"$item2 ()\"/>";
    }
    else {
      $tags .= "<tag k=\"is_in\" v=\"$item ()\"/>";
      $tags .= "<tag k=\"is_in:region\" v=\"$item ()\"/>";
    }
    $tags .= "<tag k=\"KSJ2:CON\" v=\"$item3\"/>";
    if ($item3 =~ /郡$/) {$place_tag = "county";}
    else {$place_tag = "city";}               # for "政令指定都市" "東京特別区"
  }
  elsif ($flag == 4) {
    $name = $item4;
    $string = $item.$item2.$item3.$item4;
    $tags .= "<tag k=\"KSJ2:PRN\" v=\"$item\"/>";
    $tmp_tags = "<tag k=\"is_in\" v=\"$item ()\"/>";
    $tmp_tags .= "<tag k=\"is_in:region\" v=\"$item ()\"/>";
    unless ($item2 eq "*") {
      $tags .= "<tag k=\"KSJ2:SUN\" v=\"$item2\"/>";
      $tmp_tags = "<tag k=\"is_in\" v=\"$item2 ()\"/>";
      $tmp_tags .= "<tag k=\"is_in:region\" v=\"$item2 ()\"/>";
    }
    unless ($item3 eq "*") {
      $tags .= "<tag k=\"KSJ2:CON\" v=\"$item3\"/>";
      if ($item3 =~ /郡$/) {
        $tmp_tags = "<tag k=\"is_in\" v=\"$item3 ()\"/>";
        $tmp_tags .= "<tag k=\"is_in:county\" v=\"$item3 ()\"/>";
      }                                                # for "町" "村"
      else {
        $tmp_tags = "<tag k=\"is_in\" v=\"$item3 ()\"/>";
        $tmp_tags .= "<tag k=\"is_in:city\" v=\"$item3 ()\"/>";
      }                                                # for "政令指定都市の区"
    }
    $tags .= $tmp_tags;
    $tags .= "<tag k=\"KSJ2:CN2\" v=\"$item4\"/>";
    if ($item4 =~ /市$/) {$place_tag = "city";}
    elsif ($item4 =~ /区$/) {$place_tag = "town";}
    elsif ($item4 =~ /町$/) {$place_tag = "town";}
    elsif ($item4 =~ /村$/) {$place_tag = "village";}
    else {$place_tag = "locality";}                    # for "所属未定地"
  }

  $tags .= "<tag k=\"place\" v=\"$place_tag\"/>";
  $tags .= "<tag k=\"layer\" v=\"1\"/>";
  $tags .= "<tag k=\"name\" v=\"$name ()\"/>";
  $tags .= "<tag k=\"name:en\" v=\"\"/>";
  $tags .= "<tag k=\"name:ja\" v=\"$name\"/>";
  $tags .= "<tag k=\"name:ja_rm\" v=\"\"/>";

  my $node 
    = sprintf("<node id=\"%d\" visible=\"true\" lat=\"%s\" lon=\"%s\">$tags</node>"
    , $negative_id, $centerHash{$string}{"lat"}, $centerHash{$string}{"long"});
  print OSM "$node\n";
  $num_places++;
  printf LOG "Node %d: %s, %s, %s, %s\n" , $negative_id, $place_tag
    , $string  , $centerHash{$string}{"lat"}, $centerHash{$string}{"long"};

}


sub write_node() {

  my ($i, $item, $coordinate) = @_;
  my $node_id = 0;
  my ($lat, $long) = split(/\s/, $coordinate);

  unless (defined($lat) && defined($long)) {
    print LOG "Skip error data : id = $item, coordinate = $coordinate\n";
    print "Skip error data : id = $item, coordinate = $coordinate\n";
    $num_error++;
    return $i;
  }
  if (($lat eq "") || ($long eq "")) {
    print LOG "Skip error data : id = $item, coordinate = $coordinate, lat = $lat, long = $long\n";
    print "Skip error data : id = $item, coordinate = $coordinate, lat = $lat, long = $long\n";
    $num_error++;
    return $i;
  }
  if (($lat > $north) || ($lat < $south) 
      || ($long > $east) || ($long < $west)) {
    print LOG "Skip error data : id = $item, coordinate = $coordinate, lat = $lat, long = $long\n";
    print "Skip error data : id = $item, coordinate = $coordinate, lat = $lat, long = $long\n";
    $num_error++;
    return $i;
  }

  my $tags = &write_osm_constant_tag();

  $tags .= "<tag k=\"KSJ2:curve_id\" v=\"$item\"/>";
  $tags .= "<tag k=\"KSJ2:coordinate\" v=\"$coordinate\"/>";
  $tags .= "<tag k=\"KSJ2:lat\" v=\"$lat\"/>";
  $tags .= "<tag k=\"KSJ2:long\" v=\"$long\"/>";

  if (exists($nodes{"$lat $long"})) {
    $node_id = $nodes{"$lat $long"};
  }
  else {
    $negative_id--;
    $node_id = $negative_id;
    $nodes{"$lat $long"} = $node_id;
    my $node 
      = sprintf("<node id=\"%d\" visible=\"true\" lat=\"%s\" lon=\"%s\">$tags</node>"
      , $node_id, $lat, $long);
    print OSM "$node\n";
    $num_nodes++;
  }

  $node_ref .= sprintf("<nd ref=\"%d\" />", $node_id);
  printf LOG "Node %d: %s, %s\n", $node_id, $lat, $long;
  $i++;
  return $i;

}


sub write_way() {

  my ($flag, $i, $item) = @_;
  $negative_id--;

  my $tags = &write_osm_constant_tag();

  $tags .= "<tag k=\"boundary\" v=\"administrative\"/>";

  if ($flag eq "inner") {$tags .= "<tag k=\"admin_level\" v=\"8\"/>";}
  else {$tags .= "<tag k=\"admin_level\" v=\"6\"/>";}

  $tags .= "<tag k=\"KSJ2:curve_id\" v=\"$item\"/>";
#  $tags .= "<tag k=\"KSJ2:points\" v=\"$curveHash{$item}{'points'}\"/>"; # comment out to reduce data size

  my $way 
    = sprintf("<way id=\"%d\" action=\"modify\" visible=\"true\">$node_ref$tags</way>"
    , $negative_id);
  print OSM "$way\n";
  $num_ways++;
  printf LOG "Way %d: %d nodes, curve id=%s\n"
    , $negative_id, $i, $item;
  $node_ref = "";

}


# run this script.

main();


# end of script

__END__