def draw_me(self, canvas): """描きます""" # 色相環 color_count = len(self.color_list) # print( # f"color_count={color_count} self.area_size=({self.area_size[0]}, {self.area_size[1]})") for i in range(0, color_count): theta = math.radians(i * self.unit_arc) color = self.color_list[i] # print(f"[{i}] theta={theta} color={color}") # 円弧 # 楕円、描画する画像を指定、座標(x,y),xyの半径、角度,色、線の太さ(-1は塗りつぶし) start_angle = math.degrees(theta) - self.unit_arc / 2 end_angle = math.degrees(theta) + self.unit_arc / 2 if start_angle == end_angle: end_angle += 1 # 差が 0 だと変なとこ描画するんで cv2.ellipse(canvas, point_for_cv2(self.__origin), point_for_cv2(self.__area_size), 0, 360 - start_angle, 360 - end_angle, color_for_cv2(color, BAR_TICKS), thickness=int(self.__tickness))
def draw_bars_rate(self, canvas): """バー率を描きます""" top = self.top + self.label_gap # 左列のバー率 left = self.__left - 3 * GRID_UNIT cv2.putText( canvas, f"{int(self.rates[0]*100):3}%", point_for_cv2((left, top)), # x,y self.font, self.font_scale, color_for_cv2(BRIGHT_GRAY, BAR_TICKS), self.line_type) # 中列のバー率 left = (self.__lower_x + self.__upper_x) / 2 - 1.5 * GRID_UNIT cv2.putText( canvas, f"{int(self.rates[1]*100):3}%", point_for_cv2((left, top)), # x,y self.font, self.font_scale, color_for_cv2(DARK_GRAYISH_GRAY, BAR_TICKS), self.line_type) # 右列のバー率 left = self.__right - 0.5 * GRID_UNIT cv2.putText( canvas, f"{int(self.rates[2]*100):3}%", point_for_cv2((left, top)), # x,y self.font, self.font_scale, color_for_cv2(BRIGHT_GRAY, BAR_TICKS), self.line_type)
def draw_outline(self, canvas): """輪郭を描きます""" cv2.rectangle(canvas, point_for_cv2((self.__left, self.__top)), point_for_cv2((self.__right, self.__bottom)), color_for_cv2(BRIGHT_GRAY, BAR_TICKS), thickness=self.thickness)
def draw_vertical_line(canvas, column, row): """│描画""" left = (column + 0.5) * GRID_UNIT top = row * GRID_UNIT bottom = (row + 1) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left, bottom)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS)
def draw_horizontal_line(canvas, column, row): """─描画""" left = column * GRID_UNIT right = (column + 1) * GRID_UNIT top = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((right, top)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS)
def draw_rank2_box(self, canvas): """2段目の箱の輪郭を描きます""" # 線の太さを考慮 thickness_minus1 = self.thickness - 1 cv2.rectangle(canvas, point_for_cv2((self.__lower_x - thickness_minus1, self.__top - thickness_minus1)), point_for_cv2((self.__upper_x + thickness_minus1, self.__bottom + thickness_minus1)), color_for_cv2(DARK_GRAYISH_GRAY, BAR_TICKS), thickness=thickness_minus1 + 1)
def draw_tone_name(canvas, bar_box, tone_name): """トーン名を描きます""" line_type = 2 cv2.putText(canvas, f"{tone_name}", point_for_cv2((bar_box.left, BAR_BOX_TOP - 3.5 * GRID_UNIT)), cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, color_for_cv2(DARK_GRAYISH_GRAY, BAR_TICKS), line_type) cv2.putText( canvas, f"tone diameter", point_for_cv2( (bar_box.left + GRID_UNIT, BAR_BOX_TOP - 2.5 * GRID_UNIT)), cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, color_for_cv2(DARK_GRAYISH_GRAY, BAR_TICKS), line_type)
def draw_left_bottom_round_corner(canvas, column, row): """└描画(丸み)""" # 曲線 right = (column + 1) * GRID_UNIT top = row * GRID_UNIT cv2.ellipse( canvas, point_for_cv2((right, top)), point_for_cv2((GRID_UNIT / 2, GRID_UNIT / 2)), 0, 90, # yが逆さの座標系 180, color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS, lineType=2)
def draw_right_bottom_round_corner(canvas, column, row, line_color): """┘描画(丸み)""" # 曲線 left = column * GRID_UNIT top = row * GRID_UNIT cv2.ellipse( canvas, point_for_cv2((left, top)), point_for_cv2((GRID_UNIT / 2, GRID_UNIT / 2)), 0, 0, # yが逆さの座標系 90, color_for_cv2(line_color), thickness=LINE_THICKNESS, lineType=2)
def draw_left_top_round_corner(canvas, column, row, line_color): """┌描画(丸み)""" # 曲線 right = (column + 1) * GRID_UNIT bottom = (row + 1) * GRID_UNIT cv2.ellipse( canvas, point_for_cv2((right, bottom)), point_for_cv2((GRID_UNIT / 2, GRID_UNIT / 2)), 0, 180, # yが逆さの座標系 270, color_for_cv2(line_color), thickness=LINE_THICKNESS, lineType=2)
def draw_right_top_round_corner(canvas, column, row): """┐描画(丸み)""" # 曲線 left = column * GRID_UNIT bottom = (row + 1) * GRID_UNIT cv2.ellipse( canvas, point_for_cv2((left, bottom)), point_for_cv2((GRID_UNIT / 2, GRID_UNIT / 2)), 0, 270, # yが逆さの座標系 360, color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS, lineType=2)
def draw_3figures(self, canvas, num, left, top, color): """3桁の数字の描画""" def parse_figures(num): if num > 99: return [ f"{int(num/100)}", f"{int(num/10) % 10}", f"{num % 10}" ] if num > 9: return ["", f"{int(num/10) % 10}", f"{num % 10}"] if num > -1: return ["", f"", f"{num % 10}"] if num > -10: return ["", f"-", f"{num % 10}"] if num > -100: return ["-", f"{int(num/10) % 10}", f"{num % 10}"] # 入りきらない return ["X", "X", f"X"] figures = parse_figures(num) for i, figure in enumerate(figures): cv2.putText( canvas, f"{figure}", point_for_cv2((left + i * 0.7 * GRID_UNIT, top)), # x,y self.font, self.font_scale, color_for_cv2(color, BAR_TICKS), self.line_type)
def draw_circle(self, canvas): """描きます""" # 円レール。描画する画像を指定、座標(x,y),半径、色、線の太さ(-1は塗りつぶし) cv2.circle(canvas, point_for_cv2(self.center), int(self.radius), color_for_cv2(PALE_GRAY, BAR_TICKS), thickness=2)
def draw_point(canvas, center, r_radius, r_theta, fill_color): point_x = (r_radius * circle_radius) * math.cos(r_theta) + center[0] point_y = (r_radius * circle_radius) * -math.sin(r_theta) + center[1] cv2.circle( canvas, point_for_cv2((point_x, point_y)), 6, # radius color_for_cv2(fill_color), thickness=-1)
def draw_jp(canvas, text, left_top, true_type_font, font_size, color): """日本語の表示""" canvas = cv2_put_text_5(canvas=canvas, text=text, left_top=point_for_cv2(left_top), true_type_font=true_type_font, font_size=font_size, color=color_for_cv2(color), anchor=2) # 今指定した座標は文字描写域の中心だぞ
def draw(self, canvas): """描きます""" # 3辺 cv2.line(canvas, point_for_cv2(self.nodes_p[0]), point_for_cv2(self.nodes_p[1]), color_for_cv2(self.__edge_color, BAR_TICKS), thickness=2) cv2.line(canvas, point_for_cv2(self.nodes_p[1]), point_for_cv2(self.nodes_p[2]), color_for_cv2(self.__edge_color, BAR_TICKS), thickness=2) cv2.line(canvas, point_for_cv2(self.nodes_p[2]), point_for_cv2(self.nodes_p[0]), color_for_cv2(self.__edge_color, BAR_TICKS), thickness=2) # 3頂点 if self.__node_radius > 0: cv2.circle(canvas, point_for_cv2(self.nodes_p[0]), int(self.__node_radius), color_for_cv2(self.__nodes_color[0], BAR_TICKS), thickness=-1) cv2.circle(canvas, point_for_cv2(self.nodes_p[1]), int(self.__node_radius), color_for_cv2(self.__nodes_color[2], BAR_TICKS), thickness=-1) cv2.circle(canvas, point_for_cv2(self.nodes_p[2]), int(self.__node_radius), color_for_cv2(self.__nodes_color[1], BAR_TICKS), thickness=-1) # 重心 gravity = self.triangular_center_of_gravity() cv2.circle(canvas, point_for_cv2(gravity), int(self.__node_radius), color_for_cv2(self.__center_color, BAR_TICKS), thickness=-1)
def draw_color_cross(canvas, column, row, color): """×ます""" # 円 left = column * GRID_UNIT right = (column + 1) * GRID_UNIT top = row * GRID_UNIT bottom = (row + 1) * GRID_UNIT # バロック ダイアゴナル cv2.line(canvas, point_for_cv2((left, bottom)), point_for_cv2((right, top)), color_for_cv2(color), thickness=LINE_THICKNESS) # シニスター ダイアゴナル cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((right, bottom)), color_for_cv2(color), thickness=LINE_THICKNESS)
def draw_color_circle(canvas, column, row, color): """○ます""" # 円 left = (column + 0.5) * GRID_UNIT top = (row + 0.5) * GRID_UNIT cv2.circle(canvas, point_for_cv2((left, top)), int(GRID_UNIT / 2), color_for_cv2(color), thickness=-1)
def draw_left_bottom_corner(canvas, column, row, line_color): """└描画""" # 水平線部 left = (column + 0.5) * GRID_UNIT right = (column + 1) * GRID_UNIT top = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((right, top)), color_for_cv2(line_color), thickness=LINE_THICKNESS) # 垂直線部 left = (column + 0.5) * GRID_UNIT top = (row + 0) * GRID_UNIT bottom = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left, bottom)), color_for_cv2(line_color), thickness=LINE_THICKNESS)
def draw_left_tee(canvas, column, row): """┤描画""" # 水平線部 left = (column + 0) * GRID_UNIT right = (column + 0.5) * GRID_UNIT top = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((right, top)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS) # 垂直線部 left = (column + 0.5) * GRID_UNIT top = (row + 0) * GRID_UNIT bottom = (row + 1) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left, bottom)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS)
def draw_border(circle_rail, canvas): """背景の左限、右限の線""" diameter = 2 * circle_rail.radius half_height = diameter * math.tan(math.radians(30)) # 矩形 left = circle_rail.center[0] - circle_rail.radius top = circle_rail.center[1] - half_height right = circle_rail.center[0] + circle_rail.radius bottom = circle_rail.center[1] + half_height cv2.rectangle(canvas, point_for_cv2((left, top)), point_for_cv2((right, bottom)), color_for_cv2(GRAY, BAR_TICKS), thickness=2) # 左限の線 cv2.line(canvas, point_for_cv2((circle_rail.center[0] - circle_rail.radius, circle_rail.drawing_top)), point_for_cv2((circle_rail.center[0] - circle_rail.radius, circle_rail.drawing_bottom)), color_for_cv2(GRAY, BAR_TICKS), thickness=2) # 右限の線 cv2.line(canvas, point_for_cv2((circle_rail.center[0] + circle_rail.radius, circle_rail.drawing_top)), point_for_cv2((circle_rail.center[0] + circle_rail.radius, circle_rail.drawing_bottom)), color_for_cv2(GRAY, BAR_TICKS), thickness=2)
def draw_clock_hand(self, canvas): """時計の針を描きます""" inner_p = (self.radius1 * math.cos(self.theta) + self.center[0], -self.radius1 * math.sin(self.theta) + self.center[1]) outer_p = (self.radius2 * math.cos(self.theta) + self.center[0], -self.radius2 * math.sin(self.theta) + self.center[1]) cv2.line(canvas, point_for_cv2(inner_p), point_for_cv2(outer_p), color_for_cv2(PALE_GRAY, BAR_TICKS), thickness=2) # 時計の針の先 # 楕円、描画する画像を指定、座標(x,y),xyの半径、角度,色、線の太さ(-1は塗りつぶし) start_angle = math.degrees(self.theta) - self.unit_arc / 2 end_angle = math.degrees(self.theta) + self.unit_arc / 2 if start_angle == end_angle: end_angle += 1 # 差が 0 だと変なとこ描画するんで cv2.ellipse(canvas, point_for_cv2(self.center), point_for_cv2((self.radius2, self.radius2)), 0, 360 - start_angle, 360 - end_angle, color_for_cv2(PALE_GRAY, BAR_TICKS), thickness=int(self.tickness)) cv2.ellipse(canvas, point_for_cv2(self.center), point_for_cv2((self.radius3, self.radius3)), 0, 360 - start_angle, 360 - end_angle, color_for_cv2(PALE_GRAY, BAR_TICKS), thickness=int(self.tickness))
def draw_3bars(self, canvas): """バーを描きます""" # yは逆さ # バーR cv2.rectangle(canvas, point_for_cv2((self.__left, self.__top)), point_for_cv2( (self.__red_right, self.__top + self.one_height)), color_for_cv2(SOFT_RED, BAR_TICKS), thickness=-1) # バーG cv2.rectangle(canvas, point_for_cv2( (self.__left, self.__top + self.one_height)), point_for_cv2((self.__green_right, self.__top + 2 * self.one_height)), color_for_cv2(SOFT_GREEN, BAR_TICKS), thickness=-1) # バーB cv2.rectangle(canvas, point_for_cv2( (self.__left, self.__top + 2 * self.one_height)), point_for_cv2((self.__blue_right, self.__bottom)), color_for_cv2(SOFT_BLUE, BAR_TICKS), thickness=-1)
def draw_up_arrow(canvas, column, row, line_color): """↑描画""" left = (column + 0.5) * GRID_UNIT top = (row + 0.2) * GRID_UNIT bottom = (row + 1) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left, bottom)), color_for_cv2(line_color), thickness=LINE_THICKNESS) # 矢頭 left2 = (column + 0.2) * GRID_UNIT top2 = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left2, top2)), color_for_cv2(line_color), thickness=LINE_THICKNESS) # 矢頭 left2 = (column + 0.8) * GRID_UNIT top2 = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left2, top2)), color_for_cv2(line_color), thickness=LINE_THICKNESS)
def draw_left_arrow(canvas, column, row): """←描画""" left = (column + 0.2) * GRID_UNIT right = (column + 1) * GRID_UNIT top = (row + 0.5) * GRID_UNIT # 線 cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((right, top)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS) # 矢頭 left2 = (column + 0.5) * GRID_UNIT top2 = (row + 0.2) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left2, top2)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS) # 矢頭 left2 = (column + 0.5) * GRID_UNIT top2 = (row + 0.8) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left2, top2)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS)
def draw_down_arrow(canvas, column, row): """↓描画""" left = (column + 0.5) * GRID_UNIT top = row * GRID_UNIT bottom = (row + 0.8) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((left, bottom)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS) # 矢頭 left2 = (column + 0.2) * GRID_UNIT bottom2 = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, bottom)), point_for_cv2((left2, bottom2)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS) # 矢頭 left2 = (column + 0.8) * GRID_UNIT bottom2 = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, bottom)), point_for_cv2((left2, bottom2)), color_for_cv2(LINE_COLOR), thickness=LINE_THICKNESS)
def draw_space(canvas, column, row): """半角スペースを三角形で描画""" center = (column + 0.5) * GRID_UNIT bottom2 = (row + 0.8) * GRID_UNIT # 底辺部 left = (column + 0.1) * GRID_UNIT right = (column + 0.9) * GRID_UNIT bottom = (row + 1) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, bottom)), point_for_cv2((right, bottom)), color_for_cv2(FONT_COLOR), thickness=FONT_THICKNESS) # 左斜辺 left2 = (column + 0.1) * GRID_UNIT cv2.line(canvas, point_for_cv2((left2, bottom)), point_for_cv2((center, bottom2)), color_for_cv2(FONT_COLOR), thickness=FONT_THICKNESS) # 右斜辺 left2 = (column + 0.9) * GRID_UNIT cv2.line(canvas, point_for_cv2((center, bottom2)), point_for_cv2((right, bottom)), color_for_cv2(FONT_COLOR), thickness=FONT_THICKNESS)
def draw_right_arrow(canvas, column, row, line_color): """→描画""" left = column * GRID_UNIT right = (column + 0.8) * GRID_UNIT top = (row + 0.5) * GRID_UNIT cv2.line(canvas, point_for_cv2((left, top)), point_for_cv2((right, top)), color_for_cv2(line_color), thickness=LINE_THICKNESS) # 矢頭 right2 = (column + 0.5) * GRID_UNIT top2 = (row + 0.2) * GRID_UNIT cv2.line(canvas, point_for_cv2((right, top)), point_for_cv2((right2, top2)), color_for_cv2(line_color), thickness=LINE_THICKNESS) # 矢頭 right2 = (column + 0.5) * GRID_UNIT top2 = (row + 0.8) * GRID_UNIT cv2.line(canvas, point_for_cv2((right, top)), point_for_cv2((right2, top2)), color_for_cv2(line_color), thickness=LINE_THICKNESS)
def draw_canvas(canvas, bar_box, circle_rail, outer_circle, large_triangle, clock_hand, _error_angle): """アニメの1コマを作成します""" circle_rail.draw_circle(canvas) # 円レール circle_rail.draw_triangle(canvas) # 円に内接する正三角形 draw_border(circle_rail, canvas) # 背景の上限、下限の線 large_triangle.draw(canvas) bar_box.draw_3bars(canvas) # RGBバー bar_box.draw_x_axis_label(canvas) # X軸のラベル # 水平線R # 線、描画する画像を指定、座標1点目、2点目、色、線の太さ cv2.line(canvas, point_for_cv2(large_triangle.nodes_p[0]), point_for_cv2((bar_box.red_right, bar_box.red_top)), color_for_cv2(RED, BAR_TICKS), thickness=2) # 水平線G cv2.line( canvas, point_for_cv2(large_triangle.nodes_p[2]), # 青と緑が入れ替わっているのが工夫 point_for_cv2((bar_box.green_right, bar_box.green_top)), color_for_cv2(GREEN, BAR_TICKS), thickness=2) # 水平線B cv2.line(canvas, point_for_cv2(large_triangle.nodes_p[1]), point_for_cv2((bar_box.blue_right, bar_box.blue_top)), color_for_cv2(BLUE, BAR_TICKS), thickness=2) outer_circle.draw_me(canvas) # 外環状 # 時計の針 clock_hand.draw_clock_hand(canvas) # バー箱の2段目の黒枠 bar_box.draw_rank2_box(canvas) # 色成分数 # 1色成分 n3bars_width = bar_box.create_3bars_width() color = convert_3bars_to_ticks(n3bars_width, bar_box.width) bar_box.draw_rgb_number(canvas, color) # 角度(弧度法)表示 point_x = (outer_circle.radius/2 + 12*GRID_UNIT) * \ math.cos(circle_rail.theta) + circle_rail.center[0] point_y = (outer_circle.radius/2 + 12*GRID_UNIT) * \ -math.sin(circle_rail.theta) + circle_rail.center[1] cv2.putText(canvas, f"{math.degrees(circle_rail.theta):3.0f}", point_for_cv2((point_x, point_y)), cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, color_for_cv2(BLACK, BAR_TICKS), lineType=2) # debug 重心 #gravity1 = circle_rail.triangle.triangular_center_of_gravity() #gravity2 = large_triangle.triangular_center_of_gravity() #diff_x = abs(gravity2[0]-gravity1[0]) #diff_y = abs(gravity2[1]-gravity1[1]) # cv2.putText(canvas, # # gravity diff=({diff_x:11.5f}, {diff_y:11.5f}) # f"error angle={error_angle} deg", # point_for_cv2((GRID_UNIT, GRID_UNIT)), # x,y # cv2.FONT_HERSHEY_SIMPLEX, # FONT_SCALE, # color_for_cv2(BLACK, BAR_TICKS), # lineType=2) return canvas
def draw_canvas(canvas, bar_box, circle_rail, outer_circle, large_triangle, clock_hand, _error_angle): """アニメの1コマを作成します""" circle_rail.draw_circle(canvas) # 円レール circle_rail.draw_triangle(canvas) # 円に内接する正三角形 draw_border(circle_rail, canvas) # 背景の上限、下限の線 large_triangle.draw(canvas) # 大三角形 bar_box.draw_3bars(canvas) # RGBバー bar_box.draw_x_axis_label(canvas) # X軸のラベル # 垂直線R # 線、描画する画像を指定、座標1点目、2点目、色、線の太さ cv2.line(canvas, point_for_cv2(large_triangle.nodes_p[0]), point_for_cv2((bar_box.red_right, bar_box.red_top)), color_for_cv2(RED, BAR_TICKS), thickness=2) # 垂直線G cv2.line( canvas, point_for_cv2(large_triangle.nodes_p[2]), # 青と緑が入れ替わっているのが工夫 point_for_cv2((bar_box.green_right, bar_box.green_top)), color_for_cv2(GREEN, BAR_TICKS), thickness=2) # 垂直線B cv2.line(canvas, point_for_cv2(large_triangle.nodes_p[1]), point_for_cv2((bar_box.blue_right, bar_box.blue_top)), color_for_cv2(BLUE, BAR_TICKS), thickness=2) outer_circle.draw_me(canvas) # 外環状 # 時計の針 clock_hand.draw_clock_hand(canvas) # バー箱の2段目の黒枠 bar_box.draw_rank2_box(canvas) # 色成分数 bar_box.draw_rgb_number( canvas, convert_3bars_to_ticks(bar_box.create_3bars_width(), bar_box.width)) # 角度(弧度法)表示 point_x = (outer_circle.radius/2 + 12*GRID_UNIT) * \ math.cos(circle_rail.theta) + circle_rail.center[0] point_y = (outer_circle.radius/2 + 12*GRID_UNIT) * \ -math.sin(circle_rail.theta) + circle_rail.center[1] cv2.putText(canvas, f"{math.degrees(circle_rail.theta):3.0f}", point_for_cv2((point_x, point_y)), cv2.FONT_HERSHEY_SIMPLEX, FONT_SCALE, color_for_cv2(BLACK, BAR_TICKS), lineType=2) return canvas