11import math
22from abc import ABC , abstractmethod
33
4- import pyproj
4+ from haversine import Unit , haversine
55
66from yaramo .base_element import BaseElement
77
8+ from .utils .coordinateconversion import transform_dbref_to_wgs84 , transform_wgs84_to_dbref
9+
810
911class GeoNode (ABC , BaseElement ):
1012 """This is the baseclass of specific GeoNodes that use different coordinate systems.
1113
1214 A GeoNode is characterized by it's x and y coordinates.
1315 """
1416
15- def __init__ (self , x , y , ** kwargs ):
17+ def __init__ (self , x , y , dbref_crs : str = "ER0" , ** kwargs ):
1618 super ().__init__ (** kwargs )
1719 self .x = x
1820 self .y = y
21+ self .dbref_crs = dbref_crs
1922
2023 @abstractmethod
2124 def get_distance_to_other_geo_node (self , geo_node_b : "GeoNode" ):
@@ -39,66 +42,43 @@ def to_serializable(self):
3942
4043
4144class Wgs84GeoNode (GeoNode ):
42- def get_distance_to_other_geo_node (self , geo_node_b : "Wgs84GeoNode" ):
43- assert type (self ) == type (
44- geo_node_b
45- ), "You cannot calculate the distance between a Wgs84GeoNode and a geo node of a different type!"
46- return self .__haversine_distance (geo_node_b ) / 1000
45+ def get_distance_to_other_geo_node (self , geo_node_b : "GeoNode" ):
46+ geo_node_b = geo_node_b .to_wgs84 ()
47+ return self .__haversine_distance (geo_node_b )
4748
4849 def __haversine_distance (self , geo_node_b : "GeoNode" ):
49- pi_over_180 = float (math .pi / 180 )
50- return (
51- 2
52- * 6371000
53- * math .asin (
54- math .pi
55- / 180
56- * math .sqrt (
57- math .pow (math .sin ((pi_over_180 * (geo_node_b .x - self .x )) / 2 ), 2 )
58- + math .cos (pi_over_180 * self .x )
59- * math .cos (pi_over_180 * geo_node_b .x )
60- * math .pow (math .sin ((pi_over_180 * (geo_node_b .y - self .y )) / 2 ), 2 )
61- )
62- )
63- )
64-
65- def to_wgs84 (self ):
50+ own = (self .x , self .y )
51+ other = (geo_node_b .x , geo_node_b .y )
52+ return haversine (own , other , unit = Unit .METERS )
53+
54+ def to_wgs84 (self ) -> "Wgs84GeoNode" :
6655 return self
6756
68- def to_dbref (self ):
69- transformer = pyproj .Transformer .from_crs ("epsg:4326" , "epsg:31468" )
70- x , y = transformer .transform (self .y , self .x )
71- return DbrefGeoNode (x , y )
57+ def to_dbref (self ) -> "DbrefGeoNode" :
58+ x , y = transform_wgs84_to_dbref (self .x , self .y , self .dbref_crs )
59+ return DbrefGeoNode (x , y , self .dbref_crs )
7260
7361 def to_euclidean (self ) -> "EuclideanGeoNode" :
74- raise NotImplementedError
62+ return self . to_dbref (). to_euclidean ()
7563
7664
7765class DbrefGeoNode (GeoNode ):
78- def get_distance_to_other_geo_node (self , geo_node_b : "DbrefGeoNode" ):
79- assert type (self ) == type (
80- geo_node_b
81- ), "You cannot calculate the distance between a DbrefGeoNode and a geo node of a different type!"
82- return self .__eucldian_distance (geo_node_b )
83-
84- def __eucldian_distance (self , geo_node_b : "GeoNode" ):
85- min_x = min (self .x , geo_node_b .x )
86- min_y = min (self .y , geo_node_b .y )
87- max_x = max (self .x , geo_node_b .x )
88- max_y = max (self .y , geo_node_b .y )
89- return math .sqrt (math .pow (max_x - min_x , 2 ) + math .pow (max_y - min_y , 2 ))
66+ def get_distance_to_other_geo_node (self , geo_node_b : "GeoNode" ):
67+ # Separate DB Ref distance method not implemented yet, therefore use WGS84 distance
68+ return self .to_wgs84 ().get_distance_to_other_geo_node (geo_node_b )
9069
91- def to_wgs84 (self ):
92- raise NotImplementedError
70+ def to_wgs84 (self ) -> "Wgs84GeoNode" :
71+ x , y = transform_dbref_to_wgs84 (self .x , self .y , self .dbref_crs )
72+ return Wgs84GeoNode (x , y , self .dbref_crs )
9373
94- def to_dbref (self ):
74+ def to_dbref (self ) -> "DbrefGeoNode" :
9575 return self
9676
9777 def to_euclidean (self ) -> "EuclideanGeoNode" :
9878 # This transformation is just for testing purposes and not correct, see documentation in EuclideanGeoNode.
9979 _x_shift = 4533770.0
10080 _y_shift = 5625780.0
101- return EuclideanGeoNode (self .x - _x_shift , self .y - _y_shift )
81+ return EuclideanGeoNode (self .x - _x_shift , self .y - _y_shift , self . dbref_crs )
10282
10383
10484class EuclideanGeoNode (GeoNode ):
@@ -109,9 +89,7 @@ class EuclideanGeoNode(GeoNode):
10989 """
11090
11191 def get_distance_to_other_geo_node (self , geo_node_b : "EuclideanGeoNode" ):
112- assert type (self ) == type (
113- geo_node_b
114- ), "You cannot calculate the distance between a EuclideanGeoNode and a geo node of a different type!"
92+ geo_node_b = geo_node_b .to_euclidean ()
11593 return self .__eucldian_distance (geo_node_b )
11694
11795 def __eucldian_distance (self , geo_node_b : "GeoNode" ):
@@ -122,12 +100,12 @@ def __eucldian_distance(self, geo_node_b: "GeoNode"):
122100 return math .sqrt (math .pow (max_x - min_x , 2 ) + math .pow (max_y - min_y , 2 ))
123101
124102 def to_wgs84 (self ) -> "Wgs84GeoNode" :
125- raise NotImplementedError
103+ return self . to_dbref (). to_wgs84 ()
126104
127- def to_dbref (self ):
105+ def to_dbref (self ) -> "DbrefGeoNode" :
128106 _x_shift = 4533770.0
129107 _y_shift = 5625780.0
130- return DbrefGeoNode (self .x + _x_shift , self .y + _y_shift )
108+ return DbrefGeoNode (self .x + _x_shift , self .y + _y_shift , self . dbref_crs )
131109
132110 def to_euclidean (self ) -> "EuclideanGeoNode" :
133111 return self
0 commit comments