仮想計算機構

IT業界と無縁な派遣社員のブログ

【Sage】サイクロイドのアニメーションを作った

サイクロイドのアニメーションを作る。
参考:サイクロイド - Wikipedia

環境

OS:Windows 10
Python 3.7.7
Sage 9.2

用いる式


x=r(\theta-\sin(\theta))\\
y=r(1-\cos(\theta))

プログラム

半径1の円が1回転するまでの様子を描画する。

theta=var('theta')
r=1
ts = [2*pi*(i+1)/30 for i in range(30)]

時刻 t における「サイクロイド」「回転する円」「円の中心とサイクロイドを結ぶベクトル」の3つを描画する。

frames = [arrow((r*t,r),(r*(t-sin(t)),r*(1-cos(t))))
     +circle((r*t,r),radius=r)
     +parametric_plot((r*(theta-sin(theta)),r*(1-cos(theta))),(theta,0,t)) for t in ts]

作成したフレームをanimate関数に渡し、gifファイルとして保存する。

animate(frames,xmin=-0.5,xmax=2*pi+0.5,ymin=-0.5,ymax=2.5).gif(savefile="cycloid.gif")

実行結果

【Sage】Trefoil knot の可視化

Parametric surfacewikipedia に載っている CG を Sage で再現した。
参考:https://en.wikipedia.org/wiki/Parametric_surface

環境

OS:Windows 10
Python 3.7.7
Sage version 9.2

プログラム

u,v=var('u,v')
r = 5
parametric_plot3d((r * sin(3 * u) / (2 + cos(v)),
                   r * (sin(u) + 2 * sin(2 * u)) / (2 + cos(v + pi * 2 / 3)),
                   r / 2 * (cos(u) - 2 * cos(2 * u)) * (2 + cos(v)) * (2 + cos(v + pi * 2 / 3)) / 4),
                   (u,-pi,3*pi),
                   (v,-pi,3*pi),
                  plot_points=[100,100],
                  opacity=0.3)

実行結果

manimでドラえもんを描く

はじめに


manim の練習としてキャラクターの描画を行います。

環境

OS : Windows 10
Python : 3.7.6
Manim Community : 0.13.0

プログラム

from manim import *
import math

