diff --git a/examples/dokk/datafiles/2CF8_lig.sdf b/examples/dokk/datafiles/thrombin/ligand.sdf
similarity index 100%
rename from examples/dokk/datafiles/2CF8_lig.sdf
rename to examples/dokk/datafiles/thrombin/ligand.sdf
diff --git a/examples/dokk/datafiles/2CF8_prot.pdb b/examples/dokk/datafiles/thrombin/protein.pdb
similarity index 100%
rename from examples/dokk/datafiles/2CF8_prot.pdb
rename to examples/dokk/datafiles/thrombin/protein.pdb
diff --git a/examples/dokk/datafiles/2CF8_surf.face b/examples/dokk/datafiles/thrombin/surface.face
similarity index 100%
rename from examples/dokk/datafiles/2CF8_surf.face
rename to examples/dokk/datafiles/thrombin/surface.face
diff --git a/examples/dokk/datafiles/2CF8_surf.vert b/examples/dokk/datafiles/thrombin/surface.vert
similarity index 100%
rename from examples/dokk/datafiles/2CF8_surf.vert
rename to examples/dokk/datafiles/thrombin/surface.vert
diff --git a/examples/dokk/dokk.py b/examples/dokk/dokk.py
index fcdb8e2298ee991df37edff46fc4c9d44fb3cefd..60abd7d89d1484676507072b3e4f46013cd4a426 100644
--- a/examples/dokk/dokk.py
+++ b/examples/dokk/dokk.py
@@ -1,27 +1,12 @@
 import glwin
-from ost import gfx
-from ost import io
+from ost import io, geom, gfx
 
-prot=io.LoadPDB('datafiles/2CF8_prot.pdb')
-prot_go=gfx.Entity('prot', prot)
-scene.Add(prot_go)
-
-surf=io.LoadSurface('datafiles/2CF8_surf','msms')
-surf.Attach(prot,5)
-surf_go=gfx.Surface('surf',surf)
-scene.Add(surf_go)
-
-lig=io.LoadSDF('datafiles/2CF8_lig.sdf')
-lig_go=gfx.Entity('lig', lig)
-lig_go.SetRenderMode(gfx.CUSTOM)
-lig_go.SetColor(gfx.GREEN,'ele=C')
-scene.Add(lig_go)
+from level import Level
 
 dokk_win=glwin.DokkGLWin()
 
-scene.CenterOn(lig_go)
 
-if '--fullscreen' in sys.argv:
-  dokk_win.Show(fullscreen=True)
-else:
-  dokk_win.Show(fullscreen=False)
+level=Level('thrombin')
+dokk_win.SetLevel(level)
+dokk_win.Show(fullscreen=('--fullscreen' in sys.argv))
+
diff --git a/examples/dokk/glwin.py b/examples/dokk/glwin.py
index bb49f5d6859965b1bdc1c324904303694a3367c7..78017b1cd8bd8d5a7c620f1efa5b6d771b588229 100644
--- a/examples/dokk/glwin.py
+++ b/examples/dokk/glwin.py
@@ -10,15 +10,17 @@ class DokkGLCanvas(QGLWidget):
     
   def __init__(self, format, parent=None):
     QGLWidget.__init__(self, format, parent)
-    self.last_pos_=QPoint()
+    self.last_pos_=QPoint()    
     self.setAutoFillBackground(False)
-    self.setAttribute(Qt.WA_KeyCompression,True)
-    
+    #self.setAttribute(Qt.WA_KeyCompression,True)
+    self.resize(800, 800)
   def initializeGL(self):
     gfx.Scene().InitGL()
 
   def paintGL(self):
     gfx.Scene().RenderGL()
+  def SetLevel(self, level):
+    self.level_=level
   def paintEvent(self, event):
     gfx.Scene().RenderGL()
     painter=QPainter(self)
@@ -30,7 +32,7 @@ class DokkGLCanvas(QGLWidget):
     painter.drawRect(QRect(QPoint(0, 0), QSize(self.width(), 25)))
     painter.setPen(QPen(QColor(255,255,255), Qt.SolidLine))
     painter.setFont(QFont("Verdana"))
-    painter.drawText(QPoint(10, 20), "Test Message")
+    painter.drawText(QPoint(10, 20), "You are %.1f away from the solution" % self.level_.GetRMSD())
   def resizeGL(self, w, h):
     gfx.Scene().Resize(w, h)
 
@@ -40,16 +42,33 @@ class DokkGLCanvas(QGLWidget):
   def mouseMoveEvent(self, event):
     delta=QPoint(event.x(), event.y())-self.last_point_
     self.last_point_=QPoint(event.x(), event.y())
