2025年10月15日水曜日

東京都デジタルツインのLasデータをデータベースにロードし等高線を生成してマップ上に表示する #JoelKallmanDay

東京都デジタルサービス局による東京都デジタルツイン実現プロジェクトで公開している島しょ地域点群データより、伊豆諸島の神津島の西にある恩馳島(おんばせじま)の1つのメッシュに含まれるLasデータから等高線を生成し、APEXアプリケーションのマップ上に表示します。

点群データはデータ量が多く、手元で動かせるOracle Database 23ai Freeでは、一本の等高線を生成するだけで何時間もかかります。そのため、作業の目的は等高線を生成することではなく、Oracle Databaseで点群データを扱う手順の確認です。
  1. LasファイルからCSVファイルを生成しました。
  2. CSVファイルをフラットな点群データとしてデータベースにアップロードしました。
  3. フラットな点群データをOracle Spatialの点群データ型であるSDO_PC型へ変換しました。
  4. SDO_PC型のデータから等高線(SDO_GEOMETRY型)を生成しました。
  5. 生成した等高線をマップ上に表示しました。
  6. オープンデータのDXF形式の等高線をGDALのogr2ogrを使って表示しました。
作成したAPEXアプリケーションのマップ表示は以下になります。IDが09QC6295のメッシュを対象として作業を実施しています。標高0mから60mまで、10m間隔で等高線を生成し、表示しています。


APEXアプリケーションは、等高線を保持している表からほぼ自動で生成できます。そのため、APEXアプリケーションの作成よりは、それまでの準備が実際の作業になります。


Lasファイルの取得



東京都デジタルツイン実現プロジェクトの島しょ地域点群データより、オリジナル(DSM)及びグラウンドデータ(DEM)を開きます。


等高線を生成する対象のメッシュを選択してダウンロードします。


選択したメッシュの名前(本記事の作業では09QC6295.zip)が付いたZIPファイルが、手元にダウンロードされます。それを解凍すると.lasファイルになります。

unzip 09QC6295.zip

onbase % unzip 09QC6295.zip 

Archive:  09QC6295.zip

  inflating: 09QC6295.las            

onbase % 



LasからCSVファイルへの変換



本記事では作業をmacOS上で実施します。データベースにLasデータをロードするには、CSV形式に変換する必要があります。CSVへの変換は、PDALまたはLAStoolsで実施できます。本記事では、LAStoolsにOpen source toolsとして含まれているlas2lasおよびlas2txtを使用することにしました。LAStoolsにはOpen source tools、Free tools、Closed source toolsと、それぞれ使用条件の異なるソフトウェアが含まれています。そのため、使用するツールごとに事前にライセンスを確認します。Open source toolsについてはLGPL-2.1のようです。

ARM版macOSに対応したLAStoolsのバイナリが見つけれらなかったため、GitHubからOpen source toolsのリポジトリをクローンし、ビルドしました。

作業ディレクトリ以下にLAStoolsのリポジトリをクローンします。

git clone https://github.com/LAStools/LAStools.git

onbase % git clone https://github.com/LAStools/LAStools.git

Cloning into 'LAStools'...

remote: Enumerating objects: 11261, done.

remote: Counting objects: 100% (1841/1841), done.

remote: Compressing objects: 100% (413/413), done.

remote: Total 11261 (delta 1585), reused 1463 (delta 1428), pack-reused 9420 (from 2)

Receiving objects: 100% (11261/11261), 21.22 MiB | 6.80 MiB/s, done.

Resolving deltas: 100% (8580/8580), done.

onbase % 


リポジトリをクローンするとディレクトリLAStoolsが作成されます。作成されたディレクトリLAStoolsへ移動します。

cd LAStools

onbase % cd LAStools 

LAStools % ls

bin data lastools.dsw LICENSE.txt

CHANGES.txt example_batch_scripts LAStools.sln readme_logo.jpg

CMakeLists.txt HALL_OF_SHAME.txt LASzip README.md

COPYING.txt LASlib license.html src

LAStools %