class Manimemon(Scene):
    def construct(self):
        # face
        blue_face = Circle(color=BLUE,fill_opacity=1,radius=1.3).set_z_index(0)
        white_face = Circle(color=WHITE,fill_opacity=1).set_z_index(1).shift(0.2*DOWN)

        # eyes
        eye_w = 0.4
        eye_h = 0.5
        eye = VGroup(Ellipse(width=eye_w,height=eye_h,color=WHITE,fill_opacity=1).set_z_index(2),
                          Ellipse(width=eye_w,height=eye_h,color=BLACK).set_z_index(3))
        eyes = VGroup(eye,eye.copy()).arrange(buff=0).shift(0.9*UP)

        black_left_eye = Circle(radius=0.1,color=BLACK,fill_opacity=1)
        black_right_eye = Circle(radius=0.1,color=BLACK,fill_opacity=1)
        black_eyes = VGroup(black_right_eye,black_left_eye).set_z_index(4).arrange(buff=0.1).shift(0.9*UP)
        
        light_left_eye = Circle(radius=0.01,color=WHITE,fill_opacity=1).move_to(black_left_eye)
        light_right_eye = Circle(radius=0.01,color=WHITE,fill_opacity=1).move_to(black_right_eye)
        light_eyes = VGroup(light_left_eye,light_right_eye).set_z_index(4)

        # nose
        nose = Circle(color=RED,fill_opacity=1,radius=0.1).set_z_index(3).shift(0.6*UP)
        nasalis = Line(color=BLACK,start=DOWN*0.7,end=nose.get_center()).set_z_index(2)

        # mouse
        mouse = Arc(color=BLACK,radius=0.7,start_angle=3.14,angle=3.14).set_z_index(2).shift(DOWN*0.7+[0,0.7,0])

        # beard
        r1,r2 = 0.4,1
        beard_angles = [math.pi/3+math.pi/2, math.pi/2+math.pi/2, math.pi*2/3+math.pi/2,
                        math.pi/3-math.pi/2, math.pi/2-math.pi/2, math.pi*2/3-math.pi/2]
        beard = VGroup(*[Line(color=BLACK,
                                    start=[r1*math.cos(theta),r1*math.sin(theta),0],
                                    end=[r2*math.cos(theta),r2*math.sin(theta),0])
                               for theta in beard_angles]).set_z_index(2)

        # manimemon
        manimemon = VGroup(blue_face,white_face,eyes,black_eyes,light_eyes,
                           nose,nasalis,mouse,beard)
        
        self.play(AnimationGroup(*[GrowFromCenter(mo) for mo in manimemon],lag_ratio=0.4))
        self.play(Wiggle(manimemon))
        self.play(FadeOut(manimemon))

        code = '''
from manim import *
import math

class Manimemon(Scene):
    def construct(self):
        # face
        blue_face = Circle(color=BLUE,
                           fill_opacity=1,
                           radius=1.3).set_z_index(0)
        white_face = Circle(color=WHITE,
                            fill_opacity=1).set_z_index(1).shift(0.2*DOWN)

        # eyes
        eye_w = 0.4
        eye_h = 0.5
        eye = VGroup(Ellipse(width=eye_w,
                             height=eye_h,
                             color=WHITE,
                             fill_opacity=1).set_z_index(2),
                     Ellipse(width=eye_w,
                             height=eye_h,
                             color=BLACK).set_z_index(3))
        eyes = VGroup(eye,eye.copy()).arrange(buff=0).shift(0.9*UP)

        black_left_eye = Circle(radius=0.1,
                                color=BLACK,
                                fill_opacity=1)
        black_right_eye = Circle(radius=0.1,
                                 color=BLACK,
                                 fill_opacity=1)
        black_eyes = VGroup(black_right_eye,black_left_eye)
        black_eyes.set_z_index(4).arrange(buff=0.1).shift(0.9*UP)
        
        light_left_eye = Circle(radius=0.01,
                                color=WHITE,
                                fill_opacity=1).move_to(black_left_eye)
        light_right_eye = Circle(radius=0.01,
                                 color=WHITE,
                                 fill_opacity=1).move_to(black_right_eye)
        light_eyes = VGroup(light_left_eye,light_right_eye).set_z_index(4)

        # nose
        nose = Circle(color=RED,
                      fill_opacity=1,
                      radius=0.1).set_z_index(3).shift(0.6*UP)
        nasalis = Line(color=BLACK,
                       start=DOWN*0.7,
                       end=nose.get_center()).set_z_index(2)

        # mouse
        mouse = Arc(color=BLACK,
                    radius=0.7,
                    start_angle=math.pi,
                    angle=math.pi).set_z_index(2).shift(DOWN*0.7+[0,0.7,0])

        # beard
        r1,r2 = 0.4,1
        beard_angles = [math.pi*5/6, math.pi, math.pi*7/6,
                        -math.pi/6, 0, math.pi/6]
        beard = VGroup(*[Line(color=BLACK,
                              start=[r1*math.cos(theta),r1*math.sin(theta),0],
                              end=[r2*math.cos(theta),r2*math.sin(theta),0])
                         for theta in beard_angles]).set_z_index(2)

        # manimemon
        manimemon = VGroup(blue_face,white_face,eyes,black_eyes,light_eyes,
                           nose,nasalis,mouse,beard)
        
        self.play(AnimationGroup(*[GrowFromCenter(mo) for mo in manimemon],
                                 lag_ratio=0.4))
        self.play(Wiggle(manimemon))
        self.play(FadeOut(manimemon))
        '''
        rendered_code = Code(code=code,
                             background="window",
                             language="Python",
                             font="Monospace",
                             font_size=20).move_to(8*DOWN)
        self.play(rendered_code.animate.move_to(8*UP),
                  run_time=15)
        self.wait(1)
        self.play(FadeOut(rendered_code))

実行

> manim .\scene.py

実行結果


「PythonとJavaScriptではじめるデータビジュアライゼーション」3.6.5 の freeze について

発生したエラー

datasetというモジュールの利用する際のエラーについて。SQLクエリの結果をCSVに変換・保存する際に freeze を利用します。書籍P66における例でいうと

dataset.freeze(winners, format='csv', filename='data/nobel_winners_ds.csv')

という書き方になりますが、これは以下のエラーによりうまくいきません。

AttributeError: module 'dataset' has no attribute 'freeze'

下記のQAによると、dataset モジュール自体が2つのモジュールに分かれているようです。

必要なのは datafreeze のインストールです。

> pip install datafreeze

元のコード自体は下記のように変更しておきます。

from dataset.app import freeze
freeze(winners, format='csv', filename='data/nobel_winners_ds.csv')

改めて実行するとまたエラーが出てしまいます。

  File "C:\Users\user\anaconda3\envs\py376\lib\site-packages\datafreeze\format\common.py", line 7, in <module>
    from normality import slugify
ModuleNotFoundError: No module named 'normality'

normality というモジュールがないと怒られているのでインストールします。

> pip install normality

改めて実行すると、dataディレクトリ配下にCSVファイルが正しく保存されていることが確認できました。

筆者の環境

OS : Windows 10
Python : 3.7.6 (anaconda)
dataset : 1.5.0
datafreeze : 0.1.0
normality : 2.2.5

【パタヘネ】【Python】乗算ハードウェアの第1のバージョンのシミュレーション

乗算ハードウェアのシミュレーション

パタヘネ(上)図 3.3 計算のハードウェアで乗算を実行した場合のレジスタの変化を表示するプログラムを作成しました。乗数の対象は6ビット符号なし整数です。例えば

2\times 3=6

という乗算においては2が被乗数、3が乗数、6が積になります。ハードウェア上では乗数に6ビット、被乗数と積にそれぞれ12ビットのレジスタを割り当てます。

実行環境

Python 3.7.6
OS : Windows 10

プログラム

import sys

if len(sys.argv)==3:
    md = int(sys.argv[1])
    mr = int(sys.argv[2])
else:
    md = 50 # multiplicand
    mr = 10 # multiplier

p = 0 # product

print('{} x {} = {}'.format(md,mr,md*mr))
print('-'*50)
print('cycle | step | multiplier | multiplicand | product')
print('-'*50)
print('0 | init  | {:06b} | {:012b} | {:012b}'.format(mr,md,p))

for i in range(6):
    # product = product + multiplicand
    str_mr = format(mr,'06b')
    if str_mr[-1] == '1':
        p += md
        print('{} | plus  | {:06b} | {:012b} | {:012b}'.format(i+1,mr,md,p))

    # left shift
    md = md<<1
    print('{} | shift | {:06b} | {:012b} | {:012b}'.format(i+1,mr,md,p))

    # right shift
    mr = mr>>1
    print('{} | shift | {:06b} | {:012b} | {:012b}'.format(i+1,mr,md,p))

print('-'*50)

実行例

> python .\main.py 12 14
12 x 14 = 168
--------------------------------------------------
cycle | step | multiplier | multiplicand | product
--------------------------------------------------
0 | init  | 001110 | 000000001100 | 000000000000
1 | shift | 001110 | 000000011000 | 000000000000
1 | shift | 000111 | 000000011000 | 000000000000
2 | plus  | 000111 | 000000011000 | 000000011000
2 | shift | 000111 | 000000110000 | 000000011000
2 | shift | 000011 | 000000110000 | 000000011000
3 | plus  | 000011 | 000000110000 | 000001001000
3 | shift | 000011 | 000001100000 | 000001001000
3 | shift | 000001 | 000001100000 | 000001001000
4 | plus  | 000001 | 000001100000 | 000010101000
4 | shift | 000001 | 000011000000 | 000010101000
4 | shift | 000000 | 000011000000 | 000010101000
5 | shift | 000000 | 000110000000 | 000010101000
5 | shift | 000000 | 000110000000 | 000010101000
6 | shift | 000000 | 001100000000 | 000010101000
6 | shift | 000000 | 001100000000 | 000010101000
--------------------------------------------------

参考文献

パターソン&ヘネシー『コンピュータの構成と設計 第5版 上』日経BP

Windows環境 で openFrameworks をインストールして動かしてみる

0.筆者の環境

OS : Windows 10
CPU : Intel Core i5 2.60GHz
IDE : Visual Studio Community 2019 Version 16.8.4

1.インストール

1.1 ダウンロード

以下のサイトからダウンロードします。

筆者の環境はVS2019ですが、Visual Studio 2017 を選択します。

f:id:riverta1992:20210908210132p:plain

ダウンロードが開始されます。ダウンロードが完了したら解凍しましょう。

1.2 プロジェクトの作成

projectGenerator フォルダの中から projectGenerator という実行ファイルを探して起動します。

f:id:riverta1992:20210908210255p:plain

