101

Appendix I: Smart Objects Two Venturi Example Java Code

/* Smart Objects Applet Two by Dustin Eggink, Annotated October 24 2001.

This implementation of Smart Objects utilizes a Cassowary solver to manage constraints

asserted within this code. The constraints relate to a VRML model of the Vanna Venturi

House by Robert Venturi. */

package VannaCass; // MUST BE COMPILED IN A FOLDER NAMED "VannaCass" THAT

// CONTAINS ALL SMART OBJECTS FILES.

////////////////////////////IMPORTS/////////////////////

//// JAVA IMPORTS

import java.awt.*;

import java.applet.*;

import java.util.Vector;

//// VRML IMPORTS

import vrml.external.field.EventOut;

import vrml.external.field.EventOutSFVec3f;

import vrml.external.field.EventOutObserver;

import vrml.external.Node;

import vrml.external.Browser;

import vrml.external.exception.*;

import vrml.external.field.EventInSFVec3f;

import vrml.external.field.EventOutSFBool;

import vrml.external.field.EventOutMFVec3f;

import vrml.external.field.EventInSFColor;

import vrml.external.field.EventOutSFColor;

import vrml.external.field.EventInSFFloat;

import vrml.external.field.EventOutSFFloat;

//// CASSOWARY IMPORT

import CassEggink.*;

////////////////////CLASS///////////////////////////////

public class SmartObjectsTwo extends Applet implements EventOutObserver

