def test_interpolate3D(self): mat1 = rotax([0, 0, 0], [0, 0, 1], 30.0 * degtorad) mat2 = rotax([0, 0, 0], [0, 0, 1], 60.0 * degtorad) mat3 = rotax([0, 0, 0], [0, 0, 1], 90.0 * degtorad) # add translation (0,1,0) to mat2 mat2 = N.array([[0.5, 0.86602539, 0., 0.], [-0.86602539, 0.5, 0., 0.], [0., 0., 1., 0.], [0., 1., 0., 1.]], 'f') matList = [mat1, mat2, mat3] indexList = [0.33333333, 0.66666666667, 1.0] data = [[0., 0., 0., 1.], [1.0, 0.0, 0.0, 1.0], [2., 0., 0., 1.]] p = 0.5 M = interpolate3DTransform(matList, indexList, p) res = N.dot(data, M)[1] self.assertEqual(self.diff(res[0], 0.70710677), True) self.assertEqual(self.diff(res[1], 1.20710677), True) # 50% translation along Y axis self.assertEqual(self.diff(res[2], 0.0), True) p = 1.5 M = interpolate3DTransform(matList, indexList, p) res = N.dot(data, M)[1] self.assertEqual(self.diff(res[0], -0.70710677), True) self.assertEqual(self.diff(res[1], 0.70710677), True) self.assertEqual(self.diff(res[2], 0.0), True)
def __init__(self, point1 = None, point2 = None, slab = None): # Huaicai 4/23/05: added some comments below to help understand the code. if slab: # convert from 2d (x, y) coordinates into its 3d world (x, y, 0) #coordinates(the lower-left and upper-right corner). #In another word, the 3d coordinates minus the z offset of the plane x = dot(A(point1), A(point2)) # Get the vector from upper-right point to the lower-left point dx = subtract.reduce(x) # Get the upper-left and lower right corner points oc = x[1] + V(point2[0]*dot(dx,point2[0]), point2[1]*dot(dx,point2[1])) # Get the four 3d cooridinates on the bottom crystal-cutting plane sq1 = cat(x,oc) + slab.normal*dot(slab.point, slab.normal) # transfer the above 4 3d coordinates in parallel to get that on #the top plane, put them together sq1 = cat(sq1, sq1+slab.thickness*slab.normal) self.data = V(maximum.reduce(sq1), minimum.reduce(sq1)) elif point2: # just 2 3d points self.data = V(maximum(point1, point2), minimum(point1, point2)) elif point1: # list of points: could be 2d or 3d? +/- 1.8 to make the bounding #box enclose the vDw ball of an atom? self.data = V(maximum.reduce(point1) + BBOX_MARGIN, minimum.reduce(point1) - BBOX_MARGIN) else: # a null bbox self.data = None
def getMatrices(self, matA, matB): matInA, matInB = self.set(matA, matB) #assert that matrices have either size 1, or equal size assert len(matInA) == 1 or len(matInB) == 1 or \ len(matInA) == len(matInB) matrixOut = [] #now the actual multiplication if len(matInA) == 1: for i in range(len(matInB)): #loop over node's incoming matrices matrixOut.append(Numeric.dot(matInA[0], matInB[i])) elif len(matInB) == 1: for i in range(len(matInA)): #loop over node's incoming matrices matrixOut.append(Numeric.dot(matInA[i], matInB[0])) else: for i in range(len(matInA)): #loop over node's incoming matrices matrixOut.append(Numeric.dot(matInA[i], matInB[i])) return matrixOut
def __findTransformation(self, x, y): """ Match two arrays by rotation and translation. Returns the rotation matrix and the translation vector. Back transformation: for atom i new coordinates will be:: y_new[i] = N.dot(r, y[i]) + t for all atoms in one step:: y_new = N.dot(y, N.transpose(r)) + t @param x: coordinates @type x: array @param y: coordinates @type y: array @return: rotation matrix, translation vector @rtype: array, array @author: Michael Habeck """ from numpy.oldnumeric.linear_algebra import singular_value_decomposition as svd ## center configurations x_av = N.sum(x) / len(x) y_av = N.sum(y) / len(y) x = x - x_av y = y - y_av ## svd of correlation matrix v, l, u = svd(N.dot(N.transpose(x), y)) ## build rotation matrix and translation vector r = N.dot(v, u) t = x_av - N.dot(r, y_av) return r, t
def __pairwiseDistances(self, u, v): """ pairwise distance between 2 3-D numpy arrays of atom coordinates. @param u: coordinates @type u: array @param v: coordinates @type v: array @return: Numpy array len(u) x len(v) @rtype:array @author: Wolfgang Rieping. """ ## check input if not type( u ) == arraytype or\ not type( v ) == arraytype: raise ComplexError('unsupported argument type ' + \ str( type(u) ) + ' or ' + str( type(v) ) ) diag1= N.diagonal(N.dot(u,N.transpose(u))) diag2= N.diagonal(N.dot(v,N.transpose(v))) dist= -N.dot(v,N.transpose(u))-N.transpose(N.dot(u,N.transpose(v))) dist= N.transpose(N.asarray(map(lambda column,a:column+a, \ N.transpose(dist), diag1))) return N.transpose(N.sqrt(N.asarray( map(lambda row,a: row+a, dist, diag2))))
def test_interpolate3D(self): mat1=rotax([0,0,0], [0,0,1],30.0*degtorad) mat2=rotax([0,0,0], [0,0,1],60.0*degtorad) mat3=rotax([0,0,0], [0,0,1],90.0*degtorad) # add translation (0,1,0) to mat2 mat2 = N.array([ [ 0.5 , 0.86602539, 0. , 0. ], [-0.86602539, 0.5 , 0. , 0. ], [ 0. , 0. , 1. , 0. ], [ 0. , 1. , 0. , 1. ]],'f') matList=[mat1, mat2, mat3] indexList = [0.33333333, 0.66666666667, 1.0] data = [[0.,0.,0.,1.],[1.0, 0.0, 0.0,1.0],[2.,0.,0.,1.]] p=0.5 M = interpolate3DTransform(matList, indexList, p) res=N.dot(data, M)[1] self.assertEqual( self.diff(res[0], 0.70710677 ),True) self.assertEqual(self.diff(res[1], 1.20710677 ),True) # 50% translation along Y axis self.assertEqual(self.diff(res[2], 0.0),True) p=1.5 M = interpolate3DTransform(matList, indexList, p) res=N.dot(data, M)[1] self.assertEqual(self.diff(res[0], -0.70710677 ),True) self.assertEqual(self.diff(res[1], 0.70710677 ),True) self.assertEqual(self.diff(res[2], 0.0),True)
def angleBetween(vec1, vec2): """ Return the angle between two vectors, in degrees, but try to cover all the weird cases where numerical anomalies could pop up. """ # paranoid acos(dotproduct) function, wware 051103 # [TODO: should merge with threepoint_angle_in_radians] TEENY = 1.0e-10 lensq1 = Numeric.dot(vec1, vec1) if lensq1 < TEENY: return 0.0 lensq2 = Numeric.dot(vec2, vec2) if lensq2 < TEENY: return 0.0 #Replaced earlier formula "vec1 /= lensq1 ** .5" to fix the #following bug: #The above formula was modifying the arguments using the /= statement. #Numeric.array objects (V objects) are mutable, and op= operators modify #them so replacing [--ninad 20070614 comments, based on an email #conversation with Bruce where he noticed the real problem.] vec1 = vec1 / lensq1 ** .5 vec2 = vec2 / lensq2 ** .5 # The case of nearly-equal vectors will be covered by the >= 1.0 clause. #diff = vec1 - vec2 #if dot(diff, diff) < TEENY: # return 0.0 dprod = Numeric.dot(vec1, vec2) if dprod >= 1.0: return 0.0 if dprod <= -1.0: return 180.0 return (180 / math.pi) * math.acos(dprod)
def rtz(self, pt): d = pt - self.p0 z = dot(d, self.zn) d = d - z * self.zn r = vlen(d) theta = Numeric.arctan2(dot(d, self.v), dot(d, self.u)) return Numeric.array((r, theta, z), 'd')
def findTransformation(x, y): """ Match two arrays by rotation and translation. Returns the rotation matrix and the translation vector. @param x: first set of coordinates @type x: array('f') @param y: second set of coordinates @type y: array('f') @return: rotation matrix (3x3) and translation vector (1x3) @rtype: array, array """ ## center configurations x_av = N.average(x) y_av = N.average(y) x = x - x_av y = y - y_av ## svd of correlation matrix v, l, u = svd(N.dot(N.transpose(x), y)) ## build rotation matrix and translation vector r = N.dot(v, u) t = x_av - N.dot(r, y_av) return r, t
def __init__(self, point1=None, point2=None, slab=None): # Huaicai 4/23/05: added some comments below to help understand the code. if slab: # convert from 2d (x, y) coordinates into its 3d world (x, y, 0) #coordinates(the lower-left and upper-right corner). #In another word, the 3d coordinates minus the z offset of the plane x = dot(A(point1), A(point2)) # Get the vector from upper-right point to the lower-left point dx = subtract.reduce(x) # Get the upper-left and lower right corner points oc = x[1] + V(point2[0] * dot(dx, point2[0]), point2[1] * dot(dx, point2[1])) # Get the four 3d cooridinates on the bottom crystal-cutting plane sq1 = cat(x, oc) + slab.normal * dot(slab.point, slab.normal) # transfer the above 4 3d coordinates in parallel to get that on #the top plane, put them together sq1 = cat(sq1, sq1 + slab.thickness * slab.normal) self.data = V(maximum.reduce(sq1), minimum.reduce(sq1)) elif point2: # just 2 3d points self.data = V(maximum(point1, point2), minimum(point1, point2)) elif point1: # list of points: could be 2d or 3d? +/- 1.8 to make the bounding #box enclose the vDw ball of an atom? self.data = V( maximum.reduce(point1) + BBOX_MARGIN, minimum.reduce(point1) - BBOX_MARGIN) else: # a null bbox self.data = None
def drawVector(self): coords3D = self.vector + [1] # apply viewing transformation to vector newPtsWithView = Numeric.dot([coords3D], self.viewingMat)[0] # compute 2D projection of vector (broken on 2 segments for # depth cueing x1 = self.xm + int(newPtsWithView[0] * (self.xm)) y1 = self.ym + int(newPtsWithView[1] * (self.ym)) # change vector's segments coordinates self.canvas.coords(self.lId1, self.xm, self.ym, x1, y1) # update vector shadows # Y=0 plane if self.drawShadowY: pt = [coords3D[0], 0, coords3D[2], 1.] newPtsWithView = Numeric.dot([pt], self.viewingMat)[0] xm = self.xm + int(newPtsWithView[0] * (self.xm)) ym = self.ym + int(newPtsWithView[1] * (self.ym)) if self.fillShadowPlanes: self.canvas.coords(self.shadowPY, self.xm, self.ym, xm, ym, x1, y1) self.canvas.coords(self.shadowY, self.xm, self.ym, xm, ym, x1, y1) # X=0 plane if self.drawShadowX: pt = [0, coords3D[1], coords3D[2], 1.] newPtsWithView = Numeric.dot([pt], self.viewingMat)[0] xm = self.xm + int(newPtsWithView[0] * (self.xm)) ym = self.ym + int(newPtsWithView[1] * (self.ym)) if self.fillShadowPlanes: self.canvas.coords(self.shadowPX, self.xm, self.ym, xm, ym, x1, y1) self.canvas.coords(self.shadowX, self.xm, self.ym, xm, ym, x1, y1) # Z=0 plane if self.drawShadowZ: pt = [coords3D[0], coords3D[1], 0, 1.] newPtsWithView = Numeric.dot([pt], self.viewingMat)[0] xm = self.xm + int(newPtsWithView[0] * (self.xm)) ym = self.ym + int(newPtsWithView[1] * (self.ym)) if self.fillShadowPlanes: self.canvas.coords(self.shadowPZ, self.xm, self.ym, xm, ym, x1, y1) self.canvas.coords(self.shadowZ, self.xm, self.ym, xm, ym, x1, y1) if self.vector[0] < 0.0: self.canvas.tag_raise('verticalCircle', 'moving') else: self.canvas.tag_lower('verticalCircle', 'moving') if self.vector[1] < 0.0: self.canvas.tag_raise('horizontalCircle', 'moving') else: self.canvas.tag_lower('horizontalCircle', 'moving') if self.vector[2] < 0.0 or self.vector[1] < 0.0: self.canvas.tag_raise('axis', 'moving') else: self.canvas.tag_lower('axis', 'moving')
def createCanvas(self, master, size=200): self.frame = Tkinter.Frame(self, relief = 'sunken', borderwidth=5) if self.name is not None: self.title = Tkinter.Label(self.frame, text=self.name) self.title.pack(side=self.labelSide) self.canvas = Tkinter.Canvas(self.frame, width=size, height=size) # set the focus so that we get keyboard events, and add callbacks self.canvas.bind('<KeyPress>', self.modifierDown) self.canvas.bind("<KeyRelease>", self.modifierUp) xm = self.xm = ym = self.ym = self.r self.canvas.create_oval(0, 0, size, size) self.canvas.create_oval(xm-(xm/4), 0, xm+(xm/4), size, tags='verticalCircle') self.canvas.create_oval(0, ym-(ym/4), size, ym+(ym/4), tags='horizontalCircle') # apply viewing transformation to vector XaxisWithView = Numeric.dot([(1.,0.,0.,1.)],self.viewingMat)[0] x1 = self.xm+int(XaxisWithView[0]*(self.xm)) y1 = self.ym+int(XaxisWithView[1]*(self.ym)) self.canvas.create_line(xm, ym, x1, y1, fill='red', tags='axis') XaxisWithView = Numeric.dot([(0.,1.,0.,1.)],self.viewingMat)[0] x2 = self.xm+int(XaxisWithView[0]*(self.xm)) y2 = self.ym+int(XaxisWithView[1]*(self.ym)) self.canvas.create_line(xm, ym, x2, y2, fill='green', tags='axis') XaxisWithView = Numeric.dot([(0.,0.,1.,1.)],self.viewingMat)[0] x3 = self.xm+int(XaxisWithView[0]*(self.xm)) y3 = self.ym+int(XaxisWithView[1]*(self.ym)) self.canvas.create_line(xm, ym, x3, y3, fill='blue', tags='axis') self.textId = self.canvas.create_text(0, size, anchor='sw', text="XY") # shadow line in X=0 plane self.shadowPX = self.canvas.create_polygon(0,0,0,0,0,0, fill='red', tag='moving') self.shadowPY = self.canvas.create_polygon(0,0,0,0,0,0, fill='green', tag='moving') self.shadowPZ = self.canvas.create_polygon(0,0,0,0,0,0, fill='blue', tag='moving') self.shadowX = self.canvas.create_line(0, 0, 0, 0, fill='black', tag='moving') self.shadowY = self.canvas.create_line(0, 0, 0, 0, fill='black', tag='moving') self.shadowZ = self.canvas.create_line(0, 0, 0, 0, fill='black', tag='moving') self.lId1 = self.canvas.create_line(0, 0, 0, 0, fill='black', width=3, arrow='last') self.canvas.pack(side='top') self.frame.pack(expand=1, fill='x') self.xm = self.ym = self.r self.drawVector()
def drawLinearDimension(color, # what color are we drawing this in right, up, # screen directions mapped to xyz coords bpos, # position of the handle for moving the text p0, p1, # positions of the ends of the dimension text, highlighted=False): outOfScreen = cross(right, up) bdiff = bpos - 0.5 * (p0 + p1) csys = CylindricalCoordinates(p0, p1 - p0, bdiff, right) # This works OK until we want to keep the text right side up, then the # criterion for right-side-up-ness changes because we've changed 'up'. br, bt, bz = csys.rtz(bpos) e0 = csys.xyz((br + 0.5, 0, 0)) e1 = csys.xyz((br + 0.5, 0, 1)) drawline(color, p0, e0) drawline(color, p1, e1) v0 = csys.xyz((br, 0, 0)) v1 = csys.xyz((br, 0, 1)) if highlighted: drawline(color, v0, v1, width=THICKLINEWIDTH) else: drawline(color, v0, v1) # draw arrowheads at the ends a1, a2 = 0.25, 1.0 * csys.zinv arrow00 = csys.xyz((br + a1, 0, a2)) arrow01 = csys.xyz((br - a1, 0, a2)) drawline(color, v0, arrow00) drawline(color, v0, arrow01) arrow10 = csys.xyz((br + a1, 0, 1-a2)) arrow11 = csys.xyz((br - a1, 0, 1-a2)) drawline(color, v1, arrow10) drawline(color, v1, arrow11) # draw the text for the numerical measurement, make # sure it goes from left to right xflip = dot(csys.z, right) < 0 # then make sure it's right side up theoreticalRight = (xflip and -csys.z) or csys.z theoreticalOutOfScreen = cross(theoreticalRight, bdiff) yflip = dot(theoreticalOutOfScreen, outOfScreen) < 0 if debug_flags.atom_debug: print "DEBUG INFO FROM drawLinearDimension" print csys print theoreticalRight, theoreticalOutOfScreen print xflip, yflip if yflip: def fx(y): return br + 1.5 - y / (1. * HEIGHT) else: def fx(y): return br + 0.5 + y / (1. * HEIGHT) if xflip: def fz(x): return 0.9 - csys.zinv * x / (1. * WIDTH) else: def fz(x): return 0.1 + csys.zinv * x / (1. * WIDTH) def tfm(x, y, fx=fx, fz=fz): return csys.xyz((fx(y), 0, fz(x))) f3d = Font3D() f3d.drawString(text, tfm=tfm, color=color)
def drawVector(self): coords3D = self.vector + [1] # apply viewing transformation to vector newPtsWithView = Numeric.dot( [coords3D], self.viewingMat)[0] # compute 2D projection of vector (broken on 2 segments for # depth cueing x1 = self.xm+int(newPtsWithView[0]*(self.xm)) y1 = self.ym+int(newPtsWithView[1]*(self.ym)) # change vector's segments coordinates self.canvas.coords(self.lId1, self.xm, self.ym, x1, y1) # update vector shadows # Y=0 plane if self.drawShadowY: pt = [coords3D[0], 0, coords3D[2], 1.] newPtsWithView = Numeric.dot( [pt], self.viewingMat)[0] xm = self.xm+int(newPtsWithView[0]*(self.xm)) ym = self.ym+int(newPtsWithView[1]*(self.ym)) if self.fillShadowPlanes: self.canvas.coords(self.shadowPY,self.xm,self.ym,xm,ym,x1,y1) self.canvas.coords(self.shadowY,self.xm,self.ym,xm,ym,x1,y1) # X=0 plane if self.drawShadowX: pt = [0, coords3D[1], coords3D[2], 1.] newPtsWithView = Numeric.dot( [pt], self.viewingMat)[0] xm = self.xm+int(newPtsWithView[0]*(self.xm)) ym = self.ym+int(newPtsWithView[1]*(self.ym)) if self.fillShadowPlanes: self.canvas.coords(self.shadowPX,self.xm,self.ym,xm,ym,x1,y1) self.canvas.coords(self.shadowX, self.xm, self.ym, xm, ym, x1,y1) # Z=0 plane if self.drawShadowZ: pt = [coords3D[0], coords3D[1], 0, 1.] newPtsWithView = Numeric.dot( [pt], self.viewingMat)[0] xm = self.xm+int(newPtsWithView[0]*(self.xm)) ym = self.ym+int(newPtsWithView[1]*(self.ym)) if self.fillShadowPlanes: self.canvas.coords(self.shadowPZ,self.xm,self.ym,xm,ym,x1,y1) self.canvas.coords(self.shadowZ, self.xm, self.ym, xm, ym, x1,y1) if self.vector[0]<0.0: self.canvas.tag_raise('verticalCircle', 'moving') else: self.canvas.tag_lower('verticalCircle', 'moving') if self.vector[1]<0.0: self.canvas.tag_raise('horizontalCircle', 'moving') else: self.canvas.tag_lower('horizontalCircle', 'moving') if self.vector[2]<0.0 or self.vector[1]<0.0: self.canvas.tag_raise('axis', 'moving') else: self.canvas.tag_lower('axis', 'moving')
def squared_distance_matrix(x, y): d1 = N.diagonal(N.dot(x, N.transpose(x))) d2 = N.diagonal(N.dot(y, N.transpose(y))) a1 = N.add.outer(d1,d2) a2 = N.dot(x, N.transpose(y)) return a1 - 2 * a2
def constrainedPosition(self): a = self.atoms p0, p1, p2, p3 = a[0].posn(), a[1].posn(), a[2].posn(), a[3].posn() axis = norm(p2 - p1) midpoint = 0.5 * (p1 + p2) return _constrainHandleToAngle(self.center() + self.handle_offset, p0 - dot(p0 - midpoint, axis) * axis, midpoint, p3 - dot(p3 - midpoint, axis) * axis)
def squared_distance_matrix(x, y): d1 = N.diagonal(N.dot(x, N.transpose(x))) d2 = N.diagonal(N.dot(y, N.transpose(y))) a1 = N.add.outer(d1, d2) a2 = N.dot(x, N.transpose(y)) return a1 - 2 * a2
def rotateAboutPoint(self): """ Rotates the selected entities along the specified vector, about the specified pivot point (pivot point it the starting point of the drawn vector. """ if len(self.mouseClickPoints) != self.mouseClickLimit: print_compact_stack("Rotate about point bug: mouseclick points != mouseclicklimit: ") return pivotPoint = self.mouseClickPoints[0] ref_vec_endPoint = self.mouseClickPoints[1] rot_vec_endPoint = self.mouseClickPoints[2] reference_vec = norm(ref_vec_endPoint - pivotPoint) lineVector = norm(rot_vec_endPoint - pivotPoint) #lineVector = endPoint - startPoint quat1 = Q(lineVector, reference_vec) #DEBUG Disabled temporarily . will not be used if dot(lineVector, reference_vec) < 0: theta = math.pi - quat1.angle else: theta = quat1.angle #TEST_DEBUG-- Works fine theta = quat1.angle rot_axis = cross(lineVector, reference_vec) if dot(lineVector, reference_vec) < 0: rot_axis = - rot_axis cross_prod_1 = norm(cross(reference_vec, rot_axis)) cross_prod_2 = norm(cross(lineVector, rot_axis)) if dot(cross_prod_1, cross_prod_2) < 0: quat2 = Q(rot_axis, theta) else: quat2 = Q(rot_axis, - theta) movables = self.graphicsMode.getMovablesForLeftDragging() self.assy.rotateSpecifiedMovables( quat2, movables = movables, commonCenter = pivotPoint) self.glpane.gl_update() return
def interpolate3DTransform(matrixList, indexList, percent): """ This function gets input of two list and a percent value. Return value is a 4x4 matrix corresponding to percent% of the transformation. matrixList: a list of 4x4 transformation matrix indexList : a list of sorted index (positive float number) percent : a positive float number. if only one matrix in the matrix list: percent = 0.0 means no transformation (identity) 1.0 means 100% of the transformation (returns mat) 0.58 means 58% of translation and rotatetion 58% of rotation angle along the same rotation axis percent can go above 1.0 If matrixList has more than one matrix: matrixList=[M1, M2, M3] #Attention: All M uses the same reference frame indexList =[0.2, 0.5, 1.0] #Attention: assume the list sorted ascendingly p = 0.5 means apply M2 p = 0.8 means apply M3 p = 0.9 means apply M2 first, then apply 50% of M'. M' is the transformation from M2 to M3. 50% = (0.9-0.8) / (1.0-0.8) M2 x M' = M3 --> M2.inverse x M2 x M'= M2.inverse x M3 --> M'= M2.inverse x M """ listLen = len(matrixList) if listLen != len(indexList): raise ValueError("matrix list should have same length of index list") if listLen == 0: raise ValueError("no matrix found in the matrix list") offset = -1 for i in range(listLen): if indexList[i] >= percent: offset = i break prevMat = nextMat = N.identity(4, 'f') if offset == -1: prevMat = matrixList[-1] p = percent / indexList[-1] return _interpolateMat(matrixList[-1], p) elif offset == 0: nextMat = matrixList[0] p = percent / indexList[0] return _interpolateMat(N.array(matrixList[0]), p) else: prevMat = matrixList[offset - 1] nextMat = matrixList[offset] p = (percent - indexList[offset - 1]) / (indexList[offset] - indexList[offset - 1]) from numpy.oldnumeric.linear_algebra import inverse M = N.dot(inverse(prevMat), nextMat) Mat = _interpolateMat(M, p) return N.dot(prevMat, Mat)
def interpolate3DTransform(matrixList, indexList, percent): """ This function gets input of two list and a percent value. Return value is a 4x4 matrix corresponding to percent% of the transformation. matrixList: a list of 4x4 transformation matrix indexList : a list of sorted index (positive float number) percent : a positive float number. if only one matrix in the matrix list: percent = 0.0 means no transformation (identity) 1.0 means 100% of the transformation (returns mat) 0.58 means 58% of translation and rotatetion 58% of rotation angle along the same rotation axis percent can go above 1.0 If matrixList has more than one matrix: matrixList=[M1, M2, M3] #Attention: All M uses the same reference frame indexList =[0.2, 0.5, 1.0] #Attention: assume the list sorted ascendingly p = 0.5 means apply M2 p = 0.8 means apply M3 p = 0.9 means apply M2 first, then apply 50% of M'. M' is the transformation from M2 to M3. 50% = (0.9-0.8) / (1.0-0.8) M2 x M' = M3 --> M2.inverse x M2 x M'= M2.inverse x M3 --> M'= M2.inverse x M """ listLen = len(matrixList) if listLen != len(indexList): raise ValueError("matrix list should have same length of index list") if listLen == 0: raise ValueError("no matrix found in the matrix list") offset = -1 for i in range(listLen): if indexList[i] >= percent: offset = i break prevMat = nextMat = N.identity(4,'f') if offset == -1: prevMat = matrixList[-1] p = percent/indexList[-1] return _interpolateMat(matrixList[-1], p) elif offset == 0: nextMat = matrixList[0] p = percent/indexList[0] return _interpolateMat(N.array(matrixList[0]), p) else: prevMat = matrixList[offset-1] nextMat = matrixList[offset] p = (percent-indexList[offset-1])/( indexList[offset]-indexList[offset-1]) from numpy.oldnumeric.linear_algebra import inverse M = N.dot(inverse(prevMat), nextMat) Mat = _interpolateMat(M, p) return N.dot(prevMat, Mat)
def project_2d_noeyeball(self, pt): """ Bruce: Project a point into our plane (ignoring eyeball). Warning: arbitrary origin! Huaicai 4/20/05: This is just to project pt into a 2d coordinate system (self.right, self.up) on a plane through pt and parallel to the screen plane. For perspective projection, (x, y) on this plane is different than that on the plane through pov. """ x, y = self.right, self.up return V(dot(pt, x), dot(pt, y))
def calc_torsion_angle(atom_list): """ Calculates torsional angle defined by four atoms, A1-A2-A3-A4, Return torsional angle value between atoms A2 and A3. @param atom_list: list of four atoms describing the torsion bond @type atom_list: list @return: value of the torsional angle (float) """ # Note: this appears to be very general and perhaps ought to be moved to a more # general place (someday), perhaps VQT.py or nearby. [bruce 080828 comment] from numpy.oldnumeric import dot from math import atan2, pi, sqrt from geometry.VQT import cross if len(atom_list) != 4: # The list has to have four members. return 0.0 # Calculate pairwise distances v12 = atom_list[0].posn() - atom_list[1].posn() v43 = atom_list[3].posn() - atom_list[2].posn() v23 = atom_list[1].posn() - atom_list[2].posn() # p is a vector perpendicular to the plane defined by atoms 1,2,3 # p is perpendicular to v23_v12 plane p = cross(v23, v12) # x is a vector perpendicular to the plane defined by atoms 2,3,4. # x is perpendicular to v23_v43 plane x = cross(v23, v43) # y is perpendicular to v23_x plane y = cross(v23, x) # Calculate lengths of the x, y vectors. u1 = dot(x, x) v1 = dot(y, y) if u1 < 0.0 or \ v1 < 0.0: return 360.0 u2 = dot(p, x) / sqrt(u1) v2 = dot(p, y) / sqrt(v1) if u2 != 0.0 and \ v2 != 0.0: # calculate the angle return atan2(v2, u2) * (180.0 / pi) else: return 360.0
def rotateAboutPoint(self): """ Rotates the selected entities along the specified vector, about the specified pivot point (pivot point it the starting point of the drawn vector. """ if len(self.mouseClickPoints) != self.mouseClickLimit: print_compact_stack( "Rotate about point bug: mouseclick points != mouseclicklimit: " ) return pivotPoint = self.mouseClickPoints[0] ref_vec_endPoint = self.mouseClickPoints[1] rot_vec_endPoint = self.mouseClickPoints[2] reference_vec = norm(ref_vec_endPoint - pivotPoint) lineVector = norm(rot_vec_endPoint - pivotPoint) #lineVector = endPoint - startPoint quat1 = Q(lineVector, reference_vec) #DEBUG Disabled temporarily . will not be used if dot(lineVector, reference_vec) < 0: theta = math.pi - quat1.angle else: theta = quat1.angle #TEST_DEBUG-- Works fine theta = quat1.angle rot_axis = cross(lineVector, reference_vec) if dot(lineVector, reference_vec) < 0: rot_axis = -rot_axis cross_prod_1 = norm(cross(reference_vec, rot_axis)) cross_prod_2 = norm(cross(lineVector, rot_axis)) if dot(cross_prod_1, cross_prod_2) < 0: quat2 = Q(rot_axis, theta) else: quat2 = Q(rot_axis, -theta) movables = self.graphicsMode.getMovablesForLeftDragging() self.assy.rotateSpecifiedMovables(quat2, movables=movables, commonCenter=pivotPoint) self.glpane.gl_update() return
def norm (A): """ Return normalized vector A. """ if type(A) == types.ListType: A=Numeric.array(A,'f') res= A/Numeric.sqrt(Numeric.dot(A,A)) return res.tolist() elif type(A)==Numeric.ArrayType: return A/Numeric.sqrt(Numeric.dot(A,A)) else: print "Need a list or Numeric array" return None
def norm(A): """ Return normalized vector A. """ if type(A) == list: A = Numeric.array(A, 'f') res = A / Numeric.sqrt(Numeric.dot(A, A)) return res.tolist() elif type(A) == Numeric.ArrayType: return A / Numeric.sqrt(Numeric.dot(A, A)) else: print("Need a list or Numeric array") return None
def planeXline(ppt, pv, lpt, lv): """ Find the intersection of a line (point lpt on line, unit vector lv along line) with a plane (point ppt on plane, unit vector pv perpendicular to plane). Return the intersection point, or None if the line and plane are (almost) parallel. WARNING: don't use a boolean test on the return value, since V(0,0,0) is a real point but has boolean value False. Use "point is not None" instead. """ d = Numeric.dot(lv, pv) if abs(d) < 0.000001: return None return lpt + lv * (Numeric.dot(ppt - lpt, pv) / d)
def test4Embed(self): arr = Numeric.array([[0,1.0,5.0], [1.0,0,1.0], [0.0,1.0,0]],Numeric.Float) self.failUnless(DG.DoTriangleSmoothing(arr)) coords = DG.EmbedBoundsMatrix(arr,randomSeed=100); v1 = coords[0]-coords[1] v2 = coords[1]-coords[2] d1 = Numeric.dot(v1,v1) self.failUnless(feq(d1,1.0, 0.001)); d2 = Numeric.dot(v2,v2) self.failUnless(feq(d2,1.0, 0.001));
def test4Embed(self): arr = Numeric.array([[0,1.0,5.0], [1.0,0,1.0], [0.0,1.0,0]],Numeric.Float) self.assertTrue(DG.DoTriangleSmoothing(arr)) coords = DG.EmbedBoundsMatrix(arr,randomSeed=100); v1 = coords[0]-coords[1] v2 = coords[1]-coords[2] d1 = Numeric.dot(v1,v1) self.assertTrue(feq(d1,1.0, 0.001)); d2 = Numeric.dot(v2,v2) self.assertTrue(feq(d2,1.0, 0.001));
def ptonline(xpt, lpt, ldr): """ return the point on a line (point lpt, direction ldr) nearest to point xpt """ ldr = norm(ldr) return Numeric.dot(xpt - lpt, ldr) * ldr + lpt
def setup_quat_center(self, atomList=None): """ Setup the plane's quat using a list of atoms. If no atom list is supplied, the plane is centered in the glpane and parallel to the screen. @param atomList: A list of atoms. @type atomList: list """ if atomList: self.atomPos = [] for a in atomList: self.atomPos += [a.posn()] planeNorm = self._getPlaneOrientation(self.atomPos) if dot(planeNorm, self.glpane.lineOfSight) < 0: planeNorm = -planeNorm self.center = add.reduce(self.atomPos) / len(self.atomPos) self.quat = Q(V(0.0, 0.0, 1.0), planeNorm) else: self.center = V(0.0, 0.0, 0.0) # Following makes sure that Plane edges are parallel to # the 3D workspace borders. Fixes bug 2448 x, y, z = self.glpane.right, self.glpane.up, self.glpane.out self.quat = Q(x, y, z) self.quat += Q(self.glpane.right, pi)
def pca(data): transposed = 0 if shape(data)[0] < shape(data)[1]: transposed = 1 data = transpose(data) cov = dot(transpose(data), data) ## eigenvectors are row vectors val, vec = eigenvectors(cov) try: val = val.real except: pass try: vec = vec.real except: pass order = argsort(val) val = Numeric.take(val, order) vec = Numeric.take(vec, order) pc = Numeric.dot(data, transpose(vec)) if transposed: pc = Numeric.transpose(pc) return val, vec, pc
def _mapToSphere (self, NewPt): # Given a new window coordinate, will modify NewVec in place X = 0 Y = 1 Z = 2 NewVec = Vector3fT () # //Copy paramter into temp point TempPt = copy.copy (NewPt) # //Adjust point coords and scale down to range of [-1 ... 1] TempPt [X] = (NewPt [X] * self.m_AdjustWidth) - 1.0 TempPt [Y] = 1.0 - (NewPt [Y] * self.m_AdjustHeight) # //Compute the square of the length of the vector to the point from the center length = Numeric.sum (Numeric.dot (TempPt, TempPt)) # //If the point is mapped outside of the sphere... (length > radius squared) if (length > 1.0): # //Compute a normalizing factor (radius / sqrt(length)) norm = 1.0 / sqrt (length); # //Return the "normalized" vector, a point on the sphere NewVec [X] = TempPt [X] * norm; NewVec [Y] = TempPt [Y] * norm; NewVec [Z] = 0.0; else: # //Else it's on the inside # //Return a vector to a point mapped inside the sphere sqrt(radius squared - length) NewVec [X] = TempPt [X] NewVec [Y] = TempPt [Y] NewVec [Z] = sqrt (1.0 - length) return NewVec
def inverse4X4(matrix): """ returns the inverse of the given 4x4 transformation matrix t_1: the negetive of Translation vector r_1: the inverse of rotation matrix inversed transformation is 1) t_1 applied first 2) then r_1 is applied to validate the result, N.dot(matrix, mat_inverse)==N.identity(4,'f') """ # check the shape if matrix.shape != (4, 4) and matrix.shape != (16, ): raise ValueError("Argument must Numeric array of shape (4,4) or (16,)") return None if matrix.shape == (16, ): matrix = N.array(matrix, 'f') matrix = N.reshape(matrix, (4, 4)) # force the matrix to be (4,4) t_1 = N.identity(4, 'f') t_1[:2, 3] = -matrix[:2, 3] r_1 = N.identity(4, 'f') r_1[:3, :3] = N.transpose(matrix[:3, :3]) mat_inverse = N.dot(r_1, t_1) #asert N.dot(matrix, mat_inverse) is N.identity(4,'f') return mat_inverse
def update_numberOfBases(self): """ Updates the numberOfBases in the PM while a resize handle is being dragged. @see: self.getCursorText() where it is called. """ #@Note: originally (before 2008-04-05, it was called in #DnaStrand_ResizeHandle.on_drag() but that 'may' have some bugs #(not verified) also see self.getCursorText() to know why it is #called there (basically a workaround for bug 2729 if self.grabbedHandle is None: return currentPosition = self.grabbedHandle.currentPosition resize_end = self.grabbedHandle.origin new_duplexLength = vlen( currentPosition - resize_end ) numberOfBasePairs_to_change = getNumberOfBasePairsFromDuplexLength('B-DNA', new_duplexLength) original_numberOfBases = self.struct.getNumberOfBases() #If the dot product of handle direction and the direction in which it #is dragged is negative, this means we need to subtract bases direction_of_drag = norm(currentPosition - resize_end) if dot(self.grabbedHandle.direction, direction_of_drag ) < 0: total_number_of_bases = original_numberOfBases - numberOfBasePairs_to_change self.propMgr.numberOfBasesSpinBox.setValue(total_number_of_bases) else: total_number_of_bases = original_numberOfBases + numberOfBasePairs_to_change self.propMgr.numberOfBasesSpinBox.setValue(total_number_of_bases - 1)
def __CM_Align_to_chunk(self): """ Rotary or Linear Motor context menu command: "Align to chunk" This uses the chunk connected to the first atom of the motor. """ # I needed this when attempting to simulate the rotation of a long, skinny # chunk. The axis computed from the attached atoms was not close to the axis # of the chunk. I figured this would be a common feature that was easy to add. # ##e it might be nice to dim this menu item if the chunk's axis hasn't moved since this motor was made or recentered; # first we'd need to extend the __CM_ API to make that possible. [mark 050717] cmd = greenmsg("Align to Chunk: ") chunk = self.atoms[0].molecule # Get the chunk attached to the motor's first atom. # wware 060116 bug 1330 # The chunk's axis could have its direction exactly reversed and be equally valid. # We should choose between those two options for which one has the positive dot # product with the old axis, to avoid reversals of motor direction when going # between "align to chunk" and "recenter on atoms". #bruce 060116 modified this fix to avoid setting axis to V(0,0,0) if it's perpendicular to old axis. newAxis = chunk.getaxis() if dot(self.axis,newAxis) < 0: newAxis = - newAxis self.axis = newAxis self.assy.changed() # wware 060116 bug 1331 - assembly changed when axis changed info = "Aligned motor [%s] on chunk [%s]" % (self.name, chunk.name) env.history.message( cmd + info ) self.assy.w.win_update() return
def __init__(self, crv, vector): if not isinstance(crv, Crv.Crv): raise NURBSError, 'Parameter crv not derived from Crv class!' coefs = numerix.zeros((4, crv.cntrl.shape[1], 2), numerix.Float) coefs[:, :, 0] = crv.cntrl coefs[:, :, 1] = numerix.dot(translate(vector), crv.cntrl) Srf.__init__(self, coefs, crv.uknots, [0., 0., 1., 1.])
def rotate(self, rot, coords): """Apply rotation to the coordinates. Rotation can be a 3x3 matrix or 3 Euler angles""" if isinstance(rot[0], types.FloatType): rot = EulerAnglesToMat(rot) return Numeric.dot(coords, Numeric.transpose(rot))
def viewParallelTo(self): """ Set view parallel to the vector defined by 2 selected atoms. """ cmd = greenmsg("Set View Parallel To: ") atoms = self.assy.selatoms_list() if len(atoms) != 2: msg = redmsg("You must select 2 atoms.") env.history.message(cmd + msg) return v = norm(atoms[0].posn() - atoms[1].posn()) if vlen(v) < 0.0001: # Atoms are on top of each other. info = 'The selected atoms are on top of each other. No change in view.' env.history.message(cmd + info) return # If vec is pointing into the screen, negate (reverse) vec. if dot(v, self.glpane.lineOfSight) > 0: v = -v # Compute the destination quat (q2). q2 = Q(V(0, 0, 1), v) q2 = q2.conj() self.glpane.rotateView(q2) info = 'View set parallel to the vector defined by the 2 selected atoms.' env.history.message(cmd + info)
def doit(self, atom1, atom2, angle, mov_atoms, returnVal=0): mol = atom1.top if mov_atoms is None: mov_atoms = mol.subTree(atom1, atom2, mol.allAtoms) assert len(mov_atoms) mov_coords = Numeric.array(mov_atoms.coords) lenCoords = len(mov_coords) x = Numeric.array(atom1.coords) y = Numeric.array(atom2.coords) rot = (angle * 3.14159/180.)%(2 * Numeric.pi) matrix = rotax(x, y, rot) _ones = Numeric.ones(lenCoords, 'f') _ones.shape = (lenCoords,1) mov_coords = Numeric.concatenate((mov_coords, _ones),1) newcoords = Numeric.dot(mov_coords, matrix) nc = newcoords[:,:3].astype('f') for i in range(lenCoords): at = mov_atoms[i] at._coords[at.conformation] = nc[i].tolist() event = EditAtomsEvent('coords', mov_atoms) self.vf.dispatchEvent(event) #have to return nc for setTorsionGC if returnVal: return nc
def viewParallelTo(self): """ Set view parallel to the vector defined by 2 selected atoms. """ cmd = greenmsg("Set View Parallel To: ") atoms = self.assy.selatoms_list() if len(atoms) != 2: msg = redmsg("You must select 2 atoms.") env.history.message(cmd + msg) return v = norm(atoms[0].posn()-atoms[1].posn()) if vlen(v) < 0.0001: # Atoms are on top of each other. info = 'The selected atoms are on top of each other. No change in view.' env.history.message(cmd + info) return # If vec is pointing into the screen, negate (reverse) vec. if dot(v, self.glpane.lineOfSight) > 0: v = -v # Compute the destination quat (q2). q2 = Q(V(0,0,1), v) q2 = q2.conj() self.glpane.rotateView(q2) info = 'View set parallel to the vector defined by the 2 selected atoms.' env.history.message(cmd + info)
def doit(self, nodes): if len(nodes) == 0: return 'ERROR' # prevent logging if nothing was picked vt = self.vf.transformedCoordinatesWithInstances(nodes) g = [0., 0., 0.] i = 0 for v in vt: g[0] += v[0] g[1] += v[1] g[2] += v[2] i += 1 g[0] = g[0] / i g[1] = g[1] / i g[2] = g[2] / i vi = self.vf.GUI.VIEWER if vi.redirectTransformToRoot or vi.currentObject == vi.rootObject: self.vf.centerGeom(vi.rootObject, g, topCommand=0, log=1, setupUndo=1) else: m = vi.currentObject.GetMatrixInverse(root=vi.currentObject) g.append(1.0) g = Numeric.dot(m, g)[:3] self.vf.centerGeom(vi.currentObject, g, topCommand=0, log=1, setupUndo=1)
def closest_pt_params_to_ray(self, ray): "" p2, v2 = ray.params # note: at first I wrote self.params() (using method not attr) p1, v1 = self.params # do some math, solve for k in p1 + k * v1 = that point (remember that the vecs can be of any length): # way 1: express p2-p1 as a weighted sum of v1, v2, cross(v1,v2), then take the v1 term in that sum and add it to p1. # way 2: There must be a NumPy function that would just do this in about one step... # way 3: or maybe we can mess around with dot(v1,v2) sort of like in corner_analyzer in demo_polygon... # way 4: or we could google for "closest points on two lines" or so... # way 5: or we could call it the intersection of self with the plane containing p2, and directions v2 and the cross prod, # and use a formula in VQT. Yes, that may not be self-contained but it's fastest to code! v1n = norm(v1) v2n = norm(v2) perp0 = cross(v1n, v2n) if vlen(perp0) < 0.01: ##k btw what if the lines are parallel, in what way should we fail? # and for that matter what if they are *almost* parallel so that we're too sensitive -- do we use an env param # to decide whether to fail in that case too? If we're an Instance we could do that from self.env... #e print "closest_pt_params_to_ray: too sensitive, returning None" ###### teach caller to handle this; let 0.01 be option return None perpn = norm(perp0) perpperp = cross(perpn,v2n) inter = planeXline(p2, perpperp, p1, v1n) # intersect plane (as plane point and normal) with line (as point and vector) if inter is None: print "inter is None (unexpected); data:",p1,v1,p2,v2,perp0 return None # inter is the retval for a variant which just wants the closest point itself, i.e. closest_pt_to_ray return dot(inter - p1, v1n) / vlen(v1)
def doit(self, atom1, atom2, angle, mov_atoms, returnVal=0): mol = atom1.top if mov_atoms is None: mov_atoms = mol.subTree(atom1, atom2, mol.allAtoms) assert len(mov_atoms) mov_coords = Numeric.array(mov_atoms.coords) lenCoords = len(mov_coords) x = Numeric.array(atom1.coords) y = Numeric.array(atom2.coords) rot = (angle * 3.14159 / 180.) % (2 * Numeric.pi) matrix = rotax(x, y, rot) _ones = Numeric.ones(lenCoords, 'f') _ones.shape = (lenCoords, 1) mov_coords = Numeric.concatenate((mov_coords, _ones), 1) newcoords = Numeric.dot(mov_coords, matrix) nc = newcoords[:, :3].astype('f') for i in range(lenCoords): at = mov_atoms[i] at._coords[at.conformation] = nc[i].tolist() event = EditAtomsEvent('coords', mov_atoms) self.vf.dispatchEvent(event) #have to return nc for setTorsionGC if returnVal: return nc
def recompute_geom_both_ends_constrained(self): """ Using self.b0L_pvec and self.chain_quat_cum and self.bm1R_pvec, figure out self.twist... [used for rings, and for linear chains with both ends constrained] """ bonds = self.listb # what pvec would we have on the right end of the chain, if there were no per-bond twist? bm1R_pvec_no_twist = self.chain_quat_cum.rot( self.b0L_pvec ) # note, this is a vector perp to bond[-1] axism1 = self.axes[-1] # what twist is needed to put that vector over the actual one (or its neg), perhaps with 90-deg offset? i = len(bonds) - 1 ## if self.twist90 and i % 2 == 1: ## bm1R_pvec_no_twist = norm(cross(axism1, bm1R_pvec_no_twist)) # use negative if that fits better if dot(bm1R_pvec_no_twist, self.bm1R_pvec) < 0: bm1R_pvec_no_twist = - bm1R_pvec_no_twist # total twist is shared over every bond # note: we care which direction we rotate around axism1 total_twist = twistor_angle( axism1, bm1R_pvec_no_twist, self.bm1R_pvec) # in radians; angular range is undefined, for now # [it's actually +- 2pi, twice what it would need to be in general], # so we need to coerce it into the range we want, +- pi/2 (90 degrees); here too we use the fact # that in this case, a twist of pi (180 degrees) is the same as 0 twist. while total_twist > math.pi/2: total_twist -= math.pi while total_twist <= - math.pi/2: total_twist += math.pi self.twist = total_twist / len(bonds) return
def doit(self,mobAtoms): """ mobAtoms: AtomSet that is being frozen. Assuming the AtomSet are from same molecule """ # fixme: need checking for mat (matrix) and mobAtoms geomContainer = mobAtoms[0].top.geomContainer mGeom = geomContainer.masterGeom mat = mGeom.rotation mat = Numeric.reshape(mat, (4,4)) # update coords mobAtoms = mobAtoms.findType(Atom) coords = mobAtoms.coords hCoords = Numeric.concatenate((coords,Numeric.ones((len(coords),1),\ 'd')), 1) tCoords = Numeric.dot(hCoords, mat)[:,:3] tCoords = tCoords.tolist() mobAtoms.updateCoords(tCoords, 0) # overwritten the original coords # reset the rotation matrix of masterGeom identity = Numeric.identity(4,'f').ravel() mGeom.SetRotation(Numeric.identity(4,'f').ravel() ) event = EditAtomsEvent('coords', mobAtoms) self.vf.dispatchEvent(event) mGeom.viewer.Redraw() return
def __init__(self, crv, vector): if not isinstance(crv, Crv.Crv): raise NURBSError, 'Parameter crv not derived from Crv class!' coefs = numerix.zeros((4,crv.cntrl.shape[1],2), numerix.Float) coefs[:,:,0] = crv.cntrl coefs[:,:,1] = numerix.dot(translate(vector), crv.cntrl) Srf.__init__(self, coefs, crv.uknots, [0., 0., 1., 1.])
def ConcatRotation(self, matrix): """Overwrite rotation methods""" self._modified = True Transformable.ConcatRotation(self, matrix) self.rotation.shape = (4, 4) #eqn = Numeric.array(self.rotation[0,:3]) # because direction is (1.,0.,0.) eqn = numpy.dot(self.direction, self.rotation) #print '=================================================' #print 'eqn', eqn, eqn.shape #self.n = 1.0 / sqrt( Numeric.add.reduce(eqn*eqn) ) x, y, z = eqn[:3] self.n = 1.0 / sqrt(x * x + y * y + z * z) self.eqn[:3] = eqn[:3] #print 'self.eqn',self.eqn self.eqn[3] = -Numeric.dot(self.eqn[:3], self.translation) #print self.eqn #get the value so that the plane is equivalent to having the proper #normal vector and a translation from the origin along the vector for o in self.copyXform: o._NormalizeN() self.rotation.shape = (16, ) self.viewer.deleteOpenglList()
def doit(self, mobAtoms): """ mobAtoms: AtomSet that is being frozen. Assuming the AtomSet are from same molecule """ # fixme: need checking for mat (matrix) and mobAtoms geomContainer = mobAtoms[0].top.geomContainer mGeom = geomContainer.masterGeom mat = mGeom.rotation mat = Numeric.reshape(mat, (4, 4)) # update coords mobAtoms = mobAtoms.findType(Atom) coords = mobAtoms.coords hCoords = Numeric.concatenate((coords,Numeric.ones((len(coords),1),\ 'd')), 1) tCoords = Numeric.dot(hCoords, mat)[:, :3] tCoords = tCoords.tolist() mobAtoms.updateCoords(tCoords, 0) # overwritten the original coords # reset the rotation matrix of masterGeom identity = Numeric.identity(4, 'f').ravel() mGeom.SetRotation(Numeric.identity(4, 'f').ravel()) event = EditAtomsEvent('coords', mobAtoms) self.vf.dispatchEvent(event) mGeom.viewer.Redraw() return