Skip to content

Commit 3462a34

Browse files
committed
WIP add point on feature
1 parent b72f3ef commit 3462a34

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

measurement/measurement.go

+106
Original file line numberDiff line numberDiff line change
@@ -681,3 +681,109 @@ func calculateRhumbDestination(origin []float64, distance float64, bearing float
681681
// normalise to -180...+180
682682
return []float64{(math.Mod(((λ2*180.0)/math.Pi+540), 360) - 180.0), (φ2 * 180.0) / math.Pi}
683683
}
684+
685+
// PointOnFeature takes a Feature and returns a point guaranteed to be on the surface of the feature.
686+
func PointOnFeature(f feature.Feature, properties map[string]interface{}, id string) (*geometry.Point, error) {
687+
fs := []feature.Feature{}
688+
fs = append(fs, f)
689+
fc, err := feature.NewFeatureCollection(fs)
690+
if err != nil {
691+
return nil, err
692+
}
693+
return PointOnFeatureCollection(*fc, properties, id)
694+
}
695+
696+
// PointOnFeatureCollection gets a feature collection and returns a point guaranteed to be on the surface of the feature.
697+
func PointOnFeatureCollection(fc feature.Collection, properties map[string]interface{}, id string) (*geometry.Point, error) {
698+
centroid, err := CentroidFeatureCollection(fc, properties, id)
699+
if err != nil {
700+
return nil, err
701+
}
702+
cent, err := centroid.ToPoint()
703+
var onSurface = false
704+
705+
for i := 0; !onSurface && i < len(fc.Features); i++ {
706+
var geom = fc.Features[i].Geometry
707+
onSurface = pointOnFeatureCollection(geom, *cent)
708+
}
709+
710+
return cent, nil
711+
}
712+
713+
func pointOnFeatureCollection(t interface{}, cent geometry.Point) bool {
714+
var x, y, x1, y1, x2, y2 float64
715+
var onBorderOrPoint = false
716+
var onSurface = false
717+
718+
switch gtp := t.(type) {
719+
case geometry.Point:
720+
if cent.Lat == gtp.Lat && cent.Lng == gtp.Lng {
721+
onSurface = true
722+
}
723+
case []geometry.Point:
724+
var onMultiPoint = false
725+
726+
for k := 0; !onMultiPoint && k < len(gtp); k++ {
727+
if cent.Lat == gtp[k].Lat && cent.Lng == gtp[k].Lng {
728+
onSurface = true
729+
onMultiPoint = true
730+
}
731+
}
732+
733+
onBorderOrPoint = onMultiPoint
734+
case geometry.LineString:
735+
for k := 0; !onBorderOrPoint && k < (len(gtp.Coordinates) - 1); k++ {
736+
x = cent.Lat
737+
y = cent.Lng
738+
x1 = gtp.Coordinates[k].Lat
739+
y1 = gtp.Coordinates[k].Lng
740+
x2 = gtp.Coordinates[k + 1].Lat
741+
y2 = gtp.Coordinates[k + 1].Lng
742+
if pointOnSegment(x, y, x1, y1, x2, y2) {
743+
onBorderOrPoint = true
744+
onSurface = true
745+
}
746+
}
747+
case geometry.MultiLineString:
748+
for j:= 0; j < len(gtp.Coordinates); j++ {
749+
onBorderOrPoint = false
750+
var line = gtp.Coordinates[j];
751+
for k := 0; !onBorderOrPoint && k < len(line.Coordinates) - 1; k++ {
752+
x = cent.Lat
753+
y = cent.Lng
754+
x1 = line.Coordinates[k].Lat;
755+
y1 = line.Coordinates[k].Lng;
756+
x2 = line.Coordinates[k + 1].Lat;
757+
y2 = line.Coordinates[k + 1].Lng;
758+
if pointOnSegment(x, y, x1, y1, x2, y2) {
759+
onBorderOrPoint = true
760+
onSurface = true
761+
}
762+
}
763+
}
764+
case geometry.Polygon:
765+
for _, c := range gtp.Coordinates {
766+
//todo: decide if cent is on surface
767+
print(len(c.Coordinates))
768+
}
769+
onSurface = true
770+
case geometry.MultiPolygon:
771+
coords := gtp.Coordinates
772+
for _, coord := range coords {
773+
for _, pl := range coord.Coordinates {
774+
//todo: decide if cent is on surface
775+
print(len(pl.Coordinates))
776+
}
777+
}
778+
onSurface = true
779+
}
780+
781+
return onSurface || onBorderOrPoint
782+
}
783+
784+
func pointOnSegment(x float64, y float64, x1 float64, y1 float64, x2 float64, y2 float64) bool {
785+
var ab = math.Sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
786+
var ap = math.Sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1))
787+
var pb = math.Sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y))
788+
return ab == (ap + pb)
789+
}

0 commit comments

Comments
 (0)