国土数値地理情報から白地図を作る。5

使いやすい白地図にするために適度なサイズで閉じた曲線の地図を作成したいと思います。市区町村の境界線を削除した段階で県境の線が途切れています。上図は群馬県の部分を拡大したものです。各都道府県にこのような途切れた部分があります。重なった点を削除しているので線が途切れてしまってます。この問題をなんとかしてデータを軽くする方法を考えます。

まずは座標データの間隔がどのくらいになっているのか調べてみます。まずは結果をみてください。県ごとにこのぐらい。緯度経度の座標の二乗差の値です。

ken=1 ave distance=5.0200113684345E-8
ken=2 ave distance=5.3156668164525E-8
ken=3 ave distance=8.3779704917477E-9
ken=4 ave distance=1.085904100952E-8
ken=5 ave distance=5.9052304052192E-8
ken=6 ave distance=1.0551567807381E-7
ken=7 ave distance=7.8584973816981E-8
ken=8 ave distance=1.9429582047053E-7
ken=9 ave distance=1.1079762371445E-7
ken=10 ave distance=1.3666066173892E-7
ken=11 ave distance=2.0144502241745E-7
ken=12 ave distance=8.3430549743722E-8
ken=13 ave distance=1.309855058907E-8
ken=14 ave distance=4.7069462046374E-8
ken=15 ave distance=5.1975147707033E-8
ken=16 ave distance=1.0831079341081E-7
ken=17 ave distance=4.0007845746881E-8
ken=18 ave distance=2.3367516558465E-8
ken=19 ave distance=6.9846723484265E-8
ken=20 ave distance=1.06297918979E-7
ken=21 ave distance=2.3300018210669E-7
ken=22 ave distance=1.1522431651823E-8
ken=23 ave distance=7.2972781784462E-8
ken=24 ave distance=1.1607524038164E-8
ken=25 ave distance=1.6562118764917E-7
ken=26 ave distance=3.1007666175784E-8
ken=27 ave distance=2.2050518353815E-7
ken=28 ave distance=4.5387640328185E-8
ken=29 ave distance=1.762651328722E-7
ken=30 ave distance=1.893787347694E-8
ken=31 ave distance=5.4418585271751E-8
ken=32 ave distance=2.0243061140028E-8
ken=33 ave distance=6.0194199671794E-8
ken=34 ave distance=5.4104463719212E-8
ken=35 ave distance=2.8155338343764E-8
ken=36 ave distance=1.6344519839681E-8
ken=37 ave distance=2.9825720490774E-8
ken=38 ave distance=1.9030558043225E-8
ken=39 ave distance=2.6529391013701E-8
ken=40 ave distance=5.805289717951E-8
ken=41 ave distance=6.1803594614252E-8
ken=42 ave distance=1.3768802763865E-8
ken=43 ave distance=6.2543088072567E-8
ken=44 ave distance=4.955193423389E-8
ken=45 ave distance=2.1652320679639E-8
ken=46 ave distance=1.7302600741194E-8
ken=47 ave distance=2.1280015621815E-8

県別の最小と最大は

min(ave)=8.3779704917477E-9
max(ave)=2.3300018210669E-7

すべての値の最小と最大値は

min=3.9999949775827E-16
max=9.8725095528889E-5

このようになりました。
かなり幅があるので、どうしよう?という感じの結果です。この計算を行ったコードは次の通りです。前に作った県ごとのXMLを読み込んで点と点の距離を求めているだけです。

measureDotDistance.php

<?php
//XMLフォルダに保存した各県のデータを読み取りSVGを描画
//県境を削除する。

ini_set('memory_limit', '2540M');

mb_language("Japanese");//文字コードの設定
mb_internal_encoding("UTF-8");

