Esempio n. 1
0
def _manGetShapepointsTimeDist(startLoc,
                               endLoc,
                               speedMPS,
                               expDurationSec,
                               verticalFirst=True):
    # if verticalFirst is true, it means go north/south first then go east/west
    if verticalFirst:
        path = [startLoc, [endLoc[0], startLoc[1]], endLoc]
        dist = [
            0,
            geoDistance2D(startLoc, [endLoc[0], startLoc[1]]),
            geoDistance2D([endLoc[0], startLoc[1]], endLoc)
        ]
    else:
        path = [startLoc, [startLoc[0], endLoc[1]], endLoc]
        dist = [
            0,
            geoDistance2D(startLoc, [startLoc[0], endLoc[1]]),
            geoDistance2D([startLoc[0], endLoc[1]], endLoc)
        ]

    if (expDurationSec != None):
        time = [
            0, expDurationSec * dist[1] / (dist[1] + dist[2]),
            expDurationSec * dist[2] / (dist[1] + dist[2])
        ]
    else:
        time = [0, dist[1] / speedMPS, dist[2] / speedMPS]

    return [path, time, dist]
def _getTimeDistManhattan(fromLocs, toLocs, speedMPS):
    """
	Generate two dictionaries, one for time, another for distance, using Manhattan

	Parameters
	----------
	fromLocs: list, Required
		The start node coordinates in format of [[lat, lon], [lat, lon], ... ]
	toLocs: list, Required
		The End node coordinates in format of [[lat, lon], [lat, lon], ... ]
	speedMPS: float, Required
		A constant speed for calculation

	returns
	-------
	timeSecs: dictionary
		A dictionary for time from nodes to nodes, unit is in [seconds]
	distMeters: dictionary
		A dictionary for distance from nodes to nodes, unit is in [meters]
	
	"""

    distMeters = {}
    timeSecs = {}
    for i in range(len(fromLocs)):
        for j in range(len(toLocs)):
            fromLocsDict = locs2Dict(fromLocs)
            toLocsDict = locs2Dict(toLocs)
            manDist = geoDistance2D(fromLocs[i], (
                fromLocsDict[i]['lat'], toLocsDict[j]['lon'])) + geoDistance2D(
                    (fromLocsDict[i]['lat'], toLocsDict[j]['lon']), toLocs[j])
            distMeters[i, j] = manDist
            timeSecs[i, j] = manDist / speedMPS
    return [timeSecs, distMeters]
Esempio n. 3
0
def areaOfTriangle(loc1, loc2, loc3):
    """
	Calculates the area of triangle defined by three locations

	Parameters
	----------
	loc1: list
		First location
	loc2: list
		Second location
	loc3: list
		Third location

	Return
	------
	float
		Area of triangle
	"""

    # Using Heron's Formula
    a = geoDistance2D(loc1, loc2)
    b = geoDistance2D(loc2, loc3)
    c = geoDistance2D(loc1, loc3)

    s = (a + b + c) / 2
    area = math.sqrt(s * (s - a) * (s - b) * (s - c))

    return area
Esempio n. 4
0
def _genNodesRoadBased(numNodes=None,
                       boundingRegion=None,
                       distToRoad=None,
                       dataProvider=None,
                       dataProviderArgs=None):
    """
	Generate randomized node using Uniform distribution within a bounding area and close to roads
	
	Note
	----
	This function is an approximation, the error is getting larger when the location is closer to poles

	Parameters
	----------
	numNodes: int, Required
		Number of nodes to be generated
	boudingArea: list, Required
		A defined polygon, nodes are generated within this area
	distToRoad: float, Required
		The maximun distance to road for generated nodes.
	dataProvider: string, Conditional, default as None
		Specifies the data source to be used for generating nodes on a road network. See :ref:`Data Providers` for options and requirements.
	dataProviderArgs: dictionary, Conditional, default as None
		For some data providers, additional parameters are required (e.g., API keys or database names). See :ref:`Data Providers` for the additional arguments required for each supported data provider.
	
	Returns
	-------
	list of lists
		A list of coordinates, within a given distance to its nearest street
	"""

    # Initialize
    locs = []
    holes = []
    goodLocs = []

    # Generate nodes, if it is not close enough, discard and regenerate
    while (len(locs) < numNodes):
        newLocs = _genNodesUniformBounded(numNodes - len(locs), boundingRegion)
        goodLocs = []
        for i in range(len(newLocs)):
            goodFlag = True
            for j in range(len(holes)):
                if (geoDistance2D(newLocs[i], holes[j][0]) < holes[j][1]):
                    goodFlag = False
                    break
            if (goodFlag):
                goodLocs.append(newLocs[i])
        if (len(goodLocs) > 0):
            snapLocs = privGetSnapLocBatch(goodLocs, dataProvider,
                                           dataProviderArgs)
            for i in range(len(snapLocs)):
                dist = geoDistance2D(goodLocs[i], snapLocs[i])
                if (dist > distToRoad):
                    holes.append([goodLocs[i], dist - distToRoad])
                else:
                    locs.append(goodLocs[i])

    return locs
def _getTimeDistEuclidean2D(fromLocs, toLocs, speedMPS):
    """
	Generate two dictionaries, one for time, another for distance, using euclidean (in 2D)

	Parameters
	----------
	fromLocs: list, Required
		The start node coordinates in format of [[lat, lon], [lat, lon], ... ]
	toLocs: list, Required
		The End node coordinates in format of [[lat, lon], [lat, lon], ... ]
	speedMPS: float, Required
		A constant speed for calculation

	returns
	-------
	timeSecs: dictionary
		A dictionary for time from nodes to nodes, unit is in [seconds]
	distMeters: dictionary
		A dictionary for distance from nodes to nodes, unit is in [meters]
	
	"""

    distMeters = {}
    timeSecs = {}
    for i in range(len(fromLocs)):
        for j in range(len(toLocs)):
            eucDist = geoDistance2D(fromLocs[i], toLocs[j])
            distMeters[i, j] = eucDist
            timeSecs[i, j] = eucDist / speedMPS
    return [timeSecs, distMeters]
Esempio n. 6
0
def distributeTimeDist(path, totalTime):
    """
	This function gives time stamps for a series of coordinates, given a start time and total time, used in shapepoint calculating. The distribution is made based on the euclidean distance between neigboring coordinates - they are very close to each other

	Parameters
	----------
	path: list of lists
		A path that consist a list of locations as shapepoints/waypoints, in the form of [[lat, lon], [lat, lon], ..., [lat, lon]], it will be considered as open polyline.
	totalTime: float
		Required, total time to be distributed

	Returns
	-------
	timeSecs: list
		A list of time stamps, those time stamps are not accumulative in seconds.
	distMeters: list
		Distance between neighboring coordinates in meters.
	"""

    timeSecs = []
    distMeters = []
    totalDistMeters = 0
    distMeters.append(0)
    timeSecs.append(0)
    for i in range(1, len(path)):
        d = geoDistance2D(path[i - 1], path[i])
        distMeters.append(d)
        totalDistMeters += d

    for i in range(1, len(path)):
        timeSecs.append(totalTime * float(distMeters[i]) /
                        float(totalDistMeters))

    return [timeSecs, distMeters]
