Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using radixtree for check spatialIDs' overlap #35

Merged
merged 20 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0677e91
added multidimensional radix tree into CheckSpatialIdsOverlap
mi-24v Jul 12, 2024
19f5397
added handling f-index in CheckSpatialIdsOverlap
mi-24v Jul 16, 2024
a15052f
fixed handling minus f-index in CheckSpatialIdsArrayOverlap
mi-24v Jul 19, 2024
7c8a6d6
optimization of altitude conversion at same zoom level
mi-24v Jul 25, 2024
1eed978
optimization of altitude conversion in CheckSpatialIdsArrayOverlap
mi-24v Jul 25, 2024
0da2345
added fuzzing tests AddZBaseOffsetToZ at z=18
mi-24v Jul 23, 2024
e2883c0
added benchmark test for CheckSpatialIdsOverlap, CheckExtendedSpatial…
mi-24v Jul 23, 2024
0d39eb9
fix altitude range specification for CheckSpatialIdsOverlap
mi-24v Jul 25, 2024
7509580
fixed dependency
mi-24v Aug 13, 2024
26f3757
created example program for benchmark graph
mi-24v Aug 13, 2024
de00e69
added DetectOverlap for radix-tree caching
mi-24v Aug 21, 2024
136ba26
updated base branch v4.1.0 via merge
mi-24v Aug 26, 2024
a7018fe
updated base branch v4.1.1 via merge
mi-24v Sep 9, 2024
16f4cef
Revert "added DetectOverlap for radix-tree caching"
mi-24v Oct 3, 2024
9bca547
Appended comparison tests
HarutakaMatsumoto Oct 16, 2024
b090a2f
fixed comparison tests between `AddZBaseOffsetToZ` and `convertZToMin…
mi-24v Oct 17, 2024
d1587dd
moved example benchmark of checkSpatialIdsArrayOverlap
mi-24v Oct 16, 2024
056776c
use `ConvertZToMinMaxAltitudekey` instead of `AddZBaseOffsetToZ`
mi-24v Oct 17, 2024
a0e7440
remove `AddZBaseOffsetToZ`
mi-24v Oct 17, 2024
e6054cc
renamed example detect overlap directory
mi-24v Oct 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions common/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ const (
// InnerIDAltitudekeyIndex altitudekeyはinnerID[1]
InnerIDAltitudekeyIndex = 1
)

// ZBaseOffsetForNegativeFIndex
//
// 元の最大高さを保ったまま正方向と負方向でfインデックスを半数ずつ導入するためのzBaseOffset
const ZBaseOffsetForNegativeFIndex = 1 << (ZOriginValue - 1)
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package integrate
package detector

import (
"fmt"
"github.com/trajectoryjp/multidimensional-radix-tree/src/tree"
"github.com/trajectoryjp/spatial_id_go/v4/common/consts"
"github.com/trajectoryjp/spatial_id_go/v4/common/errors"
"github.com/trajectoryjp/spatial_id_go/v4/integrate"
"github.com/trajectoryjp/spatial_id_go/v4/transform"
"strconv"
"strings"
)
Expand All @@ -27,36 +32,9 @@ import (
// 以下の条件に当てはまる場合、エラーインスタンスが返却される。ただしこのときbool値にfalseが返却される。
// 空間IDフォーマット不正:空間IDのフォーマットに違反する値が"重複判定対象空間ID"に入力されていた場合。
func CheckSpatialIdsOverlap(spatialId1 string, spatialId2 string) (bool, error) {
// ズームレベルの取り出し
arr1 := strings.Split(spatialId1, "/")
arr2 := strings.Split(spatialId2, "/")
if len(arr1) != 4 || len(arr2) != 4 {
// 不正形式
return false, fmt.Errorf("invalid format. spatialId1: %v, spatialId2: %v", spatialId1, spatialId2)
}
zoom1, _ := strconv.Atoi(arr1[0])
zoom2, _ := strconv.Atoi(arr2[0])

// zoomレベルで場合分け
// zoomレベルが等しいとき、変換なし
if zoom1 > zoom2 {
// spatialId2のzoomレベルをzoom1に合わせるよう変換
convertedSpatialId, err := ChangeSpatialIdsZoom([]string{spatialId1}, int64(zoom2))
if err != nil {
return false, err
}
spatialId1 = convertedSpatialId[0]
} else if zoom1 < zoom2 {
// spatialId1のzoomレベルをzoom2に合わせるよう変換
convertedSpatialId, err := ChangeSpatialIdsZoom([]string{spatialId2}, int64(zoom1))
if err != nil {
return false, err
}
spatialId2 = convertedSpatialId[0]
}

return spatialId1 == spatialId2, nil

ids1 := []string{spatialId1}
ids2 := []string{spatialId2}
return CheckSpatialIdsArrayOverlap(ids1, ids2)
}

// CheckSpatialIdsArrayOverlap 2つの空間ID重複の判定関数
Expand All @@ -71,35 +49,97 @@ func CheckSpatialIdsOverlap(spatialId1 string, spatialId2 string) (bool, error)
//
// spatialIds1, spatialIds2: 重複判定対象の空間ID列。ズームレベルが異なっている入力も許容。
//
// ただし高度は16,777,216未満 〜 -16,777,216m以上に制限される(この範囲で高度変換を行う)
//
// 戻り値:
//
// bool:
// 重複の有無が返却される。true: 重複あり false: 重複なし
//
// error:
// 以下の条件に当てはまる場合、エラーインスタンスが返却される。ただしこのときbool値にfalseが返却される
// 以下の条件に当てはまる場合、エラーインスタンスが返却される。このときbool値はfalseで返却される
// 空間IDフォーマット不正:空間IDのフォーマットに違反する値が"重複判定対象空間ID"に入力されていた場合。
// 空間ID高度範囲外:高度範囲外の空間IDが入力されていた場合。
func CheckSpatialIdsArrayOverlap(spatialIds1 []string, spatialIds2 []string) (bool, error) {
// spatialIds1から各要素の取り出し
for _, spatialId1 := range spatialIds1 {
// spatialIds2から各要素の取り出し
for _, spatialId2 := range spatialIds2 {
// 取り出した要素の比較
result, err := CheckSpatialIdsOverlap(spatialId1, spatialId2)
if err != nil {
// エラー発生時、falseとerrorを返却
return false, err
}
if result {
// 重複判定時、trueとnilを返却
return result, nil
}
// f,x,yで3次元分の2分木
tr := tree.CreateTree(tree.Create3DTable())
// spatialIds1から各要素をradix treeに格納
for indexSpatialId1, spatialId1 := range spatialIds1 {
zoom1, f1, x1, y1, err := getSpatialIdAttrs(spatialId1)
if err != nil {
return false, fmt.Errorf("%w @spatialId1[%v]", err, indexSpatialId1)
}
convertedFIndex, errAltConversion := transform.AddZBaseOffsetToZ(int64(f1), uint8(zoom1), consts.ZBaseOffsetForNegativeFIndex)
if convertedFIndex < 0 {
return false, errors.NewSpatialIdError(errors.InputValueErrorCode, fmt.Sprintf("input f-index %v is out of altitude range @spatialId1[%v] = %v", f1, indexSpatialId1, spatialId1))
}
if errAltConversion != nil {
return false, fmt.Errorf("%w @spatialId1[%v] = %v", errAltConversion, indexSpatialId1, spatialId1)
}
index1 := tree.Indexs{convertedFIndex, int64(x1), int64(y1)}
tr.Append(index1, tree.ZoomSetLevel(zoom1), spatialId1)
}
// spatialIds2から各要素の取り出し
for indexSpatialId2, spatialId2 := range spatialIds2 {
zoom2, f2, x2, y2, err := getSpatialIdAttrs(spatialId2)
if err != nil {
return false, fmt.Errorf("%w @spatialId2[%v]", err, indexSpatialId2)
}
// 取り出した要素の比較
// 高度インデックスをオフセット変換のみ実行して自然数にする
convertedFIndex2, errAltConversion := transform.AddZBaseOffsetToZ(int64(f2), uint8(zoom2), consts.ZBaseOffsetForNegativeFIndex)
if convertedFIndex2 < 0 {
return false, errors.NewSpatialIdError(errors.InputValueErrorCode, fmt.Sprintf("input f-index %v is out of altitude range @spatialId2[%v] = %v", f2, indexSpatialId2, spatialId2))
}
if errAltConversion != nil {
return false, fmt.Errorf("%w @spatialId2[%v] = %v", errAltConversion, indexSpatialId2, spatialId2)
}
result := tr.IsOverlap(tree.Indexs{convertedFIndex2, int64(x2), int64(y2)}, tree.ZoomSetLevel(zoom2))
if result {
// 重複判定時、trueとnilを返却
return result, nil
}
}

return false, nil
}

// getSpatialIdAttrs 空間IDフォーマットチェック関数
//
// 入力された空間IDの各成分を格納した配列を返却する。
// 以下の条件に当てはまる場合はフォーマット違反となりエラーインスタンスが返却される。
//
// ・空間IDの各成分に数値が入力されていない場合
// ・区切り文字の数が3つで無い場合
//
// 引数:
//
// spatialId:空間ID
//
// 戻り値:
//
// 空間IDに含まれる精度(ズームレベル), F, X, Y成分を格納した以下のtuple
// (精度(ズームレベル), F成分, X成分, Y成分)
// 入力された拡張空間IDのフォーマットが不正な場合、戻り値を0にしエラーインスタンスを返却。
func getSpatialIdAttrs(spatialId string) (int, int, int, int, error) {
// 分割
spatialIdAttributes := strings.Split(spatialId, consts.SpatialIDDelimiter)
if len(spatialIdAttributes) != 4 {
// 不正形式(要素数)
return 0, 0, 0, 0, errors.NewSpatialIdError(errors.InputValueErrorCode, fmt.Sprintf("spatialId: %v", spatialId))
}
var errNumberConversion error
zoom, errNumberConversion := strconv.Atoi(spatialIdAttributes[0])
f, errNumberConversion := strconv.Atoi(spatialIdAttributes[1])
x, errNumberConversion := strconv.Atoi(spatialIdAttributes[2])
y, errNumberConversion := strconv.Atoi(spatialIdAttributes[3])
// 不正形式(数値)
if errNumberConversion != nil {
return 0, 0, 0, 0, errors.NewSpatialIdError(errors.InputValueErrorCode, fmt.Sprintf("spatialId: %v", spatialId))
}
return zoom, f, x, y, nil
}

// CheckExtendedSpatialIdsOverlap 2つの拡張空間IDの重複の判定関数
//
// 比較対象として入力された2つの拡張空間IDのズームレベルを変換して揃え、重複の判定を行う。
Expand Down Expand Up @@ -148,12 +188,12 @@ func CheckExtendedSpatialIdsOverlap(extendedSpatialId1 string, extendedSpatialId
}

// 変換後のZoomレベルを指定して変換
extendedSpatialIds1, err := ChangeExtendedSpatialIdsZoom([]string{extendedSpatialId1}, int64(targetHorizontalZoom), int64(targetVerticalZoom))
extendedSpatialIds1, err := integrate.ChangeExtendedSpatialIdsZoom([]string{extendedSpatialId1}, int64(targetHorizontalZoom), int64(targetVerticalZoom))
if err != nil {
// 変換エラー
return false, err
}
extendedSpatialIds2, err := ChangeExtendedSpatialIdsZoom([]string{extendedSpatialId2}, int64(targetHorizontalZoom), int64(targetVerticalZoom))
extendedSpatialIds2, err := integrate.ChangeExtendedSpatialIdsZoom([]string{extendedSpatialId2}, int64(targetHorizontalZoom), int64(targetVerticalZoom))
if err != nil {
// 変換エラー
return false, err
Expand Down
Loading
Loading