add area and webmerc_area field; deprecate pseudoarea

master
Oliver Tonnhofer 2016-11-11 12:21:05 +01:00
parent c9e5f22bb7
commit 9c86495275
5 changed files with 74 additions and 5 deletions

View File

@ -253,6 +253,15 @@ Like `geometry`, but the geometries will be validated and repaired when this tab
Area of polygon geometries in square meters. This area is calculated in the webmercator projection, so it is only accurate at the equator and gets off the more the geometry moves to the poles. It's still good enough to sort features by area for rendering purposes.
``area``
^^^^^^^^
Area of polygon geometries in the unit of the selected projection (m² or degrees²). Note that a `meter` in the webmercator projection is only accurate at the equator and gets off the more the geometry moves to the poles. It's still good enough to sort features by area for rendering purposes.
``webmerc_area``
^^^^^^^^^^^^^^^^
Area of polygon geometries in m². This field only works for the webmercator projection (EPSG:3857). The latitude of the geometry is considered when calculating the area. This area is not precise, but a soccer field geometry at the equator should have roughly the same size as a soccer field in Svalbard.
``hstore_tags``
^^^^^^^^^^^^^^^

View File

@ -3,6 +3,7 @@ package mapping
import (
"errors"
"fmt"
"math"
"regexp"
"strconv"
"strings"
@ -34,7 +35,9 @@ func init() {
"validated_geometry": {"validated_geometry", "validated_geometry", Geometry, nil, nil, false},
"hstore_tags": {"hstore_tags", "hstore_string", HstoreString, nil, nil, false},
"wayzorder": {"wayzorder", "int32", nil, MakeWayZOrder, nil, false},
"pseudoarea": {"pseudoarea", "float32", PseudoArea, nil, nil, false},
"pseudoarea": {"pseudoarea", "float32", nil, MakePseudoArea, nil, false},
"area": {"area", "float32", Area, nil, nil, false},
"webmerc_area": {"webmerc_area", "float32", WebmercArea, nil, nil, false},
"zorder": {"zorder", "int32", nil, MakeZOrder, nil, false},
"enumerate": {"enumerate", "int32", nil, MakeEnumerate, nil, false},
"string_suffixreplace": {"string_suffixreplace", "string", nil, MakeSuffixReplace, nil, false},
@ -213,7 +216,12 @@ func Geometry(val string, elem *element.OSMElem, geom *geom.Geometry, match Matc
return string(geom.Wkb)
}
func PseudoArea(val string, elem *element.OSMElem, geom *geom.Geometry, match Match) interface{} {
func MakePseudoArea(fieldName string, fieldType FieldType, field Field) (MakeValue, error) {
log.Print("warn: pseudoarea type is deprecated and will be removed. See area and webmercarea type.")
return Area, nil
}
func Area(val string, elem *element.OSMElem, geom *geom.Geometry, match Match) interface{} {
area := geom.Geom.Area()
if area == 0.0 {
return nil
@ -221,6 +229,23 @@ func PseudoArea(val string, elem *element.OSMElem, geom *geom.Geometry, match Ma
return float32(area)
}
func WebmercArea(val string, elem *element.OSMElem, geom *geom.Geometry, match Match) interface{} {
area := geom.Geom.Area()
if area == 0.0 {
return nil
}
bounds := geom.Geom.Bounds()
midY := bounds.MinY + (bounds.MaxY-bounds.MinY)/2
pole := 6378137 * math.Pi // 20037508.342789244
midLat := 2*math.Atan(math.Exp((midY/pole)*math.Pi)) - math.Pi/2
area = area * math.Cos(midLat)
return float32(area)
}
var hstoreReplacer = strings.NewReplacer("\\", "\\\\", "\"", "\\\"")
func HstoreString(val string, elem *element.OSMElem, geom *geom.Geometry, match Match) interface{} {

View File

@ -4,6 +4,8 @@ import (
"testing"
"github.com/omniscale/imposm3/element"
"github.com/omniscale/imposm3/geom"
"github.com/omniscale/imposm3/geom/geos"
)
func TestBool(t *testing.T) {
@ -231,6 +233,39 @@ func TestWayZOrder(t *testing.T) {
}
}
func TestAreaFields(t *testing.T) {
tests := []struct {
wkt string
expected float32
areaFunc MakeValue
}{
{"POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))", 100.0, Area},
{"POLYGON((-10 0, 10 0, 10 10, -10 10, -10 0))", 200.0, Area},
{"POLYGON((-10 -10, 10 -10, 10 10, -10 10, -10 -10))", 400.0, WebmercArea},
{"POLYGON((1000000 2000000, 1001000 2000000, 1001000 2001000, 1000000 2001000, 1000000 2000000))", 1000000.0, Area},
{"POLYGON((1000000 2000000, 1001000 2000000, 1001000 2001000, 1000000 2001000, 1000000 2000000))", 952750.625000, WebmercArea},
{"POLYGON((1000000 5000000, 1001000 5000000, 1001000 5001000, 1000000 5001000, 1000000 5000000))", 755628.687500, WebmercArea},
{"POLYGON((1000000 10000000, 1001000 10000000, 1001000 10001000, 1000000 10001000, 1000000 10000000))", 399584.031250, WebmercArea},
}
g := geos.NewGeos()
for _, test := range tests {
ggeom := g.FromWkt(test.wkt)
if ggeom == nil {
t.Fatalf("unable to create test geometry from %v", test.wkt)
}
geometry, err := geom.AsGeomElement(g, ggeom)
if err != nil {
t.Fatalf("unable to create test geometry %v: %v", test.wkt, err)
}
elem := &element.OSMElem{}
match := Match{}
if v := test.areaFunc("", elem, &geometry, match); v.(float32) != test.expected {
t.Errorf("%v %f != %f", test.wkt, v, test.expected)
}
}
}
func TestMakeSuffixReplace(t *testing.T) {
field := Field{
Name: "name", Key: "name", Type: "string_suffixreplace",

View File

@ -241,7 +241,7 @@ tables:
- name: type
type: mapping_value
- name: area
type: pseudoarea
type: webmerc_area
- args:
values:
- land

View File

@ -69,7 +69,7 @@
"key": null
},
{
"type": "pseudoarea",
"type": "webmerc_area",
"name": "area",
"key": null
},
@ -841,7 +841,7 @@
"key": null
},
{
"type": "pseudoarea",
"type": "webmerc_area",
"name": "area",
"key": null
}