Esempio n. 7
0
def _eucGetShapepointsTimeDist(startLoc, endLoc, speedMPS, expDurationSec):
    path = [startLoc, endLoc]
    dist = [0, geoDistance2D(startLoc, endLoc)]
    if (expDurationSec != None):
        time = [0, expDurationSec]
    else:
        time = [0, dist[1] / speedMPS]
    return [path, time, dist]
Esempio n. 8
0
def _genNodesRoadBased(numNodes=None,
                       boundingRegion=None,
                       distToRoad=None,
                       dataProvider=None,
                       APIkey=None,
                       databaseName=None):
    """
	Generate randomized node using Uniform distribution within a bounding area and close to roads

	Note
	----
	This function is an approximation, the error is getting larger when the location is closer to poles

	Parameters
	----------
	numNodes: int, Required
		Number of nodes to be generated
	boudingArea: list, Required
		A defined polygon, nodes are generated within this area
	distToRoad: float, Required
		The maximun distance to road for generated nodes.
	dataProvider: string, Conditional, See :ref:`Dataprovider`
		Specifies the data source to be used for generating nodes on a road network.  
	APIkey: string, Conditional, See :ref:`Dataprovider`
		Some data providers require an API key (which you'll need to register for).
	databaseName: string, Conditional, See :ref:`Dataprovider`
		If you are hosting a data provider on your local machine (e.g., pgRouting), you'll need to specify the name of the local database. 
	
	Returns
	-------
	list of lists
		A list of coordinates, within a given distance to its nearest street
	"""

    # Initialize
    locs = []

    # Generate nodes, if it is not close enough, discard and regenerate
    while (len(locs) < numNodes):
        newLocs = _genNodesUniformBounded(numNodes - len(locs), boundingRegion)
        snapLocs = privGetSnapLocBatch(newLocs, dataProvider, APIkey,
                                       databaseName)
        for i in range(len(snapLocs)):
            if (geoDistance2D(newLocs[i], snapLocs[i]) <= distToRoad):
                locs.append(newLocs[i])

    return locs
Esempio n. 9
0
def pgrGetTimeDist(fromLocs, toLocs, databaseName):
	"""
	This function generated time and distance matrix using pgRouting

	Parameters
	----------
	fromLoc: list, Conditional
		Used in 'one2many' mode. To state the coordinate of the starting node
	locs: list of lists
		Used in 'all2all', 'one2many', 'many2one' modes. A list of coordinates, in the format of [[lat1, lon1], [lat2, lon2], ...]
	toLoc: list, Conditional
		Used in 'many2one' mode. To state the coordinate of the ending node
	databaseName: string	
		If you are hosting a data provider on your local machine (e.g., pgRouting), you'll need to specify the name of the local database. 

	Returns
	-------
	timeSecs: dictionary
		The key of each item in this dictionary is in (coordID1, coordID2) format, the travelling time from first entry to second entry, the units are seconds
	distMeters: dictionary
		The key of each item in this dictionary is in (coordID1, coordID2) format, the travelling distance from first entry to second entry, the units are meters
	"""

	conn = psycopg2.connect("dbname='%s' user='******' host='%s' password='******'" % (
		databaseName, 
		VRV_SETTING_PGROUTING_USERNAME, 
		VRV_SETTING_PGROUTING_HOST, 
		VRV_SETTING_PGROUTING_PASSWORD))
	conn.autocommit = True
	cur = conn.cursor()

	dummyClassID = 821 # Hard-coded number, no specific meaning
	# FIXME! For database security reason, we need to testify if class_id = 821 is not used in the original database	

	sqlCommand  = " select max(id) from ways_vertices_pgr;"
	cur.execute(sqlCommand)
	row = cur.fetchone()
	newlyInsertVidNum = int(row[0]) + 1

	locs = fromLocs.copy()
	for i in range(len(toLocs)):
		try:
			locs.index(toLocs[i])
		except ValueError:
			locs.append(toLocs[i])

	startVidList = []
	endVidList = []
	for i in range(len(fromLocs)):
		startVidList.append(newlyInsertVidNum + locs.index(fromLocs[i]))
	for i in range(len(toLocs)):
		endVidList.append(newlyInsertVidNum + locs.index(toLocs[i]))

	for i in range(len(locs)):
		# Add dummy vertices
		street = pgrGetNearestStreet(locs[i], databaseName)
		snapLoc = pgrGetSnapToRoadLatLon(street['gid'], locs[i], databaseName)
		dicSnapLoc = loc2Dict(snapLoc)
		sqlCommand	= "	insert into ways_vertices_pgr (id, lon, lat) values (%s, %s, %s);" % (
			newlyInsertVidNum + locs.index(locs[i]),
			dicSnapLoc['lon'],
			dicSnapLoc['lat'])
		cur.execute(sqlCommand)

		# Add four two road segments
		distSource2Snapped = geoDistance2D(street['sourceLoc'], snapLoc)
		distSnapped2Target = geoDistance2D(snapLoc, street['targetLoc'])
		ratio = distSource2Snapped / (distSource2Snapped + distSnapped2Target)
		dicSourceLoc = loc2Dict(street['sourceLoc'])
		dicTargetLoc = loc2Dict(street['targetLoc'])
		sqlCommand  = "	insert into ways (class_id, source, target, length_m, x1, y1, x2, y2, cost_s, reverse_cost_s) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" % (
			dummyClassID, 
			street['source'],
			newlyInsertVidNum + locs.index(locs[i]),
			distSource2Snapped,
			dicSourceLoc['lon'],
			dicSourceLoc['lat'],
			dicSnapLoc['lon'],
			dicSnapLoc['lat'],
			street['cost_s'] * ratio,
			street['reverse_cost_s'] * ratio)
		cur.execute(sqlCommand)
		sqlCommand  = "	insert into ways (class_id, source, target, length_m, x1, y1, x2, y2, cost_s, reverse_cost_s) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" % (
			dummyClassID, 
			newlyInsertVidNum + locs.index(locs[i]),
			street['target'],
			distSnapped2Target,
			dicSnapLoc['lon'],
			dicSnapLoc['lat'],
			dicTargetLoc['lon'],
			dicTargetLoc['lat'],
			street['cost_s'] * (1 - ratio),
			street['reverse_cost_s'] * (1 - ratio))
		cur.execute(sqlCommand)

	sqlCommand  = "	select " 
	sqlCommand += "		start_vid as start_node, "
	sqlCommand += "		end_vid as end_node, "
	sqlCommand += "		sum(cost) as time, "
	sqlCommand += "		sum(length_m) as distance "
	sqlCommand += "	from ("
	sqlCommand += "		select "
	sqlCommand += "			a.*, "
	sqlCommand += "			b.length_m"
	sqlCommand += "		from pgr_dijkstra("
	sqlCommand += "			'select gid as id, source, target, cost_s as cost, reverse_cost_s as reverse_cost from ways', "
	sqlCommand += "			ARRAY%s, " % (startVidList)
	sqlCommand += "			ARRAY%s, " % (endVidList)
	sqlCommand += "			directed := true) a "
	sqlCommand += "		left join "
	sqlCommand += "			ways b "
	sqlCommand += "		on "
	sqlCommand += "			a.edge = b.gid "
	sqlCommand += "		order by "
	sqlCommand += "			a.path_seq"
	sqlCommand += "		) x "
	sqlCommand += "	group by "
	sqlCommand += "		start_vid, "
	sqlCommand += "		end_vid;"
	cur.execute(sqlCommand)
	row = cur.fetchall()

	for i in range(len(startVidList)):
		sqlCommand  = "	delete from ways_vertices_pgr where id = %s;" % (startVidList[i])
		cur.execute(sqlCommand)
	for i in range(len(endVidList)):
		sqlCommand  = "	delete from ways_vertices_pgr where id = %s;" % (endVidList[i])
		cur.execute(sqlCommand)
	sqlCommand  = "	delete from ways where class_id = %s;" % (dummyClassID)
	cur.execute(sqlCommand)

	conn.close()

	rawDist = {}
	rawTime = {}
	for i in range(len(row)):
		rawTime[row[i][0], row[i][1]] = row[i][2]
		rawDist[row[i][0], row[i][1]] = row[i][3]
	distMeters = {}
	timeSecs = {}

	for i in range(len(fromLocs)):
		for j in range(len(toLocs)):
			try:
				distMeters[i, j] = rawDist[startVidList[i], endVidList[j]]
			except:
				distMeters[i, j] = 0
			try:
				timeSecs[i, j] = rawTime[startVidList[i], endVidList[j]]
			except:
				timeSecs[i, j] = 0

	return [timeSecs, distMeters]
