def rotate_camera_by_screen(self, start_x, start_y, end_x, end_y): factors_x, factors_y = self._get_axes_vectors() width, height = self._get_screen_dimensions() # calculate rotation factors - based on the distance to the center # (between -1 and 1) rot_x_factor = (2.0 * start_x) / width - 1 rot_y_factor = (2.0 * start_y) / height - 1 # calculate rotation angles (between -90 and +90 degrees) xdiff = end_x - start_x ydiff = end_y - start_y # compensate inverse rotation left/right side (around x axis) and # top/bottom (around y axis) if rot_x_factor < 0: ydiff = -ydiff if rot_y_factor > 0: xdiff = -xdiff rot_x_angle = rot_x_factor * math.pi * ydiff / height rot_y_angle = rot_y_factor * math.pi * xdiff / width # rotate around the "up" vector with the y-axis rotation original_distance = self.view["distance"] original_up = self.view["up"] y_rot_matrix = Matrix.get_rotation_matrix_axis_angle( factors_y, rot_y_angle) new_distance = Matrix.multiply_vector_matrix(original_distance, y_rot_matrix) new_up = Matrix.multiply_vector_matrix(original_up, y_rot_matrix) # rotate around the cross vector with the x-axis rotation x_rot_matrix = Matrix.get_rotation_matrix_axis_angle( factors_x, rot_x_angle) new_distance = Matrix.multiply_vector_matrix(new_distance, x_rot_matrix) new_up = Matrix.multiply_vector_matrix(new_up, x_rot_matrix) self.view["distance"] = new_distance self.view["up"] = new_up
def rotate_camera_by_screen(self, start_x, start_y, end_x, end_y): factors_x, factors_y = self._get_axes_vectors() width, height = self._get_screen_dimensions() # calculate rotation factors - based on the distance to the center # (between -1 and 1) rot_x_factor = (2.0 * start_x) / width - 1 rot_y_factor = (2.0 * start_y) / height - 1 # calculate rotation angles (between -90 and +90 degrees) xdiff = end_x - start_x ydiff = end_y - start_y # compensate inverse rotation left/right side (around x axis) and # top/bottom (around y axis) if rot_x_factor < 0: ydiff = -ydiff if rot_y_factor > 0: xdiff = -xdiff rot_x_angle = rot_x_factor * math.pi * ydiff / height rot_y_angle = rot_y_factor * math.pi * xdiff / width # rotate around the "up" vector with the y-axis rotation original_distance = self.view["distance"] original_up = self.view["up"] y_rot_matrix = Matrix.get_rotation_matrix_axis_angle(factors_y, rot_y_angle) new_distance = Matrix.multiply_vector_matrix(original_distance, y_rot_matrix) new_up = Matrix.multiply_vector_matrix(original_up, y_rot_matrix) # rotate around the cross vector with the x-axis rotation x_rot_matrix = Matrix.get_rotation_matrix_axis_angle(factors_x, rot_x_angle) new_distance = Matrix.multiply_vector_matrix(new_distance, x_rot_matrix) new_up = Matrix.multiply_vector_matrix(new_up, x_rot_matrix) self.view["distance"] = new_distance self.view["up"] = new_up
def get_bezier_lines(points_with_bulge, segments=32): # TODO: add a recursive algorithm for more than two points if len(points_with_bulge) != 2: return [] else: result_points = [] p1, bulge1 = points_with_bulge[0] p2, bulge2 = points_with_bulge[1] if not bulge1 and not bulge2: # straight line return [Line(p1, p2)] straight_dir = pnormalized(psub(p2, p1)) bulge1 = math.atan(bulge1) rot_matrix = Matrix.get_rotation_matrix_axis_angle((0, 0, 1), -2 * bulge1, use_radians=True) dir1_mat = Matrix.multiply_vector_matrix( (straight_dir[0], straight_dir[1], straight_dir[2]), rot_matrix) dir1 = (dir1_mat[0], dir1_mat[1], dir1_mat[2], 'v') if bulge2 is None: bulge2 = bulge1 else: bulge2 = math.atan(bulge2) rot_matrix = Matrix.get_rotation_matrix_axis_angle((0, 0, 1), 2 * bulge2, use_radians=True) dir2_mat = Matrix.multiply_vector_matrix( (straight_dir[0], straight_dir[1], straight_dir[2]), rot_matrix) dir2 = (dir2_mat[0], dir2_mat[1], dir2_mat[2], 'v') # interpretation of bulge1 and bulge2: # /// taken from http://paulbourke.net/dataformats/dxf/dxf10.html /// # The bulge is the tangent of 1/4 the included angle for an arc # segment, made negative if the arc goes clockwise from the start # point to the end point; a bulge of 0 indicates a straight segment, # and a bulge of 1 is a semicircle. alpha = 2 * (abs(bulge1) + abs(bulge2)) dist = pdist(p2, p1) # calculate the radius of the circumcircle - avoiding divide-by-zero if (abs(alpha) < epsilon) or (abs(math.pi - alpha) < epsilon): radius = dist / 2.0 else: # see http://en.wikipedia.org/wiki/Law_of_sines radius = abs(dist / math.sin(alpha / 2.0)) / 2.0 # The calculation of "factor" is based on random guessing - but it # seems to work well. factor = 4 * radius * math.tan(alpha / 4.0) dir1 = pmul(dir1, factor) dir2 = pmul(dir2, factor) for index in range(segments + 1): # t: 0..1 t = float(index) / segments # see: http://en.wikipedia.org/wiki/Cubic_Hermite_spline p = padd( pmul(p1, 2 * t**3 - 3 * t**2 + 1), padd( pmul(dir1, t**3 - 2 * t**2 + t), padd(pmul(p2, -2 * t**3 + 3 * t**2), pmul(dir2, t**3 - t**2)))) result_points.append(p) # create lines result = [] for index in range(len(result_points) - 1): result.append(Line(result_points[index], result_points[index + 1])) return result