-    if delta.y()!=0:
-      gfx.Scene().Apply(gfx.InputEvent(gfx.INPUT_DEVICE_MOUSE,
-                                       gfx.INPUT_COMMAND_ROTX, delta.y()*0.5), 
-                        False)
-    if delta.x()!=0:
-      gfx.Scene().Apply(gfx.InputEvent(gfx.INPUT_DEVICE_MOUSE,
-                                       gfx.INPUT_COMMAND_ROTY, delta.x()*0.5), 
-                        False)
-    self.update()
-
+    if event.button() & Qt.LeftButton:
+      tf=gfx.Scene().GetTransform()      
+      if event.modifiers() & Qt.ShiftModifier:
+        if event.modifiers() & Qt.AltModifier:
+          self.level_.Shift(tf.GetRot().GetRow(2)*delta.y()*0.1)          
+        else:
+         self.level_.Shift((tf.GetRot().GetRow(0)*delta.x()
+                           -tf.GetRot().GetRow(1)*delta.y())*0.1)
+      else:
+        if delta.y()!=0:
+          self.level_.RotateAxis(tf.GetRot().GetRow(0), delta.y()*0.005)
+        if delta.x()!=0:
+          self.level_.RotateAxis(tf.GetRot().GetRow(1), delta.x()*0.005)
+      self.level_.UpdateScores()
+      self.update()
+    elif event.button() & Qt.RightButton:
+      if delta.y()!=0:
+        gfx.Scene().Apply(gfx.InputEvent(gfx.INPUT_DEVICE_MOUSE,
+                                         gfx.INPUT_COMMAND_ROTX, delta.y()*0.5),
+                          False)
+      if delta.x()!=0:
+        gfx.Scene().Apply(gfx.InputEvent(gfx.INPUT_DEVICE_MOUSE,
+                                         gfx.INPUT_COMMAND_ROTY, delta.x()*0.5),
+                          False)
+      self.update()
+  def mouseDoubleClickEvent(self, event):
+    self.level_.SetPivot(event.x(), self.height()-event.y())
   def wheelEvent(self, event):
     self.OnTransform(gfx.INPUT_COMMAND_TRANSZ,0,gfx.TRANSFORM_VIEW,
               0.1*(-event.delta()))
@@ -86,7 +105,8 @@ class DokkGLWin(gfx.GLWinBase):
         self.canvas_=DokkGLCanvas(self._CreateFormat())
     def DoRefresh(self):
       self.refresh_=True
-      
+    def SetLevel(self, level):
+      self.canvas_.SetLevel(level)
     def Show(self, fullscreen):
       if fullscreen:
         self.canvas_.showFullScreen()
