Skip to content

Commit

Permalink
Add support for a Quantized Mesh DTM (Digital Terrain Model) collecti…
Browse files Browse the repository at this point in the history
…on to OGC API GeoVolumes - allow the same collection to both contain 3D Tiles + DTM
  • Loading branch information
rkettelerij committed Oct 23, 2023
1 parent 1ec49cf commit 58bc28e
Show file tree
Hide file tree
Showing 11 changed files with 283 additions and 70 deletions.
10 changes: 7 additions & 3 deletions engine/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,19 +203,23 @@ type CollectionEntry3dGeoVolumes struct {
// Optional basepath to 3D tiles on the tileserver. Defaults to the collection ID.
TileServerPath *string `yaml:"tileServerPath"`

// Optional URI template for individual 3D tiles, defaults to "tiles/{level}/{x}/{y}.glb".
URITemplate3dTiles *string `yaml:"uriTemplate3dTiles"`
// URI template for individual 3D tiles.
URITemplate3dTiles *string `yaml:"uriTemplate3dTiles" validate:"required_without_all=URITemplateDTM"`

// Optional URI template for subtrees, only required when "implicit tiling" extension is used.
URITemplateImplicitTilingSubtree *string `yaml:"uriTemplateImplicitTilingSubtree"`

// URI template for digital terrain model (DTM) in Quantized Mesh format, REQUIRED when you want to serve a DTM.
URITemplateDTM *string `yaml:"uriTemplateDTM"`
URITemplateDTM *string `yaml:"uriTemplateDTM" validate:"required_without_all=URITemplate3dTiles"`

// Optional URL to 3D viewer to visualize the given collection of 3D Tiles.
URL3DViewer *YAMLURL `yaml:"3dViewerUrl" validate:"url"`
}

func (gv *CollectionEntry3dGeoVolumes) Has3DTiles() bool {
return gv.URITemplate3dTiles != nil
}

func (gv *CollectionEntry3dGeoVolumes) HasDTM() bool {
return gv.URITemplateDTM != nil
}
Expand Down
161 changes: 161 additions & 0 deletions engine/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package engine

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestGeoSpatialCollections_Unique(t *testing.T) {
tests := []struct {
name string
g GeoSpatialCollections
want []GeoSpatialCollection
}{
{
name: "empty input",
g: nil,
want: []GeoSpatialCollection{},
},
{
name: "no dups, sorted by id",
g: []GeoSpatialCollection{
{
ID: "3",
},
{
ID: "1",
},
{
ID: "1",
},
{
ID: "2",
},
},
want: []GeoSpatialCollection{
{
ID: "1",
},
{
ID: "2",
},
{
ID: "3",
},
},
},
{
name: "no dups, sorted by title",
g: []GeoSpatialCollection{
{
ID: "3",
Metadata: &GeoSpatialCollectionMetadata{
Title: ptrTo("a"),
LastUpdatedBy: "",
},
},
{
ID: "1",
Metadata: &GeoSpatialCollectionMetadata{
Title: ptrTo("c"),
LastUpdatedBy: "",
},
},
{
ID: "3",
Metadata: &GeoSpatialCollectionMetadata{
Title: ptrTo("a"),
LastUpdatedBy: "",
},
},
{
ID: "2",
Metadata: &GeoSpatialCollectionMetadata{
Title: ptrTo("b"),
LastUpdatedBy: "",
},
},
},
want: []GeoSpatialCollection{
{
ID: "3",
Metadata: &GeoSpatialCollectionMetadata{
Title: ptrTo("a"),
LastUpdatedBy: "",
},
},
{
ID: "2",
Metadata: &GeoSpatialCollectionMetadata{
Title: ptrTo("b"),
LastUpdatedBy: "",
},
},
{
ID: "1",
Metadata: &GeoSpatialCollectionMetadata{
Title: ptrTo("c"),
LastUpdatedBy: "",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, tt.g.Unique(), "Unique()")
})
}
}

func TestGeoSpatialCollections_ContainsID(t *testing.T) {
tests := []struct {
name string
g GeoSpatialCollections
id string
want bool
}{
{
name: "ID is present",
g: []GeoSpatialCollection{
{
ID: "3",
},
{
ID: "1",
},
{
ID: "2",
},
},
id: "1",
want: true,
},
{
name: "ID is not present",
g: []GeoSpatialCollection{
{
ID: "3",
},
{
ID: "1",
},
{
ID: "2",
},
},
id: "55",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, tt.g.ContainsID(tt.id), "ContainsID(%v)", tt.id)
})
}
}

