Tutorials | (back to the list of tutorials) |
import igeo.*; class MyModule{ IVec position; double size; }
This code above defines a class named "MyModule", containing several data. "class" is a keyword to define a class, followed by a name of the class. Usually name of a class starts with a capital letter.
In the following tutorial, some key topics of object-oriented programming are shown. For more comprehensive description about object-oriented programming, please see the Processing's tutorial and the Java tutorial.
import processing.opengl.*; import igeo.*; size(480, 360, IG.GL); MyModule module = new MyModule();
The defined class is used as a type in
declaration of a variable like
However, the code above alone doesn't work by itself. Those two codes above need to be combined. Before combining, there is one thing to prepare. Here we introduce new programming mode "continuous mode" in Processing, whereas what we were writing so far was called "basic mode". See this page at processing.org for more information about programming modes in Processing.
The code above is rewritten in "continuous mode" below.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module = new MyModule(); }
To write in "continuous mode", you need to put all the lines we were writing into "void setup(){" ... "}" except "import" statements.
Now we can combine the class definition with the main code and run the code in Processing without compile errors.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module = new MyModule(); } class MyModule{ IVec position; double size; }
When you run this code, it doesn't generate any geometry because we haven't define any behavior in the class yet.
You can access to the fields to read a value or to assign a value to by writing "." and the name of the field after the instance. See the example below.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module = new MyModule(); module.position = new IVec(0,0,0); module.size = 20.0; IG.p("size of module is "+module.size); } class MyModule{ // instance fields IVec position; double size; }
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module = new MyModule(new IVec(0,0,0), 20); } class MyModule{ // instance fields IVec position; double size; // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } }
You can also add multiple constructors with different input arguments. When you use one of constructors, you put a specific set of types of variables in the input arguments of the constructor.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module1 = new MyModule(new IVec(0,0,0), 20); MyModule module2 = new MyModule(new IVec(50,0,0)); } class MyModule{ // instance fields IVec position; double size; // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } MyModule(IVec pos){ position = pos; size = 1.0; // default size } }
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module1 = new MyModule(new IVec(0,0,0), 20); module1.createModule(); MyModule module2 = new MyModule(new IVec(50,0,0)); module2.createModule(); } class MyModule{ // instance fields IVec position; double size; // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } MyModule(IVec pos){ position = pos; size = 10.0; } void createModule(){ new IBox(position, size); } }
In this example code, name of the method is
"createModule",
preceded by a keyword "void" which specifies that
this method has no return value, and followed by
"()" to specify that this method has no input argument.
This method is actually executed inside "setup()" method at the
line of
The following code is an example of an instance method with input arguments.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module1 = new MyModule(new IVec(0,0,0), 20); module1.createModule(); MyModule module2 = new MyModule(new IVec(50,0,0)); module2.createModuleWithArm(5, 40); } class MyModule{ // instance fields IVec position; double size; // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } MyModule(IVec pos){ position = pos; size = 10.0; // default size } void createModule(){ new IBox(position, size); } void createModuleWithArm(double armSize, double armLen){ new IBox(position, size); IVec armPos1 = position.dup().add(-armLen/2,0,0); armPos1.add(0,0,size); new IBox(armPos1, armLen, armSize, armSize); IVec armPos2 = armPos1.dup().add(armLen/2,-armLen/2,0); armPos2.add(0,0,armSize); new IBox(armPos2, armSize, armLen, armSize); } }
To set up input arguments, you declare a variable inside the parenthesis "()" after the method name and the declared variables can be used inside the method as input values passed from outside of the method.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module1 = new MyModule(new IVec(0,0,0), 20); IBox box = module1.createModule(); box.clr(1.0,0,0); MyModule module2 = new MyModule(new IVec(50,0,0)); IBox[] boxes = module2.createModuleWithArm(5, 40); for(IBox bx : boxes){ bx.clr(0,0,1.0); } } class MyModule{ // instance fields IVec position; double size; // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } MyModule(IVec pos){ position = pos; size = 10.0; // default size } IBox createModule(){ return new IBox(position, size); } IBox[] createModuleWithArm(double armSize, double armLen){ IBox[] boxes = new IBox[3]; boxes[0] = new IBox(position, size); IVec armPos1 = position.dup().add(-armLen/2, 0, 0); armPos1.add(0,0,size); boxes[1] = new IBox(armPos1, armLen, armSize, armSize); IVec armPos2 = armPos1.dup().add(armLen/2, -armLen/2, 0); armPos2.add(0,0,armSize); boxes[2] = new IBox(armPos2, armSize, armLen, armSize); return boxes; } }
To define a return value of a method, you first put the type of return value before the method name, instead of "void". Then inside the body of the method, you add a return statement with the keyword "return" and the variable containing the data you want to output at the end of the body.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module1 = new MyModule(new IVec(0,0,0), 20); IBox box = module1.createModule(); box.clr(1.0,0,0); MyModule module2 = new MyModule(new IVec(50,0,0)); IBox[] boxes = module2.createModuleWithArm(5, 40); for(IBox bx : boxes){ bx.clr(0,0,1.0); } IG.p("default size is " + MyModule.defaultSize); } static class MyModule{ // static fields static double defaultSize = 10.0; // instance fields IVec position; double size; // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } MyModule(IVec pos){ position = pos; size = defaultSize; } IBox createModule(){ return new IBox(position, size); } IBox[] createModuleWithArm(double armSize, double armLen){ IBox[] boxes = new IBox[3]; boxes[0] = new IBox(position, size); IVec armPos1 = position.dup().add(-armLen/2, 0, 0); armPos1.add(0,0,size); boxes[1] = new IBox(armPos1, armLen, armSize, armSize); IVec armPos2 = armPos1.dup().add(armLen/2, -armLen/2, 0); armPos2.add(0,0,armSize); boxes[2] = new IBox(armPos2, armSize, armLen, armSize); return boxes; } }
Inside the class you can access to static fields in the same way with instance fields but when you change the value, the change is reflected on all class instances which read the static field. Outside the class you can access to static fields by putting the class name and "." before the name of the field like "MyModule.defaultSize".
One detailed technical issue which beginners can ignore is the "static" keyword at the beginning of the class definition "class MyModule{". This issue happens when you write classes in a same file in Processing. In "continuous mode" in Processing, there is one thing hidden for convenience, which is the class definition of the sketch itself. Internally the whole sketch is inside a sketch class (this shows up in "Java mode") and classes written inside the same sketch are treated as inner classes inside the sketch class. To use static fields or static methods, an inner class needs to be a "static class". That's why there's the keyword "static" at the beginning of the class definition.
You can write classes outside of the sketch class if you create separate files with the file extension of ".java" in new tabs in Processing. For more information to write separate Java files in Processing, please see this page at processing.org.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyModule module1 = new MyModule(new IVec(0,0,0), 20); IBox box = module1.createModule(); box.clr(1.0,0,0); MyModule module2 = new MyModule(new IVec(50,0,0)); IBox[] boxes = module2.createModuleWithArm(5, 40); for(IBox bx : boxes){ bx.clr(0,0,1.0); } } static class MyModule{ // static fields static double defaultSize = 10.0; // instance fields IVec position; double size; // static methods static IVec randomXShift(IVec pos, double min, double max){ IVec shifted = pos.dup(); shifted.add(IRandom.get(min,max),0,0); return shifted; } static IVec randomYShift(IVec pos, double min, double max){ IVec shifted = pos.dup(); shifted.add(0,IRandom.get(min,max),0); return shifted; } // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } MyModule(IVec pos){ position = pos; size = defaultSize; } IBox createModule(){ return new IBox(position, size); } IBox[] createModuleWithArm(double armSize, double armLen){ IBox[] boxes = new IBox[3]; boxes[0] = new IBox(position, size); IVec armPos1 = randomXShift(position, -(armLen-size), 0); armPos1.add(0,0,size); boxes[1] = new IBox(armPos1, armLen, armSize, armSize); IVec armPos2 = randomXShift(armPos1, 0, armLen-size); armPos2 = randomYShift(armPos2, -(armLen-size), 0); armPos2.add(0,0,armSize); boxes[2] = new IBox(armPos2, armSize, armLen, armSize); return boxes; } }
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); IG.open("surface12.3dm"); ISurface[] surfaces = IG.surfaces(); int unum=40, vnum=40; double uinc=1.0/unum, vinc=1.0/vnum; for(ISurface surf : surfaces){ for(int i=0; i < unum; i++){ for(int j=0; j < vnum; j++){ IVec pt = surf.pt(i*uinc, j*vinc); MyModule module = new MyModule(pt, 1.5); if(IRandom.percent(50)){ IBox box = module.createModule(); box.clr(0.7,0,0); } else{ double armLength = IRandom.get(2,10); IBox[] boxes = module.createModuleWithArm(0.5,armLength); for(IBox bx:boxes){ bx.clr(IRandom.gray()); } } } } surf.del(); } } static class MyModule{ // static fields static double defaultSize = 10.0; // instance fields IVec position; double size; // static methods static IVec randomXShift(IVec pos, double min, double max){ IVec shifted = pos.dup(); shifted.add(IRandom.get(min,max),0,0); return shifted; } static IVec randomYShift(IVec pos, double min, double max){ IVec shifted = pos.dup(); shifted.add(0,IRandom.get(min,max),0); return shifted; } // instance methods MyModule(IVec pos, double sz){ position = pos; size = sz; } MyModule(IVec pos){ position = pos; size = defaultSize; } IBox createModule(){ return new IBox(position, size); } IBox[] createModuleWithArm(double armSize, double armLen){ IBox[] boxes = new IBox[3]; boxes[0] = new IBox(position, size); IVec armPos1 = randomXShift(position, -(armLen-size), 0); armPos1.add(0,0,size); boxes[1] = new IBox(armPos1, armLen, armSize, armSize); IVec armPos2 = randomXShift(armPos1, 0, armLen-size); armPos2 = randomYShift(armPos2, -(armLen-size), 0); armPos2.add(0,0,armSize); boxes[2] = new IBox(armPos2, armSize, armLen, armSize); return boxes; } }
import processing.opengl.*; import igeo.*; size( 480, 360, IG.GL ); IG.open("surface1.3dm"); //input geometry from 3dm file ISurface[] surfs = IG.surfaces(); for( ISurface surf : surfs ){ int unum = 8, vnum = 8; double uinc = 1.0/unum, vinc = 1.0/vnum; for(int i=0; i < unum; i++){ for(int j=0; j < vnum; j++){ IVec pt11 = surf.pt( i*uinc, j*vinc ); IVec pt21 = surf.pt( (i+1)*uinc, j*vinc ); IVec pt12 = surf.pt( i*uinc, (j+1)*vinc ); IVec pt22 = surf.pt( (i+1)*uinc, (j+1)*vinc ); new ISurface(pt11,pt21,pt22).clr(i*uinc,0,j*vinc); new ISurface(pt22,pt12,pt11).clr(1-i*uinc,1-j*vinc,1); double depth = -2; IVec spt11 = surf.pt(i*uinc, j*vinc, depth); IVec spt21 = surf.pt((i+1)*uinc, j*vinc, depth); IVec spt12 = surf.pt(i*uinc, (j+1)*vinc, depth); IVec spt22 = surf.pt((i+1)*uinc, (j+1)*vinc, depth); double frameSize = 0.2; IG.squarePipe(new IVec[]{spt11, spt21, spt22, spt12}, 1, true, frameSize); double radius = 0.1; new ICylinder(pt11,spt11,radius); new ICylinder(pt21,spt21,radius); new ICylinder(pt12,spt12,radius); new ICylinder(pt22,spt22,radius); } } surf.del(); }
The code above is re-written with a class "MyPanel" below.
Note that the code below creates frames overlapping
with adjacent frames due to the simplicity of the tutorial code.
import processing.opengl.*; import igeo.*; void setup(){ size( 480, 360, IG.GL ); IG.open("surface1.3dm"); //input geometry from 3dm file ISurface[] surfs = IG.surfaces(); for( ISurface surf : surfs ){ int unum = 8, vnum = 8; double uinc = 1.0/unum, vinc = 1.0/vnum; for(int i=0; i < unum; i++){ for(int j=0; j < vnum; j++){ double depth = -2; MyPanel panel = new MyPanel(surf.pt(i*uinc, j*vinc), surf.pt((i+1)*uinc, j*vinc), surf.pt(i*uinc, (j+1)*vinc), surf.pt((i+1)*uinc, (j+1)*vinc), surf.pt(i*uinc, j*vinc, depth), surf.pt((i+1)*uinc, j*vinc, depth), surf.pt(i*uinc, (j+1)*vinc, depth), surf.pt((i+1)*uinc,(j+1)*vinc,depth)); panel.createPanel(i*uinc, 0, j*vinc, 1-i*uinc, 1-j*vinc, 1); } } surf.del(); } } static class MyPanel{ // static field static double frameSize = 0.2; static double connectionRadius = 0.1; // instance field IVec pt11,pt21,pt12,pt22; IVec spt11,spt21,spt12,spt22; MyPanel(IVec p11, IVec p21, IVec p12, IVec p22, IVec s11, IVec s21, IVec s12, IVec s22){ pt11 = p11; pt21 = p21; pt12 = p12; pt22 = p22; spt11 = s11; spt21 = s21; spt12 = s12; spt22 = s22; } void createPanel(double red1, double green1, double blue1, double red2, double green2, double blue2){ new ISurface(pt11,pt21,pt22).clr(red1,green1,blue1); new ISurface(pt22,pt12,pt11).clr(red2,green2,blue2); IG.squarePipe(new IVec[]{ spt11,spt21,spt22,spt12 }, 1, true, frameSize); new ICylinder(pt11,spt11,connectionRadius); new ICylinder(pt21,spt21,connectionRadius); new ICylinder(pt12,spt12,connectionRadius); new ICylinder(pt22,spt22,connectionRadius); } }