diff --git a/examples/dokk/level.py b/examples/dokk/level.py
new file mode 100644
index 0000000000000000000000000000000000000000..850abdaea4b36356605da802d43bf83aff5255aa
--- /dev/null
+++ b/examples/dokk/level.py
@@ -0,0 +1,44 @@
+import os
+from ost import io, gfx, qa, geom
+from ligand import Ligand
+from surface import Surface
+from protein import Protein
+
+class Level:
+  def __init__(self, name):
+    self.name_=name
+    self.Load()
+  def Load(self):
+    print 'Loading %s' % self.name_
+    level_dir=os.path.join('datafiles', self.name_)
+    ligand_ent=io.LoadSDF(os.path.join(level_dir, 'ligand.sdf'))
+    self.ligand=Ligand(ligand_ent)
+    protein_ent=io.LoadPDB(os.path.join(level_dir, 'protein.pdb'))
+    self.protein=Protein(protein_ent)
+    surface=io.LoadSurface(os.path.join(level_dir, 'surface'), 'msms')
+    self.surface=Surface(surface)
+    self.surface.handle.Attach(self.protein.handle, 5.0)
+    gfx.Scene().SetCenter(self.ligand.GetCenter())
+    print 'Done Loading'
+    self.UpdateScores()
+  def RotateAxis(self, axis, angle):
+    self.ligand.RotateAxis(axis, angle)
+  def SetPivot(self, x, y):
+    v1=gfx.Scene().UnProject(geom.Vec3(x, y, 0.0));
+    v2=gfx.Scene().UnProject(geom.Vec3(x, y, 1.0));    
+    atom=self.ligand.go.PickAtom(geom.Line3(v1, v2), 0.1)
+    if atom.IsValid():
+      self.ligand.SetPivot(atom)
+    
+  def Shift(self, vec):
+    self.ligand.Shift(vec)
+  def UpdateScores(self):
+    prot_within=self.protein.handle.FindWithin(self.ligand.GetCenter(), 
+                                               self.ligand.radius)
+    lig_view=self.ligand.handle.CreateFullView()
+    for a in prot_within:
+      score=qa.ClashScore(a, lig_view)
+      a.SetGenericFloatProperty('clash', score)
+    self.surface.go.ReapplyColorOps()
+  def GetRMSD(self):
+    return self.ligand.RMSDToSolution()
\ No newline at end of file
diff --git a/examples/dokk/ligand.py b/examples/dokk/ligand.py
new file mode 100644
index 0000000000000000000000000000000000000000..5cda3e484153b6e0a8e6407f6a9cc3d118fdb6be
--- /dev/null
+++ b/examples/dokk/ligand.py
@@ -0,0 +1,46 @@
+from ost import gfx, geom
+from ost.mol import alg
+from ost import mol
+class Ligand:
+  def __init__(self, ligand):
+    self.handle=ligand
+    self.the_solution_=ligand.Copy().CreateFullView()
+    self.go=gfx.Entity("Ligand", gfx.CUSTOM, self.handle)
+    self.go.SetColor(gfx.GREEN, 'ele=C')
+    gfx.Scene().Add(self.go)
+    gfx.Scene().SetCenter(self.go.center)
+    bbox=self.go.GetBoundingBox()
+    self.radius=geom.Length(bbox.GetMax()-bbox.GetMin())+3.0
+    self.pivot_=mol.AtomHandle()
+  def SetPivot(self, pivot):
+    self.pivot_=pivot
+  def GetCenter(self):
+    return self.handle.GetGeometricCenter()
+  def RotateAxis(self, axis, angle):
+    edi=self.handle.RequestXCSEditor()
+    rot=geom.Mat4(geom.AxisRotation(axis, angle))
+    trans=geom.Mat4()
+    
+    center=self.handle.GetGeometricCenter()
+    if self.pivot_.IsValid():
+      center=self.pivot_.GetPos()
+    trans.PasteTranslation(-center)
+    trans2=geom.Mat4()
+    trans2.PasteTranslation(center)
+    full_tf=trans2*rot*trans
+    edi.ApplyTransform(full_tf)
+    self.go.UpdatePositions()
+  def Shift(self, vec):
+    trans=geom.Mat4()
+    trans.PasteTranslation(vec)
+    edi=self.handle.RequestXCSEditor()    
+    edi.ApplyTransform(trans)
+    self.go.UpdatePositions()    
+
+  def UpdateScores(self):
+    for a in self.b.view.atoms:
+      score=qa.ClashScore(a.handle, self.a.view)
+      a.SetGenericFloatProperty('clash', score)
+  def RMSDToSolution(self):
+    return alg.CalculateRMSD(self.handle.CreateFullView(), 
+                             self.the_solution_)
\ No newline at end of file
diff --git a/examples/dokk/protein.py b/examples/dokk/protein.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad4025c528b1300925c537713f62a0d8071583b4
--- /dev/null
+++ b/examples/dokk/protein.py
@@ -0,0 +1,8 @@
+from ost import gfx
+class Protein:
+  def __init__(self, prot):
+    self.handle=prot
+    for a in self.handle.atoms:
+      a.SetGenericFloatProperty('clash', 0.0)    
+    self.prot_go_=gfx.Entity("Prot", self.handle)
+    gfx.Scene().Add(self.prot_go_)
\ No newline at end of file
diff --git a/examples/dokk/surface.py b/examples/dokk/surface.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b5a58a73352ebdb449dcb762e153248ec3fd069
--- /dev/null
+++ b/examples/dokk/surface.py
@@ -0,0 +1,13 @@
+from ost import gfx
+from ost import mol
+class Surface:
+  def __init__(self, surf):
+    self.handle=surf
+    self.go=gfx.Surface("Surf", self.handle)
+
+    gfx.Scene().Add(self.go)
+    grad=gfx.Gradient()
+    grad.SetColorAt(0.0, gfx.Color(1.0, 1.0, 1.0))
+    grad.SetColorAt(0.7, gfx.Color(1.0, 1.0, 0.0))
+    grad.SetColorAt(1.0, gfx.Color(1.0, 0.0, 0.0))    
+    self.go.ColorBy('clash', grad, 0.0, 10.0, mol.Prop.Level.ATOM)        
\ No newline at end of file
diff --git a/modules/geom/pymod/export_composite3.cc b/modules/geom/pymod/export_composite3.cc
index 1d646b5289ab91269f5770315b1c8a2dd6b5e461..8468578df28234c4b1d2ad11eafa6b57a4cde915 100644
--- a/modules/geom/pymod/export_composite3.cc
+++ b/modules/geom/pymod/export_composite3.cc
@@ -133,6 +133,9 @@ scope PlaneScope =
          return_value_policy<copy_const_reference>())                  
     .def("GetHalfExtents", &Cuboid::GetHalfExtents)
   ;