func ptrTo[T any](val T) *T {
return &val
}
85 changes: 40 additions & 45 deletions engine/templates/openapi/3dgeovolumes.go.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,48 +13,8 @@
"tags" : [ ],
"paths" : {
{{- range $index, $type := .Config.OgcAPI.GeoVolumes.Collections -}}
{{ if and $type.GeoVolumes $type.GeoVolumes.URITemplate3dTiles }}
{{- if $index -}},{{- end -}}

{{- /* keep this block at the top, since it executes a 'continue' to skip further processing */ -}}
{{ if and $type.GeoVolumes $type.GeoVolumes.HasDTM }}
"/collections/{{ $type.ID }}/quantized-mesh/{{ $type.GeoVolumes.URITemplateDTM }}" : {
"get" : {
"tags" : [ "3D Tiles" ],
"summary" : "retrieve digital terrain model (DTM)",
"description" : "Access the digital terrain model (DTM) in Quantized Mesh format.",
"operationId" : "{{ $type.ID }}.getDTM",
"parameters" : [ {
"$ref" : "#/components/parameters/level"
}, {
"$ref" : "#/components/parameters/x"
}, {
"$ref" : "#/components/parameters/y"
}, {
"$ref" : "#/components/parameters/v"
}],
"responses" : {
"200" : {
"description" : "The operation was executed successfully.",
"content" : {
"application/vnd.quantized-mesh" : {
"schema" : {
"$ref" : "#/components/schemas/binary"
}
}
}
},
"204" : {
"description" : "Tile Not Found"
},
"500" : {
"description" : "Server Error"
}
}
}
}
{{ continue }} {{/* skip further processing */}}
{{ end }}

"/collections/{{ $type.ID }}/3dtiles" : {
"get" : {
"tags" : [ "3D Tiles" ],
Expand Down Expand Up @@ -82,11 +42,7 @@
}
}
},
{{ if and $type.GeoVolumes $type.GeoVolumes.URITemplate3dTiles }}
"/collections/{{ $type.ID }}/3dtiles/{{ $type.GeoVolumes.URITemplate3dTiles }}" : {
{{ else }}
"/collections/{{ $type.ID }}/3dtiles/tiles/{level}/{x}/{y}.glb" : {
{{ end }}
"get" : {
"tags" : [ "3D Tiles" ],
"summary" : "retrieve a glTF tile of the feature collection '{{ $type.ID }}'",
Expand Down Expand Up @@ -119,6 +75,7 @@
}
}
}
{{ end }}
{{ if and $type.GeoVolumes $type.GeoVolumes.URITemplateImplicitTilingSubtree }}
,
"/collections/{{ $type.ID }}/3dtiles/{{ $type.GeoVolumes.URITemplateImplicitTilingSubtree }}" : {
Expand Down Expand Up @@ -155,6 +112,44 @@
}
}
{{ end }}
{{ if and $type.GeoVolumes $type.GeoVolumes.HasDTM }}
,
"/collections/{{ $type.ID }}/quantized-mesh/{{ $type.GeoVolumes.URITemplateDTM }}" : {
"get" : {
"tags" : [ "3D Tiles" ],
"summary" : "retrieve digital terrain model (DTM)",
"description" : "Access the digital terrain model (DTM) in Quantized Mesh format.",
"operationId" : "{{ $type.ID }}.getDTM",
"parameters" : [ {
"$ref" : "#/components/parameters/level"
}, {
"$ref" : "#/components/parameters/x"
}, {
"$ref" : "#/components/parameters/y"
}, {
"$ref" : "#/components/parameters/v"
}],
"responses" : {
"200" : {
"description" : "The operation was executed successfully.",
"content" : {
"application/vnd.quantized-mesh" : {
"schema" : {
"$ref" : "#/components/schemas/binary"
}
}
}
},
"204" : {
"description" : "Tile Not Found"
},
"500" : {
"description" : "Server Error"
}
}
}
}
{{ end }}
{{- end -}}
},
"components" : {
Expand Down
2 changes: 1 addition & 1 deletion examples/config_3d.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ogcApi:
- id: NewYork
# optional basepath to 3D tiles on the tileserver. Defaults to the collection ID.
tileServerPath: "NewYork/3DTiles"
# optional URI template for individual 3D tiles, defaults to "tiles/{level}/{x}/{y}.glb"
# URI template for individual 3D tiles
uriTemplate3dTiles: "3DTiles/{level}/{x}/{y}.b3m"

# optional URI template for subtrees, only required when "implicit tiling" extension is used
Expand Down
5 changes: 3 additions & 2 deletions ogc/common/geospatial/templates/collection.go.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ <h5 class="card-header">
<li class="list-group-item">
<h5 class="card-title">3D GeoVolumes</h5>
<ul>
{{ if and .Params.GeoVolumes .Params.GeoVolumes.Has3DTiles }}
<li>{{ i18n "GoTo" }} <a href="{{ .Config.BaseURL }}/collections/{{ .Params.ID }}/3dtiles">3D Tiles</a></li>
{{ end }}
{{ if and .Params.GeoVolumes .Params.GeoVolumes.HasDTM }}
<li>{{ i18n "GoTo" }} <a href="{{ .Config.BaseURL }}/collections/{{ .Params.ID }}/quantized-mesh">Quantized Mesh DTM</a></li>
{{ else }}
<li>{{ i18n "GoTo" }} <a href="{{ .Config.BaseURL }}/collections/{{ .Params.ID }}/3dtiles">3D Tiles</a></li>
{{ end }}
{{ if and .Params.GeoVolumes .Params.GeoVolumes.URL3DViewer }}
<li>{{ i18n "ViewIn" }} <a href="{{ .Params.GeoVolumes.URL3DViewer }}" target="_blank">3D viewer</a></li>
Expand Down
17 changes: 9 additions & 8 deletions ogc/common/geospatial/templates/collection.go.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,22 @@
"href" : "{{ .Config.BaseURL }}/collections/{{ .Params.ID }}?f=html"
}
{{ if and .Config.OgcAPI.GeoVolumes .Config.OgcAPI.GeoVolumes.Collections }}
{{ if and .Params.GeoVolumes .Params.GeoVolumes.HasDTM }}
{{ if and .Params.GeoVolumes .Params.GeoVolumes.Has3DTiles }}
,
{
"rel" : "items",
"type" : "application/json",
"title" : "Digital Terrain Model '{{ .Params.ID }}' in Quantized Mesh format",
"href" : "{{ .Config.BaseURL }}/collections/{{ .Params.ID }}/quantized-mesh?f=json"
"type" : "application/json+3dtiles",
"title" : "Tileset definition of collection {{ .Params.ID }} according to the OGC 3D Tiles specification",
"href" : "{{ .Config.BaseURL }}/collections/{{ .Params.ID }}/3dtiles?f=json"
}
{{ else }}
{{ end }}
{{ if and .Params.GeoVolumes .Params.GeoVolumes.HasDTM }}
,
{
"rel" : "items",
"type" : "application/json+3dtiles",
"title" : "Tileset definition of collection {{ .Params.ID }} according to the OGC 3D Tiles specification",
"href" : "{{ .Config.BaseURL }}/collections/{{ .Params.ID }}/3dtiles?f=json"
"type" : "application/json",
"title" : "Digital Terrain Model '{{ .Params.ID }}' in Quantized Mesh format",
"href" : "{{ .Config.BaseURL }}/collections/{{ .Params.ID }}/quantized-mesh?f=json"
}
{{ end }}
{{ end }}
Expand Down
17 changes: 9 additions & 8 deletions ogc/common/geospatial/templates/collections.go.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,22 @@
}
{{ if and $cfg.OgcAPI.GeoVolumes $cfg.OgcAPI.GeoVolumes.Collections }}
{{ if $cfg.OgcAPI.GeoVolumes.Collections.ContainsID $coll.ID }}
{{ if and $coll.GeoVolumes $coll.GeoVolumes.HasDTM }}
,{
"rel" : "items",
"type" : "application/json",
"title" : "Digital Terrain Model '{{ $coll.ID }}' in Quantized Mesh format",
"href" : "{{ $baseUrl }}/collections/{{ $coll.ID }}/quantized-mesh?f=json"
}
{{ else }}
{{ if and $coll.GeoVolumes $coll.GeoVolumes.Has3DTiles }}
,{
"rel" : "items",
"type" : "application/json+3dtiles",
"title" : "Tileset definition of collection {{ $coll.ID }} according to the OGC 3D Tiles specification",
"href" : "{{ $baseUrl }}/collections/{{ $coll.ID }}/3dtiles?f=json"
}
{{end}}
{{ if and $coll.GeoVolumes $coll.GeoVolumes.HasDTM }}
,{
"rel" : "items",
"type" : "application/json",
"title" : "Digital Terrain Model '{{ $coll.ID }}' in Quantized Mesh format",
"href" : "{{ $baseUrl }}/collections/{{ $coll.ID }}/quantized-mesh?f=json"
}
{{ end }}
{{end}}
{{end}}
{{ if and $cfg.OgcAPI.Tiles $cfg.OgcAPI.Tiles.Collections }}
Expand Down
Loading

0 comments on commit 58bc28e

Please sign in to comment.