2010-06-28 2 views
5

Я портирую код java-кода геолокации от http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates#Java (показано ниже) на python. Его можно инициализировать с помощью двух функций (fromDegrees или fromRadians). Я думал, что я мог бы сделать что-то вродеМогу ли я иметь две функции init в классе python?

class geoLocation: 

    _radLat = 0 
    _radLong = 0 
    _degLat = 0 
    _degLong = 0 


    def fromDegrees(lat, long): 
     #set _radLat, _radLong, _degLat, _degLong 

    def fromRadians(lat, long): 
     #set _radLat, _radLong, _degLat, _degLong 

    ... 

Но это не кажется оптимальным, так как я установить значения для _radLat, _radLong, _degLat и _degLong дважды. Могу ли я определить две функции init? Каков наилучший способ сделать это?

Благодаря

/** 
* <p>Represents a point on the surface of a sphere. (The Earth is almost 
* spherical.)</p> 
* 
* <p>To create an instance, call one of the static methods fromDegrees() or 
* fromRadians().</p> 
* 
* <p>This code was originally published at 
* <a href="http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates#Java"> 
* http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates#Java</a>.</p> 
* 
* @author Jan Philip Matuschek 
* @version 27 May 2010 
*/ 
public class GeoLocation { 

    private double radLat; // latitude in radians 
    private double radLon; // longitude in radians 

    private double degLat; // latitude in degrees 
    private double degLon; // longitude in degrees 

    private static final double MIN_LAT = Math.toRadians(-90d); // -PI/2 
    private static final double MAX_LAT = Math.toRadians(90d); // PI/2 
    private static final double MIN_LON = Math.toRadians(-180d); // -PI*2 
    private static final double MAX_LON = Math.toRadians(180d); // PI*2 

    private GeoLocation() { 
    } 

    /** 
    * @param latitude the latitude, in degrees. 
    * @param longitude the longitude, in degrees. 
    */ 
    public static GeoLocation fromDegrees(double latitude, double longitude) { 
     GeoLocation result = new GeoLocation(); 
     result.radLat = Math.toRadians(latitude); 
     result.radLon = Math.toRadians(longitude); 
     result.degLat = latitude; 
     result.degLon = longitude; 
     result.checkBounds(); 
     return result; 
    } 

    /** 
    * @param latitude the latitude, in radians. 
    * @param longitude the longitude, in radians. 
    */ 
    public static GeoLocation fromRadians(double latitude, double longitude) { 
     GeoLocation result = new GeoLocation(); 
     result.radLat = latitude; 
     result.radLon = longitude; 
     result.degLat = Math.toDegrees(latitude); 
     result.degLon = Math.toDegrees(longitude); 
     result.checkBounds(); 
     return result; 
    } 

    private void checkBounds() { 
     if (radLat < MIN_LAT || radLat > MAX_LAT || 
       radLon < MIN_LON || radLon > MAX_LON) 
      throw new IllegalArgumentException(); 
    } 

    /** 
    * @return the latitude, in degrees. 
    */ 
    public double getLatitudeInDegrees() { 
     return degLat; 
    } 

    /** 
    * @return the longitude, in degrees. 
    */ 
    public double getLongitudeInDegrees() { 
     return degLon; 
    } 

    /** 
    * @return the latitude, in radians. 
    */ 
    public double getLatitudeInRadians() { 
     return radLat; 
    } 

    /** 
    * @return the longitude, in radians. 
    */ 
    public double getLongitudeInRadians() { 
     return radLon; 
    } 

    @Override 
    public String toString() { 
     return "(" + degLat + "\u00B0, " + degLon + "\u00B0) = (" + 
       radLat + " rad, " + radLon + " rad)"; 
    } 

    /** 
    * Computes the great circle distance between this GeoLocation instance 
    * and the location argument. 
    * @param radius the radius of the sphere, e.g. the average radius for a 
    * spherical approximation of the figure of the Earth is approximately 
    * 6371.01 kilometers. 
    * @return the distance, measured in the same unit as the radius 
    * argument. 
    */ 
    public double distanceTo(GeoLocation location, double radius) { 
     return Math.acos(Math.sin(radLat) * Math.sin(location.radLat) + 
       Math.cos(radLat) * Math.cos(location.radLat) * 
       Math.cos(radLon - location.radLon)) * radius; 
    } 

