非同期スレッドの無限ループ内で適切にwaitを入れる試験
・----------------------------------------------------------------------------------・
・固定された円の円周上に少し小さめの円を描き時計方向に回転させ、
・その円の円周上に更に小さい円を描き反時計方向に回転させ、更にその円の
・円周上に軌跡を取るポイントを時計方向に移動させて軌跡を残して行きます。
・制御系の開発で細かい微調整が必要になりその検証を行う為のコードです。
・参考 https://qiita.com/inf102/questions/b9299d987d9828e545b5
await Task.Delay(TimeSpan.FromSeconds(1.0/1500));これで良かった気がする。
・----------------------------------------------------------------------------------・
1.画面構成
・Child1,2スライダ....円自体の回転速度調整
・Pointスライダ..........軌跡を残す位置の速度調整
・背景白チェックボックス..背景色変更と円の表示
2.動画
3.WPF (C#)
/////////////////////////////////////////
// CircleGRA (c)inf102 2023
// Wait TEST (WPF+SkiaSharp)
/////////////////////////////////////////
using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace CircleGRA {
public partial class MainWindow : Window {
[DllImport("winmm.dll")]
public static extern int timeBeginPeriod(int period);
[DllImport("winmm.dll")]
public static extern int timeEndPeriod(int period);
static int aa,bb,cc;
static double x1,y1,x2,y2,x3,y3;
static int COLORFLG;
// RESETボタン
private void Button_Click(object sender, RoutedEventArgs e) {
aa=0;
bb=0;
cc=0;
COLORFLG=0;
B1.Content ="初期化中";
}
public MainWindow() {
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
timeBeginPeriod(1);
_= Task.Run(() => Chile1Circle());
_= Task.Run(() => Chile2Circle());
_= Task.Run(() => Chile3Circle());
}
private void Button_Click2(object sender, RoutedEventArgs e) {
if ((string)B2.Content=="稼働中"){
B2.Content="停止中";
return;
}
if ((string)B2.Content=="停止中"){
B2.Content="稼働中";
return;
}
}
// 親サークル(固定)
void ParentCirclePaintSurface(object sender, SKPaintSurfaceEventArgs args) {
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
SKPaint A_LINE= new SKPaint{
Style = SKPaintStyle.Stroke,
Color = new SKColor(00, 191, 100,35),
IsAntialias=true,
StrokeWidth = 1
};
canvas.DrawCircle(220,210, 100,A_LINE);
}
void Chile1Circle(){
const int maxCount = 10;
var sec = 0;
var count = 0;
var watch = Stopwatch.StartNew();
int C1VAL=0;
while (true){
this.Dispatcher.Invoke((Action)(() =>{
if ((string)B2.Content=="稼働中"){
Child1Circle.InvalidateVisual();
C1VAL=(int)C1.Value;
C1TEXT.Text="Child1 ["+ C1VAL.ToString()+"]";
Title=aa.ToString();
aa++;
}
}));
if (aa>=720) {
aa=0;
COLORFLG++;
if (COLORFLG == 4 ) COLORFLG=0;
}
var elapsedMsec = watch.ElapsedMilliseconds;
var diffTime = count * C1VAL - elapsedMsec;
if (diffTime >= 1){
Thread.Sleep((int)diffTime);
// await Task.Delay((int)diffTime);
}
count++;
if (count == maxCount){
watch.Stop();
count = 0;
watch.Restart();
sec++;
}
}
}
void Chile2Circle() {
const int maxCount = 10;
var sec = 0;
var count = 0;
var watch = Stopwatch.StartNew();
int C2VAL=0;
while (true){
this.Dispatcher.Invoke((Action)(() =>{
if ((string)B2.Content=="稼働中"){
Child2Circle.InvalidateVisual();
C2VAL=(int)C2.Value;
C2TEXT.Text="Child2 ["+ C2VAL.ToString()+"]";
bb--;
}
}));
var elapsedMsec = watch.ElapsedMilliseconds;
var diffTime = count * C2VAL - elapsedMsec;
if (diffTime >= 1){
Thread.Sleep((int)diffTime);
//await Task.Delay((int)diffTime);
}
count++;
if (count == maxCount){
watch.Stop();
count = 0;
watch.Restart();
sec++;
}
}
}
void Chile3Circle() {
const int maxCount = 10;
var sec = 0;
var count = 0;
var watch = Stopwatch.StartNew();
int C3VAL=0;
while (true){
this.Dispatcher.Invoke((Action)(() =>{
if ((string)B2.Content=="稼働中"){
Child3Circle.InvalidateVisual();
C3VAL=(int)C3.Value;
C3TEXT.Text="POINT ["+ C3VAL.ToString()+"]";
cc++;
}
}));
var elapsedMsec = watch.ElapsedMilliseconds;
var diffTime = count * C3VAL - elapsedMsec;
if (diffTime >= 1){
//await Task.Delay((int)diffTime);
Thread.Sleep((int)diffTime);
}
count++;
if (count == maxCount){
watch.Stop();
count = 0;
watch.Restart();
sec++;
}
}
}
void Child1CirclePaintSurface(object sender, SKPaintSurfaceEventArgs args) {
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
if (CHK1.IsChecked == true){
canvas.Clear();
} else
canvas.Clear(SKColors.Black);
SKPaint A_LINE= new SKPaint{
Style = SKPaintStyle.Stroke,
Color = new SKColor(0, 255, 00,135),
IsAntialias=true,
StrokeWidth = 1
};
x1=220 + 130* Math.Sin(aa*3.14/360);
y1=210 - 130* Math.Cos(aa*3.14/360);
canvas.DrawCircle ((float)x1,(float)y1, 30,A_LINE);
}
void Child2CirclePaintSurface(object sender, SKPaintSurfaceEventArgs args) {
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
if (CHK1.IsChecked == true){
canvas.Clear();
} else
canvas.Clear(SKColors.Black);
SKPaint A_LINE= new SKPaint{
Style = SKPaintStyle.Stroke,
//Color = new SKColor(0, 255, 0,135),
Color = new SKColor(0, 255,0,135),
IsAntialias=true,
StrokeWidth = 1
};
x2=x1 + 45* Math.Sin(bb*3.14/360);
y2=y1 - 45* Math.Cos(bb*3.14/360);
canvas.DrawCircle((float)x2,(float)y2, 15,A_LINE);
}
void Child3CirclePaintSurface(object sender, SKPaintSurfaceEventArgs args) {
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
if ((string)B1.Content == "初期化中") {
canvas.Clear();
B1.Content="初期化(_C)";
}
SKPaint A_LINE = new SKPaint{
Style = SKPaintStyle.Fill,
Color = new SKColor(0, (byte)0, (byte)255),
IsAntialias=true,
StrokeWidth =1
};
if (COLORFLG==0) A_LINE.Color = new SKColor(255,0,0);
if (COLORFLG==1) A_LINE.Color = new SKColor(0,255,0);
if (COLORFLG==2) A_LINE.Color = new SKColor(0,0,255);
if (COLORFLG==3) A_LINE.Color = new SKColor(255,255,0);
x3=x2 + 15* Math.Sin (cc*3.14/360);
y3=y2 - 15* Math.Cos (cc*3.14/360);
canvas.DrawPoint((int)x3,(int)y3,A_LINE);
}
}
}
4.WPF (XAML)
<Window x:Class="CircleGRA.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:wpf="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
xmlns:local="clr-namespace:CircleGRA"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="568" Loaded="Window_Loaded" ResizeMode="NoResize">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="423"/>
<ColumnDefinition Width="140"/>
</Grid.ColumnDefinitions>
<wpf:SKElement x:Name="ParentCircle" PaintSurface="ParentCirclePaintSurface" Grid.Column="0" />
<wpf:SKElement x:Name="Child1Circle" PaintSurface="Child1CirclePaintSurface" Grid.Column="0"/>
<wpf:SKElement x:Name="Child2Circle" PaintSurface="Child2CirclePaintSurface" Grid.Column="0"/>
<wpf:SKElement x:Name="Child3Circle" PaintSurface="Child3CirclePaintSurface" Grid.Column="0"/>
<StackPanel Grid.Column="1" Grid.Row="0" Orientation="Vertical" Margin="0,0,-2,0" Background="DarkCyan">
<StackPanel Orientation="Horizontal" Margin="0,13,2,0" Width="91" >
<TextBlock Text="[速] [遅] " FontSize="19" Foreground="White" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="6,12,2,2" >
<TextBlock x:Name="C1TEXT" Text="Child1" FontSize="18" Foreground="White"/>
</StackPanel>
<StackPanel Orientation="Horizontal" >
<Slider x:Name="C1" Width="121" Maximum="200" Minimum="25" SmallChange="1" Value="80" Margin="5,0,0,0" >
</Slider>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="6,12,2,2">
<TextBlock x:Name="C2TEXT" Text="Child2" FontSize="18" Foreground="White"/>
</StackPanel>
<StackPanel Orientation="Horizontal" >
<Slider x:Name="C2" Width="121" Maximum="50" Minimum="2" SmallChange="1" Value="15" Margin="5,0,0,0">
</Slider>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="6,12,2,2">
<TextBlock x:Name="C3TEXT" Text="Point" FontSize="18" Foreground="White"/>
</StackPanel>
<StackPanel Orientation="Horizontal" >
<Slider x:Name="C3" Width="121" Maximum="20" Minimum="2" SmallChange="1" Value="2" Margin="5,0,0,0">
</Slider>
</StackPanel>
<StackPanel Orientation="Horizontal" >
<CheckBox x:Name="CHK1" Content="背景白" FontSize="18" Foreground="White" Margin="5,20,0,0"/>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="-9,20,0,0" Width="101">
<Button x:Name="B2" Width="100" Height="40" Content="稼働中" FontSize="18" Click="Button_Click2"></Button>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="-9,20,0,0" Width="101">
<Button x:Name="B1" Width="100" Height="40" Content="初期化(_C)" FontSize="18" Click="Button_Click"></Button>
</StackPanel>
</StackPanel>
</Grid>
</Window>
5.模様作成
一周毎に色を変えてますので放置しておくと多様な模様が作れます。
速度変えたら初期化ボタン押して下さい。