Python Tutorials | (back to the list of tutorials) |
Class Definition (requires iGeo version 7.3.1 or higher)![]()
![]()
![]()
add_library('igeo')
class MyModule :
def __init__(self) :
self.position = IVec(0,0,0)
self.size = 1.0
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.
Class Instance![]()
![]()
![]()
add_library('igeo')
size(480, 360, IG.GL)
module = 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.
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module = 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.
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module = MyModule()
class MyModule :
def __init__(self) :
self.position = IVec(0,0,0)
self.size = 1.0
When you run this code, it doesn't generate any geometry because we haven't define any behavior in the class yet.
Instance FieldYou 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.
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module = MyModule()
module.position = IVec(0,0,0)
module.size = 20.0
print("size of module is "+str(module.size))
class MyModule :
# instance fields
def __init__(self) :
self.position = IVec(0,0,0)
self.size = 1.0
Class Constructor![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module = MyModule(IVec(0,0,0), 20)
class MyModule :
# instance methods
def __init__(self, pos, sz) :
self.position = pos
self.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.
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module1 = MyModule(IVec(0,0,0), 20)
module2 = MyModule(IVec(50,0,0))
class MyModule :
# instance methods
def __init__(self, pos, sz=1.0) : # default size
self.position = pos
self.size = sz
Instance Method![]()
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module1 = MyModule(IVec(0,0,0), 20)
module1.createModule()
module2 = MyModule(IVec(50,0,0))
module2.createModule()
class MyModule :
# instance methods
def __init__(self, pos, sz=10.0) :
self.position = pos
self.size = sz
def createModule(self) :
IBox(self.position, self.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.
![]()
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module1 = MyModule(IVec(0,0,0), 20)
module1.createModule()
module2 = MyModule(IVec(50,0,0))
module2.createModuleWithArm(5, 40)
class MyModule :
# instance methods
def __init__(self,pos, sz=10.0) :
self.position = pos;
self.size = sz;
def createModule(self) :
IBox(self.position, self.size)
def createModuleWithArm(self, armSize, armLen) :
IBox(self.position, self.size)
armPos1 = self.position.dup().add(-armLen/2,0,0)
armPos1.add(0,0,self.size)
IBox(armPos1, armLen, armSize, armSize)
armPos2 = armPos1.dup().add(armLen/2,-armLen/2,0)
armPos2.add(0,0,armSize)
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.
Method with A Return Value![]()
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module1 = MyModule(IVec(0,0,0), 20)
box = module1.createModule()
box.clr(1.0,0,0)
module2 = MyModule(IVec(50,0,0))
boxes = module2.createModuleWithArm(5, 40)
for bx in boxes :
bx.clr(0,0,1.0)
class MyModule :
# instance methods
def __init__(self, pos, sz = 10) :
self.position = pos
self.size = sz
def createModule(self) :
return IBox(self.position, self.size)
def createModuleWithArm(self, armSize, armLen) :
boxes = []
boxes.append(IBox(self.position, self.size))
armPos1 = self.position.dup().add(-armLen/2, 0, 0)
armPos1.add(0,0,self.size)
boxes.append(IBox(armPos1, armLen, armSize, armSize))
armPos2 = armPos1.dup().add(armLen/2, -armLen/2, 0)
armPos2.add(0,0,armSize)
boxes.append(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.
Static Field![]()
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module1 = MyModule(IVec(0,0,0), 20)
box = module1.createModule()
box.clr(1.0,0,0)
module2 = MyModule(IVec(50,0,0))
boxes = module2.createModuleWithArm(5, 40)
for bx in boxes :
bx.clr(0,0,1.0)
print("default size is " + str(MyModule.defaultSize))
class MyModule :
# static field (not with "self.")
defaultSize = 10.0
# instance methods
def __init__(self, pos, sz = defaultSize) :
self.position = pos
self.size = sz
print(MyModule.defaultSize)
def createModule(self) :
return IBox(self.position, self.size)
def createModuleWithArm(self, armSize, armLen) :
boxes = []
boxes.append(IBox(self.position, self.size))
armPos1 = self.position.dup().add(-armLen/2, 0, 0)
armPos1.add(0,0,self.size)
boxes.append(IBox(armPos1, armLen, armSize, armSize))
armPos2 = armPos1.dup().add(armLen/2, -armLen/2, 0)
armPos2.add(0,0,armSize)
boxes.append(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.
Static Method![]()
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
module1 = MyModule(IVec(0,0,0), 20)
box = module1.createModule()
box.clr(1.0,0,0)
module2 = MyModule(IVec(50,0,0))
boxes = module2.createModuleWithArm(5, 40)
for bx in boxes :
bx.clr(0,0,1.0)
class MyModule :
# static fields
defaultSize = 10.0
# static methods
@staticmethod
def randomXShift(pos, min, max) :
shifted = pos.dup()
shifted.add(IRand.get(min,max),0,0)
return shifted
@staticmethod
def randomYShift(pos, min, max) :
shifted = pos.dup()
shifted.add(0,IRand.get(min,max),0)
return shifted
# instance methods
def __init__(self, pos, sz=defaultSize) :
self.position = pos
self.size = sz
def createModule(self) :
return IBox(self.position, self.size)
def createModuleWithArm(self, armSize, armLen) :
boxes = []
boxes.append(IBox(self.position, self.size))
armPos1 = MyModule.randomXShift(self.position, -(armLen-self.size), 0)
armPos1.add(0,0,self.size)
boxes.append(IBox(armPos1, armLen, armSize, armSize))
armPos2 = MyModule.randomXShift(armPos1, 0, armLen-self.size)
armPos2 = MyModule.randomYShift(armPos2, -(armLen-self.size), 0)
armPos2.add(0,0,armSize)
boxes.append(IBox(armPos2, armSize, armLen, armSize))
return boxes
Use of Class in Other Algorithms![]()
![]()
![]()
![]()
add_library('igeo')
def setup() :
size(480, 360, IG.GL)
IG.open("surface12.3dm")
surfaces = IG.surfaces()
unum=40
vnum=40
uinc=1.0/unum
vinc=1.0/vnum
for surf in surfaces :
for i in range(unum) :
for j in range(vnum) :
pt = surf.pt(i*uinc, j*vinc)
module = MyModule(pt, 1.5)
if IRand.pct(50) :
box = module.createModule()
box.clr(0.7,0,0)
else :
armLength = IRand.get(2,10)
boxes = module.createModuleWithArm(0.5,armLength)
for bx in boxes :
bx.clr(IRand.gray())
surf.del()
class MyModule :
# static fields
defaultSize = 10.0
# static methods
@staticmethod
def randomXShift(pos, min, max) :
shifted = pos.dup()
shifted.add(IRand.get(min,max),0,0)
return shifted
@staticmethod
def randomYShift(pos, min, max) :
shifted = pos.dup()
shifted.add(0,IRand.get(min,max),0)
return shifted
# instance methods
def __init__(self, pos, sz=defaultSize) :
self.position = pos
self.size = sz
def createModule(self) :
return IBox(self.position, self.size)
def createModuleWithArm(self, armSize, armLen) :
boxes = []
boxes.append(IBox(self.position, self.size))
armPos1 = MyModule.randomXShift(self.position, -(armLen-self.size), 0)
armPos1.add(0,0,self.size)
boxes.append(IBox(armPos1, armLen, armSize, armSize))
armPos2 = MyModule.randomXShift(armPos1, 0, armLen-self.size)
armPos2 = MyModule.randomYShift(armPos2, -(armLen-self.size), 0)
armPos2.add(0,0,armSize)
boxes.append(IBox(armPos2, armSize, armLen, armSize))
return boxes
Comparison of Code with/without Class![]()
![]()
![]()
![]()
add_library('igeo')
size( 480, 360, IG.GL )
IG.open("surface1.3dm") #input geometry from 3dm file
surfs = IG.surfaces()
for surf in surfs :
unum = 8
vnum = 8
uinc = 1.0/unum
vinc = 1.0/vnum
for i in range(unum) :
for j in range(vnum) :
pt11 = surf.pt( i*uinc, j*vinc )
pt21 = surf.pt( (i+1)*uinc, j*vinc )
pt12 = surf.pt( i*uinc, (j+1)*vinc )
pt22 = surf.pt( (i+1)*uinc, (j+1)*vinc )
ISurface(pt11,pt21,pt22).clr(i*uinc,0,j*vinc)
ISurface(pt22,pt12,pt11).clr(1-i*uinc,1-j*vinc,1)
depth = -2
spt11 = surf.pt(i*uinc, j*vinc, depth)
spt21 = surf.pt((i+1)*uinc, j*vinc, depth)
spt12 = surf.pt(i*uinc, (j+1)*vinc, depth)
spt22 = surf.pt((i+1)*uinc, (j+1)*vinc, depth)
frameSize = 0.2
IG.squarePipe([spt11, spt21, spt22, spt12], 1, True, frameSize)
radius = 0.1
ICylinder(pt11,spt11,radius)
ICylinder(pt21,spt21,radius)
ICylinder(pt12,spt12,radius)
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.
![]()
![]()
![]()
![]()
add_library('igeo')
def setup() :
size( 480, 360, IG.GL )
IG.open("surface1.3dm") #input geometry from 3dm file
surfs = IG.surfaces()
for surf in surfs :
unum = 8
vnum = 8
uinc = 1.0/unum
vinc = 1.0/vnum
for i in range(unum) :
for j in range(vnum) :
depth = -2
panel = \
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()
class MyPanel :
# static field
frameSize = 0.2
connectionRadius = 0.1
def __init__(self,p11,p21,p12,p22,s11,s21,s12,s22) :
self.pt11 = p11
self.pt21 = p21
self.pt12 = p12
self.pt22 = p22
self.spt11 = s11
self.spt21 = s21
self.spt12 = s12
self.spt22 = s22
def createPanel(self,red1,green1,blue1,red2,green2,blue2) :
ISurface(self.pt11,self.pt21,self.pt22).clr(red1,green1,blue1)
ISurface(self.pt22,self.pt12,self.pt11).clr(red2,green2,blue2)
IG.squarePipe([ self.spt11,self.spt21,self.spt22,self.spt12 ], 1, True, MyPanel.frameSize)
ICylinder(self.pt11,self.spt11,MyPanel.connectionRadius)
ICylinder(self.pt21,self.spt21,MyPanel.connectionRadius)
ICylinder(self.pt12,self.spt12,MyPanel.connectionRadius)
ICylinder(self.pt22,self.spt22,MyPanel.connectionRadius)
HOME
FOR PROCESSING
DOWNLOAD
DOCUMENTS
TUTORIALS (Java /
Python)
GALLERY
SOURCE CODE(GitHub)
PRIVACY POLICY
ABOUT/CONTACT