    /** 
    * <p>Computes the bounding coordinates of all points on the surface 
    * of a sphere that have a great circle distance to the point represented 
    * by this GeoLocation instance that is less or equal to the distance 
    * argument.</p> 
    * <p>For more information about the formulae used in this method visit 
    * <a href="http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates"> 
    * http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates</a>.</p> 
    * @param distance the distance from the point represented by this 
    * GeoLocation instance. Must me measured in the same unit as the radius 
    * argument. 
    * @param radius the radius of the sphere, e.g. the average radius for a 
    * spherical approximation of the figure of the Earth is approximately 
    * 6371.01 kilometers. 
    * @return an array of two GeoLocation objects such that:<ul> 
    * <li>The latitude of any point within the specified distance is greater 
    * or equal to the latitude of the first array element and smaller or 
    * equal to the latitude of the second array element.</li> 
    * <li>If the longitude of the first array element is smaller or equal to 
    * the longitude of the second element, then 
    * the longitude of any point within the specified distance is greater 
    * or equal to the longitude of the first array element and smaller or 
    * equal to the longitude of the second array element.</li> 
    * <li>If the longitude of the first array element is greater than the 
    * longitude of the second element (this is the case if the 180th 
    * meridian is within the distance), then 
    * the longitude of any point within the specified distance is greater 
    * or equal to the longitude of the first array element 
    * <strong>or</strong> smaller or equal to the longitude of the second 
    * array element.</li> 
    * </ul> 
    */ 
    public GeoLocation[] boundingCoordinates(double distance, double radius) { 

     if (radius < 0d || distance < 0d) 
      throw new IllegalArgumentException(); 

     // angular distance in radians on a great circle 
     double radDist = distance/radius; 

     double minLat = radLat - radDist; 
     double maxLat = radLat + radDist; 

     double minLon, maxLon; 
     if (minLat > MIN_LAT && maxLat < MAX_LAT) { 
      double deltaLon = Math.asin(Math.sin(radDist)/
       Math.cos(radLat)); 
      minLon = radLon - deltaLon; 
      if (minLon < MIN_LON) minLon += 2d * Math.PI; 
      maxLon = radLon + deltaLon; 
      if (maxLon > MAX_LON) maxLon -= 2d * Math.PI; 
     } else { 
      // a pole is within the distance 
      minLat = Math.max(minLat, MIN_LAT); 
      maxLat = Math.min(maxLat, MAX_LAT); 
      minLon = MIN_LON; 
      maxLon = MAX_LON; 
     } 

     return new GeoLocation[]{fromRadians(minLat, minLon), 
       fromRadians(maxLat, maxLon)}; 
    } 

} 

ответ

14

выбрал один по умолчанию (радиан или градусов) и придерживаться его. Вы можете написать classmethod для автоматического преобразования в другой:

class geoLocation: 
    def __init__(self, lat, long): 
     """init class from lat,long as radians""" 

    @classmethod 
    def fromDegrees(cls, dlat, dlong): 
     """creat `cls` from lat,long in degrees """ 
     return cls(to_radians(dlat), to_radians(dlong)) 

    @classmethod 
    def fromRadians(cls, lat, long): # just in case 
     return cls(lat, long) 

obj = geoLocation.fromDegrees(10,20) # returns a new geoLocation object 
4

я бы просто включить логическое значение в вашем методе инициализации. Вместо двух __init__ методов, выполните следующие действия:

class geoLocation: 
    def __init__(self, lat, long, degrees=True): 
     if degrees: 
      # process as fromDegrees 
      (self._radLat, self._radLong, self._degLat, self._degLong) = self.fromDegrees(lat, long) 
     else: 
      (self._radLat, self._radLong, self._degLat, self._degLong) = self.fromRadians(lat, long) 

    def fromDegrees(self, lat, long): 
     # some function returning radLat and long and degLat and long in a tuple 
    def fromRadians(self, lat, long): 
     # same idea but different calculations 
1

Другой вариант должен подклассов GeoLocation, скажем DegreesGeoLocation и RadiansGeoLocation. Теперь вы можете дать каждому свою функцию init.

Теперь вы храните местоположение дважды в своем классе, используя радианы и один раз используя градусы. Это может вызвать проблемы, если вы случайно измените одно представление, но забудете другое. Я думаю, что вы могли бы наилучшим образом использовать одно представление и предоставлять геттеры и сеттеры, которые в конечном итоге преобразуются в другое представление.

2

Одним из вариантов является использование методов фабрики класса:

class geoLocation(object): 
    @classmethod 
    def fromDegrees(cls, lat, long): 
     return cls(lat, long, True) 

    @classmethod 
    def fromDegrees(cls, lat, long): 
     return cls(lat, long, False) 

    def __init__(self, lat, long, degrees=True): 
     if degrees: 
      #blah 
     else: 
      #blah 
Смежные вопросы