Esempio n. 10
0
def pgrGetShapepointsTimeDist(startLoc, endLoc, databaseName):
	"""
	A function to get a list of shapepoints from start coordinate to end coordinate.

	Parameters
	----------
	startLoc: list
		Start location, the format is [lat, lon] (altitude, above sea level, set to be 0) or [lat, lon, alt]
	endLat: float
		Required, latitude of end coordinate
	endLon: float
		Required, longitude of end coordinate
	databaseName: string, Require
		If you are hosting a data provider on your local machine (e.g., pgRouting), you'll need to specify the name of the local database.

	Returns
	-------
	path: list of lists
		A list of coordinates in sequence that shape the route from startLoc to endLoc
	timeSecs: list
		time between current shapepoint and previous shapepoint, the first element should be 0
	distMeters: list
		distance between current shapepoint and previous shapepoint, the first element should be 0
	"""

	conn = psycopg2.connect("dbname='%s' user='******' host='%s' password='******'" % (
		databaseName, 
		VRV_SETTING_PGROUTING_USERNAME, 
		VRV_SETTING_PGROUTING_HOST, 
		VRV_SETTING_PGROUTING_PASSWORD))
	conn.autocommit = True
	cur = conn.cursor()

	# Calculate the distance between snapped location and source/target of closest street for the START coordinate
	startStreet = pgrGetNearestStreet(startLoc, databaseName)
	snapStartLoc = pgrGetSnapToRoadLatLon(startStreet['gid'], startLoc, databaseName)
	dicSnapStartLoc = loc2Dict(snapStartLoc)
	distSnapStart2Source = geoDistance2D(snapStartLoc, startStreet['sourceLoc'])
	distSnapStart2Target = geoDistance2D(snapStartLoc, startStreet['targetLoc'])

	# Calculate the distance between snapped location and source/target of closest street for the END coordinate
	endStreet = pgrGetNearestStreet(endLoc, databaseName)
	snapEndLoc = pgrGetSnapToRoadLatLon(endStreet['gid'], endLoc, databaseName)
	dicSnapEndLoc = loc2Dict(snapEndLoc)
	distSnapEnd2Source = geoDistance2D(snapEndLoc, endStreet['sourceLoc'])
	distSnapEnd2Target = geoDistance2D(snapEndLoc, endStreet['targetLoc'])

	# Find the number of vertices in the pgRouting database
	sqlCommand  = "	select count(*) from ways_vertices_pgr;"
	cur.execute(sqlCommand)
	row = cur.fetchone()
	newlyInsertVidNum = int(row[0]) + 1

	# Testify and find a dummyClassID to put temp vertices and segments
	dummyClassID = 821 # Hard-coded number, no specific meaning
	# FIXME! For database security reason, we need to testify if class_id = 821 is not used in the original database

	# insert the snapped location for START coordinate, and two segments from the coordinate to source/target of the closest street
	sqlCommand  = "	insert into ways_vertices_pgr (id, lon, lat) values (%s, %s, %s);" % (
		newlyInsertVidNum, 
		dicSnapStartLoc['lon'], 
		dicSnapStartLoc['lat'])
	sqlCommand += "	insert into ways (class_id, source, target, length_m, x1, y1, x2, y2, cost_s, reverse_cost_s) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" % (
		dummyClassID, 
		newlyInsertVidNum, 
		startStreet['target'], 
		distSnapStart2Target, 
		dicSnapStartLoc['lon'],
		dicSnapStartLoc['lat'],
		startStreet['targetLoc'][1], 
		startStreet['targetLoc'][0], 
		startStreet['cost_s'] * distSnapStart2Target / (distSnapStart2Target + distSnapStart2Source), 
		startStreet['reverse_cost_s'] * distSnapStart2Target / (distSnapStart2Target + distSnapStart2Source))
	sqlCommand += "	insert into ways (class_id, source, target, length_m, x1, y1, x2, y2, cost_s, reverse_cost_s) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" % (
		dummyClassID, 
		startStreet['source'], 
		newlyInsertVidNum, 
		distSnapStart2Source, 
		startStreet['sourceLoc'][1], 
		startStreet['sourceLoc'][0], 
		dicSnapStartLoc['lon'],
		dicSnapStartLoc['lat'],
		startStreet['cost_s'] * distSnapStart2Source / (distSnapStart2Target + distSnapStart2Source), 
		startStreet['reverse_cost_s'] * distSnapStart2Source / (distSnapStart2Target + distSnapStart2Source))

	# insert the snapped location for END coordinate, and two segments from the coordinate to source/target of the closest street
	sqlCommand += "	insert into ways_vertices_pgr (id, lon, lat) values (%s, %s, %s);" % (
		newlyInsertVidNum + 1, 
		dicSnapEndLoc['lon'], 
		dicSnapEndLoc['lat'])
	sqlCommand += "	insert into ways (class_id, source, target, length_m, x1, y1, x2, y2, cost_s, reverse_cost_s) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" % (
		dummyClassID, 
		newlyInsertVidNum + 1, 
		endStreet['target'], 
		distSnapEnd2Target, 
		dicSnapEndLoc['lon'],
		dicSnapEndLoc['lat'],
		endStreet['targetLoc'][1], 
		endStreet['targetLoc'][0], 
		endStreet['cost_s'] * distSnapEnd2Target / (distSnapEnd2Target + distSnapEnd2Source), 
		endStreet['reverse_cost_s'] * distSnapEnd2Target / (distSnapEnd2Target + distSnapEnd2Source))
	sqlCommand += "	insert into ways (class_id, source, target, length_m, x1, y1, x2, y2, cost_s, reverse_cost_s) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);" % (
		dummyClassID, 
		endStreet['source'], 
		newlyInsertVidNum + 1, 
		distSnapEnd2Source, 
		endStreet['sourceLoc'][1], 
		endStreet['sourceLoc'][0], 
		dicSnapEndLoc['lon'],
		dicSnapEndLoc['lat'],
		endStreet['cost_s'] * distSnapEnd2Source / (distSnapEnd2Target + distSnapEnd2Source), 
		endStreet['reverse_cost_s'] * distSnapEnd2Source / (distSnapEnd2Target + distSnapEnd2Source))

	# Do dijstra algorithm to find shortest path
	sqlCommand += " select b.gid as gid, b.y1 as lats1, b.x1 as lons1, b.y2 as lats2, b.x2 as lons2, a.cost as secs, b.length_m as dist "
	sqlCommand += "	from "
	sqlCommand += "		pgr_dijkstra("
	sqlCommand += "			'select gid as id, source, target, cost_s as cost, reverse_cost_s as reverse_cost from ways',"
	sqlCommand += "			%s," % (newlyInsertVidNum)
	sqlCommand += "			%s," % (newlyInsertVidNum + 1)
	sqlCommand += "			directed := true"
	sqlCommand += "		) a"
	sqlCommand += "	left join"
	sqlCommand += "		ways b"
	sqlCommand += "	on a.edge = b.gid"
	sqlCommand += "	order by a.path_seq"

	# Return the shapepoint result from dijstra algorithm
	cur.execute(sqlCommand)
	row = cur.fetchall()
	summary = pd.DataFrame(row, columns=['gid', 'lats1', 'lons1', 'lats2', 'lons2', 'secs', 'dist'])
	
	# Delete the temp data
	sqlCommand  = "	delete from ways_vertices_pgr where id = (%s);" % (newlyInsertVidNum)
	sqlCommand += "	delete from ways_vertices_pgr where id = (%s);" % (newlyInsertVidNum + 1)
	sqlCommand += "	delete from ways where class_id = %s;" % (dummyClassID)
	cur.execute(sqlCommand)

	# The last row is junk info, drop it
	summary.drop(summary.index[len(summary) - 1], inplace = True)

	# Sorting the coordinates so that they can be linked to each other
	lats1 = summary['lats1'].tolist()
	lons1 = summary['lons1'].tolist()
	lats2 = summary['lats2'].tolist()
	lons2 = summary['lons2'].tolist()
	path = []
	path.append(startLoc)
	for i in range(1, len(lats1)):
		if (lats1[i] != lats1[i - 1] and lats1[i] != lats2[i - 1]):
			path.append([lats1[i], lons1[i]])
		else:
			path.append([lats2[i], lons2[i]])
	timeSecs = summary['secs'].tolist()
	distMeters = summary['dist'].tolist()

	conn.close()

	return [path, timeSecs, distMeters]