バイナリのビルドにはcmakeを使用します。macOSに、Xcodeのコマンドライン・ツール(clang含む)やcmake(brew install cmake)をあらかじめインストールしておく必要があります。

以下のコマンドを実行し、LAStoolsのバイナリを作成します。make実行時に発生したエラーを回避するため、cmakeでCコンパイラに与えるフラグとして-Wno-error -Wno-non-pod-varargs -Wno-deprecated-declarationsを追加しています。
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-Wno-non-pod-varargs -Wno-deprecated-declarations" \
..
make -j"$(sysctl -n hw.ncpu)"

LAStools % mkdir build && cd build

build % cmake -DCMAKE_BUILD_TYPE=Release \

-DCMAKE_CXX_FLAGS="-Wno-non-pod-varargs -Wno-deprecated-declarations" \

..

-- The CXX compiler identification is AppleClang 17.0.0.17000319

-- The C compiler identification is AppleClang 17.0.0.17000319

-- Detecting CXX compiler ABI info

-- Detecting CXX compiler ABI info - done

-- Check for working CXX compiler: /usr/bin/c++ - skipped

-- Detecting CXX compile features

-- Detecting CXX compile features - done

-- Detecting C compiler ABI info

-- Detecting C compiler ABI info - done

-- Check for working C compiler: /usr/bin/cc - skipped

-- Detecting C compile features

-- Detecting C compile features - done

-- Configuring done (0.4s)

-- Generating done (0.0s)

-- Build files have been written to: /Users/**********/Documents/onbase/LAStools/build

build % make -j"$(sysctl -n hw.ncpu)"

