def sortFaces(self): import numpy as np import matrix camera = G.cameras[0] indices = self.primitives[self.nPrimitives - self.nTransparentPrimitives:] if len(indices) == 0: return m = matrix.translate(-self.translation) m = matrix.rotx(-self.rx) * m m = matrix.roty(-self.ry) * m m = matrix.rotz(-self.rz) * m m = matrix.translate(self.translation) * m cxyz = matrix.transform3(m, camera.eye) # Prepare sorting data verts = self.verts[indices] - cxyz distances = np.sum(verts ** 2, axis = -1) distances = np.amin(distances, axis = -1) distances = -distances # Sort order = np.argsort(distances) indices2 = indices[order,:] indices[...] = indices2
def getModelMatrix(self, obj): """ Calculate model view matrix for this orbital camera Currently ignores the actual model transformation Note that matrix is constructed in reverse order (using post-multiplication) """ # Note: matrix is constructed with post-multiplication in reverse order m = np.matrix(np.identity(4)) # First translate to camera center, then rotate around that center m = m * matrix.translate(self.center) # Move mesh to original position again if not obj.object.lockRotation: if self.verticalInclination != 0: m = m * matrix.rotx(self.verticalInclination) if self.horizontalRotation != 0: m = m * matrix.roty(self.horizontalRotation) # Ignore scale (bounding boxes ignore scale as well, anyway) # if any(x != 1 for x in self.scale): # m = m * matrix.scale(self.scale) center = [-self.center[0], -self.center[1], -self.center[2]] m = m * matrix.translate(center) # Move mesh to its rotation center to apply rotation if obj: m = m * obj.object.transform # Apply object transform first return m
def movePolygon(self, x, y): global grabbedPoint global grabbedPolygon # Matrix that translates the polygon. It is shifted in order to move the polygon in relation to # the point in which it was first clicked. translationMatrix = matrix.translate(-grabbedPoint.x, -grabbedPoint.y, 0) * matrix.translate(x, y, 0) # The polygon also moves the nail that attached it to a father, if there is one. if self.fatherNail != None: nailVector = [[self.fatherNail.x], [self.fatherNail.y], [0], [1]] translatedNail = np.array(translationMatrix * nailVector) if np.isnan(translatedNail[0][0]) or np.isnan( translatedNail[1][0]): return # nail position isn't updated if there is a NaN value self.fatherNail.x = translatedNail[0][0] self.fatherNail.y = translatedNail[1][0] # Each vertex of the polygon is translated. for vertex in self.vertexes: vertexVector = [[vertex.x], [vertex.y], [vertex.z], [1]] translatedVector = np.array(translationMatrix * vertexVector) vertex.x = translatedVector[0][0] vertex.y = translatedVector[1][0] self.triangulate() # the polygon's respective triangles are updated # Recursively, each descendant of the polygon is translated as well for child in self.children: child.movePolygon(x, y) # The root updates the mouse position that is grabbing the polygon, after all # polygons in the tree have moved. if self == grabbedPolygon: grabbedPoint = Vertex(x, y)
def getModelMatrix(self, obj): """ Calculate model view matrix for this orbital camera Currently ignores the actual model transformation Note that matrix is constructed in reverse order (using post-multiplication) """ # Note: matrix is constructed with post-multiplication in reverse order m = np.matrix(np.identity(4)) # First translate to camera center, then rotate around that center m = m * matrix.translate( self.center) # Move mesh to original position again if not obj.object.lockRotation: if self.verticalInclination != 0: m = m * matrix.rotx(self.verticalInclination) if self.horizontalRotation != 0: m = m * matrix.roty(self.horizontalRotation) # Ignore scale (bounding boxes ignore scale as well, anyway) #if any(x != 1 for x in self.scale): # m = m * matrix.scale(self.scale) center = [-self.center[0], -self.center[1], -self.center[2]] m = m * matrix.translate( center) # Move mesh to its rotation center to apply rotation if obj: m = m * obj.object.transform # Apply object transform first return m
def sortFaces(self): camera = G.cameras[0] indices = self.primitives[self.nPrimitives - self.nTransparentPrimitives:] if len(indices) == 0: return m = matrix.translate(-self.translation) m = matrix.rotx(-self.rx) * m m = matrix.roty(-self.ry) * m m = matrix.rotz(-self.rz) * m m = matrix.translate(self.translation) * m cxyz = matrix.transform3(m, camera.eye) # Prepare sorting data verts = self.verts[indices] - cxyz distances = np.sum(verts**2, axis=-1) distances = np.amin(distances, axis=-1) distances = -distances # Sort order = np.argsort(distances) indices2 = indices[order, :] indices[...] = indices2
def opengl绘图循环(所有图层): glfw.init() glfw.window_hint(glfw.RESIZABLE, False) window = glfw.create_window(500, 500, 'Vtuber', None, None) glfw.make_context_current(window) glViewport(0, 0, 500, 500) glEnable(GL_TEXTURE_2D) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) for 图层数据 in 所有图层: 纹理编号 = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, 纹理编号) 纹理 = cv2.resize(图层数据['npdata'], (512, 512)) width, height = 纹理.shape[:2] glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_FLOAT, 纹理) glGenerateMipmap(GL_TEXTURE_2D) 图层数据['纹理编号'] = 纹理编号 while not glfw.window_should_close(window): glfw.poll_events() glClearColor(1, 1, 1, 1) glClear(GL_COLOR_BUFFER_BIT) for 图层数据 in 所有图层: a, b, c, d = 图层数据['位置'] z = 图层数据['深度'] p1 = np.array([a, b, z, 1, 0, 0]) p2 = np.array([a, d, z, 1, 1, 0]) p3 = np.array([c, d, z, 1, 1, 1]) p4 = np.array([c, b, z, 1, 0, 1]) model = matrix.scale(1 / 250, 1 / 250, 1) @ \ matrix.translate(-1, -1, 0) @ \ matrix.rotate_ax(-math.pi / 2, axis=(0, 1)) glBindTexture(GL_TEXTURE_2D, 图层数据['纹理编号']) glColor4f(1, 1, 1, 1) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glBegin(GL_QUADS) for p in [p1, p2, p3, p4]: a = p[:4] b = p[4:6] a = a @ model a[0] *= a[2] a[1] *= a[2] if not 图层数据['名字'][:2] == '身体': 横角, 竖角 = 特征缓冲() a = a @ \ matrix.translate(0, 0, -1) @ \ matrix.rotate_ax(横角, axis=(0, 2)) @ \ matrix.rotate_ax(竖角, axis=(2, 1)) @ \ matrix.translate(0, 0, 1) a = a @ matrix.perspective(999) glTexCoord2f(*b) glVertex4f(*a) glEnd() glfw.swap_buffers(window)
def addLeaf(self, c=None, r=None): if c is None and self.leafCol is None: cols = [colors["medium orchid"], colors["magenta"], colors["pastel pink"], colors["orange red"], colors["cyan"]] rand = random.randint(0, len(cols) - 1) c = cols[rand] self.leafCol = c if self.leafCol is not None: c = self.leafCol if r is None: r = self.r - 3 t = self.position() m = self.rotMatrix m = matrix.dot(matrix.translate(t[0],t[1],t[2]), m).tolist() flower = union()( translate([0, 0.5, 0])(sphere(r)), translate([0, -0.5, 0])(sphere(r)), translate([0, 0, 0.5])(sphere(r)), translate([0, 0, -0.5])(sphere(r)) ) self.nodes.append( (multmatrix(m) (color(c) (flower) ) ) )
def forward(self,distance): if distance <= 0: return self.h = distance if self.down: if self.rotVector is not None: t = self.position() m = self.rotMatrix if self.__mode == "standard": # move initial cylinder to x axis. m = matrix.dot(m, matrix.rotate(90,0,1,0)) m = matrix.dot(matrix.translate(t[0],t[1],t[2]), m).tolist() self.addNode(m) if self.showAxes: self.__drawAxes() else: if self.dir == 'Z': self.addNode2(ang = [-90, 0, self.curAng]) else: self.addNode2() # update current position self.curPoint = np.add(self.curPoint, self.h * self.heading()) if turtle.__fullDebug__: print("curPoint = %s" % self.position()) if turtle.__toDebug__: print(" forward = %d -> heading = %s" % (self.h, self.heading().tolist()[:-1]))
def mapImageGL(srcImg, mesh, leftTop, rightBottom): log.debug("mapImageGL: 1") dstImg = gui3d.app.selectedHuman.meshData.object3d.textureTex dstW = dstImg.width dstH = dstImg.height left, top = leftTop right, bottom = rightBottom camera = getCamera(mesh) coords = mesh.r_texco texmat = gui3d.app.modelCamera.getConvertToScreenMatrix(mesh) texmat = matrix.scale((1/(right - left), 1/(top - bottom), 1)) * matrix.translate((-left, -bottom, 0)) * texmat texmat = np.asarray(texmat) texco = mesh.r_coord alpha = np.sum(mesh.r_vnorm * camera[None,:], axis=-1) alpha = np.maximum(alpha, 0) color = (np.array([0, 0, 0, 0])[None,...] + alpha[...,None]) * 255 color = np.ascontiguousarray(color, dtype=np.uint8) texco = np.ascontiguousarray(texco, dtype=np.float32) result = mh.renderSkin(dstImg, mesh.vertsPerPrimitive, coords, index = mesh.index, texture = srcImg, UVs = texco, textureMatrix = texmat, color = color, clearColor = None) return result
def opengl清楚绘图循环(所有图层, psd尺寸): def 生成纹理(img): w, h = img.shape[:2] d = 2**int(max(math.log2(w), math.log2(h)) + 1) 纹理 = np.zeros([d, d, 4], dtype=img.dtype) 纹理[:w, :h] = img return 纹理, (w / d, h / d) Vtuber尺寸 = 512, 512 glfw.init() glfw.window_hint(glfw.RESIZABLE, False) window = glfw.create_window(*Vtuber尺寸, 'Vtuber', None, None) glfw.make_context_current(window) glViewport(0, 0, *Vtuber尺寸) glEnable(GL_TEXTURE_2D) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) for 图层数据 in 所有图层: 纹理编号 = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, 纹理编号) 纹理, 纹理座标 = 生成纹理(图层数据['npdata']) width, height = 纹理.shape[:2] glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_FLOAT, 纹理) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) glGenerateMipmap(GL_TEXTURE_2D) 图层数据['纹理编号'] = 纹理编号 图层数据['纹理座标'] = 纹理座标 while not glfw.window_should_close(window): glfw.poll_events() glClearColor(1, 1, 1, 1) glClear(GL_COLOR_BUFFER_BIT) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) for 图层数据 in 所有图层: a, b, c, d = 图层数据['位置'] q, w = 图层数据['纹理座标'] p1 = np.array([a, b, 0, 1, 0, 0]) p2 = np.array([a, d, 0, 1, w, 0]) p3 = np.array([c, d, 0, 1, w, q]) p4 = np.array([c, b, 0, 1, 0, q]) model = matrix.scale(2 / psd尺寸[0], 2 / psd尺寸[1], 1) @ \ matrix.translate(-1, -1, 0) @ \ matrix.rotate_ax(-math.pi / 2, axis=(0, 1)) glBindTexture(GL_TEXTURE_2D, 图层数据['纹理编号']) glColor4f(1, 1, 1, 1) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glBegin(GL_QUADS) for p in [p1, p2, p3, p4]: a = p[:4] b = p[4:6] a = a @ model glTexCoord2f(*b) glVertex4f(*a) glEnd() glfw.swap_buffers(window)
def transform(self): m = matrix.translate(self.loc) if any(x != 0 for x in self.rot): m = m * matrix.rotx(self.rx) m = m * matrix.roty(self.ry) m = m * matrix.rotz(self.rz) if any(x != 1 for x in self.scale): m = m * matrix.scale(self.scale) return m
def __drawAxes(self): r = self.r/8 if self.__mode == "standard": hx = self.h*0.8 hy = self.r*3 hz = self.r*3 else: hx = self.r*3 hy = self.r*3 hz = self.h*0.8 # draw the Z axis. c = np.add(self.curPoint, self.h*self.rotVector/2) m = matrix.dot(matrix.translate(c[0],c[1],c[2]), self.rotMatrix).tolist() self.addNode(m, [0,0,1], r, hz, False) # draw the Y axis. m = matrix.dot(self.rotMatrix, matrix.rotate(90,-1,0,0)) m = matrix.dot(matrix.translate(c[0],c[1],c[2]), m).tolist() self.addNode(m, [0,1,0], r, hy, False) # draw the X axis. m = matrix.dot(self.rotMatrix, matrix.rotate(90,0,1,0)) m = matrix.dot(matrix.translate(c[0],c[1],c[2]), m).tolist() self.addNode(m, [1,0,0], r, hx, False)
def mapImageGL(srcImg, mesh, leftTop, rightBottom): progress = Progress()(0) log.debug("mapImageGL: 1") dstImg = G.app.selectedHuman.meshData.object3d.textureTex dstW = dstImg.width dstH = dstImg.height left, top = leftTop right, bottom = rightBottom camera = getCamera(mesh) coords = mesh.r_texco texmat = G.app.modelCamera.getConvertToScreenMatrix(mesh) texmat = matrix.scale( (1 / (right - left), 1 / (top - bottom), 1)) * matrix.translate( (-left, -bottom, 0)) * texmat texmat = np.asarray(texmat) texco = mesh.r_coord alpha = np.sum(mesh.r_vnorm * camera[None, :], axis=-1) alpha = np.maximum(alpha, 0) color = (np.array([0, 0, 0, 0])[None, ...] + alpha[..., None]) * 255 color = np.ascontiguousarray(color, dtype=np.uint8) texco = np.ascontiguousarray(texco, dtype=np.float32) progress(0.5, 0.99) result = mh.renderSkin(dstImg, mesh.vertsPerPrimitive, coords, index=mesh.index, texture=srcImg, UVs=texco, textureMatrix=texmat, color=color, clearColor=None) progress(1) return result
def opengl循环(所有图层, psd尺寸): Vtuber尺寸 = 512, 512 glfw.init() glfw.window_hint(glfw.RESIZABLE, False) window = glfw.create_window(*Vtuber尺寸, 'Vtuber', None, None) glfw.make_context_current(window) glViewport(0, 0, *Vtuber尺寸) glEnable(GL_TEXTURE_2D) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) for 图层数据 in 所有图层: 纹理编号 = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, 纹理编号) 纹理, 纹理座标 = 生成纹理(图层数据['npdata']) width, height = 纹理.shape[:2] glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_FLOAT, 纹理) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) glGenerateMipmap(GL_TEXTURE_2D) 图层数据['纹理编号'] = 纹理编号 图层数据['纹理座标'] = 纹理座标 while not glfw.window_should_close(window): glfw.poll_events() glClearColor(1, 1, 1, 0) glClear(GL_COLOR_BUFFER_BIT) for 图层数据 in 所有图层: a, b, c, d = 图层数据['位置'] z = 图层数据['深度'] if type(z) in [int, float]: z1, z2, z3, z4 = [z, z, z, z] else: [z1, z2], [z3, z4] = z q, w = 图层数据['纹理座标'] p1 = np.array([a, b, z1, 1, 0, 0, 0, 1]) p2 = np.array([a, d, z2, 1, w, 0, 0, 1]) p3 = np.array([c, d, z3, 1, w, q, 0, 1]) p4 = np.array([c, b, z4, 1, 0, q, 0, 1]) model = matrix.scale(2 / psd尺寸[0], 2 / psd尺寸[1], 1) @ \ matrix.translate(-1, -1, 0) @ \ matrix.rotate_ax(-math.pi / 2, axis=(0, 1)) glBindTexture(GL_TEXTURE_2D, 图层数据['纹理编号']) glColor4f(1, 1, 1, 1) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glBegin(GL_QUADS) for p in [p1, p2, p3, p4]: a = p[:4] b = p[4:] a = a @ model z = a[2] a[0:2] *= z b *= z 横旋转量 = 0 if not 图层数据['名字'] == '身体': 横旋转量 = math.sin(time.time() * 5) / 30 a = a @ matrix.translate(0, 0, -1) \ @ matrix.rotate_ax(横旋转量, axis=(0, 2)) \ @ matrix.translate(0, 0, 1) a = a @ matrix.perspective(999) glTexCoord4f(*b) glVertex4f(*a) glEnd() glfw.swap_buffers(window)
def getFlipMatrix(): t = matrix.translate((0, G.windowHeight, 0)) s = matrix.scale((1, -1, 1)) return t * s
def opengl绘图循环(所有图层, psd尺寸): Vtuber尺寸 = 500, 500 glfw.init() glfw.window_hint(glfw.RESIZABLE, False) glfw.window_hint(glfw.DECORATED, False) glfw.window_hint(glfw.TRANSPARENT_FRAMEBUFFER, True) glfw.window_hint(glfw.FLOATING, True) window = glfw.create_window(*Vtuber尺寸, 'Vtuber', None, None) glfw.make_context_current(window) monitor_size = glfw.get_video_mode(glfw.get_primary_monitor()).size glfw.set_window_pos(window, monitor_size.width - Vtuber尺寸[0], monitor_size.height - Vtuber尺寸[1]) glViewport(0, 0, *Vtuber尺寸) glEnable(GL_TEXTURE_2D) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) for 图层数据 in 所有图层: 纹理编号 = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, 纹理编号) 纹理, 纹理座标 = 生成纹理(图层数据['npdata']) width, height = 纹理.shape[:2] glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_FLOAT, 纹理) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) glGenerateMipmap(GL_TEXTURE_2D) 图层数据['纹理编号'] = 纹理编号 图层数据['纹理座标'] = 纹理座标 while not glfw.window_should_close(window): glfw.poll_events() glClearColor(0, 0, 0, 0) glClear(GL_COLOR_BUFFER_BIT) 横旋转量, 竖旋转量 = 特征缓冲() for 图层数据 in 所有图层: a, b, c, d = 图层数据['位置'] z1, z2, z3, z4 = 图层数据['深度'] q, w = 图层数据['纹理座标'] p1 = np.array([a, b, z1, 1, 0, 0, 0, z1]) p2 = np.array([a, d, z2, 1, z2 * w, 0, 0, z2]) p3 = np.array([c, d, z3, 1, z3 * w, z3 * q, 0, z3]) p4 = np.array([c, b, z4, 1, 0, z4 * q, 0, z4]) model = matrix.scale(2 / psd尺寸[0], 2 / psd尺寸[1], 1) @ \ matrix.translate(-1, -1, 0) @ \ matrix.rotate_ax(-math.pi / 2, axis=(0, 1)) glBindTexture(GL_TEXTURE_2D, 图层数据['纹理编号']) glColor4f(1, 1, 1, 1) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glBegin(GL_QUADS) t = [] for p in [p1, p2, p3, p4]: a = p[:4] b = p[4:8] a = a @ model a[0] *= a[2] a[1] *= a[2] if not 图层数据['名字'][:2] == '身体': a = a @ \ matrix.translate(0, 0, -1) @ \ matrix.rotate_ax(横旋转量, axis=(0, 2)) @ \ matrix.rotate_ax(竖旋转量, axis=(2, 1)) @ \ matrix.translate(0, 0, 1) a = a @ matrix.perspective(999) glTexCoord4f(*b) glVertex4f(*a) glEnd() glfw.swap_buffers(window)
def opengl绘图循环(所有图层, psd尺寸): def 生成纹理(img): w, h = img.shape[:2] d = 2**int(max(math.log2(w), math.log2(h)) + 1) 纹理 = np.zeros([d, d, 4], dtype=img.dtype) 纹理[:w, :h] = img return 纹理, (w / d, h / d) Vtuber尺寸 = 512, 512 glfw.init() 超融合() glfw.window_hint(glfw.RESIZABLE, False) window = glfw.create_window(*Vtuber尺寸, 'Vtuber', None, None) glfw.make_context_current(window) monitor_size = glfw.get_video_mode(glfw.get_primary_monitor()).size glfw.set_window_pos(window, monitor_size.width - Vtuber尺寸[0], monitor_size.height - Vtuber尺寸[1]) glViewport(0, 0, *Vtuber尺寸) glEnable(GL_TEXTURE_2D) glEnable(GL_BLEND) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) for 图层数据 in 所有图层: 纹理编号 = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, 纹理编号) 纹理, 纹理座标 = 生成纹理(图层数据['npdata']) width, height = 纹理.shape[:2] glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_FLOAT, 纹理) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) glGenerateMipmap(GL_TEXTURE_2D) 图层数据['纹理编号'] = 纹理编号 图层数据['纹理座标'] = 纹理座标 while not glfw.window_should_close(window): glfw.poll_events() glClearColor(0, 0, 0, 0) glClear(GL_COLOR_BUFFER_BIT) 横旋转量, 竖旋转量 = 特征缓冲() for 图层数据 in 所有图层: a, b, c, d = 图层数据['位置'] z = 图层数据['深度'] if type(z) in [int, float]: z1, z2, z3, z4 = [z, z, z, z] else: [z1, z2], [z3, z4] = z q, w = 图层数据['纹理座标'] p1 = np.array([a, b, z1, 1, 0, 0, 0, z1]) p2 = np.array([a, d, z2, 1, z2 * w, 0, 0, z2]) p3 = np.array([c, d, z3, 1, z3 * w, z3 * q, 0, z3]) p4 = np.array([c, b, z4, 1, 0, z4 * q, 0, z4]) model = matrix.scale(2 / psd尺寸[0], 2 / psd尺寸[1], 1) @ \ matrix.translate(-1, -1, 0) @ \ matrix.rotate_ax(-math.pi / 2, axis=(0, 1)) glBindTexture(GL_TEXTURE_2D, 图层数据['纹理编号']) glColor4f(1, 1, 1, 1) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glBegin(GL_QUADS) for p in [p1, p2, p3, p4]: a = p[:4] b = p[4:8] a = a @ model a[0:2] *= a[2] if not 图层数据['名字'][:2] == '身体': a = a @ matrix.translate(0, 0, -1) \ @ matrix.rotate_ax(横旋转量, axis=(0, 2)) \ @ matrix.rotate_ax(竖旋转量, axis=(2, 1)) \ @ matrix.translate(0, 0, 1) a = a @ matrix.perspective(999) glTexCoord4f(*b) glVertex4f(*a) glEnd() glfw.swap_buffers(window)
def rotatePolygon(self, x, y): global grabbedPoint global grabbedPolygon global rotationPoint # Returns the angle between three points, in degrees. # Useful for checking how much the polygon should rotate. # Points a, b and c must be in the form np.array([x, y, z]). def angleBetweenPoints(a, b, c): ba = a - b bc = c - b # Avoids a division by zero if (np.linalg.norm(ba) * np.linalg.norm(bc)) == 0: return 0 cosine_angle = np.dot( ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc)) # Avoids getting the arccos of a nonsensical cosine if cosine_angle > 1: cosine_angle = 1 elif cosine_angle < -1: cosine_angle = -1 angle = np.arccos(cosine_angle) if np.cross(ba, bc)[2] > 0: return np.degrees(angle) else: return np.degrees(-angle) if self == grabbedPolygon: rotationPoint = self.fatherNail # Matrix that rotates the polygon around the father nail. rotationMatrix = matrix.rotate(angleBetweenPoints( \ np.array([grabbedPoint.x, grabbedPoint.y, 0]), \ np.array([rotationPoint.x, rotationPoint.y, 0]), \ np.array([x, y, 0])\ ), \ 0, 0, 1) # The defacto matrix that rotates the polygon. It shifts the polygon so that the father nail # is in the origin, then it rotates around the father nail and finally shifts # back to the original position. nailRotationMatrix = matrix.translate(rotationPoint.x, rotationPoint.y, 0) * \ rotationMatrix * \ matrix.translate(-rotationPoint.x, -rotationPoint.y, 0) # The polygon also moves the nail that attached it to a father. Useful for the recursion. nailVector = [[self.fatherNail.x], [self.fatherNail.y], [0], [1]] rotatedNail = np.array(nailRotationMatrix * nailVector) if np.isnan(rotatedNail[0][0]) or np.isnan(rotatedNail[1][0]): return # nail position isn't updated if there is a NaN value self.fatherNail.x = rotatedNail[0][0] self.fatherNail.y = rotatedNail[1][0] # Each vertex of the polygon is rotated. for vertex in self.vertexes: vertexVector = [[vertex.x], [vertex.y], [vertex.z], [1]] rotatedVector = np.array(nailRotationMatrix * vertexVector) vertex.x = rotatedVector[0][0] vertex.y = rotatedVector[1][0] self.triangulate() # the polygon's respective triangles are updated # Recursively, each descendant of the polygon is translated as well for child in self.children: child.rotatePolygon(x, y) # The root updates the mouse position that is grabbing the polygon, after all # polygons in the tree have moved. if self == grabbedPolygon: grabbedPoint = Vertex(x, y)
def translate(self): matrix.translate(model[self.qlistwidget.currentIndex().row()]['data'], 10, 0, 0) self.opengl_widget.update()