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 "); }