Skip to content

Commit 387aebc

Browse files
committed
feat: add ISG format support and geoid2024 model
1 parent bde0f79 commit 387aebc

File tree

13 files changed

+854
-23
lines changed

13 files changed

+854
-23
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
*.asc
2+
*.isg
3+
/conv

README.md

Lines changed: 130 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,40 @@
22

33
日本のジオイド高を計算するための Go ライブラリ / Go library for calculating geoid height in Japan
44

5-
- 本ライブラリは国土地理院が提供するものではありません。
6-
- 本ライブラリは [ciscorn/japan-geoid](https://github.com/ciscorn/japan-geoid/tree/main) (MIT License)を参考に実装しています。
5+
- **外部依存ゼロ** - 標準ライブラリのみで動作します
6+
- 本ライブラリは国土地理院が提供するものではありません
7+
- 本ライブラリは [ciscorn/japan-geoid](https://github.com/ciscorn/japan-geoid/tree/main) (MIT License)を参考に実装しています
78

89
## 対応ジオイドモデル
910

10-
- 日本のジオイド 2011(Ver.2.2)([出典](https://fgd.gsi.go.jp/download/geoid.php)): `gsigeoid2011`
11-
- 日本のジオイド 2025([出典](https://www.gsi.go.jp/buturisokuchi/grageo_reference.html)): 正式公開後対応予定
11+
| パッケージ | 関数 | 内容 | サイズ |
12+
|-----------|------|------|--------|
13+
| `gsigeoid2011` | `Load()` | 日本のジオイド2011(Ver.2.2) | 約300KB |
14+
| `gsigeoid2024` | `Load()` | ジオイド2024+基準面補正パラメータ(合成版、推奨) | 約400KB |
15+
| `gsigeoid2024` | `LoadHrefconv()` | 基準面補正パラメータのみ | 約15KB |
16+
| `gsigeoid2024geoid` | `Load()` | ジオイド2024のみ | 約3.7MB |
17+
18+
### 日本のジオイド2011(Ver.2.2)
19+
20+
- 出典: https://fgd.gsi.go.jp/download/geoid.php
21+
22+
### ジオイド2024(日本とその周辺)+基準面補正パラメータ
23+
24+
- 出典: https://service.gsi.go.jp/kiban/app/geoid/
25+
26+
ジオイド・モデル「ジオイド2024日本とその周辺」は、世界測地系(日本測地系2024)における座標値(緯度と経度)で示された任意の位置でのジオイド高を表したデータです。
27+
28+
また、「基準面補正パラメータ」は、東京湾平均海面と離島独自の平均海面の差を基準面補正量と定義し、前述した任意の位置での基準面補正量を表したデータです。
29+
30+
一部の離島において衛星測位によって標高を求める際には、ジオイド高と基準面補正量を使用する必要があります。
31+
32+
ジオイドのみ(`gsigeoid2024geoid`)はサイズが大きいため、別パッケージとして分離しています。必要な場合のみインポートしてください。
33+
34+
※ ジオイドのみのデータが大きい理由:合成版は海域がnodata扱いですが、ジオイドのみのデータは海域にも値が含まれており、圧縮効率が低くなっています。
35+
36+
## 使い方
37+
38+
### gsigeoid2011
1239

1340
## 使い方
1441

@@ -20,26 +47,116 @@ import (
2047
"github.com/eukarya-inc/japan-geoid-go/gsigeoid2011"
2148
)
2249

23-
func Example() {
50+
func main() {
2451
g, err := gsigeoid2011.Load()
2552
if err != nil {
2653
panic(err)
2754
}
2855

2956
lng, lat := 138.2839817085188, 37.12378643088312
3057
height := g.GetHeight(lng, lat)
31-
fmt.Printf("Input: (lng: %.6f, lat: %.6f) -> Geoid height: %.6f\n", lng, lat, height)
58+
fmt.Printf("Geoid height: %.6f\n", height)
59+
// Output: Geoid height: 39.473871
60+
}
61+
```
62+
63+
### gsigeoid2024
64+
65+
```go
66+
package main
3267

33-
lng, lat = 10, 10
34-
height = g.GetHeight(lng, lat)
35-
fmt.Printf("Input: (lng: %.6f, lat: %.6f) -> Geoid height: %.6f\n", lng, lat, height)
68+
import (
69+
"fmt"
70+
"github.com/eukarya-inc/japan-geoid-go/gsigeoid2024"
71+
)
72+
73+
func main() {
74+
// ジオイド2024+基準面補正パラメータ(合成版)
75+
g, err := gsigeoid2024.Load()
76+
if err != nil {
77+
panic(err)
78+
}
79+
80+
lng, lat := 138.2839817085188, 37.12378643088312
81+
height := g.GetHeight(lng, lat)
82+
fmt.Printf("Geoid height: %.6f\n", height)
83+
// Output: Geoid height: 39.596702
3684

37-
// Output:
38-
// Input: (lng: 138.283982, lat: 37.123786) -> Geoid height: 39.473871
39-
// Input: (lng: 10.000000, lat: 10.000000) -> Geoid height: NaN
85+
// 基準面補正パラメータのみ(離島で使用)
86+
gHref, _ := gsigeoid2024.LoadHrefconv()
87+
// 小笠原諸島(父島)付近
88+
fmt.Printf("Hrefconv (Ogasawara): %.6f\n", gHref.GetHeight(142.19, 27.09))
89+
// Output: Hrefconv (Ogasawara): 0.642000
4090
}
4191
```
4292

93+
### gsigeoid2024geoid(ジオイドのみ、約3.7MB)
94+
95+
```go
96+
package main
97+
98+
import (
99+
"fmt"
100+
"github.com/eukarya-inc/japan-geoid-go/gsigeoid2024geoid"
101+
)
102+
103+
func main() {
104+
g, err := gsigeoid2024geoid.Load()
105+
if err != nil {
106+
panic(err)
107+
}
108+
109+
lng, lat := 138.2839817085188, 37.12378643088312
110+
height := g.GetHeight(lng, lat)
111+
fmt.Printf("Geoid height: %.6f\n", height)
112+
// Output: Geoid height: 39.596702
113+
}
114+
```
115+
116+
### ISGパーサー
117+
118+
ISG形式のファイルを直接パースする場合は、`isg` パッケージを使用できます。
119+
120+
```go
121+
package main
122+
123+
import (
124+
"fmt"
125+
"os"
126+
127+
"github.com/eukarya-inc/japan-geoid-go/isg"
128+
)
129+
130+
func main() {
131+
f, _ := os.Open("geoid.isg")
132+
defer f.Close()
133+
134+
grid, err := isg.Parse(f)
135+
if err != nil {
136+
panic(err)
137+
}
138+
139+
fmt.Printf("Model: %s\n", grid.Header.ModelName)
140+
fmt.Printf("Rows: %d, Cols: %d\n", grid.Header.NRows, grid.Header.NCols)
141+
}
142+
```
143+
144+
## 補間アルゴリズム
145+
146+
本ライブラリでは、グリッド点間のジオイド高を計算する際に **双線形補間(Bilinear Interpolation)** を使用しています。
147+
148+
指定された座標を囲む4つのグリッド点の値から、以下の式で補間値を計算します:
149+
150+
```
151+
h = h00 * (1-x) * (1-y) + h01 * x * (1-y) + h10 * (1-x) * y + h11 * x * y
152+
```
153+
154+
ここで:
155+
- `h00`, `h01`, `h10`, `h11`: 4つのグリッド点のジオイド高
156+
- `x`, `y`: グリッド内での相対位置(0.0〜1.0)
157+
158+
グリッド点がデータ範囲外または nodata の場合は `NaN` を返します。
159+
43160
## License
44161

45-
[MIT Lisence](LICENSE)
162+
[MIT License](LICENSE)

cmd/conv.go

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"compress/gzip"
5+
"fmt"
56
"io"
67
"net/http"
78
"os"
@@ -13,33 +14,48 @@ import (
1314

1415
func main() {
1516
if len(os.Args) < 2 {
16-
println("Usage: conv <file>")
17+
println("Usage: conv <file.asc|file.isg>")
1718
os.Exit(1)
1819
}
1920

2021
p := os.Args[1]
2122
name := path.Base(p)
2223

23-
f, err := loadAsc(p)
24+
f, err := loadFile(p)
2425
if err != nil {
2526
println(err.Error())
2627
os.Exit(1)
2728
}
28-
2929
defer f.Close()
3030

31-
grid, err := japangeoid.FromAsc(f)
32-
if err != nil {
33-
println(err.Error())
31+
// 拡張子に応じてパーサーを選択
32+
var grid *japangeoid.MemoryGrid
33+
switch {
34+
case strings.HasSuffix(strings.ToLower(name), ".isg"):
35+
grid, err = japangeoid.FromIsg(f)
36+
if err != nil {
37+
println(err.Error())
38+
os.Exit(1)
39+
}
40+
name = strings.TrimSuffix(name, ".isg")
41+
case strings.HasSuffix(strings.ToLower(name), ".asc"):
42+
grid, err = japangeoid.FromAsc(f)
43+
if err != nil {
44+
println(err.Error())
45+
os.Exit(1)
46+
}
47+
name = strings.TrimSuffix(name, ".asc")
48+
default:
49+
println("Unknown file extension. Supported: .asc, .isg")
3450
os.Exit(1)
3551
}
3652

37-
f2, err := os.Create(strings.TrimSuffix(name, ".asc") + ".bin.gz")
53+
outName := name + ".bin.gz"
54+
f2, err := os.Create(outName)
3855
if err != nil {
3956
println(err.Error())
4057
os.Exit(1)
4158
}
42-
4359
defer f2.Close()
4460

4561
w := gzip.NewWriter(f2)
@@ -50,10 +66,11 @@ func main() {
5066
os.Exit(1)
5167
}
5268

53-
println("Done")
69+
fmt.Printf("Done: %s (XNum=%d, YNum=%d, XMin=%.2f, YMin=%.2f)\n",
70+
outName, grid.Info.XNum, grid.Info.YNum, grid.Info.XMin, grid.Info.YMin)
5471
}
5572

56-
func loadAsc(url string) (io.ReadCloser, error) {
73+
func loadFile(url string) (io.ReadCloser, error) {
5774
if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
5875
req, err := http.NewRequest("GET", url, nil)
5976
if err != nil {

gsigeoid2024/Hrefconv2024.bin.gz

14.4 KB
Binary file not shown.
387 KB
Binary file not shown.

gsigeoid2024/geoid2024.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package gsigeoid2024
2+
3+
import (
4+
"bytes"
5+
"compress/gzip"
6+
_ "embed"
7+
"fmt"
8+
9+
japangeoid "github.com/eukarya-inc/japan-geoid-go"
10+
)
11+
12+
//go:embed JPGEO2024+Hrefconv2024.bin.gz
13+
var combinedRaw []byte
14+
15+
//go:embed Hrefconv2024.bin.gz
16+
var hrefconvRaw []byte
17+
18+
// Load はジオイド2024と基準面補正パラメータを合成したデータを読み込みます。
19+
// 一部の離島において衛星測位によって標高を求める際には、この合成データを使用してください。
20+
func Load() (*japangeoid.MemoryGrid, error) {
21+
return load(combinedRaw)
22+
}
23+
24+
// LoadHrefconv は基準面補正パラメータのみを読み込みます。
25+
// 東京湾平均海面と離島独自の平均海面の差(基準面補正量)を表したデータです。
26+
func LoadHrefconv() (*japangeoid.MemoryGrid, error) {
27+
return load(hrefconvRaw)
28+
}
29+
30+
func load(data []byte) (*japangeoid.MemoryGrid, error) {
31+
b := bytes.NewReader(data)
32+
g, err := gzip.NewReader(b)
33+
if err != nil {
34+
return nil, fmt.Errorf("failed to create gzip reader: %w", err)
35+
}
36+
37+
return japangeoid.FromBinary(g)
38+
}

gsigeoid2024/geoid2024_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package gsigeoid2024
2+
3+
import (
4+
"fmt"
5+
"math"
6+
"testing"
7+
)
8+
9+
func TestLoad(t *testing.T) {
10+
g, err := Load()
11+
if err != nil {
12+
t.Fatalf("failed to load: %v", err)
13+
}
14+
15+
// グリッド情報の確認
16+
if g.Info.XNum != 1601 {
17+
t.Errorf("XNum: got %d, want 1601", g.Info.XNum)
18+
}
19+
if g.Info.YNum != 2101 {
20+
t.Errorf("YNum: got %d, want 2101", g.Info.YNum)
21+
}
22+
23+
// 日本国内の座標でジオイド高を取得できることを確認
24+
lng, lat := 138.2839817085188, 37.12378643088312
25+
height := g.GetHeight(lng, lat)
26+
if math.IsNaN(height) {
27+
t.Errorf("GetHeight(%f, %f): got NaN, want valid height", lng, lat)
28+
}
29+
t.Logf("Load: GetHeight(%f, %f) = %f", lng, lat, height)
30+
31+
// 範囲外の座標はNaNを返すことを確認
32+
lng, lat = 10, 10
33+
height = g.GetHeight(lng, lat)
34+
if !math.IsNaN(height) {
35+
t.Errorf("GetHeight(%f, %f): got %f, want NaN", lng, lat, height)
36+
}
37+
}
38+
39+
func TestLoadHrefconv(t *testing.T) {
40+
g, err := LoadHrefconv()
41+
if err != nil {
42+
t.Fatalf("failed to load: %v", err)
43+
}
44+
45+
// グリッド情報の確認
46+
if g.Info.XNum != 1601 {
47+
t.Errorf("XNum: got %d, want 1601", g.Info.XNum)
48+
}
49+
if g.Info.YNum != 2101 {
50+
t.Errorf("YNum: got %d, want 2101", g.Info.YNum)
51+
}
52+
53+
// 日本国内の座標で値を取得できることを確認
54+
lng, lat := 138.2839817085188, 37.12378643088312
55+
height := g.GetHeight(lng, lat)
56+
// Hrefconvは本土ではNaNになる可能性があるのでログ出力のみ
57+
t.Logf("LoadHrefconv: GetHeight(%f, %f) = %f", lng, lat, height)
58+
}
59+
60+
func Example() {
61+
g, err := Load()
62+
if err != nil {
63+
panic(err)
64+
}
65+
66+
lng, lat := 138.2839817085188, 37.12378643088312
67+
height := g.GetHeight(lng, lat)
68+
fmt.Printf("Input: (lng: %.6f, lat: %.6f) -> Geoid height: %.6f\n", lng, lat, height)
69+
70+
lng, lat = 10, 10
71+
height = g.GetHeight(lng, lat)
72+
fmt.Printf("Input: (lng: %.6f, lat: %.6f) -> Geoid height: %.6f\n", lng, lat, height)
73+
74+
// Output:
75+
// Input: (lng: 138.283982, lat: 37.123786) -> Geoid height: 39.596702
76+
// Input: (lng: 10.000000, lat: 10.000000) -> Geoid height: NaN
77+
}
78+
79+
func ExampleLoadHrefconv() {
80+
g, err := LoadHrefconv()
81+
if err != nil {
82+
panic(err)
83+
}
84+
85+
// 小笠原諸島(父島)付近 - 基準面補正量がある
86+
lng, lat := 142.19, 27.09
87+
height := g.GetHeight(lng, lat)
88+
fmt.Printf("Hrefconv: %.6f\n", height)
89+
90+
// Output:
91+
// Hrefconv: 0.642000
92+
}

gsigeoid2024geoid/JPGEO2024.bin.gz

3.6 MB
Binary file not shown.

0 commit comments

Comments
 (0)