Git Product home page Git Product logo

go.geo's People

Contributors

abonec avatar bdon avatar ericrwolfe avatar furstenheim avatar gregpsycle avatar j16sdiz avatar martinodf avatar missinglink avatar mlerner avatar paulmach avatar regeda avatar ryankurte avatar turbo87 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go.geo's Issues

Marshal to GeoJSON by default

Rather than having to use ToGeoJSON(), is there a reason not to just have a built in custom MarshalJSON() that defaults to GeoJSON? That would allow embedded geo fields to marshal properly to GeoJSON out of the box.

Knearest returns duplicate points

I created a point struct with a uuid and I noticed that k nearest returns the same point multiple times. Is this expected behavior?

code sample:

type MyPoint struct {
	Lng float64
	Lat float64
	Id  uuid.UUID
}

func (p MyPoint) String() string {
	ju, err := json.MarshalIndent(p, "", " ")
	if err != nil {
		panic(err)
	}
	return string(ju)
}

func (p MyPoint) Point() orb.Point {
	return orb.Point{p.Lng, p.Lat}
}

func run() error {
	r := rand.New(rand.NewSource(42))
	qt := quadtree.New(orb.Bound{Min: orb.Point{0, 0}, Max: orb.Point{1, 1}})
	for i := 0; i < 1000; i++ {
		qt.Add(MyPoint{r.Float64(), r.Float64(), uuid.New()})
	}
	nearest := qt.KNearest(nil, orb.Point{0.5, 0.5}, 5)
	ju, err := json.MarshalIndent(nearest, "", " ")
	if err != nil {
		panic(err)
	}
	fmt.Println(string(ju))
	return nil
}

func main() {
	if err := run(); err != nil {
		log.Fatal(err)
	}
}

output

[
 {
  "Lng": 0.4930591659434973,
  "Lat": 0.5196585530161364,
  "Id": "b1e5690a-1c7d-49f5-be4f-c389756af154"
 },
 {
  "Lng": 0.4930591659434973,
  "Lat": 0.5196585530161364,
  "Id": "b1e5690a-1c7d-49f5-be4f-c389756af154"
 },
 {
  "Lng": 0.4930591659434973,
  "Lat": 0.5196585530161364,
  "Id": "b1e5690a-1c7d-49f5-be4f-c389756af154"
 },
 {
  "Lng": 0.5073640535317331,
  "Lat": 0.478560836766942,
  "Id": "691971a9-6097-4591-bd89-6791349025d0"
 },
 {
  "Lng": 0.4930591659434973,
  "Lat": 0.5196585530161364,
  "Id": "b1e5690a-1c7d-49f5-be4f-c389756af154"
 }
]

normalize cartesian coordinate range

I have this javascript code which normalizes geographic coordinates to within the ranges of lat +-90 and lon +-180 (it unwinds multiple rotations around the globe).

This function is quite nice as it avoids floating point precision errors which can occur when using other methods.

Would you be interested in me porting the code to go.geo? If so what would you call the method? it's specific to geographic coordinates.

Maybe this could close #41 as it appears to be doing something similar?

Could be named something like point.NormalizeGeographicCoordinates()

compute center of a path

heya, is it currently possible to compute the mid point along a path (a point on the line string which is exactly 50% along the line)?

I had a look at the APIs and I guess I could use path.Distance() to get the total distance, then I think I would need to walk the points to find the line segment which lies in the center, from there it's a task of interpolating along that segment to find the correct position.

is this all possible with the existing methods or would it require me to open a PR to add additional methods?

QuadKey tile

Currently I'm doing something like:

quadkey := geo.NewPoint(v.Lon, v.Lat).QuadkeyString(quadKeyLevel)

With v.Lon and v.Lat not necessarily being on a tile boundary. I'm not sure, based on the results, whether QuadKeyString will represent a tile, or if it'll be different based on different points with a tile at the same level.

postgresql/postgis: geo.PointSet scan fails for multipoint

I'm trying to select postgis multipoint to geo.PointSet - and scan fails. Checking code - seems like format actually returned by postgis is different from what's expected by geo.PointSet.

BTW for geo.Point WKB scan works fine.

Here is sample code demonstrating issue (manually setup postgresql + postgis server required for test):

package main

import (
	"database/sql"
	"testing"

	_ "github.com/lib/pq"
	geo "github.com/paulmach/go.geo"
	"github.com/stretchr/testify/require"
)

