About The Project!

This website is the work of Tyler Crawford, Devin Hunt, and Ellen Matthews.

Here it is. The culmination of 4 weeks of hard work coding and damaging our vehicles all in the name of trying to make our simulator as realistic as possible. The product: a keyframe-based spaceship accident recreation application. That's right, I said spaceship.
Specific goals of the project and this final phase include a road editor, per-frame interpolation schemes, saving and replaying, and collisions.
We have also implemented two algorithms which run in applets separate from the accident recreator: Curvature-driven Velocity Control and Twist Bender Smoothing.

Change of Scheme Per Frame
In order to have the vehicles move in realistic ways not only while 'driving' but also after a collision, we want a single path to have the ability to use different interpolation technique between each keyframe. Although the default interpolation type is cubic bezier, the user can specify the type of motion he or she desires the vehicle to undergo when traveling to a particular keyframe.

Road Editor
In previous submissions, the user was able to add and edit a single road using cubic bezier interpolation. This design allows for both smoothly curved, intuitive curve control as well as the easy and intuitive creation of straight roads. For P1D we have added the ability to create and edit an unlimited number of roads so that the accident recreation can have an accurate portrayal of the roads that lie under all the action.

Saving, Loading, Replaying

Collisions and Physics
And finally, we implemented both collision detection and a physics-based collision reaction. To hear the awesome sound effects, you will have to save the applets and run them from your computer. For a more information about the collisions in our project, see below.

The Interface And Tutorial!

Through the mouse interface you can add and remove roads, cars, and key frames. You can also lock roads, hide key frames, and load present animations. Just click and hold the mouse pointer down in a section of the screen where no editable handles exist! The menu will pop up after a short delay. To learn more about the system, please check out this tutorial. Afterwards you will find a list of all commands that are not available through the mouse interface.

space bar: starts and stop the animation / simulation.
l : switch the selected key frame to a Linear Interpolation
b : switch the selected key frame to a Bezier Interpolation
t : switch the selected key frame to a Twist Interpolation
e
: switch the selected key frame to a Twist-Bender Interpolation

The Applet!

You may access the standard export of the applet here.

You can download a prepackaged executable for windows and osx if you wish.

Crash Scenarios!

The following is a set of 6 different applets which are specially modified versions of our general-purpose accident recreation applet. Each demonstrates a common type of accident as well as two ideas for how the accident might have been avoided.

Accident 1: Chop

The Accident: Red cuts into a left turn and hits the green car waiting at a Pink light or stop.
Prevention by Pink: Stay on the right. Delay turn. Turn wheel quickly. Plan to end close to the curb after the turn.
Prevention by Blue: Blue stops 3 feet before the crossing and close to the right curb.

Accident 2: Swing

The Accident: Pink swings out during a right turn and hits the green car waiting at a red light or stop.
Prevention by Pink: Start close to the median. Go slowly. Delay turn. Turn wheel quickly.
Prevention by Blue: Blue stops 3 feet before the crossing and close to the right curb.

Accident 3: Switch

The Accident: Pink changes lanes and glances the Blue car, whom he did not see.
Prevention by Pink: Orient external mirrors properly and use them. Check if right lane is clear. Use turn signal 5 seconds before. Turn head to check.
Prevention by Green: Blue avoids being in the blind spot of Pink. She guesses that Pink may switch lanes because the car in front of Pink is moving particularly slowly.

Accident 4: Pop (from right)

The Accident: Being from the South, the other spaceships have left a gap for Pink to get through. Pink turns left, but did not see the other car coming.
Prevention by Pink: Do not pop into traffic unless you have visibility of all lanes. Go very slowly so that cars in the other lanes can see you in time to stop.
Prevention by Green: Green sees the gap or the street ahead. She slows down and is prepared for a spaceship to pop through.

Accident 5: Pop (from left)

The Accident: Pink turns left through a gap left by blue. He did not see the traffic in the other lane.
Prevention by Pink: Do not pop into traffic unless you have visibility of all lanes. Go very slowly so that cars in the other lanes can see you in time to stop.
Prevention by Green: Green sees the gap or the street ahead. She slows down and is prepared for a spaceship to pop through.

Accident 6: All Lights Green!

