diff --git a/operated/shifting_spatial_id.go b/operated/shifting_spatial_id.go index 89696fa..1ae0d25 100644 --- a/operated/shifting_spatial_id.go +++ b/operated/shifting_spatial_id.go @@ -129,8 +129,9 @@ func Get26spatialIdsAroundVoxel(spatialID string) []string { // error: エラー func GetNspatialIdsAroundVoxcels(spatialIDs []string, hLayers, vLayers int64) ([]string, error) { - if hLayers < 1 || vLayers < 1 { - return nil, fmt.Errorf("both hLayers and vLayers parameters must be >= 1") + // invalid input validation (both parameters must be non-negative) + if hLayers < 0 || vLayers < 0 { + return nil, fmt.Errorf("both hLayers and vLayers parameters must be >= 0") } hExpandParam := hLayers * 2 diff --git a/operated/shifting_spatial_id_test.go b/operated/shifting_spatial_id_test.go index a616474..1d60efa 100755 --- a/operated/shifting_spatial_id_test.go +++ b/operated/shifting_spatial_id_test.go @@ -241,6 +241,8 @@ func TestGetShiftingSpatialID07(t *testing.T) { t.Log("テスト終了") } +// TestGetNspatialIdsAroundVoxcels01 tests hLayers=1 and vLayers=1 around two spatial IDs +// Expected value should return the same result as the combined, unique result of Get26spatialIdsAroundVoxel() for each of the two "ids" func TestGetNspatialIdsAroundVoxcels01(t *testing.T) { ids := []string{"10/10/10/10/10", "10/11/11/10/10"} @@ -271,6 +273,8 @@ func TestGetNspatialIdsAroundVoxcels01(t *testing.T) { } +// TestGetNspatialIdsAroundVoxcels02 tests hLayers=1 and vLayers=1 +// Expected value should be the same result as Get26spatialIdsAroundVoxel() func TestGetNspatialIdsAroundVoxcels02(t *testing.T) { ids := []string{"10/10/10/10/10"} @@ -299,6 +303,67 @@ func TestGetNspatialIdsAroundVoxcels02(t *testing.T) { } +// TestGetNspatialIdsAroundVoxcels03 tests hLayers=0 and vLayers=0 +// Expected value should be 0 Extended Spatial IDs, or an empty string []string{} +func TestGetNspatialIdsAroundVoxcels03(t *testing.T) { + + ids := []string{"10/10/10/10/10"} + expectVal := []string{} + + nLayer := 0 + + resultVal, error := GetNspatialIdsAroundVoxcels(ids, int64(nLayer), int64(nLayer)) + if error != nil { + t.Error(error) + } + + // using maps will allow comparison with deepEqual if order is different + map1, map2 := make(map[string]string), make(map[string]string) + for _, value := range expectVal { + map1[value] = value + } + for _, value := range resultVal { + map2[value] = value + } + if !reflect.DeepEqual(map1, map2) { + // 戻り値の空間IDが期待値と異なる場合Errorをログに出力 + t.Errorf("空間ID - 期待値:%v, \n取得値: %v", map1, map2) + } + t.Log("テスト終了") + +} + +// TestGetNspatialIdsAroundVoxcels04 tests hLayers=0 and vLayers=1 +// Expected value should be 1 Extended Spatial ID above and 1 Extended Spatial ID below "id" +func TestGetNspatialIdsAroundVoxcels04(t *testing.T) { + + ids := []string{"10/10/10/10/10"} + expectVal := []string{"10/10/10/10/9", "10/10/10/10/11"} + + resultVal, error := GetNspatialIdsAroundVoxcels( + ids, + 0, + 1) + if error != nil { + t.Error(error) + } + + // using maps will allow comparison with deepEqual if order is different + map1, map2 := make(map[string]string), make(map[string]string) + for _, value := range expectVal { + map1[value] = value + } + for _, value := range resultVal { + map2[value] = value + } + if !reflect.DeepEqual(map1, map2) { + // 戻り値の空間IDが期待値と異なる場合Errorをログに出力 + t.Errorf("空間ID - 期待値:%v, \n取得値: %v", map1, map2) + } + t.Log("テスト終了") + +} + // stringスライスの中に指定文字列を含むか判定する // // 引数: diff --git a/transform/voxel_around_line.go b/transform/voxel_around_line.go index c03423a..f6f5c78 100644 --- a/transform/voxel_around_line.go +++ b/transform/voxel_around_line.go @@ -42,22 +42,17 @@ func GetExtendedSpatialIdsWithinRadiusOfLine(startPoint *object.Point, endPoint if error != nil { return nil, error } - // 2. Find the Spatial Ids that are not on the line but within the radius distance of the line // Variable Setup // the closest.measure object to determine IDs not on the path line but within the criterion distance var measure1 = closest.Measure{} - // the distances from each SpatialID in uniqueMegaBoxIDs to the route path line - var measureDistances1 []float64 - // the slice of Spatial IDs created by combining the result of all adjacent 26 SpatialIDs from all spatialIDs on the route line - var megaBoxIds []string - // the slice of unique Spatial IDs (non-duplicates) from megaBoxIDs - var uniqueMegaBoxIds []string - // the Spatial IDs in uniqueMegaBoxIds with the IDs on the route path line removed - var noLinePathMegaBoxIds []string - // the slice of Spatial Ids from noLinePathMegaBoxIds found within the radius but not on the route line + // the slice of ExtendedSpatialIDs around the Ids on the route line. (returned result already cleaned for duplicates). + var idsAroundVoxcels []string + // the Extended Spatial IDs with the IDs on the route path line removed + var idsAroundLine []string // fix this + // the slice of Extended Spatial Ids from noLinePathIdsAroundLine found within the radius but not on the route line var idsToAdd []string // points is the [2]slice / list of startPoint and endPoint in geodesic format (lat/lon) var points = []*object.Point{startPoint, endPoint} @@ -97,20 +92,18 @@ func GetExtendedSpatialIdsWithinRadiusOfLine(startPoint *object.Point, endPoint } // Return the SpatialIDs within the box created by hLayers and vLayers - megaBoxIds, error = operated.GetNspatialIdsAroundVoxcels(idsOnLine, hLayers, vLayers) + idsAroundVoxcels, error = operated.GetNspatialIdsAroundVoxcels(idsOnLine, hLayers, vLayers) if error != nil { return nil, error } - // Make unique list of spatial ids - uniqueMegaBoxIds = common.Unique(megaBoxIds) - - // Subtract the spatial ids in the line - noLinePathMegaBoxIds = common.Difference(uniqueMegaBoxIds, idsOnLine) + // Remove the spatial ids in the line from the ids around the line so that only the ids around the line remain + idsAroundLine = common.Difference(idsAroundVoxcels, idsOnLine) + // if skipsMeasurement=true, measure the distance between the route line and each id in idsAroundLine if !skipsMeasurement { - for _, id := range noLinePathMegaBoxIds { + for _, id := range idsAroundLine { // Get 8 vertexes of the SpatialID IdVertexes, error := shape.GetPointOnExtendedSpatialId(id, enum.Vertex) @@ -144,8 +137,6 @@ func GetExtendedSpatialIdsWithinRadiusOfLine(startPoint *object.Point, endPoint // dist is the closest distance between the line (ConvexHull[0]) and the vertexes of Spatial ID[i] var dist = measure1.Distance - measureDistances1 = append(measureDistances1, dist) - // Since MeasureNonnegativeDistance() was used the distance value in dist // will always be non-zero. If dist < radius, add the spatialID to idsToAdd if dist < (radius) { @@ -158,7 +149,8 @@ func GetExtendedSpatialIdsWithinRadiusOfLine(startPoint *object.Point, endPoint idsWithinCriterion = common.Unique(common.Union(idsToAdd, idsOnLine)) } else { - idsWithinCriterion = megaBoxIds + // if skipsMeasurement=false, return all ids in noLinePathIdsAroundLine and combine with idsOnLine + idsWithinCriterion = common.Unique(common.Union(idsAroundLine, idsOnLine)) } return idsWithinCriterion, nil @@ -180,7 +172,10 @@ func GetExtendedSpatialIdsWithinRadiusOfLine(startPoint *object.Point, endPoint // error: エラー func FitClearanceAroundExtendedSpatialID(spatialID string, clearance float64) (horizontalLayer int64, verticalLayer int64, error error) { - // validate clearance + // validate clearance: There are two special cases: + // 1. The clearance must be non-negative (clearance must be >= 0) + // 2. If the clearance is exactly 0, return 0 for both the horizontalLayer and verticalLayer. This is because + // if clearance is 0, the only Spatial IDs that are on the route line should be used -- no surrounding Spatial IDs if clearance < 0 { return 0, 0, fmt.Errorf("\ninvalid clearance value. Clearance must be >= 0") } @@ -200,8 +195,8 @@ func FitClearanceAroundExtendedSpatialID(spatialID string, clearance float64) (h // vLayyer is the number of vertical spatialID distances required to fit the clearance var vLayer int64 - var hUnits int64 = 2 - var vUnits int64 = 2 + var hUnits int64 = 1 + var vUnits int64 = 1 // Begin horizonal fitting loop (determine hLayer) for { diff --git a/transform/voxel_around_line_test.go b/transform/voxel_around_line_test.go index af23f9a..94d478f 100644 --- a/transform/voxel_around_line_test.go +++ b/transform/voxel_around_line_test.go @@ -13,6 +13,83 @@ import ( "github.com/trajectoryjp/spatial_id_go/v3/shape" ) +// TestGetExtendedSpatialIdsWithinRadiusOfLine01 tests when skipsMeasurement=true and radius =0 +// Expected value should return the exact same voxels as GetExtendedSpatialIdsOnLine +func TestGetExtendedSpatialIdsWithinRadiusOfLine01(t *testing.T) { + + var radius float64 = 0 + var hZoom int64 = 25 + var vZoom int64 = 25 + + startPoint, error := object.NewPoint(139.788452, 35.67093015, 0) + if error != nil { + t.Error(error) + } + endPoint, error := object.NewPoint(139.788452, 35.670840, 0) + if error != nil { + t.Error(error) + } + + idsOnLine, error := shape.GetExtendedSpatialIdsOnLine(startPoint, endPoint, hZoom, vZoom) + if error != nil { + t.Error(error) + } + idsWithinRadiusOfLine, error := GetExtendedSpatialIdsWithinRadiusOfLine(startPoint, endPoint, radius, hZoom, vZoom, true) + if error != nil { + t.Error(error) + } + + map1, map2 := make(map[string]string), make(map[string]string) + for _, value := range idsOnLine { + map1[value] = value + } + for _, value := range idsWithinRadiusOfLine { + map2[value] = value + } + if !reflect.DeepEqual(map1, map2) { + t.Errorf("期待値: %v 取得値: %v", idsOnLine, idsWithinRadiusOfLine) + } + t.Log("テスト終了") + +} + +// TestGetSpatialIdsWithinRadiusOfLine02 tests when skipsMeasurement=true and radius > 0 but radius is +// less than than the length of a voxcel. +// Expected value should return 54 voxcels: +// - GetExtendedSpatialIdsOnLine: 4 ids +// - FitClearanceAroundSpatialId: hlayer=1, vlayer=1 +// - GetNspatialIdsAroundVoxcels: (count excludes ids on line) 50 +// - GetSpatialIdsWithinRadiusOfLine: (count includes ids on line) 9 ids per layer * 6 layers = 54 ids expected +func TestGetExtendedSpatialIdsWithinRadiusOfLine02(t *testing.T) { + + var radius float64 = 0.1 + var hZoom int64 = 23 + var vZoom int64 = 23 + + startPoint, error := object.NewPoint(139.788452, 35.67093015, 0) + if error != nil { + t.Error(error) + } + endPoint, error := object.NewPoint(139.788452, 35.670840, 0) + if error != nil { + t.Error(error) + } + + idsOnLine, error := shape.GetExtendedSpatialIdsOnLine(startPoint, endPoint, hZoom, vZoom) + if error != nil { + t.Error(error) + } + idsWithinRadiusOfLine, error := GetExtendedSpatialIdsWithinRadiusOfLine(startPoint, endPoint, radius, hZoom, vZoom, true) + if error != nil { + t.Error(error) + } + + if len(idsOnLine) != 4 || len(idsWithinRadiusOfLine) != 54 { + t.Fatalf("Expected values not returned. \nExpected Number of Extended Spatial Ids on Line: 4; returned: %v\nExpected number of extended Spatial Ids within radius of line: 54; returned: %v", len(idsOnLine), len(idsWithinRadiusOfLine)) + } + +} + func TestGetExtendedSpatialIdsWithinRadiusOfLine10m_r0_horizontal(t *testing.T) { var radius float64 = 0 @@ -68,8 +145,8 @@ func TestGetExtendedSpatialIdsWithinRadiusOfLine10m_r0_horizontal(t *testing.T) func TestFitClearanceAroundExtendedSpatialID01(t *testing.T) { var clearance float64 = 0 - var expectedHLayer int64 = 1 - var expectedVLayer int64 = 1 + var expectedHLayer int64 = 0 + var expectedVLayer int64 = 0 point, error := object.NewPoint(139.788081, 35.672680, 100) if error != nil { @@ -161,6 +238,30 @@ func TestFitClearanceAroundExtendedSpatialID04(t *testing.T) { } +func TestFitClearanceAroundExtendedSpatialID05(t *testing.T) { + + var clearance float64 = 0.01 + var expectedHLayer int64 = 1 + var expectedVLayer int64 = 1 + + point, error := object.NewPoint(139.788081, 35.672680, 100) + if error != nil { + t.Error(error) + } + hLayer, vLayer, error := testFitClearanceAroundSpatialID(t, point, clearance, 21, 21) + if error != nil { + t.Error(error) + } + + if hLayer != expectedHLayer { + t.Errorf("空間ID - 期待値:%v, 取得値:%v", expectedHLayer, hLayer) + } + if vLayer != expectedVLayer { + t.Errorf("空間ID - 期待値:%v, 取得値:%v", expectedVLayer, vLayer) + } + +} + func testFitClearanceAroundSpatialID(t *testing.T, point *object.Point, clearance float64, hZoom int64, vZoom int64) (hLayer int64, vlayer int64, error error) { points := []*object.Point{point}