func TestMultipointScan(t *testing.T) {
	/*
		select version() union select postgis_full_version();
		                                                                               version
		----------------------------------------------------------------------------------------------------------------------------------------------------------------------
		 POSTGIS="2.3.2 r15302" GEOS="3.4.2-CAPI-1.8.2 r3921" PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.10.1, released 2013/08/26" LIBXML="2.9.1" LIBJSON="0.11.99" RASTER
		 PostgreSQL 9.6.2 on x86_64-pc-linux-gnu, compiled by gcc (Debian 4.9.2-10) 4.9.2, 64-bit
	*/
	db, err := sql.Open("postgres", "user=x password=x dbname=x sslmode=disable")
	require.NoError(t, err)

	const query = `
		SELECT ST_AsBinary(ST_Collect(ST_GeomFromText('POINT(1 2)'), ST_GeomFromText('POINT(1 2)')))
	`
	var ps geo.PointSet
	err = db.QueryRow(query).Scan(&ps)

	require.NoError(t, err)

	/*
		go test -run TestMultipointScan -v
		=== RUN   TestMultipointScan
		--- FAIL: TestMultipointScan (0.04s)
			Error Trace:	sample_test.go:23
			Error:		Received unexpected error:
					sql: Scan error on column index 0: go.geo: invalid WKB data
	*/
}

Adding identifer column to Point object for quad tree investigation

Hi, not an issue so much, as something I'm struggling with adapting.

I need the ability to have a number associated with a geo point, in order to reference back to what it relates to. I've customised the point type to have length of 3 instead of 2, with the 3rd float been the ID, so the idea was, when I ran a nearest command against the quad tree of points, I'd be able to find it's owner.

The creating of the point works, and the existing tests pass. But soon as the point is added to the quad tree, it appears to lose it's 3rd value, returning X and Y as expected, but the 3rd number is always 0.

Is there something I'm missing in the quad tree section, that is removing this 3rd column. Any help or advice on the best way to approach this would be much appreciated!

TODO: MarshalWKB()

should be able to serialize points, lines, point sets and paths into WKB format. Unmarshalling is already supported.

note about computing centroid for polygons

hi @paulmach

I got bit by a gotcha today, which although is technically correct, could cause confusion for some users.

When using the PointSet.Centroid() and PointSet.GeoCentroid() methods on a polygon, the calculated result was incorrect, for instance [1 1, 1 -1, -1 -1, -1 1, 1, 1] was not returning [0 0].

My error was that I failed to remove the last coordinate from the polygon (a duplicate of the first), which is a common convention to indicate that the polygon is closed (a convention in openstreetmap).

the fix was fairly simple:

isClosed = points.First().Equals(points.Last())
if isClosed {
  points.RemoveAt(len(*points) - 1)
}

The current implementation of numPoints := float64(len(ps)) is technically correct, but could possibly also bite others like me who aren't careful about it's usage.

How would you feel about me changing these calculations in PointSet to deduplicate the points before computing numPoints? This would likely slow down the code and require some memory to do the deduplication.

Other options include:

  • Just dedupe the first and last points
  • Add a Polygon type which has polygon specific code
  • Write a few words about it in the code comments
  • Not worry about it and hope that other people aren't big dummies like me :)

latitude out of range bug

[{"Location":[27.100918,93.691639]},{"Location":[27.10092,93.691639]}]

The above two points fail to cluster with a panic. I have a couple of more cases where it fails with a similar error.

I'm no math wiz, so reporting the issue.

panic: geo: latitude out of range, given 93.691639

goroutine 1 [running]:
github.com/paulmach/go%2egeo.MercatorScaleFactor(0x40576c43d03968d7, 0xc002415560)
        /home/org/.go/pkg/mod/github.com/paulmach/[email protected]/projections.go:36 +0x112
github.com/paulmach/go.geo/clustering.geocluster(0xc002460ca0, 0x2, 0x2, 0x4034000000000000, 0xa55ca0, 0xc000000000, 0xc002a89260)
        /home/org/.go/pkg/mod/github.com/paulmach/[email protected]/clustering/clustering.go:106 +0x106
github.com/paulmach/go.geo/clustering.ClusterGeoPointers(0xc000136e20, 0x2, 0x2, 0x4034000000000000, 0x2, 0x2, 0x0)
        /home/org/.go/pkg/mod/github.com/paulmach/[email protected]/clustering/clustering.go:75 +0x1ab
clusterhelper.ComputeClusteringData(0xc000546000, 0xbc3, 0xd62, 0xc004251e58, 0x1, 0x1, 0x0, 0xc002415300)
        /home/org/org/go-scripts/correct-data/cluster-helper/cluster-helper.go:43 +0x55d
main.main()
        /home/org/org/go-scripts/correct-data/correct-data.go:105 +0x7f6
exit status 2

ST_AsBinary return result of 44 length hex

By following the example, it returned "\x010100000000000000000024c00000000000003e40" to go.geo causing "go.geo: incorrect geometry" error

Any idea what's wrong? thanks!

Is a Point within a Hexagon?

This library is beautiful work Paul, much gratitude.

I see no way to check if a Point is within a hexagon using either go.geo or using go.geojson. Could such a helper function be added?

