Kuin Advent Calendar 2016 - 20日目

この記事は【Kuin Advent Calendar 2016】の20日目の記事です。

←前の日の記事   →次の日の記事

【記事中で紹介しているコードについて】
コンパイルが通らない場合など、不具合があれば、@tatt61880まで連絡いただけると助かります。よろしくお願いいたします。


東京パラリンピック2020のエンブレムを拡張した図形を表示するKuinのコードです。
[Image:paralympic.kn.png]
paralympic.kn
{東京パラリンピック2020のエンブレムを拡張した図形を表示します。}
const title: []char :: "Paralympic 2020"
var num: int
const centerX: float :: 240.0
const centerY: float :: 240.0
const wndSizeX: int :: (@centerX * 2.0) $ int
const wndSizeY: int :: (@centerY * 2.0) $ int
var rotX: float
var rotY: float
var r: []float
var rects: []@Rect
var wndMain: wnd@Wnd
var drawMain: wnd@Draw

func main()
	do @wndMain :: wnd@makeWnd(null, %aspect, @wndSizeX, @wndSizeY, @title)
	do @drawMain :: wnd@makeDraw(@wndMain, 0, 0, @wndSizeX, @wndSizeY, %scale, %scale, false)
	do @num :: 34 {12の時に通常のパラリンピックのエンブレムになります。}
	do @init()
	do @drawMain.onPaint :: @onPaint
	do wnd@setOnKeyPress(@onKeyPress)

	while(wnd@act())
	end while
end func

func onKeyPress(key: wnd@Key, shiftCtrl: wnd@ShiftCtrl): bool
	switch(key)
	case %up, %right
		do @num :+ 2
		do @init()
		do @drawMain.paint()
		ret true
	case %down, %left
		if(@num > 4)
			do @num :- 2
			do @init()
			do @drawMain.paint()
		end if
		ret true
	end switch
	ret false
end func

func onPaint(wnd: wnd@WndBase, width: int, height: int)
	do draw@clearColor(0xFFFFFFFF)
	for j(0, @num / 2 - 2)
		for i(0, @num - 1)
			var index: int :: i * 2 + j % 2
			var rot: float :: 2.0 * lib@pi * index $ float / (@num * 2) $ float
			var cx: float :: @r[j] * lib@cos(rot) + @centerX
			var cy: float :: @r[j] * lib@sin(rot) + @centerY
			var inv : bool :: false
			if(j + 1 < index & index < @num - j) {下側の回転すべき場所}
				do inv :: true
			elif(@num + j < index & index < 2 * @num - j) {上側の消えるべき場所}
				skip i
			end if
			do @rects[j].draw(cx, cy, rot, inv)
		end for
	end for
	do draw@render(0)
end func

func init()
	var scale: float :: 350.0 / @num $ float
	var points: []@Point :: #[@num]@Point
	for i(0, @num - 1)
		var x: float :: scale * lib@cos(2.0 * lib@pi * i $ float / @num $ float)
		var y: float :: scale * lib@sin(2.0 * lib@pi * i $ float / @num $ float)
		do points[i] :: (#@Point).init(x, y)
	end for
	var l: []float :: #[@num / 2]float
	for i(0, @num / 2 - 1)
		do l[i] :: points[0].getDistance(points[1 + i])
	end for

	do @rects :: #[@num / 2 - 1]@Rect
	for i(0, @num / 2 - 2)
		{θ=0の位置でのw, h}
		var w: float :: l[@num / 2 - 2 - i]
		var h: float :: l[i]
		do @rects[i] :: (#@Rect).init(w, h)
	end for

	{@r[i]は(i+1)周目の長方形の中心までの距離}
	do @r :: #[@num / 2 - 1]float
	do @r[0] :: l[@num / 2 - 2]
	for i(1, @num / 2 - 2)
		do @r[i] :: ((@r[i - 1] + @rects[i - 1].w / 2.0) ^ 2.0 + (@rects[i - 1].h / 2.0) ^ 2.0 - (@rects[i].h / 2.0) ^ 2.0) ^ 0.5 + @rects[i].w / 2.0
	end for

	{rr[i]は(i+1)周目の長方形の内側の頂点までの距離}
	var rr: []float
	do rr :: #[@num / 2]float
	do rr[0] :: l[@num / 2 - 1] / 2.0
	for i(1, @num / 2 - 1)
		do rr[i] :: (((rr[i - 1] ^ 2.0 - (@rects[i - 1].h / 2.0) ^ 2.0) ^ 0.5 + @rects[i - 1].w) ^ 2.0 + (@rects[i - 1].h / 2.0) ^ 2.0) ^ 0.5
	end for
	do @rotX :: @centerX
	do @rotY :: @centerY + ((rr[@num / 2 - 1] ^ 2.0 - (@r[0] / 2.0) ^ 2.0) ^ 0.5 + @rects[0].h / 2.0) / 2.0
end func

class Rect()
	+var w: float
	+var h: float
	+func init(w: float, h: float): @Rect
		do me.w :: w
		do me.h :: h
		ret me
	end func
	+func draw(cx: float, cy: float, rot: float, inv: bool)
		if(inv)
			do cx :: 2.0 * @rotX - cx
			do cy :: 2.0 * @rotY - cy
		end if
		do drawRotRect(cx, cy, me.w, me.h, rot, 0xFF6188FF)
		func drawRotRect(cx: float, cy: float, w: float, h: float, rot: float, color: int)
			do w :/ 2.0
			do h :/ 2.0
			var s: float :: lib@sin(rot)
			var c: float :: lib@cos(rot)
			var x1: float ::  w * c - h * s + cx
			var y1: float ::  w * s + h * c + cy
			var x2: float :: -w * c - h * s + cx
			var y2: float :: -w * s + h * c + cy
			var x3: float :: -w * c + h * s + cx
			var y3: float :: -w * s - h * c + cy
			var x4: float ::  w * c + h * s + cx
			var y4: float ::  w * s - h * c + cy
			do draw@tri(x1, y1, x2, y2, x3, y3, color)
			do draw@tri(x3, y3, x4, y4, x1, y1, color)
		end func
	end func
end class

class Point()
	+var x: float
	+var y: float
	+func init(x: float, y: float): @Point
		do me.x :: x
		do me.y :: y
		ret me
	end func
	+func getDistance(t: @Point): float
		ret ((me.x - t.x) ^ 2.0 + (me.y - t.y) ^ 2.0) ^ 0.5
	end func
end class


←前の日の記事   →次の日の記事