, , , , , , , ,

pset8: CS50 Shuttle with rotating marker in 2d map.

Course: Harvard’s CS50

Problem set 8: CS50 Shuttle

pset8 is mostly focused on JavaScript.

This problem set asks you to complete the implementation of a google-earth based driving game. Most of the grunt work is already taken care of by the distribution code, so your part is (relatively) easy to handle. The extras, of which you are required to do at least one, may be harder than the main body of the assignment — or it could all be a walk in the park for you if you’re a veteran JavaScripter.

I am not very cozy with JavaScript; so my solution is basic, with only one of the extras implemented.

You will mostly work with service.js

service.js (view | download)

Now for the extra feature I chose to implement: Rotate a marker in Google Maps

A very quick and dirty way to do the rotating/directional arrow instead of static non-rotating bus marker on the 2d map side of the problem set.

From the specs:

Replace the blue bus on the 2D map with some kind of arrow that points in the direction that the shuttle is actually facing (in the 3D world). Odds are you’ll want to rotate a canvas element or use as many as 360 different icons (one for each degree). If you take the latter approach, odds are you can get away with fewer icons, one every few degrees.

The main body of the problem set is quite easy to tackle, but this particular optional feature had me running around in circles for a few hours. First problem was how to rotate a marker, second problem was where to get the current orientation on the 3d map side of the problem set.

The pset8.pdf suggested I might want to look at the <canvas> tag…
IMHO I thought that’s like bringing a sledgehammer to do the work of a toothpick.

To make things worse, the first example of a rotating marker I could find with google was this one. Which is a bit of a mess, code-wise, from the perspective of a rookie javascripter.

1. Find The Heading

I quickly found these in shuttle.js, but I failed to find any reference documentation about V3.rotate():

var headingVec = V3.rotate(localToGlobalFrame[1], localToGlobalFrame[2], -this.headingAngle);
var rightVec = V3.rotate(localToGlobalFrame[0], localToGlobalFrame[2], -this.headingAngle);

The values in this.headingAngle are weird in that they do not range from -180 to +180 degrees, but something that perpetually either goes up or down if you keep turning left or right respectively, I *think* it’s translated to a range of -1.0 to +1.0 (after modulo maybe) but dont take my word for it…

After digging around for information about V3.rotate(), and failing to find any, I dug in the Code playground and found this example. Which has exactly what I wanted:

var camera = ge.getView().copyAsCamera(ge.ALTITUDE_RELATIVE_TO_GROUND);

There are some nice hints about other optional features on that site.

2. Rotate Something

I had already used rich markers for something else, so the next logical step was to replace the simple ‘Bus’ marker the distribution code used with a rich marker. As a side note: richmarker.js is not part of the distribution code, and for some reason it wasn’t included by the google api requests in the distribution code, so I grabbed a copy from here(this version worked for me, another version I tried did not.)

So now, with a rich marker that has a div and a unique ID, I could play around with that wherever I wanted.
ie. by using CSS transform: rotate()

modify the viewchange() function to be:

function viewchange()
	// keep map centered on shuttle's marker
	var latlng = new google.maps.LatLng(shuttle.position.latitude, shuttle.position.longitude);

	var camera = earth.getView().copyAsCamera(earth.ALTITUDE_RELATIVE_TO_GROUND);
	///////now you can use camera.getHeading();

	//change orientation of myRichBusMarker
	var myHeadingMarker      = document.getElementById('myRichBusMarker');
	var rotationStyles       = 'display:block;' +
	'-ms-transform:      rotate(' + camera.getHeading() + 'deg);' +
	'-o-transform:       rotate(' + camera.getHeading() + 'deg);' +
	'-moz-transform:     rotate(' + camera.getHeading() + 'deg);' +
	'-webkit-transform:  rotate(' + camera.getHeading() + 'deg);' ;
	myHeadingMarker.setAttribute('style', rotationStyles);

et voilà!

Inspiration for the usage of transforms came form this post.

I might return to this later to do the other optional features; auto pilot and fly mode seem interesting.

Get the full project: pset8_shuttle.zip

P.S. if you’re not using a modern browser the rotating transform will most likely not work.