Esempio n. 11
0
def privGetShapepoints2D(
        odID=1,
        objectID=None,
        modelFile=None,
        startLoc=None,
        endLoc=None,
        startTimeSec=0.0,
        expDurationSec=None,
        routeType='euclidean2D',
        speedMPS=None,
        leafletColor=config['VRV_DEFAULT_LEAFLETARCCOLOR'],
        leafletWeight=config['VRV_DEFAULT_LEAFLETARCWEIGHT'],
        leafletStyle=config['VRV_DEFAULT_LEAFLETARCSTYLE'],
        leafletOpacity=config['VRV_DEFAULT_LEAFLETARCOPACITY'],
        leafletCurveType=config['VRV_DEFAULT_ARCCURVETYPE'],
        leafletCurvature=config['VRV_DEFAULT_ARCCURVATURE'],
        useArrows=True,
        modelScale=config['VRV_DEFAULT_CESIUMMODELSCALE'],
        modelMinPxSize=config['VRV_DEFAULT_CESIUMMODELMINPXSIZE'],
        cesiumColor=config['VRV_DEFAULT_CESIUMPATHCOLOR'],
        cesiumWeight=config['VRV_DEFAULT_CESIUMPATHWEIGHT'],
        cesiumStyle=config['VRV_DEFAULT_CESIUMPATHSTYLE'],
        cesiumOpacity=config['VRV_DEFAULT_CESIUMPATHOPACITY'],
        ganttColor=config['VRV_DEFAULT_GANTTCOLOR'],
        popupText=None,
        dataProvider=None,
        dataProviderArgs=None):

    # Replace backslash
    modelFile = replaceBackslashToSlash(modelFile)

    # Ensure leading slash
    modelFile = addHeadSlash(modelFile)

    try:
        dataProvider = dataProvider.lower()
    except:
        pass

    try:
        routeType = routeType.lower()
    except:
        pass

    if (startLoc != endLoc):
        extras = {}
        if (routeType == 'euclidean2d'):
            [path, time,
             dist] = _eucGetShapepointsTimeDist(startLoc, endLoc, speedMPS,
                                                expDurationSec)
        elif (routeType == 'manhattan'):
            [path, time,
             dist] = _manGetShapepointsTimeDist(startLoc, endLoc, speedMPS,
                                                expDurationSec)
        elif (routeType == 'fastest'
              and dataProviderDictionary[dataProvider] == 'pgrouting'):
            databaseName = dataProviderArgs['databaseName']
            [path, time,
             dist] = pgrGetShapepointsTimeDist(startLoc, endLoc, databaseName)
        elif (routeType == 'fastest'
              and dataProviderDictionary[dataProvider] == 'osrm-online'):
            [path, time, dist] = osrmGetShapepointsTimeDist(startLoc, endLoc)
        elif (routeType in ['fastest', 'shortest', 'pedestrian']
              and dataProviderDictionary[dataProvider] == 'mapquest'):
            APIkey = dataProviderArgs['APIkey']
            [path, time,
             dist] = mqGetShapepointsTimeDist(startLoc, endLoc, routeType,
                                              APIkey)
        elif (routeType
              in ['fastest', 'pedestrian', 'cycling', 'truck', 'wheelchair']
              and dataProviderDictionary[dataProvider] == 'ors-online'):
            APIkey = dataProviderArgs['APIkey']
            if ('requestExtras' in dataProviderArgs.keys()):
                requestExtras = dataProviderArgs['requestExtras']
            else:
                requestExtras = True
            [path, extras, time,
             dist] = orsGetShapepointsTimeDist(startLoc, endLoc, routeType,
                                               APIkey, requestExtras)
        elif (routeType in ['fastest', 'pedestrian', 'cycling', 'truck']
              and dataProviderDictionary[dataProvider] == 'ors-local'):
            port = dataProviderArgs['port']
            if ('requestExtras' in dataProviderArgs.keys()):
                requestExtras = dataProviderArgs['requestExtras']
            else:
                requestExtras = True
            [path, extras, time,
             dist] = orsLocalGetShapepointsTimeDist(startLoc, endLoc,
                                                    routeType, port,
                                                    requestExtras)
        else:
            return

        # Check if the original point is too far away from the actual start point of the shapepoints from query
        distOri = geoDistance2D(startLoc, path[0])
        if (distOri >= config['VRV_DEFAULT_DISTANCE_ERROR_TOLERANCE']
            ):  # Go back to 10m after testing
            print(
                "Message: The origin point (lat: %s, lon: %s) is %.1f meters away from the road. You might find a gap between the origin point and the route."
                % (startLoc[0], startLoc[1], distOri))

        # Check if the actual end point is too far away from destination point
        distDes = geoDistance2D(path[-1], endLoc)
        if (distDes >= config['VRV_DEFAULT_DISTANCE_ERROR_TOLERANCE']
            ):  # Go back to 10m after testing
            print(
                "Message: The destination point (lat: %s, lon: %s) is %.1f meters away from the road. You might find a gap between destination point and the route."
                % (endLoc[0], endLoc[1], distDes))

        # convert distance to accumulated distance
        accDist = []
        accDist.append(0)
        for i in range(1, len(dist)):
            accDist.append(accDist[i - 1] + dist[i])

        # If `expDurationSec` is provided, override `speedMPS` and datasource, otherwise, if `speedMPS` is provided, override datasource
        if (expDurationSec != None):
            [newTime, newDist] = distributeTimeDist(path, expDurationSec)
            time = newTime
            dist = newDist
        elif (speedMPS != None and expDurationSec == None):
            newExpDurationSec = accDist[len(accDist) - 1] / speedMPS
            [newTime, newDist] = distributeTimeDist(path, newExpDurationSec)
            time = newTime
            dist = newDist

        # convert time to accumulated time
        accTime = []
        accTime.append(startTimeSec)
        for i in range(1, len(dist)):
            accTime.append(accTime[i - 1] + time[i])

        # For maintainability, convert locs into dictionary
        dicPath = locs2Dict(path)

        # shapepoint dataframe
        assignments = privInitDataframe('Assignments')

        # generate assignments
        for i in range(1, len(path)):
            if (i - 1) in extras:
                startElev = extras[i -
                                   1]['elev'] if 'elev' in extras[i -
                                                                  1] else None
                wayname = extras[i]['wayname'] if 'wayname' in extras[
                    i] else None
                waycategory = extras[i][
                    'waycategory'] if 'waycategory' in extras[i] else None
                surface = extras[i]['surface'] if 'surface' in extras[
                    i] else None
                waytype = extras[i]['waytype'] if 'waytype' in extras[
                    i] else None
                steepness = extras[i]['steepness'] if 'steepness' in extras[
                    i] else None
                tollway = extras[i]['tollway'] if 'tollway' in extras[
                    i] else None
            else:
                startElev = None
                wayname = None
                waycategory = None
                surface = None
                waytype = None
                steepness = None
                tollway = None

            if i in extras:
                endElev = extras[i]['elev'] if 'elev' in extras[i] else None
            else:
                endElev = None

            assignments = assignments.append(
                {
                    'odID': odID,
                    'objectID': objectID,
                    'modelFile': modelFile,
                    'startTimeSec': accTime[i - 1],
                    'startLat': dicPath[i - 1]['lat'],
                    'startLon': dicPath[i - 1]['lon'],
                    'startAltMeters': dicPath[i - 1]['alt'],
                    'endTimeSec': accTime[i],
                    'endLat': dicPath[i]['lat'],
                    'endLon': dicPath[i]['lon'],
                    'endAltMeters': dicPath[i]['alt'],
                    'leafletColor': leafletColor,
                    'leafletWeight': leafletWeight,
                    'leafletStyle': leafletStyle,
                    'leafletCurveType': leafletCurveType,
                    'leafletCurvature': leafletCurvature,
                    'useArrows': useArrows,
                    'leafletOpacity': leafletOpacity,
                    'modelScale': modelScale,
                    'modelMinPxSize': modelMinPxSize,
                    'cesiumColor': stripCesiumColor(cesiumColor),
                    'cesiumWeight': cesiumWeight,
                    'cesiumStyle': cesiumStyle,
                    'cesiumOpacity': cesiumOpacity,
                    'ganttColor': ganttColor,
                    'popupText': popupText,
                    'startElevMeters': startElev,
                    'endElevMeters': endElev,
                    'wayname': wayname,
                    'waycategory': waycategory,
                    'surface': surface,
                    'waytype': waytype,
                    'steepness': steepness,
                    'tollway': tollway
                },
                ignore_index=True)
    else:
        # For maintainability, convert locs into dictionary
        dicStartLoc = loc2Dict(startLoc)

        if (dataProviderDictionary[dataProvider] == 'ors-online'):
            [[lat, lon, elev]] = orsGetElevation([startLoc],
                                                 dataProviderArgs['APIkey'])
        else:
            elev = None

        assignments = privInitDataframe('Assignments')
        assignments = assignments.append(
            {
                'odID':
                odID,
                'objectID':
                objectID,
                'modelFile':
                modelFile,
                'startTimeSec':
                startTimeSec,
                'startLat':
                dicStartLoc['lat'],
                'startLon':
                dicStartLoc['lon'],
                'startAltMeters':
                dicStartLoc['alt'],
                'endTimeSec':
                expDurationSec + startTimeSec if
                (expDurationSec is not None) else startTimeSec,
                'endLat':
                dicStartLoc['lat'],
                'endLon':
                dicStartLoc['lon'],
                'endAltMeters':
                dicStartLoc['alt'],
                'leafletColor':
                leafletColor,
                'leafletWeight':
                leafletWeight,
                'leafletStyle':
                leafletStyle,
                'leafletCurveType':
                leafletCurveType,
                'leafletCurvature':
                leafletCurvature,
                'useArrows':
                useArrows,
                'leafletOpacity':
                leafletOpacity,
                'modelScale':
                modelScale,
                'modelMinPxSize':
                modelMinPxSize,
                'cesiumColor':
                stripCesiumColor(cesiumColor),
                'cesiumWeight':
                cesiumWeight,
                'cesiumStyle':
                cesiumStyle,
                'cesiumOpacity':
                cesiumOpacity,
                'ganttColor':
                ganttColor,
                'popupText':
                popupText,
                'startElevMeters':
                elev,
                'endElevMeters':
                elev,
                'wayname':
                None,
                'waycategory':
                None,
                'surface':
                None,
                'waytype':
                None,
                'steepness':
                None,
                'tollway':
                None
            },
            ignore_index=True)

    return assignments
