python繪制繁花曲線代碼_使用python和pygame繪制繁花曲線的方法

前段時間看了一期《最強大腦》,里面各種繁花曲線組合成了非常美麗的圖形,一時心血來潮,想嘗試自己用代碼繪制繁花曲線,想怎么組合就怎么組合。

真實的繁花曲線使用一種稱為繁花曲線規的小玩意繪制,繁花曲線規由相互契合大小兩個圓組成,用筆插在小圓上的一個孔中,緊貼大圓的內壁滾動,就可以繪制出漂亮的圖案。這個過程可以做一個抽象:有兩個半徑不相等的圓,大圓位置固定,小圓在大圓內部,小圓緊貼著大圓內壁滾動,求小圓上的某一點走過的軌跡。

進一步分析,小圓的運動可以分解為兩個部分:小圓圓心繞大圓圓心公轉、小圓繞自身圓心自轉。設大圓圓心為A,半徑為Ra,小圓圓心為B,半徑為Rb,軌跡點為C,半徑為Rc(BC距離),設小圓公轉的弧度為θ [0,∞),如圖:

因為大圓的圓心坐標是固定的,要求得小圓上的某點的軌跡,需要先求出小圓當前時刻的圓心坐標,再求出小圓自轉的弧度,最后求出小圓上某點的坐標。

第一步:求小圓圓心坐標

小圓圓心的公轉軌跡是一個半徑為 RA- RB 的圓,求小圓圓心坐標,相當于是求半徑為 RA- RB 的圓上θ 弧度對應的點的坐標。

圓上的點的坐標公式為:

x = r * cos(θ), y = r * sin(θ)

小圓圓心坐標為:( xa+ (Ra - Rb) * cos(θ), ya + (Ra - Rb) * sin(θ) )

第二步:求小圓自轉弧度

設小圓自轉弧度為α,小圓緊貼大圓運動,兩者走過的路程相同,因此有:

Ra *θ = Rb *α

小圓自轉弧度α = (Ra / Rb) *θ

第三步:求點C坐標

點C相對小圓圓心B的公轉軌跡是一個半徑為 Rc 的圓,類似第一步,有:

軌跡點C的坐標為:( xa+ Rc* cos(θ), ya+ Rc* sin(θ))

按照以上算法分析,用python代碼實現如下:

# -*- coding: utf-8 -*-

import math

'''

功能:

已知圓的圓心和半徑,獲取某弧度對應的圓上點的坐標

入參:

center:圓心

radius:半徑

radian:弧度

'''

def get_point_in_circle(center, radius, radian):

return (center[0] + radius * math.cos(radian), center[1] - radius * math.sin(radian))

'''

功能:

內外圓A和B,內圓A沿著外圓B的內圈滾動,已知外圓圓心、半徑,已知內圓半徑,已知公轉弧度和繞點半徑,計算繞點坐標

入參:

center_A:外圓圓心

radius_A:外圓半徑

radius_B:內圓半徑

radius_C:繞點半徑

radian:公轉弧度

'''

def get_point_in_child_circle(center_A, radius_A, radius_B, radius_C, radian):

# 計算內圓圓心坐標

center_B = get_point_in_circle(center_A, radius_A - radius_B, radian)

# 計算繞點弧度(公轉為逆時針,則自轉為順時針)

radian_C = 2.0*math.pi - ((radius_A / radius_B * radian) % (2.0*math.pi))

# 計算繞點坐標

return get_point_in_circle(center_B, radius_C, radian_C)

有兩點需要注意:

(1)屏幕坐標系左上角為原點,垂直向下為Y正軸,與數學坐標系Y軸方向相反,所以第14行Y坐標為減法;

(2)默認公轉為逆時針,則自轉為順時針,所以第30行求自轉弧度時,使用了2π - α%(2π);

坐標已經計算出來,接下來使用pygame繪制。思想是以0.01弧度為一個步長,不斷計算出新的坐標,把一系列坐標連起來就會形成軌跡圖。

為了能夠形成一個封閉圖形,還需要知道繪制點什么時候會重新回到起點。想了一個辦法,以X軸正半軸為基準線,每次繪制點到達基準線,計算此時繪制點與起點的距離,達到一定精度認為已經回到起點,形成封閉圖形。

''' 計算兩點距離(平方和) '''

def get_instance(p1, p2):

return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])

'''

功能:

獲取繞點路徑的所有點的坐標

入參:

center:外圓圓心

radius_A:外圓半徑

radius_B:內圓半徑

radius_C:繞點半徑

shift_radian:每次偏移的弧度,默認0.01,值越小,精度越高,計算量越大

'''

def get_points(center, radius_A, radius_B, radius_C, shift_radian=0.01):

# 轉為實數

radius_A *= 1.0

radius_B *= 1.0

radius_C *= 1.0

P2 = 2*math.pi # 一圈的弧度為 2PI

R_PER_ROUND = int(P2/shift_radian/4) + 1 # 一圈需要走多少步(弧度偏移多少次)

# 第一圈的起點坐標

start_point = get_point_in_child_circle(center, radius_A, radius_B, radius_C, 0)

points = [start_point]

# 第一圈的路徑坐標

for r in range(1, R_PER_ROUND):

points.append(get_point_in_child_circle(center, radius_A, radius_B, radius_C, shift_radian*r))

# 以圈為單位,每圈的起始弧度為 2PI*round,某圈的起點坐標與第一圈的起點坐標距離在一定范圍內,認為路徑結束

for round in range(1, 100):

s_radian = round*P2

s_point = get_point_in_child_circle(center, radius_A, radius_B, radius_C, s_radian)

if get_instance(s_point, start_point) < 0.1:

break

points.append(s_point)

for r in range(1, R_PER_ROUND):

points.append(get_point_in_child_circle(center, radius_A, radius_B, radius_C, s_radian + shift_radian*r))

return points

再加上繪制代碼,完整代碼如下:

# -*- coding: utf-8 -*-

import math

import random

'''

功能:

已知圓的圓心和半徑,獲取某弧度對應的圓上點的坐標

入參:

center:圓心

radius:半徑

radian:弧度

'''

def get_point_in_circle(center, radius, radian):

return (center[0] + radius * math.cos(radian), center[1] - radius * math.sin(radian))

'''

功能:

內外圓A和B,內圓A沿著外圓B的內圈滾動,已知外圓圓心、半徑,已知內圓半徑、公轉弧度,已知繞點半徑,計算繞點坐標

入參:

center_A:外圓圓心

radius_A:外圓半徑

radius_B:內圓半徑

radius_C:繞點半徑

radian:公轉弧度

'''

def get_point_in_child_circle(center_A, radius_A, radius_B, radius_C, radian):

# 計算內圓圓心坐標

center_B = get_point_in_circle(center_A, radius_A - radius_B, radian)

# 計算繞點弧度(公轉為逆時針,則自轉為順時針)

radian_C = 2.0*math.pi - ((radius_A / radius_B * radian) % (2.0*math.pi))

# 計算繞點坐標

center_C = get_point_in_circle(center_B, radius_C, radian_C)

center_B_Int = (int(center_B[0]), int(center_B[1]))

return center_B_Int, center_C

''' 計算兩點距離(平方和) '''

def get_instance(p1, p2):

return (p1[0] - p2[0]) * (p1[0] - p2[0]) + (p1[1] - p2[1]) * (p1[1] - p2[1])

'''

功能:

獲取繞點路徑的所有點的坐標

入參:

center:外圓圓心

radius_A:外圓半徑

radius_B:內圓半徑

radius_C:繞點半徑

shift_radian:每次偏移的弧度,默認0.01,值越小,精度越高,計算量越大

'''

def get_points(center_A, radius_A, radius_B, radius_C, shift_radian=0.01):

# 轉為實數

radius_A *= 1.0

radius_B *= 1.0

radius_C *= 1.0

P2 = 2*math.pi # 一圈的弧度為 2PI

R_PER_ROUND = int(P2/shift_radian) + 1 # 一圈需要走多少步(弧度偏移多少次)

# 第一圈的起點坐標

start_center, start_point = get_point_in_child_circle(center_A, radius_A, radius_B, radius_C, 0)

points = [start_point]

centers = [start_center]

# 第一圈的路徑坐標

for r in range(1, R_PER_ROUND):

center, point = get_point_in_child_circle(center_A, radius_A, radius_B, radius_C, shift_radian*r)

points.append(point)

centers.append(center)

# 以圈為單位,每圈的起始弧度為 2PI*round,某圈的起點坐標與第一圈的起點坐標距離在一定范圍內,認為路徑結束

for round in range(1, 100):

s_radian = round*P2

s_center, s_point = get_point_in_child_circle(center_A, radius_A, radius_B, radius_C, s_radian)

if get_instance(s_point, start_point) < 0.1:

break

points.append(s_point)

centers.append(s_center)

for r in range(1, R_PER_ROUND):

center, point = get_point_in_child_circle(center_A, radius_A, radius_B, radius_C, s_radian + shift_radian*r)

points.append(point)

centers.append(center)

print(len(points)/R_PER_ROUND)

return centers, points

import pygame

from pygame.locals import *

pygame.init()

screen = pygame.display.set_mode((600, 400))

clock = pygame.time.Clock()

color_black = (0, 0, 0)

color_white = (255, 255, 255)

color_red = (255, 0, 0)

color_yello = (255, 255, 0)

center = (300, 200)

radius_A = 150

radius_B = 110

radius_C = 50

test_centers, test_points = get_points(center, radius_A, radius_B, radius_C)

test_idx = 2

draw_point_num_per_tti = 5

while True:

for event in pygame.event.get():

if event.type==pygame.QUIT:

pygame.quit()

exit(0)

screen.fill(color_white)

pygame.draw.circle(screen, color_black, center, int(radius_A), 2)

if test_idx <= len(test_points):

pygame.draw.aalines(screen, (0, 0, 255), False, test_points[:test_idx], 1)

if test_idx < len(test_centers):

pygame.draw.circle(screen, color_black, test_centers[test_idx], int(radius_B), 1)

pygame.draw.aaline(screen, color_black, test_centers[test_idx], test_points[test_idx], 1)

test_idx = min(test_idx + draw_point_num_per_tti, len(test_points))

clock.tick(50)

pygame.display.flip()

效果:

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持我們。

本文標題: 使用python和pygame繪制繁花曲線的方法

本文地址: http://www.cppcns.com/jiaoben/python/221131.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/271110.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/271110.shtml
英文地址,請注明出處:http://en.pswp.cn/news/271110.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Axure原型制作規范

一、 名詞定義&#xff1a; Sitemap 導航圖Widgets 組件Master 庫Label 控件名Interactions 交互動作Annotations 注釋Location and size 位置和尺寸二、 Widgets規范 本站常用widgets規范&#xff1a;命名規范&#xff1a;制定命名規范從而方便搜索和升級。 a. 全站使用&#…

系統測試相關知識筆記

1、系統測試的意義系統測試是為了發現系統中的錯誤而執行程序的過程&#xff0c;發現系統中存在的問題&#xff0c;及時處理掉&#xff0c;從而規避項目后續階段順利推進的風險、和高質量的軟件交付給客戶。2、系統測試的目的希望以最少的人力和時間發現潛在的各種錯誤和缺陷。…

最小生成樹練習1(克魯斯卡爾算法Kruskal)

今天刷一下水題練手入門&#xff0c;明天繼續。 poj1861 Network&#xff08;最小生成樹&#xff09;新手入門題。 題意&#xff1a;輸出連接方案中最長的單根網線長度&#xff08;必須使這個值是所有方案中最小的&#xff09;&#xff0c;然后輸出方案。 題解&#xff1a;本題…

java變量不聲明可以直接使用嗎_我們可以在不使用Java進行初始化的情況下聲明最終變量嗎?...

在Java中&#xff0c;final是可與字段類和方法一起使用的access修飾符。當一個方法為final時&#xff0c;它不能被覆蓋。當變量為最終變量時&#xff0c;其值無法進一步修改。當類結束時&#xff0c;不能擴展。無需初始化即可聲明最終變量如果稍后聲明了最終變量&#xff0c;則…

系統測試:單元測試相關知識筆記

一、單元測試概念單元測試也成為模塊測試&#xff0c;在模塊編寫完成且無編譯錯誤后就可以進行。單元測試側重模塊中的內部處理邏輯和數據結構。如果采用機器測試&#xff0c;一般用白盒測試法。二、單元測試檢查模塊特征1、模塊接口模塊接口保證了測試模塊數據流可以正確地流入…

跨網段遠程調試vs_如何提高后臺服務應用問題的排查效率?日志 VS 遠程調試

轉眼間&#xff0c;距離Jerry最近一篇文章推送已經過去了一個多月的時間了。公眾號更新的頻率降低&#xff0c;不是因為Jerry偷懶&#xff0c;而是由于從春節過后&#xff0c;我所在的SAP成都研究院數字創新空間整個團隊&#xff0c;一直在忙一個5月份需要交付的項目上。Jerry每…

計算機硬件知識:BIOS、EFI與UEFI詳解!

本文估計很多小白看不懂&#xff0c;但是還是建議你硬著頭皮看完&#xff0c;這篇文章主要講解了這幾種“BIOS”的啟動方式&#xff0c;對電腦啟動問題判斷的理解會有益處。BIOS是個程序&#xff0c;存儲在BIOS芯片中&#xff0c;而現在的新式電腦用的基本都是UEFI啟動&#xf…

java pdf 導出下載_Java+PDF模板導出成pdf文件,并下載

1&#xff0c;根據前人經驗&#xff0c;熟悉完成基礎操作&#xff1a;https://www.cnblogs.com/wangpeng00700/p/8418594.html?tdsourcetags_pcqq_aiomsg2&#xff0c;根據鏈接中操作完成之后&#xff0c;在本地生成pdf文件已經沒有問題了。但如果放到&#xff0c;Linux服務器…

在db2數據庫上模擬死鎖場景 還是z上的

如果條件允許&#xff0c;起兩個線程互相搶資源就行了&#xff0c;但問題是&#xff0c;時間上還需要同步&#xff0c;要做到完美控制&#xff0c;還得加其他邏輯&#xff0c;忒費事&#xff0c;所以可以用下面的辦法&#xff1a; 在目標表上直接加個鎖……簡單&#xff0c;粗暴…

條件隨機場 python_用條件隨機場做網絡小說命名實體識別

一直想用統計學習方法來改善撥云搜索&#xff0c;這次先在命名實體上小小嘗試一下。線性鏈條件隨機場對于無向圖中的節點&#xff0c;定義一組特征函數&#xff0c;使其狀態僅受鄰近節點和觀測序列的影響。在標注任務中&#xff0c;節點只有前后兩個鄰近節點&#xff0c;即線性…

項目開發基礎:常用測試方法介紹

1、集成測試集成測試就是把模塊按照設計說明書的要求組合起來進行測試。1.1、集成測試方法&#xff1a;a、分別測試各個模塊&#xff0c;再把這些模塊組合起來進行整體測試&#xff0c;也就是非增量式集成。特點&#xff1a;可以對模塊進行并行測試&#xff0c;能充分利用人力&…

java 多數據源處理_java – 用于處理多個數據源的Spring事務管理

這可能是一個重復的問題,但我找不到(至少我無法理解)一個滿意的答案,因此再次提問.我正在使用兩個數據源(MySQL和Oracle).以下是執行流程&#xff1a;主方法-A調用方法-B(寫入Oracle DB)然后它(方法-A)調用方法-C(寫入mySQL DB)然后它(方法-A)調用方法-D(寫入Oracle DB) ).如果…

MyBatis Generator

1 <?xml version"1.0" encoding"UTF-8"?>2 <!DOCTYPE generatorConfiguration3 PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"4 "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"&g…

svd奇異值分解_NCL專輯 | 奇異值分解(SVD)

奇異值分解SVD(Singular Value Decomposition)是一種矩陣分解方法&#xff0c;在氣象領域中常用來分析兩個氣象場場之間的關系。NCL的函數庫中與SVD相關的函數包括svd_lapack&#xff0c;svdcov&#xff0c;svdcov_sv&#xff0c;svdstd&#xff0c;svdstd_sv。svd_lapack&…

項目測試基礎:白盒測試相關知識筆記

1、白盒測試概念白盒測試又稱為結構測試&#xff0c;主要是根據程序的內部結構和邏輯來設計測試用例&#xff0c;然后對程序的路徑和過程進行測試&#xff0c;檢查是否滿足設計的需要。2、白盒測試常用的技術介紹白盒測試常用的技術有邏輯覆蓋、循環覆蓋、基本路徑測試。2.1 邏…

java全局變量和局部變量

分類&#xff1a; 變量按作用范圍劃分分為全局變量&#xff08;成員變量&#xff09;和局部變量 成員變量按調用方式劃分分為實例屬性與類屬性 局部變量按定義位置劃分分為形參&#xff0c;方法局部變量&#xff0c;代碼塊局部變量 成員變量&#xff1a; 直接在類中聲明的…

電腦系統知識:Windows原版系統與Ghost系統的區別,你知道嗎?

經常看到有電腦小白的朋友問原版操作系統跟Ghost的區別是什么&#xff0c;該怎么選擇安裝哪種系統&#xff1f;今天在這里就說說它們之間的聯系與區別。Windows原版系統&#xff1a;原版系統就是微軟推送給用戶的原始“干凈”的系統。系統不含第三方的軟件&#xff0c;軟件補丁…