Extending and Customizing TLab
version 1, 30.12.2012 by mike
Extending and customizing TLab is possible throughout the python scripting interface - Tython. It facilitates pythonQt 2.1 for interfacing the C++/Qt with Python. In this object-oriented setting inheritance seems to be the right choice for customization. Unfortunately, inheritance of C++/Qt objects from Python is not possible with PythonQt 2.1. However, if overloading of specific C++ member methods is not necessary, then it is possible to add the C++ object as a member to the Python class, which can be seen as a poor man's approach to inheritance.
Step 1: The first simple class
At first, a basic frame of the new class is built, which is the following:
from tlab import B3Tspline class myTSP(): def __init__(self,tsp): if (type(tsp) == type(B3Tspline())): self.tsp = tsp else: print "need a B3Tspline()" def getInfo(self): print self.tsp.baseInfoString()
The constructor needs as an argument a B3Tspline, which is then known to the class. The second method
simply prints the information string of the B3TSpline to the console. To be able to use the new class from inside TLab,
it has to be known. This can be done by copying the text into a file with the ending
.py and then executing this
as a script (Tools→Run Script). Afterwards it can be used from the console:
py> tsp = myTSP(scene.objects()) % using the first object from the scene py> tsp.getInfo()
Step 2: Adding the moveFace function
In the second step some functionality is added to the class. The function which is implemented here, is a move face function. This method is taking all the control points, which are directly attached to a given face, and moves them in a certain direction.
The final script of this tutorial is the following:
from tlab import B3Tspline from PythonQt.QtGui import QVector3D class myTSP(): def __init__(self,tsp): if (type(tsp) == type(B3Tspline())): self.tsp = tsp else: print "need a B3Tspline()" def getInfo(self): print self.tsp.baseInfoString() def moveFace(self,faceid,moveVector): if (type(moveVector) != type(QVector3D())): return if (type(self.tsp) != type(B3Tspline())): return vertexlist = self.tsp.getDirectFaceVertices(faceid) for vertex in vertexlist: # print "move %i" % (vertex) if self.tsp.hasControlPoint(vertex): cp = self.tsp.controlPoint(vertex) cp = cp + moveVector self.tsp.setControlPoint(vertex,cp)
The method '
def moveFace(self,faceid,moveVector)' implements the move face function and has therefore the face id (
faceid) and a vector (
as arguments. The first step in the function is to check if the argument
moveVector is actual a three-dimensional vector and if the member
is still from the type B3Tspline. After that, the vertices directly attached to a face are used in the for-loop. Inside the loop
every selected vertex is checked if a control point is attached; and if yes then the control point is
moved in the
Step 3: Hands-on example
The starting point of the hands-on example is the simple cube (cube.topen) from the example models.
If this sphere-like geometry is loaded in the scene, it can be used with the new class by:
py> o = myTSP(scene.objects()) % using the first object from the scene py> o.moveFace(2,QVector3D(8,0,0))
To create this oval ball.
Even if the topology looks like the classical example of a subdivision surface, it should not be forgotten that the B3TSpline is a generalized non-uniform rational B-Spline (NURBS), and therefore has weights on every control point. They can be set by:
py> o.tsp.setControlPointWeight(5,0.01) py> o.tsp.setControlPointWeight(6,0.01)
The first argument of the
setControlPointWeight method is the face id and the second the weight. If it would be possible to inherit
the B3TSpline class, then the child would have the same methods like the base class. The access using the member object relates to the used
poor man's approach to mimic inheritance.
The final picture shows then how powerful control point weights can be on the final surface.