@@ -681,3 +681,109 @@ func calculateRhumbDestination(origin []float64, distance float64, bearing float
681
681
// normalise to -180...+180
682
682
return []float64 {(math .Mod (((λ2 * 180.0 )/ math .Pi + 540 ), 360 ) - 180.0 ), (φ2 * 180.0 ) / math .Pi }
683
683
}
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