The Accident: Even in space the traffic lights occasionally fail. Pink, Blue, Green and all their alien buddies head into the intersection at full speed because all lights are showing green.
Prevention # 1: Each driver should, as always, approach any intersection with caution. If they are looking left and right as they approach, they will realize that trouble is on the horizon and brake to a stop, leaving a whole lot of spaceships in close quarters, but none colliding.
Prevention # 2: Mad Skillz. Lets pretend that the spaceship drivers are actually all Hans Solo. They will of course see the impending demolition but deftly maneuver around each other, avoiding damaging their spiffy rides and making for a sweet Episode 4 trailer.

Collisions and Physics!

The physics engine which was created for the project is quite robust and allows for very smooth and realistic collisions and reactions between the oblong rockets. Figure one depicts the construction of the collision hulls employed for every ship on screen. This figure is top secret, so don’t tell anyone.

You can find a simple applet demonstrating this system here.

As figure one shows, a rocket is represented by two circular collision hulls attached by a dynamic spring (pink dotted line) with a resting distance of 2r. Though this is a far reach from true rigid body dynamics is does allow front collisions to be differentiated from rear collisions lending the rocket ships a rather natural spin/skid motion after the collision.

Collision detection involves simply comparing the collision hulls of each rocket to each others. If the distance from the center of two collision hulls is less then the sum of both hulls radii a collision has occurred, as depicted in figure two.

Reacting to this collision is a simple matter of decomposing the problem into its x and y components and solving them as one dimensional momentum. Figure three illustrates this process admirably.

As the figure demonstrates, each hull collision is dealt with independently by assuming one hull is fixed and not moving. A collision axis is created by creating a vector from center of hull A to the center of hull B. This vector is used to effectively reverse the velocity from the collision line so that the hull seemingly “bounces” off the collision line. Because the collided hull is attached to another hull via a spring, the ships motion will take on a natural drifting motion. Neat!

Twist Bender!

By combining the twist interpolation with a 4-point curve subdivision scheme, the TwistBender produces a remarkably smooth traversal. We use a function s(F0, t, F1) to find a position of a frame between F0 and F1 at time 0<t<1 using a twist interpolation. By simply combining this with the 4-point subdivision smoothing scheme, we get s(s(A, 9/8, B), 1/2, s(D, 9/8, E)). Each time we implement TwistBender, we end up adding a new frame halfway in between two existing frames, doubling the number of key frames. By interpolating with a twist between these frames, we get a very smooth traversal of the curve.

One fudge I made was to simplify the vector at the added midpoint of each pair of frames to be the average of the two vectors of the frames on either side. This insures smooth acceleration/deceleration across the curve.

You may view the applet here.

Loading Preset Animations!


The loading and saving features operate by writing to and reading from an XML file. Each file contains a <car> element for each car in the simulation. Inside each <car> element is a tag for each attribute of the car, including <keyframe> elements that contain the necessary attributes for each keyframe belonging to a car. Each file also contains a <roadeditor> element for each curve placed on the simulation screen as a road. Each <roadeditor> element contains a tag for each attribute of the road, including a list of <points> that represent the control points of the curve.
Points and vectors are both represented by ordered pairs of floats in the save files. If an element's point or vector is null when saving, no tag representing that point or vector will appear in that element's attributes in the save file.
The save feature also saves the state of interactivity of the simulation when the user saves. For example, the last keyframe that the user has edited will appear with green circles when loaded from the save file, indicating that this was the last keyframe interacted with.
Save files are located in the data folder within the applet folder.

An example of a save file with one car using 4 keyframes, twist interpolating between them, and no roads:

<save>
<car>
<loop>true</loop>
<curPos>227.47363,74.08867</curPos>
<curVel>104.64781,37.3439</curVel>
<frameTime>1.0710001</frameTime>
<timeOfNextFrame>2.1479347</timeOfNextFrame>
<cm>-25.0,23.0</cm>
<keys>
<keyframe>
<dotRadius>4.0</dotRadius>
<position>77.0,73.0</position>
<cmkey>-25.0,23.0</cmkey>
<velocity>158.0,-19.0</velocity>
<keyNumber>1</keyNumber>
<velocitySelected>false</velocitySelected>
<positionSelected>false</positionSelected>
<bSnapPoint>false</bSnapPoint>
<snapObject>0</snapObject>
<bSelected>false</bSelected>
</keyframe>
<keyframe>
<dotRadius>4.0</dotRadius>
<position>352.0,160.0</position>
<cmkey>-25.0,23.0</cmkey>
<velocity>51.0,94.0</velocity>
<keyNumber>1</keyNumber>
<velocitySelected>false</velocitySelected>
<positionSelected>false</positionSelected>
<bSnapPoint>false</bSnapPoint>
<snapObject>0</snapObject>
<bSelected>false</bSelected>
</keyframe>
<keyframe>
<dotRadius>4.0</dotRadius>
<position>370.0,377.0</position>
<cmkey>-25.0,23.0</cmkey>
<velocity>-82.0,47.0</velocity>
<keyNumber>1</keyNumber>
<velocitySelected>false</velocitySelected>
<positionSelected>false</positionSelected>
<bSnapPoint>false</bSnapPoint>
<snapObject>0</snapObject>
<bSelected>false</bSelected>
</keyframe>
<keyframe>
<dotRadius>4.0</dotRadius>
<position>127.0,351.0</position>
<cmkey>-25.0,23.0</cmkey>
<velocity>-65.0,-137.0</velocity>
<keyNumber>1</keyNumber>
<velocitySelected>false</velocitySelected>
<positionSelected>false</positionSelected>
<bSnapPoint>false</bSnapPoint>
<snapObject>0</snapObject>
<bSelected>true</bSelected>
</keyframe>
</keys>
<currentKey>0</currentKey>
<bShowKeys>true</bShowKeys>
<bAnimating>true</bAnimating>
<interpType>3</interpType>
<tanAngle>0.34276697</tanAngle>
<curMag>133.14926</curMag>
</car>
</save>

Curvature Based Speed!

That's right, we just didn't get enough of P1b the first time around, so we went back and made it even spiffier.  The goal was to make the velocities along the path no longer depend upon the lengths of the segments, but on the curvature of the path.  In the original implementation, the curve is segmented into approximately (or exactly, depending on the algorithm chosen by the user) equal-lengthed line segments.  The runner dot moved to a new point along the curve at each tick so that the points were visited in constant speed and, since they were uniformly placed along the curve, the velocity of the dot is constant. For this phase of the project, we wanted to make the dot's velocity change according to the curvature of the path at its current location.  Specifically, we wanted the dot to slow down the curvy parts.  At the same time, we did not want to modify the location of the points so that this velocity effect could be easily toggled on or off and not have an effect on the underlying structures of the curve.


Implementation
First, the curvatures of every point or endpoint of these segments along the path are calculated.  We find the vectors representing the direction of the current line segment and the next one and then use the dot product to determine the difference in their angles.  The greater the distance, the greater the amount of curvature.  This information is stored in an array.

vec V = C[lastpt].vecTo(C[i]);<br>
V.add(C[i].vecTo(C[nextpt])); <br>
V.mul(0.5);<br>
float v = V.magnitude();<br>
vec AB = C[lastpt].vecTo(C[i]); <br>
AB.mul(2);<br>
vec NB = C[lastpt].vecTo(C[nextpt]); NB.left();<br>
NB.unit();<br>
curvaturestep[i] = 1/(pow(v,2)/dot(AB, NB));<br>
Once the curvatures at the points have been found, we must use that information to determine the speed at each position that the dot will appear.  The curvature is used to determine an amount of time that the draw function will stall using Thread.sleep(long).  This amount of time is linearly related to the curvature by a factor of 1/6 so that the slow down effect is not too dramatic.The runner dot is animated at 10 intermediate positions between each point.  In order to create a smooth transition along our segments, we use the wait times we have derived for each endpoint and interpolate linearly between them to find the sleep times in between. The effect is a runner dot that smoothly accelerates and decelerates with velocity relative to the curvature at its current position.  It is a reasonable approximation to a driver navigating a curvy roadway

The applet
You can run the applet here and follow the onscreen transitions to toggle between segment-length driven (aka constant) velocity and curvature-driven velocity.