-
+  class_<AlignedCuboid>("AlignedCuboid", init<geom::Vec3, geom::Vec3>())
+    .def("GetMin", &AlignedCuboid::GetMin, return_value_policy<copy_const_reference>())
+    .def("GetMax", &AlignedCuboid::GetMax, return_value_policy<copy_const_reference>())
+  ;
 }
 
diff --git a/modules/geom/pymod/export_mat3.cc b/modules/geom/pymod/export_mat3.cc
index 9efe5a8dd8a43b0635561e0df71e75975616be62..ee66e38d6439c54dab43058f9e2d73d1cca3a56b 100644
--- a/modules/geom/pymod/export_mat3.cc
+++ b/modules/geom/pymod/export_mat3.cc
@@ -74,5 +74,7 @@ void export_Mat3()
     .def("__getitem__",Mat3_getslice)
     .def("__setitem__",Mat3_setitem)
     .def("__setitem__",Mat3_setslice)
+    .def("GetCol", &Mat3::GetCol)
+    .def("GetRow", &Mat3::GetRow)    
   ;
 }
diff --git a/modules/gfx/pymod/export_entity.cc b/modules/gfx/pymod/export_entity.cc
index b4a5fad25682847980fced80ac384cf4adbaab0b..1807c2e2b9b4d65294a650259ed37d2966cd433a 100644
--- a/modules/gfx/pymod/export_entity.cc
+++ b/modules/gfx/pymod/export_entity.cc
@@ -260,7 +260,8 @@ void export_Entity()
     .def("RadiusBy", radius_by_03)
     .def("RadiusBy", radius_by_04)
     .def("ResetRadiusBy", &Entity::ResetRadiusBy)
-
+    .def("PickAtom", &Entity::PickAtom)
+    .def("PickBond", &Entity::PickBond)
     .def("ColorByElement",&Entity::ColorByElement)
     .def("CleanColorOps", &Entity::CleanColorOps)
     .def("ReapplyColorOps", &Entity::ReapplyColorOps)
diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc
index ec1dd53ebce61d984a036799b3680b73404e2e23..5bd9c75e04a880b0603cc9eb07411d401399bd99 100644
--- a/modules/gfx/pymod/export_scene.cc
+++ b/modules/gfx/pymod/export_scene.cc
@@ -87,6 +87,7 @@ void export_Scene()
     .def("GetCenter",&Scene::GetCenter)
     .def("CenterOn",center_on1)
     .def("CenterOn",center_on2)
+    .def("UnProject",  &Scene::UnProject, arg("ignore_vp")=false)
     .def("InitGL", &Scene::InitGL)
     .def("RenderGL", &Scene::RenderGL)
     .def("Resize", &Scene::Resize)
diff --git a/modules/mol/base/pymod/export_entity.cc b/modules/mol/base/pymod/export_entity.cc
index e8c0caffc92305df01d112fdab8ededaad337764..67d273b09a1db687a7b651f1ce89ff85c2e2479f 100644
--- a/modules/mol/base/pymod/export_entity.cc
+++ b/modules/mol/base/pymod/export_entity.cc
@@ -102,7 +102,12 @@ void export_Entity()
     .add_property("residues", &EntityHandle::GetResidueList)
     .add_property("atoms", &EntityHandle::GetAtomList)
     .add_property("chains", &EntityHandle::GetChainList)
-    .add_property("bonds", &EntityHandle::GetBondList)    
+    .add_property("bonds", &EntityHandle::GetBondList)
+    .def("GetTransformationMatrix", &EntityHandle::GetTransformationMatrix,
+         return_value_policy<copy_const_reference>())
+    .add_property("transform", 
+                   make_function(&EntityHandle::GetTransformationMatrix, 
+                                 return_value_policy<copy_const_reference>()))    
     .def("RequestICSEditor", &EntityHandle::RequestICSEditor,
          X_ics_editor_overloads(args("mode")))
     .def("RequestXCSEditor", &EntityHandle::RequestXCSEditor,