Project name はいったん mySketch のまま進めます。パス等の情報を入力したらさっそく Generate を押しましょう。apps/myApps 配下に mySketch が作成されていれば成功です。mySketch フォルダの中に mySketch.sln というファイルがあるか確認し、Visual Studio で開きます。

f:id:riverta1992:20210908210513p:plain

サンプルプログラムが生成されているのがわかります。さっそくF5を押して実行してみます。

f:id:riverta1992:20210908210352p:plain

Visual Studio 2017のビルドツールがないと怒られています。バージョンが違うから当然です。

1.3 ビルド、実行

対策として、下記のように赤矢印で示した箇所を右クリックし、プロジェクトの再ターゲットを選択しましょう。

f:id:riverta1992:20210908214054p:plain

ターゲットを最新バージョンに設定します。

f:id:riverta1992:20210908210525p:plain

さて、改めてF5を押してサンプルが動くか試しましょう。下記のような何もないウィンドウが立ち上がれば成功です。

f:id:riverta1992:20210908210534p:plain

2.ほかのサンプル

他のプログラムもしっかり動くのか確かめたいので、examples フォルダの中から三角関数関係のプロジェクトを動かしてみます。

f:id:riverta1992:20210908211042p:plain

sln ファイルを選択し、右クリックでプログラムから開きます。使うのはもちろん Visual Studio 2019 です。先ほどは明示的にプロジェクトの再ターゲットを行いましたが、今度は勝手に再ターゲットを促してくれます。

f:id:riverta1992:20210908211850p:plain

設定が終わったらプログラムを確認し、F5を押します。

f:id:riverta1992:20210908211900p:plain

なんだかよくわからない三角関数のアニメーションが始まりました。サンプルがいっぱいあるので勉強のしがいがありそうです。

【Python】ニュートンフラクタルの可視化


wikiの疑似コードを参考に実装します。

プログラム

import numpy as np
import cv2

Px,Py = 360,420
img = np.zeros((Px, Py,3), np.uint8)
roots = [1+0j,-0.5+np.sqrt(3)/2j, -0.5-np.sqrt(3)/2j]
r_hsv = cv2.cvtColor(np.uint8([[[255,0,0]]]),cv2.COLOR_RGB2HSV)[0][0]
g_hsv = cv2.cvtColor(np.uint8([[[0,255,0]]]),cv2.COLOR_RGB2HSV)[0][0]
b_hsv = cv2.cvtColor(np.uint8([[[0,0,255]]]),cv2.COLOR_RGB2HSV)[0][0]
colors = [r_hsv,g_hsv,b_hsv]
xmin,xmax = -2.5,1
ymin,ymax = -1,1
N = 100
tolerance = 0.001

def f(z):
    return z**3-1

def derivative_f(z):
    return 3*z**2

def get_color(x,y):
    zx = (xmax-xmin)*x/Px+xmin
    zy = (ymax-ymin)*y/Py+ymin
    z = zx+zy*1j

    for i in range(N):
        z -= f(z)/derivative_f(z)
        for j,root in enumerate(roots):
            diff = z - root
            if abs(diff.real)<tolerance and abs(diff.imag)<tolerance:
                h,s,v = colors[j]
                
                # Coloring 1
                '''
                r,g,b = cv2.cvtColor(np.uint8([[[h,s,v]]]),cv2.COLOR_HSV2RGB)[0][0]
                '''

                # Coloring 2
                '''
                M = 20
                v = v*(M-np.min([i,M-1]))/M
                r,g,b = cv2.cvtColor(np.uint8([[[h,s,v]]]),cv2.COLOR_HSV2RGB)[0][0]
                '''
                # Coloring 3
                h = (10*i)%180
                r,g,b = cv2.cvtColor(np.uint8([[[h,255,255]]]),cv2.COLOR_HSV2RGB)[0][0]
                
                return [r,g,b]
    return [0,0,0]

for x in range(Px):
    print(x)
    for y in range(Py):
        img[x][y] = get_color(x,y)

cv2.imwrite('test.png', img)

実行結果

色付けパターン1

f:id:riverta1992:20210624200926p:plain

色付けパターン2

解に到達するまでの反復回数に応じて色の明るさを決めます。
f:id:riverta1992:20210624201052p:plain

色付けパターン3

HSV色空間を使い、解に到達するまでの反復回数に応じて色相を変えます。OpenCVにおけるHSVは最大(180,255,255)であることに注意します。

f:id:riverta1992:20210624201210p:plain