A Triangle and its Altitudes

We want to create an applet which draws a triangle with three moveable points and computes the altitudes.

Creating the Applet Class with a Canvas

Generally for any visualization we need a so called canvas (or several of them) to draw our objects of visualization. The MathletFactory provides for this purpose different predefined canvases (also "canvi"), such as a single or a side-by-side canvas for both Graphics2D or Java3D applets. Any applet shall extend therefore one of the abstract classes:
  • SingleG2DCanvasApplet
  • SideBySideG2DCanvasApplet
  • SingleJ3DCanvasApplet
  • SideBySideJ3DCanvasApplet
    There is also an an applet skeleton for pure symbolic displaying with no canvas, the NoCanvasApplet.
    All applet classes reside below the package net.mumie.mathletfactory.appletskeleton:
  • 2D applets: net.mumie.mathletfactory.appletskeleton.g2d
  • 3D applets: net.mumie.mathletfactory.appletskeleton.j3d
  • symbolic applet: net.mumie.mathletfactory.appletskeleton

The methods init() and initializeObjects()

The method init() is called from the applet context (i.e. the browser or appletviewer) or by a wrapper-main method (don`t forget, your applet won't work otherwise!). It calls at least the method initializeObjects() and adds all created objects to the canvas.

With an empty implementation, we can already have a look at our efforts (see below) until now. As can be seen, some control icons are automatically added as well as a standard help button.

import net.mumie.mathletfactory.appletskeleton.g2d.SingleG2DCanvasApplet;
import net.mumie.mathletfactory.util.BasicApplicationFrame;

public class TriangleAltitude extends SingleG2DCanvasApplet {

  public void init() {
    super.init();
    setTitle("Triangle Altitude Applet");
    initializeObjects();
  }

  protected void initializeObjects() {
  }

  public static void main(String[] args) {
    TriangleAltitude myApplet = new TriangleAltitude();
    myApplet.init();
    BasicApplicationFrame f = new BasicApplicationFrame(myApplet,500);
    f.pack();
    f.setVisible(true);
  }
}

About Number Classes

Almost all objects are based on a so called number class like MDouble, MRational, MInteger, or MComplex. They represent the real (with IEEE double precision), rational, natural, or complex numbers. All computations are done within this class.

Affine 2D Points

For the triangle we need three points A, B, C. They are realized by a so called MMAffine2DPoint and defined by the representing number class and the coordinates:

A = new MMAffine2DPoint(MDouble.class, -0.3, 0.3);
B = new MMAffine2DPoint(MDouble.class, 0.25, 0.25);
C = new MMAffine2DPoint(MDouble.class, -0.25, -0.25).

Translation Handler

Since we want the points to be moveable by mouse and keyboard we create a so called Affine2DMouseTranslateHandler and an Affine2DKeyboardTranslateHandler and add them to the points:

amth = new Affine2DMouseTranslateHandler(getCanvas());
akth = new Affine2DKeyboardTranslateHandler(getCanvas());
A.addHandler(akth);     A.addHandler(amth);
B.addHandler(akth);     B.addHandler(amth);
C.addHandler(akth);     C.addHandler(amth);

Affine 2D Line Segments

Now we need some line segments to connect the points of the triangle:

AB = new MMAffine2DLineSegment(A,B);
BC = new MMAffine2DLineSegment(B,C);
CA = new MMAffine2DLineSegment(C,A);

We also need line segments which represent the altitudes:

altitude_AB = new MMAffine2DLineSegment(C,getPerpendicularFoot(A,B,C));
altitude_BC = new MMAffine2DLineSegment(A,getPerpendicularFoot(B,C,A));
altitude_CA = new MMAffine2DLineSegment(B,getPerpendicularFoot(C,A,B)).

The method getPerpendicularFoot() returns a MMAffine2DPoint representing the footpoint of the altitude. Some mathematical computation is done within this method which is not of interest for us now.

Maybe the footpoint of an altitude does not lie on an edge of the triangle. So we extend the edges by another line segment:

aFootC = new MMAffine2DLineSegment(A,getPerpendicularFoot(A,B,C));
bFootC = new MMAffine2DLineSegment(B,getPerpendicularFoot(A,B,C));
bFootA = new MMAffine2DLineSegment(B,getPerpendicularFoot(B,C,A));
cFootA = new MMAffine2DLineSegment(C,getPerpendicularFoot(B,C,A));
cFootB = new MMAffine2DLineSegment(C,getPerpendicularFoot(C,A,B));
aFootB = new MMAffine2DLineSegment(A,getPerpendicularFoot(C,A,B)).

Adding Objects to the Canvas

Now all objects are created we have to add them to the canvas:

// points
getCanvas().addObject(A);
getCanvas().addObject(B);
getCanvas().addObject(C);

// sides
getCanvas().addObject(AB);
getCanvas().addObject(BC);
getCanvas().addObject(CA);

// altitudes
getCanvas().addObject(altitude_AB);
getCanvas().addObject(altitude_BC);
getCanvas().addObject(altitude_CA);

// footprints
getCanvas().addObject(aFootC);
getCanvas().addObject(bFootC);
getCanvas().addObject(cFootA);
getCanvas().addObject(cFootB);
getCanvas().addObject(aFootB);
getCanvas().addObject(bFootA); 

Display Properties

As can be seen in figure above all the lines and points have the standard color black. If we want to give them another color we have to define
PointDisplayProperties and LineDisplayProperties and set them for the points and lines:

private PointDisplayProperties pp = new PointDisplayProperties();
private LineDisplayProperties ll = new LineDisplayProperties();
private LineDisplayProperties mm = new LineDisplayProperties();
private LineDisplayProperties kk = new LineDisplayProperties();

pp.setObjectColor(Color.blue);
ll.setObjectColor(Color.red);
mm.setObjectColor(Color.red);
mm.setFilled(false);
kk.setObjectColor(Color.yellow);

A.setDisplayProperties(pp);
B.setDisplayProperties(pp);
C.setDisplayProperties(pp);

altitude_AB.setDisplayProperties(kk);
altitude_BC.setDisplayProperties(kk);
altitude_CA.setDisplayProperties(kk);

AB.setDisplayProperties(ll);
BC.setDisplayProperties(ll);
CA.setDisplayProperties(ll);

aFootC.setDisplayProperties(mm);
bFootC.setDisplayProperties(mm);
bFootA.setDisplayProperties(mm);
cFootA.setDisplayProperties(mm);
cFootB.setDisplayProperties(mm);
aFootB.setDisplayProperties(mm);

The result can be seen in the figure below:

Dependencies

Now our points are moveable but the lines do not move with them. Obviously the position of the lines depend on the position of the points. This is described by a so called DependencyAdapter and the method dependsOn(). For example for the edges of the triangle we have:

DependencyAdapter DPA = new DependencyAdapter() {
  public void doUpdate(MMObjectIF dependant, MMObjectIF[] free) {
    MMAffine2DLineSegment line = (MMAffine2DLineSegment) dependant;
    line.setInitialPoint((MMAffine2DPoint)free[0]);
    line.setEndPoint((MMAffine2DPoint)free[1]);
  }
};
AB.dependsOn(new MMObjectIF[]{A,B},DPA);
BC.dependsOn(new MMObjectIF[]{B,C},DPA);
CA.dependsOn(new MMObjectIF[]{C,A},DPA);

Hereby the first argument new MMObjectIF[]{A,B} of the method dependsOn() is an array of objects on which the object AB depends. This array is passed to the method doUpdate in the DependencyAdapter DPA as parameter free. AB is passed to the method doUpdate in the DependencyAdapter as parameter dependent. doUpdate describes the action to perform when an object of the array free is changed.

Reset, Screenshot, Help button

With the commands

addResetButton();
addScreenShotButton();

we can add a reset and a screenshot button. The functionality of the reset button is defined in the method reset(), which calls the method initializeObjects() and repaints the canvas:
public void reset(){
  initializeObjects();
  getCanvas().renderScene();
  getCanvas().repaint();
}

A HTML-description of the functionality of the applet can be saved in a file with the name Help_<lang>.html in a directory <applet_class_name>.files in the applet's package path. The placeholder <lang> stands for the language the file is written in.
This desciption is opend in another window by clicking the help button.\\
Example: Location of the english help file for the applet MyApplet in the package my.package:\\
./my/package/MyApplet.files/Help_en.html

Now our first applet is ready. The complete source code can be found here.

Summary: Building Mathlets

This example should illuminate the process of rapid applet development. The linear process model we used can be generalized to the following steps:
  1. Choose the display type and numbers of displays to be used and extend the corresponding applet skeleton.
  2. Add the chosen mmobjects and their iconic or symbolic representations
  3. Add necessary handlers
  4. Create the update graph by adding updaters and creating dependencies

triangle_applet.png (7.61 KB) Marek Grudzinski, 04/07/2013 11:50 AM

triangle_and_altitudes.png (25.2 KB) Marek Grudzinski, 04/07/2013 11:50 AM

triangle_and_color.png (29.9 KB) Marek Grudzinski, 04/07/2013 11:50 AM

triangle_complete.png (29.7 KB) Marek Grudzinski, 04/07/2013 11:50 AM

triangle_altitude_applet.png (17.3 KB) Marek Grudzinski, 04/07/2013 11:50 AM

Triangle_applet Triangle_and_altitudes Triangle_and_color Triangle_complete Triangle_altitude_applet
Add picture from clipboard (Maximum size: 500 MB)