{

TextArea output = null;

Browser browser = null;

ObjCons fo[]; // "ObjCons" CLASS INSTANCES WILL BE USED

ObjCons so[]; // AS POINTS TO BE CONSTRAINED

ObjCons co[];

int xx; // VARIABLES FOR HELP ALONG THE WAY

int num;

int k;

int q;

int i;

int p;

int c1;

int c2;

ClPoint center; // A CASSOWARY POINT "CENTER"

ClSimplexSolver solver; // CALLING UP THE CASSOWARY SOLVER "SOLVER"

ClLinearEquation lineq[][]; // ONE TYPE OF CONSTRAINT

ClLinearInequality linin[][]; // SECOND TYPE OF CONSTRAINT

float tx, ty, tz;

float cx, cy, cz;

/////THE FOLLOWING SERIES OF FLOAT ARRAYS WILL BE USED TO DRAW THE /////

/////PLAN OF THE MODEL IN THE JAVA WINDOW. /////

float[] x0 = new float[19]; // THE X OF THE FIRST POSITION IN THE POINT NODE

// OF THE VRML

float[] z0 = new float[19]; // OBJECT THE Z OF THE SAME, NOTE THAT Y IN

// VRML IS HEIGHT,

float[] x1 = new float[19]; // SO THE Z VALUE MUST BE USED FOR THE PLAN

float[] z1 = new float[19];

float[] x2 = new float[19];

float[] z2 = new float[19];

float[] x3 = new float[19];

float[] z3 = new float[19];

float[] re = new float[38]; // RED

float[] gr = new float[38]; // GREEN

float[] bl = new float[38]; // BLUE

float[] op = new float[38]; // OPACITY

float[] colV = new float[3]; // THE COLORS COMING OUT OF VRML

float[] colC = new float[3]; // THE COLORS COMING OUT OF CASSOWARY

float opaV; // THE TRANSPARENCY COMING OUT OF VRML

float opaC; // THE TRANSPARENCY COMING OUT OF CASSOWARY

float[] traV = new float[3]; // THE COORDINATES COMING OUT OF VRML

float[] traC = new float[3]; // THE COORDINATES COMING OUT OF CASSOWARY

float[] sclC = new float[3]; // THE SCALE COMING OUT OF CASSOWARY

float[][] ptsV = new float[8][3];

Node[] ptsN = new Node[19];

Node[] movN = new Node[19];

Node[] touN = new Node[19];

Node[] objN = new Node[19];

Node[] matN = new Node[38];

EventOutMFVec3f[] pointG = new EventOutMFVec3f[19];

EventOutSFBool[] touch = new EventOutSFBool[19];

EventOutSFBool[] activeG = new EventOutSFBool[19];

EventOutSFVec3f[] translateG = new EventOutSFVec3f[19];

EventInSFVec3f[] translateS = new EventInSFVec3f[19];

EventInSFVec3f[] scaleS = new EventInSFVec3f[19];

EventInSFColor[] colorS = new EventInSFColor[38];

EventOutSFColor[] colorG = new EventOutSFColor[38];

EventInSFFloat[] opacityS = new EventInSFFloat[38];

EventOutSFFloat[] opacityG = new EventOutSFFloat[38];

boolean error = false;

boolean actTest = false;

boolean hit = false;

////////////////////INITS/////////////////////////////

public void init()

{

background();

add(new Button("Get Numbers"));

add(new Button("X=Z"));

add(new Button("X=Y"));

add(new Button("X=X"));

add(new Button("Y=Y"));

add(new Button("Remove C's"));

output = new TextArea(10, 15);

add(output);

setLayout(new FlowLayout(FlowLayout.LEFT,30,5));

solver = new ClSimplexSolver();

fo = new ObjCons[38];

so = new ObjCons[13];

co = new ObjCons[19];

lineq = new ClLinearEquation[38][38]; // AN ARRAY OF ARRAYS OF CONSTRAINT

linin = new ClLinearInequality[38][38]; // TYPES ARE CREATED BECAUSE ANY

// CONSTRAINT THAT ONE MAY WISH TO

// REMOVE MUST BE SPECIFICALLY NAMED.

k = 1;

q = 0;

c1 = -1;

c2 = -2;

num = 1;

express();

}

////////////////////////////

public void express(){

int a;

/* THIS IS SUPPOSED TO ESTABLISH A HIERARCHY IN CASSOWARY WHERE "FO's" ARE THE STRONGEST, THEN "SO'S" AND "CO'S". SO'S ARE THE MOST PROMINENT PARTS OF THE MODEL (WALLS, STAIRWELL, CHIMNEY), SB'S ARE THE REST OF THE MODELED OBJECTS, AND CO'S ARE THE COLORS.

FO=First Objects, SO=Second Objects, CO= Color Objects */

for ( a = 0; a < 38; a++ )

fo[a] = new ObjCons(a);

for ( a = 0; a < 13; a++ )

so[a] = fo[a+6];

for ( a = 0; a < 19; a++ )

co[a] = fo[a+19];

fo[0].SetCenter(0, 0, 0); // THIS IS SPECIFICALLY WHERE THE

fo[1].SetCenter(0, 0, 0); // STRONGEST OBJECTS ARE GIVEN STRENGTH.

fo[2].SetCenter(0, 0, 0);

fo[3].SetCenter(0, 0, 0);

fo[4].SetCenter(0, 0, 0);

fo[5].SetCenter(0, 0, 0);

try {

solver.addPointStay(fo[0].CenterPt(), 1.0);

solver.addPointStay(fo[1].CenterPt(), 2.0);

solver.addPointStay(fo[2].CenterPt(), 4.0);

solver.addPointStay(fo[3].CenterPt(), 8.0);

solver.addPointStay(fo[4].CenterPt(), 16.0);

solver.addPointStay(fo[5].CenterPt(), 32.0);

ClLinearExpression cla;

ClLinearExpression cle;

solver.addConstraint(new ClLinearInequality(so[1].Z(), CL.LEQ, 1));

solver.addConstraint(new ClLinearInequality(so[1].Z(), CL.GEQ, -.5));

/////SIDEWALL LIMITS

solver.addConstraint(new ClLinearInequality(so[1].X(), CL.LEQ, 1.7));

solver.addConstraint(new ClLinearInequality(so[1].X(), CL.GEQ, -3.48));

//////FACADE HALVES CONSTRAINTS - OPPOSITE IN X, SAME IN Y

cle = new ClLinearExpression(fo[4].Y());

lineq[4][5] = new ClLinearEquation(fo[5].Y(), cle);

solver.addConstraint(lineq[4][5]);

cle = new ClLinearExpression(fo[4].X());

cle = CL.Minus(0,cle);

solver.addConstraint(new ClLinearEquation(fo[5].X(), cle));

//////WINDOW HEIGHT CONSTRAINTS

cle = new ClLinearExpression(so[7].Y());

solver.addConstraint(new ClLinearEquation(so[8].Y(), cle));

cle = new ClLinearExpression(so[8].Y());

solver.addConstraint(new ClLinearEquation(so[9].Y(), cle));

cle = new ClLinearExpression(so[9].Y());

solver.addConstraint(new ClLinearEquation(so[10].Y(), cle));

cle = new ClLinearExpression(so[10].Y());

solver.addConstraint(new ClLinearEquation(so[11].Y(), cle));

cle = new ClLinearExpression(so[11].Y());

solver.addConstraint(new ClLinearEquation(so[12].Y(), cle));

solver.addConstraint(new ClLinearInequality(so[12].Y(), CL.LEQ, .13));

solver.addConstraint(new ClLinearInequality(so[12].Y(), CL.GEQ, -.16));

//////WINDOW WITH WALL MOVEMENTS

cle = new ClLinearExpression(fo[5].X());

solver.addConstraint(new ClLinearEquation(so[7].X(), cle));

cle = new ClLinearExpression(so[7].X());

solver.addConstraint(new ClLinearEquation(so[9].X(), cle));

cle = new ClLinearExpression(so[9].X());

solver.addConstraint(new ClLinearEquation(so[10].X(), cle));

cle = new ClLinearExpression(so[10].X());

solver.addConstraint(new ClLinearEquation(so[11].X(), cle));

cle = new ClLinearExpression(so[11].X());

solver.addConstraint(new ClLinearEquation(so[12].X(), cle));

//////BATHROOM WINDOW MOVES WITH WEST WALL

cle = new ClLinearExpression(fo[4].X());

solver.addConstraint(new ClLinearEquation(so[8].X(), cle));

}

catch (ExCLInternalError e) {}

catch (ExCLRequiredFailure e) {}

}

////////////////////////SUPERs////////////////////////////////

public SmartObjectsTwo() // SAME NAME AS THE FILE AND CLASS NAME

{ super(); }

/////////////////////////START start here////////////////////////

public void start()

{

try

{

java.lang.Thread.sleep(200);

}

catch(InterruptedException e){}

try

{

while (browser==null)

{browser=(Browser)vrml.external.Browser.getBrowser(this);}

for (int q = 0; q < 38; q++) // "FOR" LOOPS ALL THE NODES TO THE "CALLBACK"

/* THE NAMING TRICK- IN ORDER TO AVOID CALLING OUT EVERY NODE IN THE VRML WORLD ONE MAY WISH TO CONSTRAIN, ALL THE NODES IN THE VRML FILE ARE NAMED SIMILARILY WITH THEIR OBJECT NUMBER ADDED TO THE END (MOBJ0, MOBJ1, MOBJ2...). COMBINED WITH A FOR LOOP, ALL NODES CAN BE GRABBED IN A SINGLE CALL. THE ONE ALTERATION WAS TO IDENTIFY COLORS AS THERE OWN OBJECTS; WHEN THE LOOP HITS 18, IT STOPS LOOKING FOR BLOCK OBJECT NODES, AND STARTS GRABBING COLOR NODES, WHICH HAVE BEEN NAMED SIMILARILY IN THE VRML FILE STARTING AT NUMBER 19. THE COLOR THAT A BLOCK OBJECT USES CAN BE FOUND BY ADDING 19

TO THE BLOCK'S NUMBER. */

{

if (q < 19) {

///// THESE NODES ARE ASSOCIATED WITH OBJECT TRANSLATION

movN[q] = browser.getNode("MOBJ" + q);

translateG[q] = (EventOutSFVec3f) movN[q].getEventOut("translation_changed");

translateG[q].advise(this, new Integer(q));

touN[q] = browser.getNode("TOBJ" + q);

activeG[q] = (EventOutSFBool) touN[q].getEventOut("isActive");

activeG[q].advise(this, new Integer(q));

objN[q] = browser.getNode("OBJ" + q);

translateS[q] = (EventInSFVec3f) objN[q].getEventIn("set_translation");

scaleS[q] = (EventInSFVec3f) objN[q].getEventIn("set_scale");

ptsN[q] = browser.getNode("COBJ" + q);

pointG[q] = (EventOutMFVec3f) ptsN[q].getEventOut("point");

}

else if ((q > 18) & (q < 38)) {

///// THESE NODES ARE ASSOCIATED WITH COLOR VALUES

matN[q] = browser.getNode("MAT" + q);

colorG[q] = (EventOutSFColor) matN[q].getEventOut("diffuseColor");

colorS[q] = (EventInSFColor) matN[q].getEventIn("set_diffuseColor");

opacityG[q] = (EventOutSFFloat) matN[q].getEventOut("transparency");

opacityS[q] = (EventInSFFloat) matN[q].getEventIn("set_transparency");

}

}

}

catch (InvalidNodeException ne) {

add(new TextField("Failed to get node:" + ne));

error = true; }

catch (InvalidEventInException ee) {

add(new TextField("Failed to get EventIn:" + ee));

error = true; }

catch (InvalidEventOutException ee) {

add(new TextField("Failed to get EventOut:" + ee));

error = true; }

}

////////////////////////////////NUMBERS FROM VRML/////////////////////////////

public void getNumbers ()

{

// A FUNCTION FOR GRABBING OBJECT "A" POINT COORDINATES AND

// COLOR VALUES FROM THE VRML WORLD, FOR THE PLAN VIEW

// same loop as in the start method

if (num == 1) {

for (int a=0; a<18; a++) {

ptsV = pointG[a].getValue();

x0[a] = ptsV[0][0]; // THE X OF THE FIRST POINT IN THE COORD LIST

z0[a] = ptsV[0][2]; // THE Z

x1[a] = ptsV[1][0]; // THE X OF THE SECOND

z1[a] = ptsV[1][2];

x2[a] = ptsV[2][0];

z2[a] = ptsV[2][2];

x3[a] = ptsV[3][0];

z3[a] = ptsV[3][2]; }

for (int a=19; a<38; a++) {

colV = colorG[a].getValue();

opaV = opacityG[a].getValue();

re[a] = colV[0]; // THE RED VALUE OF MATERIAL "A"

gr[a] = colV[1]; // GREEN

bl[a] = colV[2]; // BLUE

op[a] = opaV; } // THE OPACITY OF THE MATERIAL

output.appendText("got nums"+"\n");

num = 2; ) //SET "NUM" TO 2 SO THE FUNCTION HAPPENS ONCE.

}

///////////////////////CALLBACK start here////////////////////

public void callback(EventOut who, double where, Object which)

{

Integer whichNum = (Integer) which;

q = whichNum.intValue();

traV = translateG[q].getValue();

tx = traV[0];

ty = traV[1];

tz = traV[2];

actTest = activeG[q].getValue(); // "ACTTEST" HAPPENS WHEN YOU CLICK

acts (tx, ty, tz); // DOWN ON AN OBJECT IN THE VRML WORLD

}

//////////////////FUNCTIONS start here//////////////////

public boolean acts (float cx, float cy, float cz)

{

if (actTest == true)

{

xx = q;

if ( xx != -1 ) {

if (k == 1) // K IS 1 TO ALLOW CASSOWARY TO START

{

try {

k = (k + 1); // ADD 1 TO K SO THE CASSOWARY DOESN'T JUST KEEP STARTING

/* FIVE THINGS HAVE TO HAPPEN IN CASSOWARY (SOLVER) "addEditVar", "beginEdit", "suggestValue", "resolve", "endEdit". DO NOT MESS WITH THIS SEQUENCE */

solver

.addEditVar(fo[xx].X()) // add the variables

.addEditVar(fo[xx].Y())

.addEditVar(fo[xx].Z())

.beginEdit(); // begin the editing

}

catch (ExCLInternalError ex) {}

}

if (k != 1) // K IS NO LONGER EQUAL TO 1, SO DO THIS NEXT

{

try

{

solver

.suggestValue(fo[xx].X(),cx)

.suggestValue(fo[xx].Y(),cy)

.suggestValue(fo[xx].Z(),cz)

.resolve();

}

catch (ExCLInternalError ex) {}

catch (ExCLError ex) {}

fix();

repaint();

}

}

}

else // "ELSE" HAPPENS WHEN THE MOUSE CLICK IS REMOVED FROM THE VRML OBJECT

{

try

{

solver.endEdit();

fix(); // "FIX" EXPLAINED LATER, SENDS THE CASSOWARY VALUES TO THE VRML

repaint();

}

catch (ExCLInternalError ex) {}

k = 1; // SET K BACK TO 1 SO THE NEXT OBJECT CAN BE CONSTRAINED

}

return true;

}

///////////////////////////////////

public void fix ()

{

getNumbers();

for ( int i = 0; i < 38; a++ ){

fo[i].cvt(); // "CVT" IS A CONVERSION FUNCTION IN ObjCons THAT CONVERTS

// THE NUMBERS RETURNED BY CASSOWARY INTO FLOATS.

if (i<19) { posChange(i); sclChange(i); // CHANGE THE POSITION OF THE FIRST 19

// OBJECTS

}

else if (i>18) { colChange(i); } // CHANGE THE VALUE OF THE LAST 19 OBJECTS (THE COLORS)

}

}

//////////////////////////////////

public void posChange (int a)

{

//////// "sx, sy, sz" - COORDINATE DESIGNATIONS FROM THE ObjCons CLASS.

traC[0] = fo[a].sx;

traC[1] = fo[a].sy;

traC[2] = fo[a].sz;

translateS[a].setValue(traC);

}

//////////////////////////////////

public void colChange (int a)

{

colC[0] = re[a] + Math.abs(fo[a].sx)/3; // A SCALING MOVE TO GIVE A LITTLE MORE PLAY

colC[1] = gr[a] + Math.abs(fo[a].sx)/3; // BEFORE HITTING THE ABSOLUTE VALUES (0 OR 1)

colC[2] = bl[a] + Math.abs(fo[a].sx)/3;

opaC = op[a] + Math.abs(fo[a].sy)/10;

//////////////////// "IF" STATEMENTS TO KEEP THE VALUES OF THE COLORS AND

//////////////////// TRANSPARENCY BETWEEN 0 AND 1

if ((colC[0] > 1) || (colC[0] < 0)) { colC[0] = 1.0f; }

if ((opaC > 1) || (opaC < 0)) { opaC = 1.0f; }

if ((opaC > -.01) & (opaC < .01)) { opaC = 0.0f; }

colorS[a].setValue(colC);

opacityS[a].setValue(opaC);

}

/////////////////////////////////

public void sclChange (int a)

{

///// ONLY DEALING WITH SCALE CHANGES IN OBJECTS 3 AND 4, CONSTRAINING SCALES

//// HAS NOT YET EFFECTIVELY WORKED OUT, THIS IS A WORK AROUND.

if (a == 3) {

sclC[0] = 1.0f + fo[a].sy/6;

sclC[1] = 1.0f + fo[a].sy/6;

sclC[2] = 1.0f;

scaleS[11].setValue(sclC); }

else if (a == 4) {

sclC[0] = 1.0f - fo[a].sx/3;

sclC[1] = 1.0f + fo[a].sy/3;

sclC[2] = 1.0f + fo[a].sz/3;

scaleS[12].setValue(sclC); }

}

////////////////////////////STATICS////////////////////////

public static void main(String[] argv) {

System.err.println("Run using `appletviewer quaddemo.htm'");

}

//////////////BUTTONS FOR SETTING CONSTRAINTS////////////////

public boolean action(Event event, Object what)

{

if (error)

{

showStatus("Problems! Had an error during initialization");

return true;

}

if (event.target instanceof Button)

{

Button b = (Button) event.target;

if (b.getLabel() == "X=Z") // PROCESS FOR ADDING "X=Z" CONSTRAINT

{

showStatus("X=Z");

output.appendText("Trying Constraint X=Z \n");

if ((c1 != -1) & (c2 != -1))

{

try {

ClLinearExpression cle;

cle = new ClLinearExpression(fo[c1].X());

lineq[c1][c2] = new ClLinearEquation(fo[c2].Z(), cle);

solver.addConstraint(lineq[c1][c2]);

}

catch (ExCLInternalError e) {}

catch (ExCLRequiredFailure e) {}

output.appendText("Constraint Added: X of Object"+ c1 +" = Z of Object"+ c2 + "\n");

}

}

else if (b.getLabel() == "X=Y") // PROCESS FOR ADDING "X=Y" CONSTRAINT

{

showStatus("X=Y");

output.appendText("Trying Constraint X=Y \n");

if ((c1 != -1) & (c2 != -1))

{

try {

ClLinearExpression cle;

cle = new ClLinearExpression(fo[c1].X());

lineq[c1][c2] = new ClLinearEquation(fo[c2].Y(), cle);

solver.addConstraint(lineq[c1][c2]);

}

catch (ExCLInternalError e) {}

catch (ExCLRequiredFailure e) {}

output.appendText("Constraint Added: X of Object"+ c1 +" = Y of Object"+ c2 + "\n");

}

}

else if (b.getLabel() == "X=X") // PROCESS FOR ADDING "X=X" CONSTRAINT

{

showStatus("X=X");

output.appendText("Trying Constraint X=X \n");

if ((c1 != -1) & (c2 != -1))

{

try {

ClLinearExpression cle;

cle = new ClLinearExpression(fo[c1].X());

lineq[c1][c2] = new ClLinearEquation(fo[c2].X(), cle);

solver.addConstraint(lineq[c1][c2]);

}

catch (ExCLInternalError e) {}

catch (ExCLRequiredFailure e) {}

output.appendText("Constraint Added: X of Object"+ c1 +" = X of Object"+ c2 + "\n");

}

}

else if (b.getLabel() == "Y=Y") // PROCESS FOR ADDING "Y=Y" CONSTRAINT

{

showStatus("Y=Y");

output.appendText("Trying Constraint Y=Y \n");

if ((c1 != -1) & (c2 != -1))

{

try {

ClLinearExpression cle;

cle = new ClLinearExpression(fo[c1].Y());

lineq[c1][c2] = new ClLinearEquation(fo[c2].Y(), cle);

solver.addConstraint(lineq[c1][c2]);

}

catch (ExCLInternalError e) {}

catch (ExCLRequiredFailure e) {}

output.appendText("Constraint Added: Y of Object"+ c1 +" = Y of Object"+ c2 + "\n");

}

}

else if (b.getLabel() == "Remove C's")

{

showStatus("Remove C's");

output.appendText("Removing Constraints \n");

try {

solver.removeConstraint(lineq[c1][c2]); }

catch (ExCLInternalError e) {

System.out.println("AlignConstr.remConstr: ExCLInternalError "); }

catch (ExCLConstraintNotFound e) {

System.out.println("AlignConstr.remConstr: ExCLConstraintNotFound "); }