Tutorials | (back to the list of tutorials) |
The following code is an example of creating a subclass. A keyword to define a subclass is "extends".
import processing.opengl.*; import igeo.*; void setup(){ // ... } static class MyRotatedModule extends MyModule{ // instance fields double rotationAngle; } static class MyModule{ // ... }
This code above defines a subclass named "MyRotatedModule", inheriting the superclass "MyModule". (This code skips the "setup()" method). The inheritance relationship is defined at the line of the class definition of the subclass, by adding "extends MyModule" after the class name of "MyRotatedModule". This subclass only adds one instance field of "double rotationAngle". This subclass doesn't have constructors yet. Constructors of subclass are described in the next section.
An example of constructors of a subclass is below.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyRotatedModule module1 = new MyRotatedModule(new IVec(0,0,0), 20, Math.PI/4); MyRotatedModule module2 = new MyRotatedModule(new IVec(50,0,0), Math.PI/4); } static class MyRotatedModule extends MyModule{ // instance fields double rotationAngle; // instance methods MyRotatedModule(IVec pos, double sz, double rotAngle){ super(pos, sz); rotationAngle = rotAngle; } MyRotatedModule(IVec pos, double rotAngle){ super(pos); rotationAngle = rotAngle; } } 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){ return pos.dup().add(IRandom.get(min,max),0,0); } static IVec randomYShift(IVec pos, double min, double max){ return pos.dup().add(0,IRandom.get(min,max),0); } // 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).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).add(0,0,armSize); boxes[2] = new IBox(armPos2, armSize, armLen, armSize); return boxes; } }
Actually it's natural to override a method by calling the same method in superclass and adding more codes to expand the behavior of the method because subclassing is conceptually expanding functionality. By overriding methods, behaviors of a class with same names of methods can be varied among classes having inheritance relationship. This feature of object-oriented programming is called "polymorphism".
The code below shows an example of overriding methods of the superclass.
import processing.opengl.*; import igeo.*; void setup(){ size(480, 360, IG.GL); MyRotatedModule module1 = new MyRotatedModule(new IVec(0,0,0), 20, PI/3); IBox box = module1.createModule(); box.clr(1.0,0,0); MyRotatedModule module2 = new MyRotatedModule(new IVec(50,0,0), PI/4); IBox[] boxes = module2.createModuleWithArm(5, 40); for(IBox bx : boxes){ bx.clr(0,0,1.0); } } static class MyRotatedModule extends MyModule{ // static fields static IVec rotationAxis = new IVec(0,0,1); // instance fields double rotationAngle; // instance methods MyRotatedModule(IVec pos, double sz, double rotAngle){ super(pos, sz); rotationAngle = rotAngle; } MyRotatedModule(IVec pos, double rotAngle){ super(pos); rotationAngle = rotAngle; } IBox createModule(){ IBox box = super.createModule(); box.rot(position, rotationAxis, rotationAngle); return box; } IBox[] createModuleWithArm(double armSize, double armLen){ IBox[] boxes=super.createModuleWithArm(armSize, armLen); for(IBox box : boxes){ box.rot(position, rotationAxis, rotationAngle); } return boxes; } } 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){ return pos.dup().add(IRandom.get(min,max),0,0); } static IVec randomYShift(IVec pos, double min, double max){ return pos.dup().add(0,IRandom.get(min,max),0); } // 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).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).add(0,0,armSize); boxes[2] = new IBox(armPos2, armSize, armLen, armSize); return boxes; } }
surface12.3dm is the input file used in the code.
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 MyRotatedModule(pt, 1.5, i*uinc*PI); 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 MyRotatedModule extends MyModule{ // static fields static IVec rotationAxis = new IVec(0,0,1); // instance fields double rotationAngle; // instance methods MyRotatedModule(IVec pos, double sz, double rotAngle){ super(pos, sz); rotationAngle = rotAngle; } MyRotatedModule(IVec pos, double rotAngle){ super(pos); rotationAngle = rotAngle; } IBox createModule(){ IBox box = super.createModule(); box.rot(position, rotationAxis, rotationAngle); return box; } IBox[] createModuleWithArm(double armSize, double armLen){ IBox[] boxes=super.createModuleWithArm(armSize, armLen); for(IBox box : boxes){ box.rot(position, rotationAxis, rotationAngle); } return boxes; } } 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; } }
For more description about class inheritance, please see Java's tutorial page on inheritance.