円を描画するアルゴリズムを探していたらC言語でソースコードを公開されてるページを見つけました。
C#で書きなおしたサンプルになります。
伝説のお茶の間 No007-09(1) 円の描画(1) MichenerとBresenham
円描画のアルゴリズムのブレゼンハム(Bresenham) とミッチェナー(Michener)の紹介です。古くからあるアルゴリズムらしいのですが、あんまり解説してるサイトがないので当サイトで一通りやります
C#で書きなおしたサンプルになります。
プロジェクトの作成
PowerShellで実行。要dotnet.exe
mkdir SampleCircle
cd SampleCircle
dotnet new wpf
code .
ソースコード
<Window x:Class="SampleCircle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SampleCircle"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Image x:Name="image1" Stretch="None" />
</Grid>
</Window>
using System.Diagnostics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SampleCircle
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
static void SetPixel(ref byte[] pixels, int width, int height, int x, int y, Color c)
{
int i = (x * 4) + (y * (width * 4));
pixels[i+0] = c.B;
pixels[i+1] = c.G;
pixels[i+2] = c.R;
pixels[i+3] = c.A;
}
static void Circle(ref WriteableBitmap bitmap, int x, int y, int r, Color c)
{
int width = (int)bitmap.PixelWidth;
int height = (int)bitmap.PixelHeight;
int pixelsSize = (width * 4) * height;
byte[] pixels = new byte[pixelsSize];
int stride = (width * bitmap.Format.BitsPerPixel + 7) / 8;
bitmap.CopyPixels(pixels, stride, 0);
int cx = 0;
int cy = r;
int d = 2 - 2 * r;
SetPixel(ref pixels, width, height, cx + x, cy + y, c);
SetPixel(ref pixels, width, height, cx + x, -cy + y, c);
SetPixel(ref pixels, width, height, cy + x, cx + y, c);
SetPixel(ref pixels, width, height, -cy + x, cx + y, c);
while(true)
{
if (d > -cy)
{
cy = cy - 1;
d = d + 1 - 2 * cy;
}
if (d <= cx)
{
cx = cx + 1;
d = d + 1 + 2 * cx;
}
//Debug.WriteLine("cy{0}", cy);
if (cy == 0) break;
SetPixel(ref pixels, width, height, cx + x, cy + y, c);
SetPixel(ref pixels, width, height, -cx + x, cy + y, c);
SetPixel(ref pixels, width, height, -cx + x, -cy + y, c);
SetPixel(ref pixels, width, height, cx + x, -cy + y, c);
}
bitmap.Lock();
bitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, stride, 0, 0);
bitmap.Unlock();
}
public MainWindow()
{
InitializeComponent();
const int width = 256;
const int height = 256;
var wb = new WriteableBitmap(width, height, 75, 75, PixelFormats.Bgra32, null);
Circle(ref wb, 100, 100, 50, Color.FromArgb(255,0,0,255));
image1.Source = wb;
}
}
}
ビルド
dotnet build
実行
dotnet run
コメント