.NET繪制旋轉太極圖

.NET繪制旋轉太極圖

我之前發了一篇《用.NET寫“算命”程序》的文章,但有人紛紛提出了質疑,認為沒有“科學”(mi xin)依據??。

所謂“太極生兩儀,兩儀生四象,四象生八卦,八卦定吉兇,吉兇生大業”,因此,我只要證明.NET可以將太極圖繪制出來,不就說明.NET算命的“科學”是有依據了嘛??

首先來看一下最終效果:

太極的構成

仔細觀察這個太極圖,它分為以下幾部分:

  • 基本窗口
  • 白色左圓、黑色右圓
  • 白色左圓中的黑色1/4圓,黑色右圓中的白色1/4
  • 黑色、白色半圓
  • 旋轉動畫

因此制作時,我們從這些方面著手制作。

基本窗口

首先需要一個渲染窗口,使用FlysEngine.Desktop,可以輕松制作一個:

using var taiji = new RenderWindow();
taiji.Draw += (o, e) =>
{
    e.Clear(Color.CornflowerBlue);
};
RenderLoop.Run(taiji, () => taiji.Render(1, 0));

運行效果如下:

白色左圓、黑色右圓

Direct2D有繪制圓和非常簡單的API,可以直接調用,但在此之前需要先確定該圓的半徑,我們最窗口的較小值減去5單位的邊距(Margin),順便計算一下中心點,以便于稍后做矩陣變換:

float GetMinEdge() => Math.Min(
    taiji.XResource.RenderTarget.Size.Width, 
    taiji.XResource.RenderTarget.Size.Height);

Vector2 GetCenter() => new Vector2(
    taiji.XResource.RenderTarget.Size.Width / 2, 
    taiji.XResource.RenderTarget.Size.Height / 2);

float GetR() => (GetMinEdge() - 5.0f) / 2;

順便定義一下黑、白兩種顏色:

Color Color_Black = Color.Black;
Color Color_White = Color.White;

所以繪制的代碼如下:

float scale = GetR();
Vector2 center = GetCenter();
Matrix3x2 rotation = Matrix3x2.Rotation(angle);

ctx.Transform = rotation * Matrix3x2.Scaling(scale, scale) * Matrix3x2.Translation(center);
ctx.FillEllipse(new Ellipse(new Vector2(0.5f, 0), 0.5f, 0.5f), o.XResource.GetColor(Color_Black));
ctx.FillEllipse(new Ellipse(new Vector2(-0.5f, 0), 0.5f, 0.5f), o.XResource.GetColor(Color_White));

此時,運行效果如下:

1/4圓

1/4圓是太極的精髓之一,正是它代表了陰與陽的互生互補。

其本質就是圓的中心還有另一個顏色的圓,代碼相對簡單,只需在上文代碼中添加如下即可:

ctx.FillEllipse(new Ellipse(new Vector2(0.5f, 0), 0.25f, 0.25f), o.XResource.GetColor(Color_White));
ctx.FillEllipse(new Ellipse(new Vector2(-0.5f, 0), 0.25f, 0.25f), o.XResource.GetColor(Color_Black));

此時,運行效果如下:

黑白半圓

還需要最后臨門一腳,就是需要一個更大的圓,包含這個圖形。仔細想想,其實這個“更大的圓”是兩個不同顏色的半圓,在Direct2D中,需要使用Geometry來實現,首先來定義這個半圓:

using var arc = new PathGeometry(taiji.XResource.Direct2DFactory);
var sink = arc.Open();
sink.BeginFigure(new Vector2(-1f, 0), FigureBegin.Filled);
sink.AddArc(new ArcSegment
{
	Point = new Vector2(1f, 0), 
	Size = new Size2F(1f, 1f), 
	RotationAngle = 0.0f, 
	SweepDirection = SweepDirection.Clockwise, 
	ArcSize = ArcSize.Large, 
});
sink.EndFigure(FigureEnd.Open);
sink.Close();

然后在Draw事件的Clear之后,首先繪制黑色上半圓:

ctx.Transform = Matrix3x2.Scaling(scale, scale) * Matrix3x2.Translation(center);
ctx.FillGeometry(arc, o.XResource.GetColor(Color_Black));

運行效果如下:

然后再繪制白色下半圓,注意代碼也要寫在繪制左右圓的代碼之前:

ctx.Transform = Matrix3x2.Scaling(scale, scale) * Matrix3x2.Rotation((float)Math.PI) * Matrix3x2.Translation(center);
ctx.FillGeometry(arc, o.XResource.GetColor(Color_White));

運行效果如下:

此時就已經是一個完整的太極圖標了,最后還需要添加旋轉動畫。

旋轉動畫

動畫的本質,是圖形的坐標、旋轉隨著時間的移動,而有規律的移動。這里特指旋轉,我們定義每秒旋轉0.25圈(即每4秒轉一圈):

const float Speed = 0.25f;

轉換為旋轉角,需要在UpdateLogic中添加代碼如下:

float angle = 0.0f;
taiji.UpdateLogic += (w, dt) =>
{
	angle += MathUtil.Mod2PI(Speed * MathUtil.TwoPi * dt);
};

最后需要將旋轉角angle轉換為矩陣變換,注意在操作矩陣乘法時,旋轉往往要放在第一位,否則旋轉中心點可能會出現意外,代碼如下,用于替換上文中的直接繪制代碼:

Matrix3x2 rotation = Matrix3x2.Rotation(angle);
ctx.Transform = rotation * Matrix3x2.Scaling(scale, scale) * Matrix3x2.Translation(center);
ctx.FillGeometry(arc, o.XResource.GetColor(Color_Black));

ctx.Transform = rotation * Matrix3x2.Scaling(scale, scale) * Matrix3x2.Rotation((float)Math.PI) * Matrix3x2.Translation(center);
ctx.FillGeometry(arc, o.XResource.GetColor(Color_White));

ctx.Transform = rotation * Matrix3x2.Scaling(scale, scale) * Matrix3x2.Translation(center);

最后,運行效果如下:

總結

前言中關于“科學”的論述,只是開個玩笑……但繪制這個太極圖形,還是需要一些技巧的。

本文中的所有可直接運行的代碼,已經上傳到我的Githubhttps://github.com/sdcb/blog-data/tree/master/2020/20200119-draw-taiji-using-dotnet

喜歡的朋友請關注我的微信公眾號:【DotNet騷操作】

DotNet騷操作

posted @ 2020-01-19 15:32  .NET騷操作  閱讀(1149)  評論(5編輯  收藏
最新chease0ldman老人