Esempio n. 12
0
def privGetShapepoints2D(odID=1,
                         objectID=None,
                         modelFile=None,
                         startLoc=None,
                         endLoc=None,
                         startTimeSec=0.0,
                         expDurationSec=None,
                         routeType='euclidean2D',
                         speedMPS=None,
                         leafletColor=VRV_DEFAULT_LEAFLETARCCOLOR,
                         leafletWeight=VRV_DEFAULT_LEAFLETARCWEIGHT,
                         leafletStyle=VRV_DEFAULT_LEAFLETARCSTYLE,
                         leafletOpacity=VRV_DEFAULT_LEAFLETARCOPACITY,
                         useArrows=True,
                         modelScale=VRV_DEFAULT_CESIUMMODELSCALE,
                         modelMinPxSize=VRV_DEFAULT_CESIUMMODELMINPXSIZE,
                         cesiumColor=VRV_DEFAULT_CESIUMPATHCOLOR,
                         cesiumWeight=VRV_DEFAULT_CESIUMPATHWEIGHT,
                         cesiumStyle=VRV_DEFAULT_CESIUMPATHSTYLE,
                         cesiumOpacity=VRV_DEFAULT_CESIUMPATHOPACITY,
                         dataProvider=None,
                         dataProviderArgs=None):

    # Replace backslash
    modelFile = replaceBackslashToSlash(modelFile)

    try:
        dataProvider = dataProvider.lower()
    except:
        pass

    try:
        routeType = routeType.lower()
    except:
        pass

    if (startLoc != endLoc):
        if (routeType == 'euclidean2d'):
            [path, time,
             dist] = _eucGetShapepointsTimeDist(startLoc, endLoc, speedMPS,
                                                expDurationSec)
        elif (routeType == 'manhattan'):
            [path, time,
             dist] = _manGetShapepointsTimeDist(startLoc, endLoc, speedMPS,
                                                expDurationSec)
        elif (routeType == 'fastest'
              and dataProviderDictionary[dataProvider] == 'pgrouting'):
            databaseName = dataProviderArgs['databaseName']
            [path, time,
             dist] = pgrGetShapepointsTimeDist(startLoc, endLoc, databaseName)
        elif (routeType == 'fastest'
              and dataProviderDictionary[dataProvider] == 'osrm-online'):
            [path, time, dist] = osrmGetShapepointsTimeDist(startLoc, endLoc)
        elif (routeType in ['fastest', 'shortest', 'pedestrian']
              and dataProviderDictionary[dataProvider] == 'mapquest'):
            APIkey = dataProviderArgs['APIkey']
            [path, time,
             dist] = mqGetShapepointsTimeDist(startLoc, endLoc, routeType,
                                              APIkey)
        elif (routeType in ['fastest', 'pedestrian', 'cycling', 'truck']
              and dataProviderDictionary[dataProvider] == 'ors-online'):
            APIkey = dataProviderArgs['APIkey']
            [path, time,
             dist] = orsGetShapepointsTimeDist(startLoc, endLoc, routeType,
                                               APIkey)
        else:
            return

        # Check if the original point is too far away from the actual start point of the shapepoints from query
        distOri = geoDistance2D(startLoc, path[0])
        if (distOri >= VRV_DEFAULT_DISTANCE_ERROR_TOLERANCE
            ):  # Go back to 10m after testing
            print(
                "Message: The origin point (lat: %s, lon: %s) is %.1f meters away from the road. You might find a gap between the origin point and the route."
                % (startLoc[0], startLoc[1], distOri))

        # Check if the actual end point is too far away from destination point
        distDes = geoDistance2D(path[-1], endLoc)
        if (distDes >= VRV_DEFAULT_DISTANCE_ERROR_TOLERANCE
            ):  # Go back to 10m after testing
            print(
                "Message: The destination point (lat: %s, lon: %s) is %.1f meters away from the road. You might find a gap between destination point and the route."
                % (endLoc[0], endLoc[1], distDes))

        # convert distance to accumulated distance
        accDist = []
        accDist.append(0)
        for i in range(1, len(dist)):
            accDist.append(accDist[i - 1] + dist[i])

        # If `expDurationSec` is provided, override `speedMPS` and datasource, otherwise, if `speedMPS` is provided, override datasource
        if (expDurationSec != None):
            [newTime, newDist] = distributeTimeDist(path, expDurationSec)
            time = newTime
            dist = newDist
        elif (speedMPS != None and expDurationSec == None):
            newExpDurationSec = accDist[len(accDist) - 1] / speedMPS
            [newTime, newDist] = distributeTimeDist(path, newExpDurationSec)
            time = newTime
            dist = newDist

        # convert time to accumulated time
        accTime = []
        accTime.append(startTimeSec)
        for i in range(1, len(dist)):
            accTime.append(accTime[i - 1] + time[i])

        # For maintainability, convert locs into dictionary
        dicPath = locs2Dict(path)

        # shapepoint dataframe
        assignments = initDataframe('Assignments')

        # generate assignments
        for i in range(1, len(path)):
            assignments = assignments.append(
                {
                    'odID': odID,
                    'objectID': objectID,
                    'modelFile': modelFile,
                    'startTimeSec': accTime[i - 1],
                    'startLat': dicPath[i - 1]['lat'],
                    'startLon': dicPath[i - 1]['lon'],
                    'startAltMeters': dicPath[i - 1]['alt'],
                    'endTimeSec': accTime[i],
                    'endLat': dicPath[i]['lat'],
                    'endLon': dicPath[i]['lon'],
                    'endAltMeters': dicPath[i]['alt'],
                    'leafletColor': leafletColor,
                    'leafletWeight': leafletWeight,
                    'leafletStyle': leafletStyle,
                    'useArrows': useArrows,
                    'leafletOpacity': leafletOpacity,
                    'modelScale': modelScale,
                    'modelMinPxSize': modelMinPxSize,
                    'cesiumColor': cesiumColor,
                    'cesiumWeight': cesiumWeight,
                    'cesiumStyle': cesiumStyle,
                    'cesiumOpacity': cesiumOpacity
                },
                ignore_index=True)
    else:
        # For maintainability, convert locs into dictionary
        dicStartLoc = loc2Dict(startLoc)

        assignments = initDataframe('Assignments')
        assignments = assignments.append(
            {
                'odID':
                odID,
                'objectID':
                objectID,
                'modelFile':
                modelFile,
                'startTimeSec':
                startTimeSec,
                'startLat':
                dicStartLoc['lat'],
                'startLon':
                dicStartLoc['lon'],
                'startAltMeters':
                dicStartLoc['alt'],
                'endTimeSec':
                expDurationSec + startTimeSec if
                (expDurationSec is not None) else startTimeSec,
                'endLat':
                dicStartLoc['lat'],
                'endLon':
                dicStartLoc['lon'],
                'endAltMeters':
                dicStartLoc['alt'],
                'leafletColor':
                leafletColor,
                'leafletWeight':
                leafletWeight,
                'leafletStyle':
                leafletStyle,
                'useArrows':
                useArrows,
                'leafletOpacity':
                leafletOpacity,
                'modelScale':
                modelScale,
                'modelMinPxSize':
                modelMinPxSize,
                'cesiumColor':
                cesiumColor,
                'cesiumWeight':
                cesiumWeight,
                'cesiumStyle':
                cesiumStyle,
                'cesiumOpacity':
                cesiumOpacity
            },
            ignore_index=True)

    return assignments