I have a Polygon-type Geometry handy with [][][]float64 underlying data guaranteed to be closed and hexagonal, but there is no way to check whether a Point is in it.

The overall topic is segmenting a city into hundreds of hexagons and binning samples into each of them. Equivalent functionality in Turf.js is hexGrid() for generating hexagons in a bounding box and then assigning points to bins with pointsWithinPolygon().

Thank you!
Siddharth

MySQL scanning POLYGON WKB Always results in EMPTY

For example I used this and scanned it to a geo.PointSet

SET @g = 'POLYGON((50.866753 5.686455, 50.859819 5.708942, 50.851475 5.722675, 50.841611 5.720615, 50.834023 5.708427, 50.840744 5.689373, 50.858735 5.673923, 50.866753 5.686455))';
SELECT ST_AsBinary(PolyFromText(@g));

var p *geo.PointSet
row.Scan(&p)

//  p == EMPTY

It's very likely that I'm way off on this. What am I doing wrong?

Support MultiPolygon type when reading the WKB data from db

I'd like to be able to scan data from the multipolygon column from the PostGIS database into Go app.

I was hoping I could simply define a struct where one of the fields is of type MultiPolygon:

import(geo "github.com/paulmach/go.geo")
...
type Area struct {
	ID        uuid.UUID        `gorm:"column:id" json:"id"`
	Shape     *geo.MultiPolygon `gorm:"column:shape" json:"shape"`

However, of course such a type is not yet defined.

Is there a way to actually read the MultiPolygon data from PostGIS?

Also it seems that we have to run the ST_AsBinary function when fetching data from the database. Failing to do so results in the sql: Scan error on column index 3: go.geo: invalid WKB data error.

Couldn't we always apply the ST_AsBinary function? eg. when defining the struct? I'd say that the typical scenario is that the data is actually saved as WKB binary and the ST_AsBinary function simply changes:

shape | 01060...E614340

to

st_asbinary | \x01060...e614340

centroid calc

hey @paulmach I've been playing with an alternate irregular polygon centroid algorithm which I borrowed from https://github.com/manuelbieh/Geolib/blob/master/src/geolib.js#L404

in theory it should provide a better 'center of gravity' calc than than the existing PointSet.Centroid() algo as it converts the coords to a spherical coordinate space before averaging the values.

what are your thoughts? is this something you'd be interested in merging at some point?

see: http://geojson.io/#id=gist:anonymous/ecd1ce4af92368aa4aea&map=3/-72.39/167.70

package main

import "fmt"
import "math"
import "github.com/paulmach/go.geo"

func main() {
  // berlin := geo.NewPoint(13.408056,52.518611)
  // moscow := geo.NewPoint(37.617778,55.751667)
  // points := geo.PointSet{}
  // points.Push(berlin).Push(moscow)

  // rough new zealand polygon
  // ref: http://geojson.io/#id=gist:anonymous/adc4993b4b85f55ea9ae
  // points := geo.PointSet{}
  // points.Push(geo.NewPoint(172.1298828125,-33.97980872872456))
  // points.Push(geo.NewPoint(172.1298828125,-37.30027528134431))
  // points.Push(geo.NewPoint(165.8974609375,-38.54816542304658))
  // points.Push(geo.NewPoint(168.1728515625,-46.10370875598026))
  // points.Push(geo.NewPoint(179.7802734375,-47.8721439688873))
  // // points.Push(geo.NewPoint(-188.1298828125,-33.97980872872456))

  // antarctica bbox
  points := geo.PointSet{}
  points.Push(geo.NewPoint(148.7109375,-84.83422451455142))
  points.Push(geo.NewPoint(148.7109375,-76.51681887717322))
  points.Push(geo.NewPoint(186.6796875,-76.51681887717322))
  points.Push(geo.NewPoint(186.6796875,-84.83422451455142))

  fmt.Println(points)
  fmt.Println(points.Centroid())
  fmt.Println(getCentroid(points))
}

func getCentroid(ps geo.PointSet) *geo.Point {

  X := 0.0
  Y := 0.0
  Z := 0.0

  var toRad = math.Pi / 180
  var fromRad = 180 / math.Pi

  for _, point := range ps {

    var lon = point[0] * toRad
    var lat = point[1] * toRad

    X += math.Cos(lat) * math.Cos(lon)
    Y += math.Cos(lat) * math.Sin(lon)
    Z += math.Sin(lat)
  }

  numPoints := float64(len(ps))
  X = X / numPoints
  Y = Y / numPoints
  Z = Z / numPoints

  var lon = math.Atan2(Y, X)
  var hyp = math.Sqrt(X * X + Y * Y)
  var lat = math.Atan2(Z, hyp)

  var centroid = geo.NewPoint(lon * fromRad, lat * fromRad)

  return centroid;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.