Road Trip Advisor

Avoiding Trademark Infringement 101
Github: ProjectRTA

In my second semester of college, I took a group project class. Disregarding the social implications of group projects, it was a fairly productive class. This is the culmination of 8 weeks of work. What it does is simple: plug in a starting point, plug in an ending point, and click submit. If the locations are on the same land mass, a path between them will be calculated via Google Maps with gas stops and restaurants along the way.

This is the route I take from Chicago to UIUC.
Features

I said we had 8 weeks to do it, but that doesn't necessarily mean it took 8 weeks to do. As is expected in the given setting (college), most of the work was accomplished in 2 days. One of them was a 10-hour day in a library cubicle (not terrible), and the other was an 8-hour day spent in a random campus building's hallway during finals week (terrible). Regardless, coffee persevered and we emerged with a shoddy web demo. So instead of writing this section, I'll just show the video of my dorky self giving a brief overview.

Implementation

The functionality is simple, but the backend is a bit convoluted. The tech stack was Flask and Python. We were originally planning on making an Android app, but that part of the project was abandoned when the deadline neared. To get the map data, we used a few different Google Maps APIs (they're broken up by topic). Namely, the Geocoding API was used to convert between building address, coordinates, and place IDs (unique ID for any "place" on Google Maps, like a building or road). The Directions API was used to generate a path between two different places. We also utilized the Yelp API to do a radial search for gas, restaurant, etc. locations in a certain area.

"Oh good, it works across borders." "Well there's a road there."

The main process involved a lot of piggybacking off of these APIs. We would first convert the entered locations to place IDs, then generate a "basic path" between them. If you're looking at the GitHub, this all happens in pathRouter.py. Google returns a JSON object representing the path, with points placed along the path (we never figured out what these points actually represented, but I think they indicate road junctions). We used these points as markers to identify the path. Then we passed the data to regions.py, which chose points a certain distance apart (designed to be ~3 hours worth of driving time). There was a bit of approximation work and some clever math, and eventually we got a pretty good estimate of regions where rest stops and restaurants should be placed. Here's our algorithm to prune the points Google returned into more evenly spaced ones:

# Prunes the list for points that are too close together
			# TODO: Optimize ading in terminal point (currently just loops until len()-1
			# 		and adds at end; may cause terminal point to be close to the last point)
			def prunePathPoints(pathPoints):
				goodPoint = 0
				prunedPath = [pathPoints[0]]
				for i in xrange(0, len(pathPoints)-1):
					# Checks if points are too close
					if (coordsDistance(prunedPath[goodPoint], pathPoints[i]) < 150):
						continue
					# Checks if points are within 150 and 250 miles (good)
					elif (coordsDistance(prunedPath[goodPoint], pathPoints[i]) < 250):
						prunedPath.append(pathPoints[i])
						goodPoint+=1
					# If points are over 250 miles apart, creates a midpoint in between
					else:
						# Checks if distance from last point and its midpoint is greater than 250 as well
						# TODO: Replace with loop (what is midpoint is >750 miles away from point?)
						if (coordsDistance(prunedPath[goodPoint], \
								getMidpoint(prunedPath[goodPoint], pathPoints[i])) > 250):

							# Adds point between last point and midpoint
							# first one
							prunedPath.append(getMidpoint(prunedPath[goodPoint], \
								getMidpoint(prunedPath[goodPoint], pathPoints[i])))

							# Adds midpoint
							prunedPath.append(getMidpoint(prunedPath[goodPoint], pathPoints[i]))

							# Adds point between midpoint and next point
							# COOPER: Should this be i+1? It does the same thing as the first one?
							prunedPath.append(getMidpoint(getMidpoint(prunedPath[goodPoint], \
								pathPoints[i]), pathPoints[i]))

							goodPoint+=3
						else:
							prunedPath.append(getMidpoint(prunedPath[goodPoint], pathPoints[i]))
							prunedPath.append(pathPoints[i])
							goodPoint+=2
				# Adds terminal point
				prunedPath.append(pathPoints[-1])
				return prunedPath
				

Once that was done, we fed those points into the Yelp API to do a search for accomodations in that area. Finally, we had all of the components needed for the road trip: the starting point, the gas and restaurant stops, and the ending point. Fortunately, the Directions API allows you to specify waypoints along a path that you'd like to visit. All we had to do then was feed our data into the API and get a path that we passed on to the end user.

The extra stops only added about 20 minutes in travel time to this route.
Learning Points

I had some fun with the project, though there were some cooperation difficulties in the group. Overall, I'd say I'm happy with the way it turned out. Here are the lessons: