Rhodonea Curves và Maurer Rose trong Python

Category: Pygame

Trong bài viết này, chúng ta sẽ tạo mẫu Rhodonea Curve và Maurer Rose bằng Python! Trước khi tìm hiểu chính xác Rhodonea Curve hay Maurer Rose là gì , chúng ta cần chuẩn bị cấu trúc cơ bản của chương trình!
 

Cấu trúc cơ bản của chương trình -


Trước khi tìm hiểu về đường cong Rhodonea hay mô hình hoa hồng Maurer, trước tiên chúng ta cần chuẩn bị cấu trúc cơ bản của chương trình. Để khi tái cấu trúc mã, chúng ta chỉ cần sửa đổi một hàm trong khi phần còn lại của chương trình vẫn giữ nguyên. Dưới đây là cấu trúc cơ bản của chương trình: 

from math import sin
from math import cos
from math import radians

import pygame

# Chiều rộng và chiều cao của chương trình
(width, height) = (800, 600)

# Thiết lập cửa sổ và khởi tạo bề mặt màn hình
screen = pygame.display.set_mode((width, height))

pygame.display.set_caption('Đồ thị hoa thị (Rose Curve) trong Python!')

# Màu nền của màn hình
screen.fill((250, 250, 205))  # màu lemonChiffon (vàng nhạt)

# Hàm vẽ đồ thị hoa thị
drawPattern()

# Lật màn hình đã vẽ với màn hình hiển thị (double-buffering)
# Cơ bản là làm mới màn hình sau khi vẽ xong
pygame.display.flip()

# Vòng lặp chính
while True : 
      
    # Duyệt qua các sự kiện trong hàng đợi sự kiện
    for event in pygame.event.get() : 
  
        # Nếu người dùng đóng cửa sổ
        if event.type == pygame.QUIT : 

            # Tắt pygame và thoát chương trình
            pygame.quit()   
            quit() 
  
        # Cập nhật nội dung hiển thị trên màn hình  
        pygame.display.update()

Nếu bạn chạy mã, bạn sẽ nhận được lỗi drawPattern chưa được định nghĩa. Chúng ta sẽ định nghĩa nó sau. Nhưng bây giờ cứ để nguyên như vậy và chúng ta hãy cùng tìm hiểu đường cong Rhodonea là gì !
 

Đường cong Rhodonea là gì?


Đường cong Rhodonea (còn được gọi là hoa hồng trong toán học) về cơ bản là một đường cong có thể được biểu thị dưới dạng r=coS(Nθ)   r=cos ( n θ )   Ở đâu N   N   là một số nguyên xác định số cánh hoa (2N   2 n   nếu như N   N   là thậm chí và N   N   (khi lẻ)
Bối rối? Xem hình ảnh này so sánh một bông hồng có 12 cánh với một bông hồng có 5 cánh - 


Lưu ý rằng tọa độ trong phương trình trên ở dạng cực. Nhưng vì trong đồ họa máy tính, chúng ta biểu diễn vị trí điểm ảnh ở dạng Descartes thay vì dạng cực, nên đường cong phải được mô tả lại thành một tập hợp tất cả các điểm.(x,và)   (x,)   mỗi dạng ở dạng phương trình tham số như minh họa bên dưới: 
x=rcoS(θ),và=rSTôiN(θ)   x=rcos ( θ ) ,=rs trong ( θ )   
 

Bắt tay vào thực hiện Rose Curves


Những điều trên chỉ là lý thuyết, nếu bạn chưa hiểu hết khái niệm, bạn sẽ hiểu sau khi xem nó hoạt động . Chỉ cần thêm đoạn mã sau vào dòng 17 (ngay phía trên nơi chúng ta gọi drawPattern):

# Vẽ một đường hoa thị (rose) với n cánh và bán kính khoảng `size`
def drawRhodoneaCurve(n, size):
    points =[]
    for i in range(0, 361):
        # Phương trình của đường hoa thị (Rhodonea curve)
        r = size * sin(radians(n * i))

        # Chuyển đổi sang tọa độ Đề các (Cartesian)
        x = r * cos(radians(i))
        y = r * sin(radians(i))

        list.append(points, (width / 2 + x, height / 2 + y))

    # Vẽ một tập hợp các đoạn thẳng nối các điểm trong danh sách
    # Không khép kín đường, vẽ màu đen và đặt độ dày nét là 5
    pygame.draw.lines(screen, (0, 0, 0), False, points, 5)

def drawPattern():
    # Thử thay đổi các giá trị này theo ý bạn
    drawRhodoneaCurve(12, 200)

Điều này sẽ tạo ra kết quả sau - 
 


Giải thích
 

  • Chúng tôi tính toán các đỉnh (mỗi điểm quan trọng trên hoa hồng sau đó được kết nối bằng các cạnh đơn giản là các đoạn thẳng) bằng cách sử dụng công thức mà chúng tôi đã thảo luận ở phần trên

  • Chúng tôi lưu trữ một danh sách gọi là points chứa tất cả các đỉnh của hoa hồng và sau đó danh sách các đỉnh này được đưa vào pygame.draw.lines để vẽ một chuỗi các đường thẳng liên tục và ở đây chúng tôi sử dụng nó để vẽ chuỗi đa giác (vì hoa hồng chỉ là một chuỗi đa giác)

  • Lưu ý rằng chúng ta đang sử dụng phương thức radian ở đây. Điều này là do các góc được định dạng theo độ (chúng ta có thể sử dụng trực tiếp radian nhưng range chỉ chấp nhận số nguyên, còn đối với đường cong Maurer, dù sao chúng ta cũng phải sử dụng độ, vậy tại sao không bắt đầu từ bây giờ) - hy vọng là chúng ta không phải tự chuyển đổi vì Python3 cung cấp các hàm tích hợp degrees và radian .

  • Cũng lưu ý rằng chúng ta đang dịch chuyển tọa độ theo (chiều rộng/2, chiều cao/2). Điều này là do mặc định PyGame có tọa độ ở góc trên bên trái. Nhưng chúng ta muốn nó nằm ở giữa nên dịch chuyển nó bằng một nửa chiều rộng và chiều cao màn hình. Chúng ta có thể dịch chuyển toàn bộ hệ tọa độ nhưng cách này dễ hơn!


Lưu ý về việc làm cho chương trình tương tác hơn:
Chương trình hiện tại chưa thực sự tương tác, nhưng bạn có thể làm cho nó tương tác bằng cách tăng số lượng cánh hoa lên một lượng fractal mỗi khung hình, và tùy thuộc vào tốc độ tăng dần, bạn có thể đạt được kết quả khá ấn tượng. Việc làm cho chương trình tương tác nằm ngoài phạm vi (vì điều đó sẽ làm tăng đáng kể số lượng LOC và có lẽ cũng làm tăng độ phức tạp của chương trình, đồng thời vi phạm cấu trúc cơ bản mà chúng ta đã tạo ra lúc đầu), nhưng tôi đã thử nghiệm một chút và đây là kết quả của việc tạo biến n trước rồi tăng nó lên 0,1 ở mỗi khung hình!
 

Vậy Maurer Rose là gì?


Bây giờ chúng ta đã biết về Rhodonea Curves, hãy cùng tìm hiểu về Maurer Rose:-
Maurer rose là một đường cong Rhodonea có dạng r=coS(Nθ)   r=cos ( n θ )   gồm 361 đường thẳng được nối với nhau bởi 361 điểm - mỗi đường có dạng (STôiN(Nk),k)   ( s trong ( nk ) ,k )   cho mọi k   k   trong bộ {0,ngày,2ngày,3ngày,...,360ngày}   { 0 ,d ,2 ngày ,3 ngày ,... ,360 ngày }   , Ở đâu ngày   ngày   là một số nguyên.
Các giá trị thay đổi của ngày   ngày   có thể tạo ra nhiều loại hoa hồng khác nhau ngay cả khi tất cả chúng đều có cùng số cánh hoa (có nghĩa là cùng giá trị của N   N   )
Bây giờ tọa độ Descartes sẽ có dạng:-[Tex] \trái \( x= rcos(k ), y= rsin(k ) \phải \) [/Tex]
 

Làm bẩn tay với Maurer Roses


Vì vậy, để tạo ra thứ gì đó từ những gì chúng ta vừa học, chúng ta ghi đè hàm drawPattern trước đó bằng hàm mới:-

# Vẽ một hoa thị Maurer (Maurer rose) với giá trị n và d, kích thước khoảng `size`
def drawMaurerRose(n, d, size):
    points =[]
    for i in range(0, 361):
        # Phương trình của hoa thị Maurer
        k = i * d
        r = size * sin(radians(n * k))

        # Chuyển sang tọa độ Đề các (Cartesian)
        x = r * cos(radians(k))
        y = r * sin(radians(k))

        list.append(points, (width / 2 + x, height / 2 + y))

    # Vẽ các đoạn thẳng nối các điểm trong danh sách
    # Không khép kín đường, vẽ màu đen và đặt độ dày nét là 5
    pygame.draw.lines(screen, (0, 0, 0), False, points, 5)

def drawPattern():
    # Thử thay đổi các giá trị này theo ý bạn
    drawMaurerRose(6, 79, 200)

Và bây giờ khi bạn chạy chương trình, bạn sẽ nhận được kết quả sau:
 


Giải thích:
Chỉ có những dòng được tô sáng là thay đổi, còn lại mọi thứ đều giống nhau -
 

  • Tên hàm đã được đổi từ drawRhodoneaCurve thành drawMaurerRose và hiện mong đợi một tham số bổ sung d!

  • Bây giờ chúng ta giới thiệu một biến k mới thực sự xuất phát từ công thức. Giá trị của nó ở mỗi lần lặp bằng i*d, vì vậy với d=1, hàm này hoàn toàn giống với drawRhodoneaCurve!!

  • Bây giờ chúng ta sử dụng k thay vì i và cần lưu ý rằng độ rộng của đường đã được thay đổi từ 5 thành 2 (nếu không, một số đường sẽ xuất hiện như một đường do độ dày của chúng lớn).

  • Và câu lệnh invoke tất nhiên cũng đã được thay đổi, giờ đây nó gọi hàm drawMaurerRose mới tạo với n=6 và d=71. Các giá trị được sao chép từ WikiPedia vì giá trị d ngẫu nhiên đôi khi có thể tạo ra những bông hoa hồng trông kỳ lạ!

Published on Jul 28, 2025

Related Posts