CS 101 (Fall 2000)
Lab 6: Falling Arches

Lab Assigned Design Due
(In class)

1 PM
(In Lab)
(In Lab)
Lab Due
(In class)
1 PM
10 Oct None 18-19 Oct 25-26 Oct 27 Oct


In the past labs, we have come to view recursion as a powerful paradigm for computation. Similarly, recursive data structures allow one to build large, interconnected using relatively little effort. In this lab, you construct a model for simulating the shape of a catenary: the shape of our beloved St. Louis arch.


By the end of this lab, you should

Before starting:

[[[ Download PC zip ]]]
Zip includes:

Recall that the following lines should appear at the top of any files that use the terminal or canvas classes.

import terminal.*;
import canvas.*;

Problem description:

Long before our city began its expansion into the NFL, the pioneers of our country expanded to the West, crossing the Mississippi and braving the perils of midwestern life. As a monument to their efforts, the City of St. Louis erected Eero Saarinen's famous Arch in 1965. Its grace, beauty, and elegance have inspired poets, musicians, and artists of the past four decades.

Now, it's time that CS101 had its turn. The following will be described in class, so plan to take notes on this problem statement, but here is a summary.

A catenary is the shape made when you suspend a string by holding its ends, and let gravity pull on the string. If you look at a telephone wire strung between two poles, the shape you see is a catenary, though not one that would garner artistic praise.

It turns out that our Arch is also a catenary, but turned upside down.

How are we to simulate an catenary acting on a string? If we look really closely at the string, we see that it is composed of a list of mass points, with each adjacent pair of masses connected by a spring.

With gravity turned off, the picture is as shown in Figure 1(a).

(a) (b)
Gravity turned off After 100 iterations
Figure 1. A sequence of masses connected by springs, at the beginning and end of the simulation.
After letting gravity have its way with the masses, and accounting for the springs between the masses, our picture as shown in Figure 1(b).


An immutable class that represents a force vector.

Force(int xComponent, yComponent)
Construct a force with the specified x and y components
int getX()
returns the x component
int getY()
returns the y component
Force add(Force other)
returns a new Force that is the sum of this Force and the other Force. Because this object is immutable, neither of the input Forces is affected.
Mass.java extends Rect.java

Mass(int id, CS101Canvas canvas, int xLoc, int size)
constructs a unit mass, displayed on the canvas as a square of the specified size. The square is drawn with its upper, left-hand corner at (xLoc,0). The id is used to identify the mass in debugging messages.
int getCenterX()
returns the x-coordinate of the center of this Mass.
int getCenterY()
returns the y-coordinate of the center of this Mass.
Spring getRightSpring()
returns the spring connecting this mass to its right neighbor.
Spring getLeftSpring()
returns the spring connecting this mass to its left neighbor.
Mass getNext()
returns the Mass to the right of this Mass.
Mass getPrev()
returns the Mass to the left of this Mass.
void setLeftSpring(Spring spring)
establshes the supplied Spring as the spring to this mass's left.
void setRightSpring(Spring spring)
establshes the supplied Spring as the spring to this mass's right.
void relocateTo(int x, int y)
Although Rect has its own definition of this method, we override that definition in Mass. We do this because when the mass moves, the springs attached to it must update themeselves on the display.

Therefore, in this method you must:

  1. really relocate the mass, by calling super.RelocateTo(x,y).
  2. cause the Springs attached to this mass to redisplay themselves, by calling their update() method.
void tick(Force gravity)
This method simulates a second (well, 1.414 seconds) of the mass's life. For the two masses at the extreme left and right ends of the arch, nothing should be done---these masses stay put. For all other masses, you should do the following. The force of gravity is supplied as a parameter. You must take that force, and combine it additively with the forces applied by the mass's left and right springs (see the API for the Spring object). Since the square has unit mass, and since we are ticking just a sqrt(2) seconds, the square's location is changed exactly by the pixels corresponding to the force applied.

For example, if the resulting force is (3,-2), then the square should be relocated to a position 3 pixels to its right and 2 pixels up on the screen.

This is supplied to you, fully working. The API below is for your convenience.

Spring(CS101Canvas canvas, double k, Mass left, Mass right)
constructs a Spring. When stretched at one end, the string reacts with a force in the opposite direction. That force is equal to the compression distance times the string's constant factor, supplied as k.

The Spring is attached to the masses specified as its left and right parameters. It establishes its normal (uncompressed and unstretched) length from the position of those when the Spring is instantiated.

The Spring adds itself to the canvas, and it draws itself between the centers of its left and right masses.

Mass getLeftMass()
returns the mass connected to the spring's left.
Mass getRightMass()
returns the mass connected to the spring's right.
Force getRightForce()
returns the force currently applied at the right end of the Spring, assuming the left end is fixed and cannot be moved.
Force getLeftForce()
returns the force currently applied at the left end of the Spring, assuming the right end is fixed and cannot be moved.
causes the Spring to update itself, drawing itself between the centers of its adjacent masses.
private Force computeForce(Mass fixed, Mass moved)
You can take a look at this method if you're interested. It calculates the force exerted by the spring on the moved mass with respectr to the fixed mass.

Arch(int numMasses, int baseWidth, Force gravity, double springK)
The constructor must essentially instantiate and interconnect the objects shown in Figure 1(a). Specifically, you should:
  1. Make a new CS101Canvas (local or instance variable?)
  2. Capture the parameters in instance variables, but only as needed.
  3. Use iteration to create numMasses Mass objects, connected by Springs as shown in Figure 1(a). The code to do this is only about 10 lines long, but it is tricky to get the iteration right.
void iterForward()
visits each Mass object from left to right, calling tick on each mass.
void iterBackward()
visits each Mass object from right to left, calling tick on each mass.
String toString()
returns a string describing the Arch, as in:
Arch Mass 1->Spring Mass 1--Mass 2->Mass 2->Spring Mass 2--Mass 3->Mass 3
It's easiest to use iteration or recursion and rely on the toString() methods of the objects in the list.

Looking forward to implementation

  1. Implement the Force and test it from Startup.
  2. Implement and test Mass
  3. Implement Arch to the point where it constructs and interconnects the masses and springs.
  4. Complete the tick() method.
  5. Complete a code cover sheet.
  6. Provide printouts of any files you created or modified for this assignment.
  7. Provide transcripts of your runs showing the required statistics (as computed by your program, not by you!).
  8. Be prepared to answer the following questions when you demo:
    1. What happens when the spring constant is large?
    2. Why do the masses continue to wiggle, even after the Arch seems finished?
    3. What happens when you have more masses, but the same gravity and spring constant?
    4. What happens when gravity increases?
  9. Extra credit: Modify your solution so that the Arch starts at the bottom of the screen, and falls up instead of down.

Last modified 19:56:53 CDT 25 October 2000 by Ron K. Cytron