Esempio n. 13
0
def _buildFlightPath(path, speedMPS):
    """
	Since _buildFlightProfile is not very flexible, this function gives a more customized method to generate profile, by listing lists of lats, lons and alts.

	Parameters
	----------
	path: list of lists
		A list of locations along with the flight path, in the format of [lat, lon] (altitude, above sea level, set to be 0) or [lat, lon, alt].
	speedMPS: float
		A constant speed, during this path the vehicle will cruise in this speed.

	Return
	------
	flight dataframe
		A dataframe to be interpreted into assignments dataframe.
	"""

    # Flight Profile dataframe
    flight = pd.DataFrame(columns=[
        'lat', 'lon', 'altAGL', 'accuGroundDistance', 'description',
        'loiterTime', 'groundDistance', 'flightDistance', 'accuFlightDistance',
        'timeFromPreviousPosition', 'pathStartTimeSec', 'pathEndTimeSec'
    ])

    # Check and guarantee that each point in path has 3 dimension
    dicPath = locs2Dict(path)

    # Add flight path one coordinate at a time
    accuGroundDistance = 0
    accuFlightDistance = 0
    accuPathTime = 0
    for i in range(len(path)):
        # Calculate fields for flight dataframe
        if i > 0:
            groundDistance = geoDistance2D(path[i - 1], path[i])
            deltaAGL = dicPath[i]['alt'] - dicPath[i - 1]['alt']
            flightDistance = math.sqrt(groundDistance * groundDistance +
                                       deltaAGL * deltaAGL)
        else:
            groundDistance = 0
            flightDistance = 0
        accuGroundDistance += groundDistance
        accuFlightDistance += flightDistance
        timeFromPreviousPosition = accuFlightDistance / speedMPS
        accuPathTime += timeFromPreviousPosition

        # And one way point to the flight path
        flight = flight.append(
            {
                'lat': dicPath[i]['lat'],
                'lon': dicPath[i]['lon'],
                'altAGL': dicPath[i]['alt'],
                'accuGroundDistance': accuGroundDistance,
                'description': "Waypoint",
                'loiterTime': 0.0,
                'groundDistance': groundDistance,
                'flightDistance': flightDistance,
                'accuFlightDistance': accuFlightDistance,
                'timeFromPreviousPosition': accuFlightDistance / speedMPS,
                'pathStartTimeSec': accuPathTime,
                'pathEndTimeSec': accuPathTime
            },
            ignore_index=True)

    return flight
