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()[0])   % 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 (moveVector) 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 self.tsp 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 moveVector direction.

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()[0])   % 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.

See also

Tython documentation, Möbius tutorial