//ファイルリスト
$xmlFile[1] ="./XML/hokkaido.xml";
$xmlFile[2] ="./XML/aomori.xml";
$xmlFile[3] ="./XML/iwate.xml";
$xmlFile[4] ="./XML/miyagi.xml";
$xmlFile[5] ="./XML/akita.xml";
$xmlFile[6] ="./XML/yamagata.xml";
$xmlFile[7] ="./XML/fukushima.xml";
$xmlFile[8] ="./XML/ibaraki.xml";
$xmlFile[9] ="./XML/tochigi.xml";
$xmlFile[10] ="./XML/gunnma.xml";
$xmlFile[11] ="./XML/saitama.xml";
$xmlFile[12] ="./XML/chiba.xml";
$xmlFile[13] ="./XML/tokyo.xml";
$xmlFile[14] ="./XML/kanagawa.xml";
$xmlFile[15] ="./XML/niigata.xml";
$xmlFile[16] ="./XML/toyama.xml";
$xmlFile[17] ="./XML/isihikawa.xml";
$xmlFile[18] ="./XML/fukui.xml";
$xmlFile[19] ="./XML/yamanashi.xml";
$xmlFile[20] ="./XML/nagano.xml";
$xmlFile[21] ="./XML/gifu.xml";
$xmlFile[22] ="./XML/sizuoka.xml";
$xmlFile[23] ="./XML/aiti.xml";
$xmlFile[24] ="./XML/mie.xml";
$xmlFile[25] ="./XML/shiga.xml";
$xmlFile[26] ="./XML/kyoto.xml";
$xmlFile[27] ="./XML/osaka.xml";
$xmlFile[28] ="./XML/hyougo.xml";
$xmlFile[29] ="./XML/nara.xml";
$xmlFile[30] ="./XML/wakayama.xml";
$xmlFile[31] ="./XML/tottori.xml";
$xmlFile[32] ="./XML/shimane.xml";
$xmlFile[33] ="./XML/okayama.xml";
$xmlFile[34] ="./XML/hiroshima.xml";
$xmlFile[35] ="./XML/yamaguchi.xml";
$xmlFile[36] ="./XML/tokushima.xml";
$xmlFile[37] ="./XML/kagawa.xml";
$xmlFile[38] ="./XML/ehime.xml";
$xmlFile[39] ="./XML/kouchi.xml";
$xmlFile[40] ="./XML/fukuoka.xml";
$xmlFile[41] ="./XML/saga.xml";
$xmlFile[42] ="./XML/nagasaki.xml";
$xmlFile[43] ="./XML/kumamoto.xml";
$xmlFile[44] ="./XML/ooita.xml";
$xmlFile[45] ="./XML/miyazaki.xml";
$xmlFile[46] ="./XML/kagoshima.xml";
$xmlFile[47] ="./XML/okinawa.xml";


readXMLmeasureDistance($xmlFile);

function readXMLmeasureDistance($xmlFile){
  $startKenNo = 1;
  $endKenNo = 47;

  for ($ken=$startKenNo; $ken<$endKenNo+1; $ken++){
    //XMLの読み込み
    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;
    $dom->load($xmlFile[$ken]);

    $root = $dom->getElementsByTagName("*")->item(0);//最初の要素の中身を取り出す

    //読み込んだxmlの中身を$coordinateStringに展開する。
    $j = 0;
    foreach( $root->getElementsByTagName("gml") as $itemGML ){//これでgmlの中身を$itemに取れる。
      $dataArray = explode("\n",$itemGML->nodeValue);//改行コードで配列にわける

      $i=0;
      foreach ($dataArray as $item) {//各要素ごとに繰り返す
        $item = trim($item);
        if($item != ""){//空白文字列の時には処理をしない。
          $coordinate[$ken][$j][$i]=$item;
          $i++;
        }//if
      }//foreach
      $j++;
    }//foreach( $root->
  }//for ($ken=$startKenNo; $ken<$endKenNo+1; $ken++) XMLの読み込み完了



  //======================距離を調べて点と点が離れている時には別の配列データにする。
  $min = 1.0;
  $max = 0.0;
  for ($ken=$startKenNo ;$ken<$endKenNo+1 ; ++$ken){
    $figMax = count($coordinate[$ken]);
    $ss = 0.0;
    $count = 0;
    for ($i=0 ;$i<$figMax ; $i++){
      $jmax = count($coordinate[$ken][$i]);
      for ($j=0 ;$j<$jmax-1 ; $j++){
        $latilongArray = explode(" ",$coordinate[$ken][$i][$j]);//空白区切りでデータを取り出す
        $latitude1String = $latilongArray[0];//各要素を取り出す
        $longitude1String = $latilongArray[1];

        $latilongArray = explode(" ",$coordinate[$ken][$i][$j+1]);//空白区切りでデータを取り出す
        $latitude2String = $latilongArray[0];//各要素を取り出す
        $longitude2String = $latilongArray[1];

        $x1 = floatval($latitude1String);//文字列のデータをfloatに変換する。
        $y1 = floatval($longitude1String);
        $x2 = floatval($latitude2String);
        $y2 = floatval($longitude2String);
        $dx = $x2 - $x1;
        $dy = $y2 - $y1;
        $s = $dx * $dx  + $dy * $dy;//$jと$j+1の距離の二乗 この値で判定する。
        $ss = $ss + $s;
        $count++;

        if ($min>$s){
          $min = $s;
        }
        if ($max<$s){
          $max = $s;
        }
      }// for $j
    }// for $i
    $ave[$ken] = $ss/$count;

    print("ken=" . $ken . " ave distance=" . $ave[$ken] . "\n");
  }
  print("min(ave)=" .  min($ave) . "\n");
  print("max(ave)=" .  max($ave) . "\n");
  print("min=" .  $min . "\n");
  print("max=" .  $max . "\n");


}// end of function

さてここからどうしよう?
県境のデータは単純に間引きすると県と県がうまく重ならなくなるので重なりを考慮しながら間引く必要があります。そして空いてしまっている部分に直線をいれるという処理をします。どうしよう?うまい方法ないかな?