Esempio n. 14
0
def _buildFlightProfile(startLoc, cruiseAltMetersAGL, endLoc, takeoffSpeedMPS,
                        rateOfClimbMPS, cruiseSpeedMPS, landSpeedMPS,
                        rateOfDescentMPS):
    """
	Build a flight profile, by profile, it means it has take_off/cruise/loiter(mission)/landing phase, if we want to construct a customized profile, use _buildFlightPath

	Parameters
	----------
	startLoc: list
		Start location, the format is [lat, lon] (altitude, above sea level, set to be 0) or [lat, lon, alt].
	cruiseAltMetersAGL: float
		Cruise altitude, meters above sea level.
	endLoc: list
		End location, the format is [lat, lon] (altitude, above sea level, set to be 0) or [lat, lon, alt].
	rateOfClimbMPS: float
		Rate of climb of the aircraft, it is a vertical speed.
	climbGradientInDegree: float
		Climb gradient, the unit is degree, horizontal as zero, minimal value as 0, maximum value as 90 (vertical up).
	cruiseSpeedMPS: float
		Speed of cruise, in the unit of meters/second.
	rateOfDescentMPS: float
		Rate of descent, vertical speed.
	descentGradientInDegree: float
		Descent gradient, the unit is degree, horizontal as zero, minimal value as 0, maximum value as 90 (vertical down).
	
	Return
	------
	flight dataframe
		A dataframe to be interpreted into assignments dataframe
	"""

    # Interpret locations into readable dictionary
    dicStartLoc = loc2Dict(startLoc)
    dicEndLoc = loc2Dict(endLoc)

    # Calculate gradients of climbing and landing
    climbGradientInDegree = math.degrees(
        math.asin(rateOfClimbMPS / takeoffSpeedMPS))
    descentGradientInDegree = math.degrees(
        math.asin(rateOfDescentMPS / landSpeedMPS))

    # calculate the ideal takeoff/landing time/ground distance
    idealTakeoffTimeSec = (cruiseAltMetersAGL -
                           dicStartLoc['alt']) / rateOfClimbMPS
    idealTakeoffGroundDistance = (cruiseAltMetersAGL -
                                  dicStartLoc['alt']) / math.tan(
                                      math.radians(climbGradientInDegree))
    idealLandingTimeSec = (cruiseAltMetersAGL -
                           dicEndLoc['alt']) / rateOfDescentMPS
    idealLandingGroundDistance = (cruiseAltMetersAGL -
                                  dicEndLoc['alt']) / math.tan(
                                      math.radians(descentGradientInDegree))

    # including start and end, takeoffAt and arrivalAt are not included in here
    markPath = [startLoc, endLoc]

    # Total ground distance
    totalGroundDistance = geoDistancePath2D(markPath)

    # Flight Profile dataframe
    flight = pd.DataFrame(columns=[
        'lat', 'lon', 'altAGL', 'accuGroundDistance', 'description',
        'loiterTime'
    ])

    # For the first location, add one row
    flight = flight.append(
        {
            'lat': dicStartLoc['lat'],
            'lon': dicStartLoc['lon'],
            'altAGL': dicStartLoc['alt'],
            'accuGroundDistance': 0.0,
            'description': "beforeTakeoff",
            'loiterTime': 0.0
        },
        ignore_index=True)

    # Check if distance is enough for taking off and landing
    if (totalGroundDistance >
            idealTakeoffGroundDistance + idealLandingGroundDistance):
        # if can reach cruise altitude, everything is ideal
        takeoffMileage = geoMileageInPath2D(markPath,
                                            idealTakeoffGroundDistance)
        landingMileage = geoMileageInPath2D(
            markPath, totalGroundDistance - idealLandingGroundDistance)

        # if can cruise, it means we need two locations
        flight = flight.append(
            {
                'lat': takeoffMileage['loc'][0],
                'lon': takeoffMileage['loc'][1],
                'altAGL': cruiseAltMetersAGL,
                'accuGroundDistance': idealTakeoffGroundDistance,
                'description': "takeoffAtAlt",
                'loiterTime': 0.0
            },
            ignore_index=True)
        flight = flight.append(
            {
                'lat': landingMileage['loc'][0],
                'lon': landingMileage['loc'][1],
                'altAGL': cruiseAltMetersAGL,
                'accuGroundDistance':
                totalGroundDistance - idealLandingGroundDistance,
                'description': "arrivalAtAlt",
                'loiterTime': 0.0
            },
            ignore_index=True)
    else:
        # if can not reach cruise altitude, the profile is "triangle", i.e. the takeoffAt position are the same as arrivalAt position
        deltaAGLTakeoffLanding = dicStartLoc['alt'] - dicEndLoc['alt']
        deltaAGLCruiseTakeoff = (
            (totalGroundDistance - deltaAGLTakeoffLanding /
             math.tan(math.radians(descentGradientInDegree))) *
            (math.tan(math.radians(climbGradientInDegree)) +
             math.tan(math.radians(descentGradientInDegree))))
        deltaAGLCruiseLanding = deltaAGLCruiseTakeoff + deltaAGLTakeoffLanding
        takeoffGroundDistance = deltaAGLCruiseTakeoff / math.tan(
            math.radians(climbGradientInDegree))
        landingGroundDistance = deltaAGLCruiseLanding / math.tan(
            math.radians(descentGradientInDegree))

        takeoffMileage = geoMileageInPath2D(markPath, takeoffGroundDistance)

        flight = flight.append(
            {
                'lat': takeoffMileage['loc'][0],
                'lon': takeoffMileage['loc'][1],
                'altAGL': deltaAGLCruiseTakeoff + dicStartLoc['alt'],
                'accuGroundDistance': takeoffGroundDistance,
                'description': "takeoffAtAlt and arrivalAtAlt",
                'loiterTime': 0.0
            },
            ignore_index=True)

    # For the last location, add one row
    flight = flight.append(
        {
            'lat': dicEndLoc['lat'],
            'lon': dicEndLoc['lon'],
            'altAGL': dicEndLoc['alt'],
            'accuGroundDistance': totalGroundDistance,
            'description': "afterArrival",
            'loiterTime': 0.0
        },
        ignore_index=True)

    # Reorder flight in order
    flight = flight.sort_values('accuGroundDistance', ascending=True)
    flight = flight.reset_index(drop=True)

    # Add the 'groundDistance' column to flight dataframe
    groundDistance = [0.0]
    for i in range(1, len(flight)):
        groundDistance.append(
            geoDistance2D(
                (flight.iloc[i]['lat'], flight.iloc[i]['lon']),
                (flight.iloc[i - 1]['lat'], flight.iloc[i - 1]['lon'])))
    flight['groundDistance'] = groundDistance

    # Add the 'flightDistance' column to flight dataframe
    flightDistance = [0.0]
    for i in range(1, len(flight)):
        deltaHeight = flight.iloc[i]['altAGL'] - flight.iloc[i - 1]['altAGL']
        groundDistance = flight.iloc[i]['groundDistance']
        flightDistance.append(
            math.sqrt(deltaHeight * deltaHeight +
                      groundDistance * groundDistance))
    flight['flightDistance'] = flightDistance

    # Add the 'accuFlightDistance' column to flight dataframe
    accuFlightDistance = [0.0]
    for i in range(1, len(flight)):
        accuFlightDistance.append(accuFlightDistance[i - 1] +
                                  flight.iloc[i]['flightDistance'])
    flight['accuFlightDistance'] = accuFlightDistance

    # Add the 'time' column to flight dataframe
    duration = [0.0]
    for i in range(1, len(flight)):
        if (flight.iloc[i]['description'] == "takeoffAtAlt"
                or flight.iloc[i]['description']
                == "takeoffAtAlt and arrivalAtAlt"):
            speed = takeoffSpeedMPS
            duration.append(flight.iloc[i]['flightDistance'] / speed)
        elif (flight.iloc[i]['description'] == "arrivalAtAlt"):
            speed = cruiseSpeedMPS
            duration.append(flight.iloc[i]['flightDistance'] / speed)
        elif (flight.iloc[i]['description'] == "afterArrival"):
            speed = landSpeedMPS
            duration.append(flight.iloc[i]['flightDistance'] / speed)
    flight['timeFromPreviousPosition'] = duration

    # Add the 'accuTime' column to flight dataframe
    startTimeSec = []
    endTimeSec = []
    startTimeSec.append(0.0)
    endTimeSec.append(flight.iloc[0]['loiterTime'])
    for i in range(1, len(flight)):
        startTimeSec.append(endTimeSec[i - 1] +
                            flight.iloc[i]['timeFromPreviousPosition'])
        endTimeSec.append(endTimeSec[i - 1] +
                          flight.iloc[i]['timeFromPreviousPosition'] +
                          flight.iloc[i]['loiterTime'])
    flight['pathStartTimeSec'] = startTimeSec
    flight['pathEndTimeSec'] = endTimeSec

    return flight