奥运五环
先看实际例子。


https://olympics.com/ioc/olympic-rings
奥林匹克标志 (Olympic Logo /Symbole Olympique/Olympic Rings)是由皮埃尔·德·顾拜旦先生于1913年构思设计的,是由《奥林匹克宪章》确定的,也被称为奥运五环标志,它是世界范围内最为人们广泛认知的奥林匹克运动会标志。它由5个奥林匹克环套接组成,有蓝、黄、黑、绿、红5种颜色。环从左到右互相套接,上面是蓝、黑、红环,下面是是黄、绿环。整个造型为一个底部小的规则梯形。(from baidu百科)
五环的两个版本
在北京奥运会上看到的五环标志是国际奥委会1986年公布的版本,在环与环套接之处留有间隙。下图是本文程序的绘制效果。
2010年之后,五环标志的视觉样式变为“无缝交错”版本,也就是在今年(2021)东京2020奥运会看到的、以及将要在明年年初北京2022冬奥会上看到的五环。下图是本文程序的绘制效果。
程序说明
- 利用pensize(),color(),circle()画出圆环。
- 正确处理圆环之间的遮挡关系。采用分段法,除黄色环一次画出,其他四个环都分两次画出。在两环的交叠区域,后绘制的部分遮盖较早绘制的部分。
- 每一段圆环的绘制分为三步:_move_to()移到起始位置,_jump_circle()根据需要跳过一段圆弧,_draw_ring()落笔绘制。在draw_5rings()中定义了p,c,r三个List,实际是查表,每一次循环从List读取需要的参数。数据之间是有关联的。例如c[0]跳过45度,r[0]落笔画出180度即半圆环,所以在后面的c[6]跳过45+180=225度之后,再画出r[6]的180度,即另一半,从而完成整个圆环。OlympicRings实例化时指定speed等于1到10 之间的数,可以观察动画过程。
- draw_5rings(True)将输出带有套接间隙的奥运五环。_draw_ring()函数中的ex变量设置为5,这是为了多出一点余量,确保圆环完整。
源代码
# -* encoding: utf-8 *
# Turtle example: The Olympic rings
# Author: wanghuiict
from turtle import Turtle,Screen
U=28 # unit
R=2.75
class OlympicRings(Turtle):
def __init__(self, speed=0):
Turtle.__init__(self)
self.hideturtle()
self.speed(speed)
''' (w * steps) * (h * steps) '''
def draw_recflag(self, step, color='red', w=30, h=20):
self.pensize(1)
self.penup()
self.home()
self.left(180)
self.forward(w/2 * step)
self.right(90)
self.forward(h/2 * step - R * step)
self.pendown()
self.fill(True)
self.color(color)
self.begin_fill()
for _ in range(2):
self.right(90)
self.forward(w * step)
self.right(90)
self.forward(h * step)
self.end_fill()
self.penup()
def _move_to(self, distance, angle=90, distance2=0):
self.penup()
self.home()
self.fd(distance)
self.lt(angle)
if distance2 != 0:
self.fd(distance2)
def __circle_part(self, radius, extent=360, show=True):
if radius == 0:
return
if not show:
self.penup()
else:
self.pendown()
self.circle(radius, extent)
def _jump_circle(self, radius, extent):
return self.__circle_part(radius, extent, False)
def _draw_ring(self, radius, extent, color, showspace=False):
if showspace == True:
self.color('white')
self.pensize(0.7 * U)
self.__circle_part(radius, extent)
self.color(color)
self.pensize(0.5 * U)
if showspace == True:
ex = 5 if extent > 0 else -5
self.__circle_part(radius, ex)
self.__circle_part(radius, -extent-ex-ex)
else:
self.__circle_part(radius, extent)
def draw_5rings(self, showspace=True):
p = [(R*U, 90, 0), ((6.4+R)*U, 90, 0), (-(6.4+R)*U, 270, 0),
(-(3.2+R)*U, 270, 3*U), ((3.2-R)*U, 270, 3*U), (-(6.4+R)*U, 270, 0),
(R*U, 90, 0), ((3.2-R)*U, 270, 3*U), ((6.4+R)*U, 90, 0)]
c = [(R*U, 45), (0, 0), (0, 0),
(0, 0), (R*U, 135), (R*U, 135),
(R*U, 225), (R*U, 315), (R*U, 225)]
r = [(180, '#232223'), (225, '#EE324E'), (135, '#0081BC'),
(360, '#FCB131'), (180, '#009D57'), (225, '#0081BC'),
(180, '#232223'), (180, '#009D57'), (135, '#EE324E')]
for i in range(9):
self._move_to(p[i][0], p[i][1], p[i][2])
self._jump_circle(c[i][0], c[i][1])
self._draw_ring(R*U, r[i][0], r[i][1], showspace)
if __name__ == '__main__':
W=60
H=40
wn = Screen()
wn.bgcolor("lightgreen")
wn.title("The Olympic rings")
wn.screensize(W*10, H*10)
a = OlympicRings(speed=0)
a.draw_recflag(12, color='white', w=W, h=H)
a.draw_5rings(False)
wn.exitonclick()