```# -*- coding: utf-8 -*-

# Copyright 2017 Juan José Martín Miralles
#
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# Unless required by applicable law or agreed to in writing, software
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and

# Python modules
import math
import warnings
import datetime
import datetime as dt
from datetime import datetime

# Third party modules
import geopy
import geopy.distance as geo_dist
import pandas as pd

TIME_FORMATS = ['%H:%M', '%H%M', '%I:%M%p', '%I%M%p', '%H:%M:%S', '%H%M%S', '%I:%M:%S%p', '%I%M%S%p']

class TrackException(Exception):
"""
Generic exception for TrackAnimation
"""

def __init__(self, msg, original_exception):
super(TrackException, self).__init__(msg + (": %s" % original_exception))
self.original_exception = original_exception

def getBearing(start_point, end_point):
"""
Calculates the bearing between two points.

Parameters
----------
start_point: geopy.Point
end_point: geopy.Point

Returns
-------
point: int
Bearing in degrees between the start and end points.
"""
warnings.warn("The getBearing function is deprecated and "
"will be removed in version 2.0.0. "
FutureWarning,
stacklevel=8
)
return get_bearing(start_point, end_point)

def get_bearing(start_point, end_point):
"""
Calculates the bearing between two points.

Parameters
----------
start_point: geopy.Point
end_point: geopy.Point

Returns
-------
point: int
Bearing in degrees between the start and end points.
"""

d_lng = end_lng - start_lng
if abs(d_lng) > math.pi:
if d_lng > 0.0:
d_lng = -(2.0 * math.pi - d_lng)
else:
d_lng = (2.0 * math.pi + d_lng)

tan_start = math.tan(start_lat / 2.0 + math.pi / 4.0)
tan_end = math.tan(end_lat / 2.0 + math.pi / 4.0)
d_phi = math.log(tan_end / tan_start)
bearing = (math.degrees(math.atan2(d_lng, d_phi)) + 360.0) % 360.0

return bearing

def getCoordinates(start_point, end_point, distance_meters):
"""
Calculates the new coordinates between two points depending
of the specified distance and the calculated bearing.

Parameters
----------
start_point: geopy.Point
end_point: geopy.Point
distance_meters: float

Returns
-------
point: geopy.Point
A new point between the start and the end points.
"""
warnings.warn("The getCoordinates function is deprecated and "
"will be removed in version 2.0.0. "
FutureWarning,
stacklevel=8
)
return get_coordinates(start_point, end_point, distance_meters)

def get_coordinates(start_point, end_point, distance_meters):
"""
Calculates the new coordinates between two points depending
of the specified distance and the calculated bearing.

Parameters
----------
start_point: geopy.Point
end_point: geopy.Point
distance_meters: float

Returns
-------
point: geopy.Point
A new point between the start and the end points.
"""
bearing = get_bearing(start_point, end_point)

distance_km = distance_meters / 1000
d = geo_dist.VincentyDistance(kilometers=distance_km)
destination = d.destination(point=start_point, bearing=bearing)

return geopy.Point(destination.latitude, destination.longitude)

def getPointInTheMiddle(start_point, end_point, time_diff, point_idx):
"""
Calculates a new point between two points depending of the
time difference between them and the point index.

Parameters
----------
start_point: DataFrame
end_point: DataFrame
time_diff: float
point_idx: int
Point index between the start and the end points

Returns
-------
point: list
A new point between the start and the end points.
"""
warnings.warn("The getPointInTheMiddle function is deprecated and "
"will be removed in version 2.0.0. "
FutureWarning,
stacklevel=8
)
return get_point_in_the_middle(start_point, end_point, time_diff, point_idx)

def get_point_in_the_middle(start_point, end_point, time_diff, point_idx):
"""
Calculates a new point between two points depending of the
time difference between them and the point index.

Parameters
----------
start_point: DataFrame
end_point: DataFrame
time_diff: float
point_idx: int
Point index between the start and the end points

Returns
-------
point: list
A new point between the start and the end points.
"""
time_proportion = (time_diff * point_idx) / end_point['TimeDifference'].item()

distance_proportion = end_point['Distance'].item() * time_proportion
time_diff_proportion = end_point['TimeDifference'].item() * time_proportion
speed = distance_proportion / time_diff_proportion
distance = time_diff * speed
cum_time_diff = int(start_point['CumTimeDiff'].item() + time_diff_proportion)
# date = datetime.strptime(start_point['Date'].item(), '%Y-%m-%d %H:%M:%S') + dt.timedelta(seconds=int(
# time_diff_proportion))
date = pd.to_datetime(start_point['Date'].astype(str), format='%Y-%m-%d %H:%M:%S') + dt.timedelta(
seconds=int(time_diff_proportion))
altitude = (end_point['Altitude'].item() + start_point['Altitude'].item()) / 2
name = start_point['CodeRoute'].item()

geo_start = geopy.Point(start_point['Latitude'].item(), start_point['Longitude'].item())
geo_end = geopy.Point(end_point['Latitude'].item(), end_point['Longitude'].item())
middle_point = get_coordinates(geo_start, geo_end, distance_proportion)

df_middle_point = ([[name, middle_point.latitude, middle_point.longitude, altitude,
date, speed, int(time_diff), distance, None, cum_time_diff]])

return df_middle_point

def rgb(value, minimum, maximum):
"""
Calculates an rgb color of a value depending of
the minimum and maximum values.

Parameters
----------
value: float or int
minimum: float or int
maximum: float or int

Returns
-------
rgb: tuple
"""
value = float(value)
minimum = float(minimum)
maximum = float(maximum)

if minimum == maximum:
ratio = 0
else:
ratio = 2 * (value - minimum) / (maximum - minimum)

b = int(max(0, 255 * (1 - ratio)))
r = int(max(0, 255 * (ratio - 1)))
g = 255 - b - r

return r / 255.0, g / 255.0, b / 255.0

def calculateCumTimeDiff(df):
"""
Calculates the cumulative of the time difference
between points for each track of 'dfTrack'.
"""
warnings.warn("The calculateCumTimeDiff function is deprecated and "
"will be removed in version 2.0.0. "
FutureWarning,
stacklevel=8
)
return calculate_cum_time_diff(df)

def calculate_cum_time_diff(df):
"""
Calculates the cumulative of the time difference
between points for each track of 'dfTrack'.
"""
df = df.copy()

df_cum = pd.DataFrame()
grouped = df['CodeRoute'].unique()

for name in grouped:
df_slice = df[df['CodeRoute'] == name]
df_slice = df_slice.reset_index(drop=True)
df_slice['CumTimeDiff'] = df_slice['TimeDifference'].cumsum()
df_cum = pd.concat([df_cum, df_slice])

df_cum = df_cum.reset_index(drop=True)

return df_cum

def isTimeFormat(time):
"""
Check if 'time' variable has the format of one
of the 'time_formats'
"""
warnings.warn("The isTimeFormat function is deprecated and "
"will be removed in version 2.0.0. "
FutureWarning,
stacklevel=8
)
return is_time_format(time)

def is_time_format(time):
"""
Check if 'time' variable has the format of one
of the 'time_formats'
"""
if time is None:
return False

for time_format in TIME_FORMATS:
try:
datetime.strptime(time, time_format)
return True
except ValueError:
pass

return False
```