package com.didi.codeProfiles;
import java.applet.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
public class CodeProfiles extends Applet implements Runnable {
int programLineIndexAsWritten[] = new int[256]; int i11 = line(80);
long programLineExecutionCount[] = new long[256]; int i16 = line(132);
int programTrace[] = new int[4096], lastLineCallInProgram; int i1 = line(1);
Line programLines[] = null; int i6 = line(42);
//============================================================================//
// //
// CodeProfiles was written August 9-15 2002 for CODeDOC; commissioned by //
// Christiane Paul, Curator at the Whitney Museum of American Art, NY USA //
// //
// The assignment was to write code that moves three points in space. The //
// artists shared the code with one another and the public, to focus upon //
// the code and process as well as artist comments on one another's code. //
// //
// This code reads in its own source and displays it in a tiny font, then //
// moves three points in "code space." It essentially comments on itself. //
// //
// The white Insertion Point traces the code in the order it was written. //
// The amber Fixation Point traces word by word as someone might read it. //
// The green Execution Point shows a sample of how the computer reads it. //
// The code lines themselves gradually get brighter as they execute more. //
// //
// This code was written in my un-optimized prototyping style; built with //
// meaning, visuals, usability, and fun taking priority over engineering. //
// Thank you Greta Peterman and Marek Walczak for your valuable critique. //
// //
// W. Bradford Paley brad@didi.com //
// Copyright (c) 2002, all rights reserved related work at textarc.org //
// //
//============================================================================//
//==============================================================================
class Line {
String s;
int leadingPixels = -1, x, y, lineIndex, lineAsWrittenIndex, i1 = line(16);
boolean hasLineCall = false; int i2 = line(101);
double brightness; int i17 = line(134);
public Line(String s) { line(17);
this.s = s; line(18);
}
}
//==============================================================================
class Cubic {
double a, b, c, d = line(151);
public Cubic (double a, double b, double c, double d) {
this.a = a; this.b = b; this.c = c; this.d = d; line(152);
}
public double evaluate (double u) { line(182);
return (((d*u) + c) * u + b) * u + a;
}
}
//==============================================================================
public CodeProfiles () { line(2);
setBackground(Color.black); line(79);
}
//==============================================================================
int drawnInsertionLine, drawnInsertionLineBackup, drawnInsertionPoint,
drawnFixationLine, drawnFixationPoint, drawnPC = line(75);
Line lineDrawnLarger, lastLineDrawnLarger; int i14 = line(117);
double lineDrawnLargerRatio = 1./3.; int i25 = line(244);
void step () {
// start all three points we're moving where the mouse was clicked
if (lineToStartTraces != null) { line(251);
// point the fixation point at this line
drawnFixationPoint = 0; line(230);
drawnFixationLine = lineUnderMouseIndex; line(224);
// point the insertion point at this line
drawnInsertionPoint = drawnInsertionLineBackup = 0; line(232);
// if it has a line() call we're all set
if (lineToStartTraces.hasLineCall) {
drawnInsertionLine = lineToStartTraces.lineAsWrittenIndex;
line(231);
// otherwise find a line() call
} else {
// start where the mouse was clicked
int i = lineToStartTraces.lineIndex; line(235);
// go forward until we see a line() call
while (i != 0 && ! programLines[i].hasLineCall) {
i = ++i % programLines.length; line(252);
drawnInsertionLineBackup--; line(234);
}
if (i == 0) drawnInsertionLine = lastLineCallInProgram;
else drawnInsertionLine = programLines[i].lineAsWrittenIndex;
line(233);
}
resetTraceVectors = true; line(225);
// have drawnPC wait until this line is executed, then trace
drawnPCWaitTargetLine = drawnInsertionLine; line(236);
lineToStartTraces = null; line(253);
}
// increase a ratio (used to reveal cropped lines) if we're lingering
if (lastLineDrawnLarger == lineDrawnLarger) { line(246);
lineDrawnLargerRatio = Math.min(1., lineDrawnLargerRatio * 1.05);
} else {
lineDrawnLargerRatio = 1./3.; line(247);
lastLineDrawnLarger = lineDrawnLarger; line(245);
}
//--------------------------------------------------------------------------
// step the pseudo-fixation point to show how a person might read the code
// (word by word: quickly)
// first check to see if we need to step to the next line
Line lastLine = programLines[drawnFixationLine]; line(206);
if (programLines[drawnFixationLine] == null ||
drawnFixationPoint >= programLines[drawnFixationLine].s.length()-1) {
line(95);
// step to the next line to be read
do {
drawnFixationLine = (++drawnFixationLine) % programLines.length;
line(83);
} while (programLines[drawnFixationLine] == null ||
programLines[drawnFixationLine].s.trim().length() == 0);
line(98);
// and reset the fixation point
drawnFixationPoint = 0; line(96);
}
// step the fixation point past the next word
drawnFixationPoint = programLines[drawnFixationLine].s.
indexOf(" ", drawnFixationPoint); line(93);
if (programLines[drawnFixationLine].s.
indexOf(" ", drawnFixationPoint) != -1)
drawnFixationPoint += 14; line(216);
if (drawnFixationPoint == -1) drawnFixationPoint =
programLines[drawnFixationLine].s.length()-2; line(94);
drawnFixationPoint++; line(97);
// follow this point if we catch it
if (lineDrawnLarger == lastLine)
lineDrawnLarger = programLines[drawnFixationLine]; line(205);
//--------------------------------------------------------------------------
// step the pseudo-insertion point to show how the code was written
// (character by character: slowly)
// increment the insertion point, and if it's at the end of the line
lastLine = programLines[programLineIndexAsWritten[drawnInsertionLine]+
drawnInsertionLineBackup]; line(210);
if (++drawnInsertionPoint >
programLines[programLineIndexAsWritten[drawnInsertionLine]+
drawnInsertionLineBackup].s.trim().length()) { line(91);
// either back up less (in code space)
if (drawnInsertionLineBackup < 0) {
drawnInsertionLineBackup++; line(106);
} else { line(107);
// or step to the next line in the order that they were written
do { drawnInsertionLine = (++drawnInsertionLine) %
programLineIndexAsWritten.length; line(84);
} while (programLineIndexAsWritten[drawnInsertionLine] == 0);
// then back up in the actual code 'til there's another line() call
drawnInsertionLineBackup = 0; line(104);
do {
drawnInsertionLineBackup--;
} while (drawnInsertionLine + drawnInsertionLineBackup > 0 &&
programLineIndexAsWritten[drawnInsertionLine]+
drawnInsertionLineBackup > 0 &&
programLines[programLineIndexAsWritten[drawnInsertionLine]+
drawnInsertionLineBackup].s.indexOf("//") != 0 &&
programLines[programLineIndexAsWritten[drawnInsertionLine]+
drawnInsertionLineBackup].hasLineCall == false); line(105);
drawnInsertionLineBackup++; line(108);
}
// and always reset the insertion point to the beginning of the line
drawnInsertionPoint = 0; line(92);
}
// follow this point if we catch it
if (lineDrawnLarger == lastLine)
lineDrawnLarger = programLines[programLineIndexAsWritten[drawnInsertionLine]+
drawnInsertionLineBackup]; line(209);
//--------------------------------------------------------------------------
// step the pseudo-program counter to show how a profiler reads the code
// (line by line: very quickly)
if (drawnPCWaitTargetLine == -1) {
lastLine = programLines[programLineIndexAsWritten[
programTrace[drawnPC]]]; line(207);
drawnPC = (++drawnPC) % programTrace.length; line(74);
// get a fresh sample of execution trace once we've shown the full array
// (use the current insertion point to hash the sample a little)
if (drawnPC == 0) pc = -drawnInsertionLine * 10; line(99);
// follow this point if we catch it
if (lineDrawnLarger == lastLine)
lineDrawnLarger = programLines[programLineIndexAsWritten[
programTrace[drawnPC]]]; line(208);
}
}
//==============================================================================
long lastUpdateTime = 0; int i10 = line(69);
boolean go = true; int i23 = line(243);
Line lineToStartTraces = null; int i26 = line(254);
public void run () {
programLines = readFile(getParameter("fileName")); line(32);
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
lineDrawnLarger = findLineUnderMouse(e); line(116);
}});
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
lineDrawnLarger = findLineUnderMouse(e); line(250);
}
public void mouseClicked(MouseEvent e) {
lineToStartTraces = findLineUnderMouse(e); line(248);
}});
while (go) {
// step forward in the state of the world model
step(); line(73);
// draw the whole world again
drawAll(getGraphics()); line(72);
// insure at least 15 milliseconds between draws
try {
Thread.sleep(Math.max(0,
15 - (System.currentTimeMillis() - lastUpdateTime))); line(70);
} catch (Exception e) { e.printStackTrace(); }
lastUpdateTime = System.currentTimeMillis(); line(71);
}
}
//==============================================================================
int lineUnderMouseIndex; int i22 = line(227);
public Line findLineUnderMouse (MouseEvent e) { line(114);
Line lineUnderMouse = null; line(119);
lineUnderMouseIndex = -1; line(226);
for (int i = 0; i < programLines.length; i++) {
if (e.getX() > (programLines[i].x - programLines[i].leadingPixels) &&
e.getX() < (programLines[i].x -
programLines[i].leadingPixels + columnWidth) &&
e.getY() > programLines[i].y - 3 &&
e.getY() < programLines[i].y) {
lineUnderMouse = programLines[lineUnderMouseIndex = i];
line(118);
break;
}
} line(115);
return lineUnderMouse;
}
//==============================================================================
int pc = 0, drawnPCWaitTargetLine = -1; int i5 = line(38);
int line (int i) { return line(i, false); }
int line (int i, boolean recur) { if (recur) line(3);
// if a click made us wait for this line to execute, stop waiting and trace
if (drawnPCWaitTargetLine == i) {
drawnPC = pc = 0; if (recur) line(237);
drawnPCWaitTargetLine = -1; if (recur) line(240);
}
// trace execution
if (programTrace != null && pc < programTrace.length &&
drawnPCWaitTargetLine == -1)
programTrace[Math.max(0, Math.min(pc++, programTrace.length-1))] = i;
if (recur) line(39);
// count the number of times this line is executed
if (programLineExecutionCount != null)
programLineExecutionCount[i]++; if (recur) line(133);
return i;
}
//==============================================================================
void brightenExecutedLines (Graphics g, boolean all) { line(135);
// loop through all lines as written and update their brightness
for (int i = 0; i < programLineIndexAsWritten.length; i++) { line(140);
// calculate a new brightness level
double newBrightness =
(Math.log((double) programLineExecutionCount[i] + 1)); line(141);
// if it's different enough
if (all || (programLines != null && (Math.abs(newBrightness -
programLines[programLineIndexAsWritten[i]].brightness) > .4)) &&
programLineIndexAsWritten[i] != 0) {
line(143);
// find the line we want to check
int index = programLineIndexAsWritten[i], backup = 0; line(137);
// set the new level
programLines[index].brightness = newBrightness; line(142);
// set the new color
int greenComponent = (int) Math.min(150,
70 + programLines[index].brightness * 2); line(149);
g.setColor(
new Color(greenComponent/3, greenComponent, greenComponent/3));
line(136);
// draw the line again (and those before it until another line() call)
if (programLines != null && programLines[index] != null) {
do {
g.drawString(programLines[index+backup].s,
programLines[index+backup].x,
programLines[index+backup].y); line(138);
backup--;
} while (index+backup > 0 &&
programLines[index+backup].s.indexOf("//") != 0 &&
programLines[index+backup].hasLineCall == false); line(139);
}
}
}
}
//==============================================================================
Line[] readFile (String fileName) { line(4);
Vector v = new Vector(); line(10);
try { line(7);
// open the file
InputStream is = (new URL(getCodeBase() + fileName)).openStream();
line(5);
BufferedReader br = new BufferedReader (new InputStreamReader(is));
line(19);
// read every line in it
Line l; line(12);
do { line(13);
l = readLine(br); line(9);
if (l != null) v.addElement(l); line(11);
} while (l != null); line(14);
is.close(); line(6);
} catch (Exception e) { System.err.println(e); } line(8);
// put all the lines we read into an array of Line objects
Line lines[] = new Line[v.size()]; line(33);
for (int i = 0; i < v.size(); i++) {
lines[i] = (Line) v.elementAt(i); line(48);
// remember where we are in the program
lines[i].lineIndex = i;
// if there's a call to line() here put the index of this Line in
// programLineIndexAsWritten
int lineCallPos = lines[i].s.indexOf("line("); line(85);
int lineCallEndPos = lines[i].s.indexOf(")", lineCallPos); line(82);
if (lineCallPos != -1 &&
Character.isDigit(lines[i].s.charAt(lineCallEndPos-1))) {
// remember if there's a call to line() in this line
lines[i].hasLineCall = true; line(103);
// this array finds the line index from the time it was written
// (the parameter to line() )
programLineIndexAsWritten[lastLineCallInProgram =
lines[i].lineAsWrittenIndex = Integer.parseInt(
lines[i].s.substring(lineCallPos + 5, lineCallEndPos))] = i;
line(81);
}
}
return lines;
}
//==============================================================================
byte buffer[] = new byte[1000]; int i3 = line(31);
Line readLine (BufferedReader br) { line(15);
int length = 0; line(20);
int ch = 0; line(21);
try { line(22);
while ((ch = br.read()) != '\n' && ch != '\r' && ch != -1)
buffer[length++] = (byte) ch; line(23);
// -1 means EOF
if (ch == -1) return null; line(24);
// skip a line feed if this was a carriage return
if (ch == '\r') { line(25);
ch = br.read(); line(26);
} line(27);
} catch (Exception e) { return null; } line(28);
if (length == 0) return new Line(""); line(29);
return new Line(new String(buffer, 0, length + line(30) * 0) + " ");
}
//==============================================================================
Image cacheImage, offscreenImage; int i7 = line(54);
Graphics cacheGraphics, offscreenGraphics; int i8 = line(55);
boolean drawCacheNeeded = true, resetTraceVectors = false; int i9 = line(62);
Vector pastPCPositions = null; int i13 = line(109);
Vector pastFixationPositions = null; int i18 = line(177);
Line lastFixationLine; int i21 = line(200);
Vector pastInsertionPositions = null; int i19 = line(184);
Line lastInsertionLine; int i20 = line(197);
public synchronized void drawAll (Graphics g) { line(53);
// don't even try if we don't have a full-sized window yet
/v2/img/enterproject.gif
if (size().width < 21 || size().height < 21) { line(255);
return;
}
//--------------------------------------------------------------------------
// get an offscreen buffer: double-buffering for smooth animation
if (offscreenImage == null ||
size().width != offscreenImage.getWidth(this) ||
size().height != offscreenImage.getHeight(this)) { line(56);
setFont(new Font("Courier", Font.PLAIN,
Math.max(1, size().width / 320))); line(78);
offscreenImage = createImage(size().width, size().height); line(57);
offscreenGraphics = offscreenImage.getGraphics(); line(58);
resetTraceVectors = true; line(228);
}
// get a cache buffer: so we don't have to draw everything every frame
if (cacheImage == null ||
size().width != cacheImage.getWidth(this) ||
size().height != cacheImage.getHeight(this)) { line(59);
cacheImage = createImage(size().width, size().height); line(60);
cacheGraphics = cacheImage.getGraphics(); line(61);
drawCacheNeeded = true; line(63);
}
// be safe--check to see if we got what we wanted above
if (cacheGraphics == null || offscreenGraphics == null)
return; line(131);
//--------------------------------------------------------------------------
// draw the cache if it needs refreshing
if (drawCacheNeeded) drawCache(cacheGraphics); line(66);
// fix the cache if there are changes in it
if (programLines != null)
brightenExecutedLines(cacheGraphics, false); line(144);
// copy the graphics cache into the back buffer
offscreenGraphics.drawImage(cacheImage, 0, 0, this); line(67);
//--------------------------------------------------------------------------
// draw the traces
if (resetTraceVectors) { line(229);
pastPCPositions = new Vector(); line(217);
pastFixationPositions = new Vector(); line(218);
pastInsertionPositions = new Vector(); line(219);
resetTraceVectors = false;
}
drawFixationTrace(g);
drawInsertionTrace(g);
drawExecutionTrace(g);
//--------------------------------------------------------------------------
// draw the line under the mouse or stuck to a point larger and brighter
Line lineRecentlyDrawnLarger = lineDrawnLarger; line(124);
if (lineRecentlyDrawnLarger != null) { line(121);
offscreenGraphics.setColor(new Color(30, 255, 30)); line(120);
offscreenGraphics.setFont(
new Font(getFont().getName(), getFont().getStyle(), 12)); line(122);
offscreenGraphics.drawString(lineRecentlyDrawnLarger.s, (int) Math.min(
size().width - lineDrawnLargerRatio *
getFontMetrics(offscreenGraphics.getFont()).
stringWidth(lineRecentlyDrawnLarger.s.trim()),
lineRecentlyDrawnLarger.x), lineRecentlyDrawnLarger.y); line(123);
offscreenGraphics.setFont(getFont()); line(125);
}
//--------------------------------------------------------------------------
// draw the line the pseudo-program counter is pointing to
offscreenGraphics.setColor(Color.green); line(85);
int index = programLineIndexAsWritten[programTrace[drawnPC]],
backup = 0; line(100);
if (drawnPCWaitTargetLine == -1 && programTrace[drawnPC] != 0 &&
programLines != null && programLines[index] != null) {
do {
offscreenGraphics.drawString(programLines[index+backup].s,
programLines[index+backup].x, programLines[index+backup].y);
line(86);
// remember the position if it's not a blank line
if (programLines[index+backup].s.trim().length() != 0 &&
programLines[index+backup].y > 1 && drawnPC < pc) {
pastPCPositions.insertElementAt(
new Point(programLines[index+backup-1].x,
programLines[index+backup-1].y),
Math.max(0, pastPCPositions.size() + backup));
} line(110);
backup--;
} while (index+backup > 0 &&
programLines[index+backup].s.indexOf("//") != 0 &&
programLines[index+backup].hasLineCall == false); line(102);
}
//--------------------------------------------------------------------------
// draw the fixation point
if (programLines != null) { line(113);
offscreenGraphics.setColor(new Color(255, 255*7/8, 0)); line(87);
// if it's the attended line draw it larger and brighter
if (lineRecentlyDrawnLarger == programLines[drawnFixationLine])
offscreenGraphics.setFont(new Font(getFont().getName(),
getFont().getStyle(), 12)); line(126);
offscreenGraphics.drawString(
programLines[drawnFixationLine].s.substring(0, drawnFixationPoint),
(int) Math.min(size().width - lineDrawnLargerRatio *
getFontMetrics(offscreenGraphics.
getFont()).stringWidth(programLines[drawnFixationLine].s.trim()),
programLines[drawnFixationLine].x),
programLines[drawnFixationLine].y); line(88);
// remember the position if it's not a blank line
if (lastFixationLine == null ||
lastFixationLine != programLines[drawnFixationLine] &&
programLines[drawnFixationLine].s.trim().length() != 0 &&
programLines[drawnFixationLine].y > 1) {
pastFixationPositions.addElement(
new Point(programLines[drawnFixationLine].x +
getFontMetrics(getFont()).stringWidth(
programLines[drawnFixationLine].s.trim()),
programLines[drawnFixationLine].y)); line(178);
pastFixationPositions.addElement(
new Point(programLines[drawnFixationLine].x,
programLines[drawnFixationLine].y)); line(201);
}
lastFixationLine = programLines[drawnFixationLine]; line(202);
// if it's the line drawn larger put the font back to normal
if (lineRecentlyDrawnLarger == programLines[drawnFixationLine])
offscreenGraphics.setFont(getFont()); line(127);
}
//--------------------------------------------------------------------------
// draw the insertion point
offscreenGraphics.setColor(Color.white); line(89);
if (programLineIndexAsWritten[drawnInsertionLine] != 0) {
Line insertionLine = programLines[programLineIndexAsWritten[
drawnInsertionLine]+drawnInsertionLineBackup]; line(148);
// if it's the attended line draw it larger and brighter
if (lineRecentlyDrawnLarger == insertionLine)
offscreenGraphics.setFont(new Font(getFont().getName(),
getFont().getStyle(), 12)); line(146);
offscreenGraphics.drawString(
insertionLine.s.substring(0, drawnInsertionPoint),
(int) Math.min(size().width - lineDrawnLargerRatio *
getFontMetrics(offscreenGraphics.getFont()).
stringWidth(insertionLine.s.trim()),
insertionLine.x), insertionLine.y); line(90);
// remember the position if it's not a blank line
if (lastInsertionLine == null ||
lastInsertionLine != insertionLine &&
insertionLine.s.trim().length() != 0 &&
insertionLine.y > 1) {
pastInsertionPositions.addElement(
new Point(insertionLine.x, insertionLine.y)); line(199);
pastInsertionPositions.addElement(
new Point(insertionLine.x +
getFontMetrics(getFont()).stringWidth(
insertionLine.s.trim()),
insertionLine.y)); line(185);
}
lastInsertionLine = insertionLine; line(198);
// if it's the line drawn larger put the font back to normal
if (lineRecentlyDrawnLarger == insertionLine)
offscreenGraphics.setFont(getFont()); line(147);
}
//--------------------------------------------------------------------------
// copy the graphics cache into the back buffer
g.drawImage(offscreenImage, 0, 0, this); line(68);
}
//==============================================================================
void drawExecutionTrace (Graphics g) {
// if we just started a new sample of trace, start a new trace line
if (drawnPC == 0) pastPCPositions = new Vector(); line(150);
// trim the line to trace only the last 200 PC positions
while (pastPCPositions.size() > 200)
pastPCPositions.removeElementAt(0); line(111);
// draw from the tail forward
for (int i = 1; i < pastPCPositions.size(); i++) {
// fade it out slowly
int lineBrightness = Math.min(140, 20 + i +
// adjust to let short lines glow brightly
Math.max(0, 200 - pastPCPositions.size())); line(211);
offscreenGraphics.setColor(
new Color(lineBrightness/8, lineBrightness, lineBrightness/8));
offscreenGraphics.drawLine(
((Point) pastPCPositions.elementAt(i-1)).x,
((Point) pastPCPositions.elementAt(i-1)).y,
((Point) pastPCPositions.elementAt(i)).x,
((Point) pastPCPositions.elementAt(i)).y); line(112);
}
}
//==============================================================================
void drawInsertionTrace (Graphics g) {
// trim the line to trace only the last 30 insertion positions
while (pastInsertionPositions.size() > 30)
pastInsertionPositions.removeElementAt(0); line(186);
if (pastInsertionPositions.size() > 1) { line(187);
Cubic[][] insertionSpline = calculateNaturalCubic(pastInsertionPositions);
line(188);
Line insertionLine = programLines[programLineIndexAsWritten[
drawnInsertionLine]+drawnInsertionLineBackup]; line(212);
double lastStepRatio = (insertionLine.s.trim().length() == 0) ? 1. :
(double) drawnInsertionPoint / insertionLine.s.trim().length();
line(213);
// draw from the tail forward
double steps = 40; line(189);
for (int i = 0;
i < insertionSpline.length -
(lastStepRatio < .5 && lastStepRatio != 0. ? 2 : 1); i++) {
// fade it out slowly
int lineBrightness = Math.min(140, 20 + i*5 +
Math.max(0, 30 - insertionSpline.length)*5); line(204);
offscreenGraphics.setColor(
new Color(lineBrightness, lineBrightness, lineBrightness));
// figure out where to stop
int lastStep = (int) steps; line(214);
if (lastStepRatio < .5 && lastStepRatio != 0. &&
i == insertionSpline.length - 3)
lastStep = (int) (lastStepRatio * 2 * steps);
else if (lastStepRatio >= .5 && i == insertionSpline.length - 2)
lastStep = (int) ((lastStepRatio - .5) * 2 * steps); line(215);
// do the drawing
Point p2, p1 = new Point(
(int) Math.round(insertionSpline[i][0].evaluate(0)),
(int) Math.round(insertionSpline[i][1].evaluate(0))); line(194);
for (int j = 1; j <= lastStep; j++) {
p2 = new Point(
(int) Math.round(insertionSpline[i][0].evaluate(j / steps)),
(int) Math.round(insertionSpline[i][1].evaluate(j / steps)));
line(195);
if (p1 != null)
offscreenGraphics.drawLine(p1.x, p1.y, p2.x, p2.y);
line(190);
p1 = p2; line(196);
}
}
}
}
//==============================================================================
void drawFixationTrace (Graphics g) {
// trim the line to trace only the last 80 fixation positions
while (pastFixationPositions.size() > 80)
pastFixationPositions.removeElementAt(0); line(179);
if (pastFixationPositions.size() > 1) { line(183);
Cubic[][] fixationSpline = calculateNaturalCubic(pastFixationPositions);
line(180);
// draw from the tail forward
for (int i = 0; i < fixationSpline.length - 1; i++) {
// fade it out slowly
int lineBrightness = Math.min(120, 20 + (int) (i*1.5) +
Math.max(0, 80 - fixationSpline.length)*2); line(203);
offscreenGraphics.setColor(
new Color(lineBrightness, lineBrightness*7/8, lineBrightness/4));
double steps = 13; line(157);
Point p2, p1 = new Point(
(int) Math.round(fixationSpline[i][0].evaluate(0)),
(int) Math.round(fixationSpline[i][1].evaluate(0))); line(191);
for (int j = 1; j <= steps; j++) {
p2 = new Point(
(int) Math.round(fixationSpline[i][0].evaluate(j / steps)),
(int) Math.round(fixationSpline[i][1].evaluate(j / steps)));
line(192);
if (p1 != null)
offscreenGraphics.drawLine(p1.x, p1.y, p2.x, p2.y);
line(181);
p1 = p2; line(193);
}
}
}
}
//==============================================================================
void drawCache (Graphics g) {
// start with a "no-electron CRT" black background
g.setColor(Color.black); line(44);
g.fillRect(0, 0, size().width, size().height); line(45);
if (programLines != null && cacheImage.getHeight(this) != 0) {
drawCode(g, cacheImage.getWidth(this), cacheImage.getHeight(this));
line(64);
// we drew it
drawCacheNeeded = false; line(65);
}
}
//==============================================================================
int columnWidth; int i27 = line(249);
public void drawCode (Graphics g, int w, int h) { line(41);
int columns = 4, linesPerCol = (programLines.length+columns-1) / columns,
margin = w/8, colSpacing = columnWidth = (w - margin*2 - getFontMetrics(
g.getFont()).stringWidth(" ")*100) / (columns - 1); line(49);
double lineHeight = (h - margin*2) / (double) (linesPerCol+2); line(50);
// draw the code in "early CRT phosphor" green
g.setColor(new Color(20, 80, 20)); line(46);
// draw every line of the code we have read
for (int i = 0; i < programLines.length; i++) { line(43);
if (programLines[i] != null) {
// trim leading spaces the first time we draw the line
if (programLines[i].leadingPixels == -1) { line(128);
programLines[i].leadingPixels =
programLines[i].s.indexOf(programLines[i].s.trim()) *
getFontMetrics(g.getFont()).stringWidth(" "); line(129);
// trailing spaces make us pause in the word-by-word reading mode
programLines[i].s = programLines[i].s.trim() + " ";
line(130);
}
programLines[i].x = margin + programLines[i].leadingPixels +
(i / linesPerCol) * colSpacing; line(76);
programLines[i].y =
margin + (int) ((i % linesPerCol) * lineHeight); line(77);
g.drawString(
programLines[i].s, programLines[i].x, programLines[i].y); line(47);
}
}
brightenExecutedLines(g, true); line(145);
}
//==============================================================================
Thread thread; int i4 = line(34);
public void start() { line(35);
thread = new Thread(this); line(36);
thread.start(); line(37);
}
//==============================================================================
public void stop() { line(241);
go = false; line(242);
}
//==============================================================================
public void update (Graphics g) { paint(g); line(40); }
//==============================================================================
public void paint (Graphics g) { line(51);
drawAll(g); line(52);
}
//==============================================================================
Cubic[][] calculateNaturalCubic (Vector v) { line(153);
int i, n = v.size()-1; line(159);
double gammas[] = new double[n+1]; line(154);
double deltaXs[] = new double[n+1]; line(155);
double DXs[] = new double[n+1]; line(156);
double deltaYs[] = new double[n+1]; line(175);
double DYs[] = new double[n+1]; line(176);
//--------------------------------------------------------------------------
// gammas
gammas[0] = 1/2d; line(158);
for (i = 1; i < n; i++)
gammas[i] = 1/(4-gammas[i-1]); line(160);
gammas[n] = 1/(2-gammas[n-1]); line(161);
//--------------------------------------------------------------------------
// deltas for x
deltaXs[0] = 3 * (((Point) v.elementAt(1)).x - ((Point) v.elementAt(0)).x) *
gammas[0]; line(162);
for (i = 1; i < n; i++)
deltaXs[i] =
(3 * (((Point) v.elementAt(i+1)).x - ((Point) v.elementAt(i-1)).x) -
deltaXs[i-1]) * gammas[i]; line(163);
deltaXs[n] = (3 * (((Point) v.elementAt(n)).x - ((Point) v.elementAt(n-1)).x) -
deltaXs[n-1]) * gammas[n]; line(164);
// Ds for x
DXs[n] = deltaXs[n]; line(165);
for (i = n-1; i >= 0; i--)
DXs[i] = deltaXs[i] - gammas[i] * DXs[i+1]; line(166);
//--------------------------------------------------------------------------
// deltas for y
deltaYs[0] = 3 * (((Point) v.elementAt(1)).y - ((Point) v.elementAt(0)).y) *
gammas[0]; line(167);
for (i = 1; i < n; i++)
deltaYs[i] =
(3 * (((Point) v.elementAt(i+1)).y - ((Point) v.elementAt(i-1)).y) -
deltaYs[i-1]) * gammas[i]; line(168);
deltaYs[n] = (3 * (((Point) v.elementAt(n)).y - ((Point) v.elementAt(n-1)).y) -
deltaYs[n-1]) * gammas[n]; line(169);
// Ds for y
DYs[n] = deltaYs[n]; line(170);
for (i = n-1; i >= 0; i--)
DYs[i] = deltaYs[i] - gammas[i] * DYs[i+1]; line(171);
//--------------------------------------------------------------------------
// coefficients of the cubics
Cubic coefficients[][] = new Cubic[n][2]; line(172);
for (i = 0; i < n; i++) {
coefficients[i][0] = new Cubic(((Point) v.elementAt(i)).x, DXs[i],
3 * (((Point) v.elementAt(i+1)).x - ((Point) v.elementAt(i)).x) -
2 * DXs[i] - DXs[i+1],
2 * (((Point) v.elementAt(i)).x - ((Point) v.elementAt(i+1)).x) +
DXs[i] + DXs[i+1]); line(173);
coefficients[i][1] = new Cubic(((Point) v.elementAt(i)).y, DYs[i],
3 * (((Point) v.elementAt(i+1)).y - ((Point) v.elementAt(i)).y) -
2 * DYs[i] - DYs[i+1],
2 * (((Point) v.elementAt(i)).y - ((Point) v.elementAt(i+1)).y) +
DYs[i] + DYs[i+1]); line(174);
}
return coefficients;
}
}
Users of Netscape Communicator 4.7 on the PC and Netscape on the Macintosh, please click here