[  1%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader.cpp.o

[  3%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_shp.cpp.o

[  3%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasignore.cpp.o

[  4%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_las.cpp.o

[  7%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_bil.cpp.o

[  8%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/laswriter.cpp.o

[  8%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_asc.cpp.o

[  8%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_qfit.cpp.o

[  9%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_bin.cpp.o

[ 10%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreadermerged.cpp.o

[ 12%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_dtm.cpp.o

[ 13%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_ply.cpp.o

[ 13%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreaderbuffered.cpp.o

[ 14%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreaderstored.cpp.o

[ 16%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreaderpipeon.cpp.o

[ 16%] Building CXX object LASlib/src/CMakeFiles/LASlib.dir/lasreader_txt.cpp.o

In file included from /Users/ynakakoshi/Documents/onbase/LAStools/LASlib/src/lasreader.cpp:31:

In file included from /Users/ynakakoshi/Documents/onbase/LAStools/LASlib/inc/lasreader.hpp:55:

In file included from /Users/ynakakoshi/Documents/onbase/LAStools/LASlib/inc/lasdefinitions.hpp:63:

/Users/ynakakoshi/Documents/onbase/LAStools/LASzip/src/laspoint.hpp:303:9: warning: unknown pragma ignored [-Wunknown-pragmas]

  303 | #pragma warning(push)

      |         ^


[中略]


29 warnings generated.

21 warnings generated.

[100%] Linking CXX executable /Users/ynakakoshi/Documents/onbase/LAStools/bin64/lasinfo64

[100%] Built target lasinfo

build % 


ビルドが正常に完了するとリポジトリをクローンしたディレクトリLAStoolsの下にディレクトリbin64が作成され、そこに一連のLAStoolsのOpen source toolsのバイナリが配置されます。

cd ..
ls bin64

build % cd ..

LAStools % ls bin64

las2las64 lascopcindex64 lasindex64 lasmerge64 laszip64

las2txt64 lasdiff64 lasinfo64 lasprecision64 txt2las64

LAStools %


これらのコマンドを使用するために、環境変数PATHに含めます。

export PATH=$PWD/bin64:$PATH

LAStools % export PATH=$PWD/bin64:$PATH

LAStools % 


ビルドしたLAStoolsを使用して、先ほど解凍したLasファイル09QC6295.lasよりCSVファイルを生成します。

等高線を生成するにあたって地表面だけを対象にします。建物・樹木などは含まないように、LasデータよりClass 1/9のDSM(陸部)データを除きます。las2las64を実行し、Class 2/4、12、22のみを取り出します。

mv 09QC6295.las 09QC6295_all.las
las2las64 -i 09QC6295_all.las -o 09QC6295.las -keep_class 2 4 12 22

onbase % mv 09QC6295.las 09QC6295_all.las

onbase % las2las64 -i 09QC6295_all.las -o 09QC6295.las -keep_class 2 4 12 22

onbase %


las2txt64を実行し、LasデータをCSVに変換します。parseオプションにxyzirnedcaRGBを指定していますが、今回使用するデータは最初のxyzの3列のみです。

las2txt64 -i 09QC6295.las -o 09QC6295.csv -parse xyzirnedcaRGB -sep comma

onbase % las2txt64 -i 09QC6295.las -o 09QC6295.csv -parse xyzirnedcaRGB -sep comma

onbase % ls -l 09QC6295.*

-rw-r--r--  1 ********  staff  161142749 10月 14 12:22 09QC6295.csv

-rw-r--r--  1 ********  staff   81351793 10月 14 12:18 09QC6295.las

-rw-r--r--@ 1 ********  staff   82706254 10月 14 11:23 09QC6295.zip

onbase % 


headコマンドでCSVファイルの先頭データを確認します。ヘッダー行を含まず、parseオプションで指定したデータが、カンマ区切りで列記されています。

head 09QC6295.csv

onbase % head 09QC6295.csv

-69888.740,-200700.000,0.810,11078,1,1,0,1,2,3,41728,43264,40704

-69749.450,-200999.240,0.930,14406,1,1,0,1,2,-11,41984,40192,35328

-69749.630,-200999.050,1.480,6361,1,1,0,1,2,-11,44288,44032,40192

-69749.360,-200999.090,1.320,9665,1,1,0,1,2,-11,45824,44544,38656

-69751.120,-200997.910,0.880,8949,1,1,0,1,2,-11,44544,44544,40704

-69750.600,-200998.300,1.580,3854,1,1,0,1,2,-11,41728,41984,38912

-69750.340,-200998.390,1.590,3962,1,1,0,1,2,-11,43264,43008,39680

-69750.080,-200998.550,1.830,3112,1,1,0,1,2,-11,45568,45824,40960

-69749.830,-200998.710,2.060,3530,1,1,0,1,2,-11,41984,42240,39168

-69749.560,-200998.790,2.010,3812,1,1,0,1,2,-11,40448,41216,38912

onbase % 



CSVをSDO_PC型の点群データとして保存



データベースに表を作成し、フラットな点群データとしてCSVファイルのデータをアップロードします。その後、SDO_PC型の点群データに変換します。CSVのアップロードにはSQLclのLOADコマンドを使用します。

CSVのアップロード先となる表を作成します。名前はLIDAR_POINTSとします。
drop table if exists lidar_points;
create table lidar_points (
  x                     NUMBER,        -- X
  y                     NUMBER,        -- Y
  z                     NUMBER,        -- Z
  intensity             NUMBER,        -- i => Intensity
  return_number         NUMBER,        -- r => Return Number
  number_of_returns     NUMBER,        -- n => Number of Returns
  edge_of_flight_line   NUMBER,        -- e => Flightline Edge
  scan_direction_flag   NUMBER,        -- d => Scan Direction Flag
  classification        NUMBER,        -- c => Classification
  scan_angle_rank       NUMBER,        -- a => Scan Angle Rank
  r                     NUMBER,        -- R => Color red (2 bytes [0-65536])
  g                     NUMBER,        -- G => Color green (2 bytes [0-65536])
  b                     NUMBER         -- B => Color blue (2 bytes [0-65536])
)
nologging;
最終的に生成した等高線はAPEXのマップに表示するため、APEXのワークスペース・スキーマに表を作成し、CSVをアップロードします。

onbase % sql wksp_apexdev@localhost/freepdb1



SQLcl: 火 10月 14 12:34:48 2025のリリース25.2 Production


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


パスワード (**********?) ******

接続先:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.9.0.25.07


SQL> drop table if exists lidar_points;


Table LIDAR_POINTSが削除されました。


SQL> create table lidar_points (

  2    x                     NUMBER,        -- X

  3    y                     NUMBER,        -- Y

  4    z                     NUMBER,        -- Z

  5    intensity             NUMBER,        -- i => Intensity

  6    return_number         NUMBER,        -- r => Return Number

  7    number_of_returns     NUMBER,        -- n => Number of Returns

  8    edge_of_flight_line   NUMBER,        -- e => Flightline Edge

  9    scan_direction_flag   NUMBER,        -- d => Scan Direction Flag

 10    classification        NUMBER,        -- c => Classification

 11    scan_angle_rank       NUMBER,        -- a => Scan Angle Rank

 12    r                     NUMBER,        -- R => Color red (2 bytes [0-65536])

 13    g                     NUMBER,        -- G => Color green (2 bytes [0-65536])

 14    b                     NUMBER         -- B => Color blue (2 bytes [0-65536])

 15  )

 16* nologging;


Table LIDAR_POINTSは作成されました。


SQL> 


SQLclのLOADコマンドを実行し、CSVファイルを表LIDAR_POINTSにアップロードします。データ量が多いのでバッチで処理する行を10000まで増やします。また、位置で列をマップするようにオプションを設定します。

set load batch_rows 10000
set loadformat column_names off
load lidar_points 09QC6295.csv

おおよそ240万の点群が表LIDAR_POINTSにロードされます。

SQL> set load batch_rows 10000

SQL> set loadformat column_names off

SQL> load lidar_points 09QC6295.csv


csv

column_names off

delimiter ,

enclosures ""

double off

encoding UTF8

row_limit off

row_terminator default

skip_rows 0

skip_after_names


データを表にロードします WKSP_APEXDEV.LIDAR_POINTS

batch_rows 10000

batches_per_commit 10

clean_names transform

column_size rounded

commit on

date_format 

errors 50

map_column_names off

method insert

timestamp_format 

timestamptz_format 

locale

scan_rows 100

truncate off

unknown_columns_fail on


#INFO 処理された行数: 2,392,691

#INFO エラーのある行数: 0

#INFO 最後にコミットされたバッチで処理された最後の行: 2,392,691

成功: エラーなしで処理されました

SQL> 


座標X、YおよびZの最小値と最大値を確認します。座標参照系は、日本測地系2011/平面直角座標系第9系(EPSG:6677)です。
SELECT
  MIN(x) as min_x, MAX(x) as max_x,
  MIN(y) as min_y, MAX(y) as max_y,
  MIN(z) as min_z, MAX(z) as max_z
FROM lidar_points;

SQL> SELECT

  2    MIN(x) as min_x, MAX(x) as max_x,

  3    MIN(y) as min_y, MAX(y) as max_y,

  4    MIN(z) as min_z, MAX(z) as max_z

  5* FROM lidar_points;


    MIN_X     MAX_X      MIN_Y      MAX_Y     MIN_Z    MAX_Z 

_________ _________ __________ __________ _________ ________ 

   -70000    -69600    -201000    -200700    -12.97    65.08 


SQL> 


Z方向が-12.97mから65.08mの間にデータがあるので、生成できる等高線もこの間になります。

このアップロードしたフラットな点群データを、Oracle SpatialでPoint Cloudを扱うデータ型であるSDO_PC型のデータとして保存します。以下のスクリプトを実行します。


SQL> @create_point_cloud


Table LIDAR_PC_BASEが削除されました。



Table LIDAR_PC_BASEは作成されました。



Table LIDAR_PC_BLKが削除されました。



Table LIDAR_PC_BLKは作成されました。


Point Cloudオブジェクトが初期化されました



PL/SQLプロシージャが正常に完了しました。



Table LIDAR_INPUT_PCが削除されました。



Table LIDAR_INPUT_PCは作成されました。


Point Cloudの作成が完了しました



PL/SQLプロシージャが正常に完了しました。


SQL>


スクリプトの実行結果を確認します。ブロックテーブルである表LIDAR_PC_BLKの内容を表示します。
SELECT
  COUNT(*) as block_count,
  SUM(num_points) as total_points,
  MIN(num_points) as min_points_per_block,
  MAX(num_points) as max_points_per_block,
  AVG(num_points) as avg_points_per_block
FROM lidar_pc_blk;
SDO_PC_PKG.INITを呼び出す際に点群のパーティション化のパラメータ(引数ptn_params)に、blk_capacity=1000を設定しているため、MAX_POINTS_PER_BLOCKは10000になっています。TOTAL_POINTSは表LIDAR_POINTS(および表LIDAR_INPUT_PC)の行数と一致します。

以上より、Point Cloudに指定した点群がロードされていることが確認できます。

SQL> SELECT

  2    COUNT(*) as block_count,

  3    SUM(num_points) as total_points,

  4    MIN(num_points) as min_points_per_block,

  5    MAX(num_points) as max_points_per_block,

  6    AVG(num_points) as avg_points_per_block

  7* FROM lidar_pc_blk;


   BLOCK_COUNT    TOTAL_POINTS    MIN_POINTS_PER_BLOCK    MAX_POINTS_PER_BLOCK                         AVG_POINTS_PER_BLOCK 

______________ _______________ _______________________ _______________________ ____________________________________________ 

           240         2392691                    6345                   10000    9969.545833333333333333333333333333333333 


SQL> 


生成した等高線を保存する表をCONTOUR_LINESとして作成します。
drop table if exists contour_lines purge;
create table contour_lines (
  contour_id number generated by default as identity primary key,
  elevation  number,
  geom_6677  mdsys.sdo_geometry,   -- EPSG:6677
  geom_wgs84 mdsys.sdo_geometry,   -- EPS_G:4326
  geom       mdsys.sdo_geometry    -- sdo_util.remove_duplicate_vertices
);

SQL> drop table if exists contour_lines purge;


Table CONTOUR_LINESが削除されました。


SQL> create table contour_lines (

  2    contour_id number generated by default as identity primary key,

  3    elevation  number,

  4    geom_6677  mdsys.sdo_geometry,   -- EPSG:6677

  5    geom_wgs84 mdsys.sdo_geometry,   -- EPSG:4326

  6    geom       mdsys.sdo_geometry    -- sdo_util.remove_duplicate_vertices

  7* );


Table CONTOUR_LINESは作成されました。


SQL> 


以下のスクリプトを実行し、等高線を生成します。for文で0..6を指定し、forループの内部でl_elevation、つまり等高線の標高に0, 10, 20, 30, 40, 50, 60を順次与えて、一本ずつ等高線を生成しています。SDO_PC_PKG.CREATE_CONTOUR_GEOMETRIESの引数elevationsには複数の値が設定でき、また引数elevations_max、elevations_min、elevations_intervalを指定することにより、等高線を生成する範囲と増分を指定することも可能です。

標高0mから60mまで、7本の等高線を生成するのに1日くらいかかったので、実際に実行するのであれば、リソースの潤沢な環境で実行するか、生成する等高線の本数を減らすことをお勧めします。

上記の処理が完了すると、生成された等高線が表CONTOUR_LINESの列GEOM_6677に、SDO_GEOMETRYのLINESTRINGとして保存されます。

select elevation, sdo_util.to_wktgeometry(geom_6677) from contour_lines;

SQL> select elevation, sdo_util.to_wktgeometry(geom_6677) from contour_lines;


   ELEVATION SDO_UTIL.TO_WKTGEOMETRY(GEOM_6677)                                                  

____________ ___________________________________________________________________________________ 

           0 LINESTRING (-69967.3933570539 -200999.5, -69967.5 -200999.350083891, -69969.5 -2    

          10 LINESTRING (-69893.5 -200905.218388821, -69895.087159423 -200905.5, -69895.5 -20    

          20 LINESTRING (-9893.5 -200913.191513301, -9894.87498406222 -200913.5, -9895.5 -200    

          30 LINESTRING (-9895.5 -200919.186358386, -9895.84202419422 -200919.5, -9897.5 -200    

          40 LINESTRING (-69774.0662795354 -200811.5, -69775.5 -200810.867211666, -69777.5 -2    

          50 LINESTRING (-9725.5 -200809.466071466, -9727.5 -200808.938161045, -9729.5 -20080    

          60 LINESTRING (-9767.5 -200881.000708521, -9769.5 -200880.815372578, -9770.44721335    


7行が選択されました。 


SQL> 


等高線の間隔は一般にメートルを単位とします。そのため、座標参照系は、日本測地系2011/平面直角座標系第9系のまま作業しています。

APEXのマップに等高線を表示するには、参照座標系を世界測地系1984(EPSG:4326)に変換する必要があります。EPSG:4326に変換したデータを保持するための列GEOM_WSG84は作成済みです。列GEOM_6677の値を世界測地系に変換して、GEOM_WSG84に保存します。
update contour_lines set geom_wgs84 =
    SDO_CS.MAKE_2D(
        SDO_CS.TRANSFORM(
            geom_6677,
            4326
       )
    );
commit;

SQL> update contour_lines set geom_wgs84 =

  2      SDO_CS.MAKE_2D(

  3          SDO_CS.TRANSFORM(

  4              geom_6677,

  5              4326

  6         )

  7*     );


7行更新しました。


SQL> commit;


コミットが完了しました。


SQL> 


世界測地系84に更新されたので、本来であればこれでAPEXのマップに等高線を表示できます。しかし、現状ではデータに問題があります。APEXのマップはMapLibre GL JSをライブラリとして使用しており、SDO_GEOMETRYのデータはGeoJSONに変換してマップ上に表示します。

select sdo_util.to_geojson(geom_wgs84) from contour_lines;

現状ではORA-13199: GeoJSON supports only a straight lineが発生し、等高線のデータをGeoJSONに変換できません。

SQL> select sdo_util.to_geojson(geom_wgs84) from contour_lines;


次のコマンド行の開始中にエラーが発生しました : 1 -

select sdo_util.to_geojson(geom_wgs84) from contour_lines

コマンド行 : 1 列 : 8 でのエラー

エラー・レポート -

SQLエラー: ORA-13199: GeoJSON supports only a straight line

ORA-06512: "MDSYS.SDO_UTIL", 行9150

ORA-06512: "MDSYS.SDO_UTIL", 行9171


https://docs.oracle.com/error-help/db/ora-13199/13199. 00000 -  "%s"

*Cause:    This is an internal error.

*Action:   Contact Oracle Support Services.


More Details :

https://docs.oracle.com/error-help/db/ora-13199/

https://docs.oracle.com/error-help/db/ora-06512/

SQL> 


データをクリーンアップするため、SDO_UTIL.REMOVE_DUPLICATTE_VERTICESを実行します。
update contour_lines set geom =
    sdo_util.remove_duplicate_vertices(
        geom_wgs84,
        1e-6
    );
commit;

SQL> update contour_lines set geom =

  2      sdo_util.remove_duplicate_vertices(

  3          geom_wgs84,

  4          1e-6

  5*     );


7行更新しました。


SQL> commit;


コミットが完了しました。


SQL> 


以上で表CONTOUR_LINESの列GEOMに、APEXのマップ上に表示できる等高線のデータが保存されました。


APEXアプリケーションの作成



アプリケーション作成ウィザードを起動します。アプリケーションの名前等高線とします。

マップのページを追加するため、ページの追加をクリックします。


マップを選択します。


ページ名等高線とします。CONTOUR_LINES形式を選択します。

ジオメトリ列GEOMツールチップ列ELEVATIONを選択します。

以上でページの追加をクリックします。


マップがページとして追加されました。

アプリケーションの作成を実行します。


等高線をマップ上に表示するAPEXアプリケーションが作成されました。


アプリケーションを実行して、マップ上に表示される等高線を確認します。

マップを確認すると、1ケ所は正しく恩馳島の上に等高線が表示されていますが、それ以外に3ケ所、不正な場所に等高線が表示されます。


デフォルトの外観では見にくいため、ストロークの色#000000)、ストロークの幅1に設定します。


島の上に表示されている等高線は問題なさそうです。


海上に表示されている等高線は問題があります。おそらくSDO_PC_PKG.CREATE_CONTOUR_GEOMETRIESの不具合と思われます。


ワークアラウンドを適用します。

等高線は元々以下の範囲に存在する点群のデータから生成されています。従って、等高線も以下の範囲に限定されます。

SQL> SELECT

  2    MIN(x) as min_x, MAX(x) as max_x,

  3    MIN(y) as min_y, MAX(y) as max_y,

  4    MIN(z) as min_z, MAX(z) as max_z

  5* FROM lidar_points;


    MIN_X     MAX_X      MIN_Y      MAX_Y     MIN_Z    MAX_Z 

_________ _________ __________ __________ _________ ________ 

   -70000    -69600    -201000    -200700    -12.97    65.08 


SQL> 


X方向で-70000から-69600、Y方向で-20100から-200700の範囲に含まれる等高線のみを、新たな表CONTOUR_LINES2へ保存します。

以下のスクリプトを実行します。参照系がEPSG:6677のデータである列GEOM_6677の等高線の範囲を限定した後、EPSG:4326への変換とクリーンアップを実施しています。


先ほど作成したマップのレイヤーソース表名CONTOUR_LINESから、ワークアラウンドを適用した表CONTOUR_LINES2に置き換えます。


等高線のデータを点群が存在する領域に限定する(点群が存在する領域以外の等高線は削除する)ことにより、恩馳島上にのみ等高線が表示されるようになりました。



オープンデータの等高線を表示する



東京都デジタルツインの島しょ地域点群データには等高線が含まれています。データの形式はDXFです。


Lasと同様に、恩馳島の1つのメッシュ09QC6295のDXFデータをOracle DatabaseにロードしてAPEXのマップ上に表示してみます。

DXFのデータベースへのロードは、GDALのogr2ogrコマンドで実行できます。GDALのogr2ogrコマンドの実行方法については、記事「GDALのogr2ogrを使ってShapefileをOracle DatabaseのSDO_GEOMETRY列にロードする」で紹介しています。

Oracle Databaseのドライバを組み込んだGDALがインストールされているコンテナを起動します。マウントしている作業ディレクトリに、DXFファイル09qc6295.dxfを配置します。

podman run --rm -it -v $PWD:/home/oracle gdal

以下のコマンドを実行します。ファイル09qc6295.dxfに記載されている等高線(1m間隔)が、表CONTOUR_LINES_FULLの列GEOMにSDO_GEOMETRY型で保存されます。
ogr2ogr -f OCI -overwrite \
OCI:wksp_apexdev/********@host.containers.internal/freepdb1 \
09qc6295.dxf \
-oo ENCODING=CP932 \
-nln CONTOUR_LINES_FULL -lco GEOMETRY_NAME=GEOM -lco SRID=4326 -lco DIM=2 \
-s_srs EPSG:6677 \
-t_srs EPSG:4326 \
-skipfailures

bash-5.1$ ogr2ogr -f OCI -overwrite \

OCI:wksp_apexdev/oracle@host.containers.internal/freepdb1 \

09qc6295.dxf \

-oo ENCODING=CP932 \

-nln CONTOUR_LINES_FULL -lco GEOMETRY_NAME=GEOM -lco SRID=4326 -lco DIM=2 \

-s_srs EPSG:6677 \

-t_srs EPSG:4326 \

-skipfailures

bash-5.1$ 


ogr2ogrの実行結果を、APEXマップにレイヤーを追加して確認します。

レイヤー名前オープンデータソース表名CONTOUR_LINES_FULL列のマッピングジオメトリ列GEOMを設定します。


ページを実行し、表示するレイヤーをオープンソースに限定します。

DXFをインポートしたデータは、APEXマップで以下のように表示されます。


今回の記事は以上になります。

Oracle APEXのアプリケーション作成の参考になれば幸いです。

追記


Claude DesktopにSQLclのMCPサーバーを組み込み、かなりの部分のSQLおよびPL/SQLのコードを生成しています。Oracle Spatialのファンクションを含んだコードでも、かなり正しく生成します。