CG Library SkiaSharp「VisualAid RealTimeRenderingSystem」

<font COLOR="BLUE">

#### 放射線被爆状況 視覚支援 即時描画システム (通称TDRシステム)</FONT>
(VisualAid & RealTimeRenderingSystem TESTDATA WQHD 2560x1440)
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/8a3cc027-7e44-467b-89b2-364b8074c53c.jpeg)

</FONT>


::: note
- ファクトリ内の汎用機から中継されUNIX系からDGRAMで流れてきます。データはAPPレベルに昇華されている為、データの扱いが楽です。
- ケックではこの試作公開は問題ありません。(可視化の試作を依頼されて開発したもの)
- 配列にデータ入れれば他にも流用でき汎用性があります。

:::



<font COLOR="blue" >

#### 1.キー操作説明</FONT>
[メインキャンパス]
- <B><font COLOR="RED" >[マウス]</B>......................メインキャンパスに置くとその方向にスクロール(8方向)

- <B><font COLOR="RED" >[マウスホイール]</B>....データマーク大きさ可変(アルファ線、ベータ線、ガンマ線、未確認)
- <B><font COLOR="RED" >[マウスボタン]</B>........スクロール速度の調整 左ボタンで少し早くなり、右ボタンで最速

[ディスプレイエリアマップキャンパス]
- <B><font COLOR="RED" >[マウス左ボタン]</B>....その地点のデータ表示。左押しながらマウス移動で即時表示

<font COLOR="blue" >

#### 2.動画 YouTube ダミーデータ使用</FONT>
<iframe width="1280" height="760" src="https://www.youtube.com/embed/qFacGTT3jR0" title="" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

<font COLOR="blue" >

#### 3.ステータス部詳細
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/667a072c-9471-4c19-898d-55eeb6825ef8.jpeg)


#### 4.コードについて</FONT>
- ソケット受信部は除いてます。
- 起動後、データ生成に時間掛かります。private void Window_LoadedのTitle2matrixを削除すると早く動作します。 非同期化させてましたが動作がおかしく場合があったので同期で動作しています。
- MainCanvasの幅高さとマーク大きさから表示可能なXY軸の個数を算出し余計な描画をしないように最適化。その為、メモリが許す限り例え100万x100万の配列にも対応。
- 円グラフはコントロールを使わず自力で描画し細かい制御に対応。
- 高速スクロール対応。

#### 参考　円グラフ描画法 ALLCircle_PaintSurface()内
```c#
// 全データ中、各データが幾つあるか算出
for (int y=0;y<1000;y++){
    for(int x = 0; x < 1000; x++) {
        if (mat[y,x] == 0) code1++;
        if (mat[y,x] == 1) code2++;
        if (mat[y,x] == 2) code3++;
        if (mat[y,x] == 3) code4++;
	}
}
                    
int SS1=code1/10000*36;
int SS2=code2/10000*36;
int SS3=code3/10000*36;

// 一色目 アルファ線
// 円グラフの0度から一色目描画
// SS1は一色目の終端角度
// 円中心から0度に描画、目的の角度(SS1)まで繰り返し
for (int h = 0; h < SS1; h++) {
    X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
    Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
    args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV1_LINE);
}

// 二色目　ベータ線
// 一色目の最後(SS1)から二色目描画
// SS2は二色目の終端角度
// SS1+SS2 は0度から見た二色目の終端角度
for (int h= SS1; h < SS1+SS2; h++) {
	X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
    Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
    args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV2_LINE);
}
/// 以降、繰り返し
```


                  


#### 5.WPF Sourcecode</FONT>

```c#
////////////////////////////////////////
// TDR System Testtype / WPF+SkiaSharp
// (c)inf102 S.H 2025.
////////////////////////////////////////

using SkiaSharp;
using SkiaSharp.Views.Desktop;
using System;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SkiaSharpSample {

    public partial class MainWindow : Window	{

        int[,] mat = new int[1000, 1000]; 

        // ローカルウィンドウ マウス位置
        static int XX,YY;

        // MATREX 表示位置(左上)
        static int START_X=500;
        static int START_Y=500;
        
        // 初期マーク大きさ
        static int CIRCEL_R=10;

        // マウスがエリアに入っているか
        static bool MOUSE_IN=false;

        // マウスボタン押し状態
        static bool LEFT_BTN=false;
        static bool RIGHT_BTN=false;

        // MAP
        static bool MAP_LEFT_BTN=false;

        // 速度
        static int SPEED=100;

        // マーク表示数　縦に5個表示中なら Y_CNT=5
        static int CNT_Y,CNT_X;

        // オーバーフロー管理 false==正常 
        static bool FLG_X=false;
        static bool FLG_Y=false;

        // 枠位置
        static int LAT_X1,LAT_X2,LAT_Y1,LAT_Y2;
               
        // Alpha
        static SKPaint LV1_LINE= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            Color = new SKColor(0,255,00)
        };

        // Beta
        static SKPaint LV2_LINE= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            Color = new SKColor(0,0,255)
        };

        // Gamma
        static SKPaint LV3_LINE= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            Color = new SKColor(255,0,0)
        };
        
        // Unknow
        static SKPaint LV4_LINE= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            Color = new SKColor(0,255,255)
        };

        // MAP XY補助線
        static float[] dashArray = new float[2];
        SKPaint XY_ARAY= new SKPaint{
	        Style =  SKPaintStyle.StrokeAndFill,
            Color = new SKColor(0, 191, 200),
            IsAntialias=true,
            PathEffect = SKPathEffect.CreateDash(dashArray, 10),
            StrokeWidth =1
        };

        // メインXY格子
        SKPaint MAIN_XY_LINE= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            StrokeWidth = 6,
            Color = new SKColor(255,255,255)
        };

        // MAP枠
        SKPaint MAP_RECT= new SKPaint{
	        Style =  SKPaintStyle.Stroke,
			IsAntialias=true,
            StrokeWidth = 4,
            Color = new SKColor(0,0,255)
        };

        // MAP数値
        SKPaint MAP_NO= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            StrokeWidth = 1,
            Color = new SKColor(255,255,255)
        };

        // MAP
        SKPaint MAP_CENTER= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            StrokeWidth = 2,
            Color = new SKColor(255,255,0)
        };

        // MAPマーク
        SKPaint MAP_MARK= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            Color = new SKColor(255,0,0)
        };

        // TOP-TITLE
        SKPaint TOP_TITLE= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            TextAlign=SKTextAlign.Center,
            TextSize=30,
            Color = new SKColor(0,100,255)
        };

        // DATA CIRCEL
        SKPaint DATA_CIRCLE= new SKPaint{
	        Style =  SKPaintStyle.Stroke,
			IsAntialias=true,
            StrokeWidth=2,
            Color = new SKColor(0,155,255)
        };

        // NUM数値
        SKPaint NUM_NO= new SKPaint{
	        Style =  SKPaintStyle.Fill,
			IsAntialias=true,
            TextAlign=SKTextAlign.Left,
            TextSize=15,
            StrokeWidth = 1,    
        };

        public void msg(string s) {
            MessageBox.Show(s);
        }

        public MainWindow()		{
			InitializeComponent();
             
            Random rnd = new Random();

            for (int y=0;y<1000;y++){
                for(int x = 0; x < 1000; x++) {
                    mat[y,x] = rnd.Next(0,4);
                }
            }
                        
            for (int y=500;y<550;y++){
                for(int x = 540; x < 590; x++) {
                    mat[y,x] = 1;
                }
            }

            for (int y=20;y<50;y++){
                for(int x = 10; x < 130; x++) {
                    mat[y,x] = 3;
                }
            }

            for (int y=560;y<580;y++){
                for(int x = 600; x < 620; x++) {
                    mat[y,x] = 2;
                }
            }

            for (int y=590;y<620;y++){
                for(int x = 630; x < 650; x++) {
                    mat[y,x] = 0;
                }
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e) {

            // Title2matrix 
            for (int xx=683;xx<1100;xx++){
                for (int yy=5;yy<29;yy++){
                    var RGB=GetPixelColorAt (TopCanvas,xx,yy);
                    if (RGB.R==0 && RGB.G == 100 && RGB.B == 255) {
                        mat[yy,xx-600]=1;
                        mat[yy+500,xx-200]=2;
                    }
                    else {
                        mat[yy,xx-600]=4;
                        mat[yy+500,xx-200]=4;
                    }                      
                }
            }

            _=Task.Run ( async ()=> {
                while (true){

                    await Task.Delay(SPEED);
                    if ( MOUSE_IN == false ) continue;

                    // 左上
                    if (XX < LAT_X1 && YY <LAT_Y1 ) {
                        START_Y--;
                        START_X--;
                        if (START_Y <= -1 ) START_Y=0;
                        if (START_X <= -1 ) START_X=0;
                    }
            
                    // 上
                    if ( (XX >LAT_X1 && XX <LAT_X2 ) && YY<LAT_Y1  ){
                        
                        START_Y--;
                        if (START_Y <=-1 ) START_Y=0;
                    }

                    // 右上
                    if ( XX > LAT_X2 && YY < LAT_Y1){
                        if (FLG_X==false) START_X++;
                                                
                        START_Y--;
                        if (START_Y<=-1 ) START_Y=0;
                    }

                    // 左
                    if ( XX <LAT_X1 && YY > LAT_Y1 && YY < LAT_Y2){
                        START_X--;
                        if (START_X <=-1 ) START_X=0;
                    }

                    // 右
                    if ( XX > LAT_X2 && YY > LAT_Y1 && YY <LAT_Y2 ){
                        if (FLG_X==false) START_X++;
                                        
                        //  START_X が大きい時に画面左を左にリサイズした時、START_Xを順次補正して右側に表示を展開させる
                        if (START_X+CNT_X >=1000) START_X=1000-CNT_X;
                              
                    }

                    // 左下
                    if ( XX < LAT_X1 && YY > LAT_Y2 ) {
                        if (FLG_Y==false) START_Y++;

                        START_X--;
                        if (START_X <=-1 ) START_X=0;
                        if (START_Y+CNT_Y >=1000) START_Y=1000-CNT_Y;
                    }

                    // 下
                    if (XX > LAT_X1 && XX < LAT_X2 && YY > LAT_Y2) {
                        if (FLG_Y==false) START_Y++;
                        if (START_Y+CNT_Y >=1000) START_Y=1000-CNT_Y;
                       
                    }

                    // 右下
                    if (XX >LAT_X2 && YY > LAT_Y2){
                        if (FLG_Y==false) START_Y++;
                        if (FLG_X==false) START_X++;

                        if (START_X+CNT_X >=1000) START_X=1000-CNT_X;
                        if (START_Y+CNT_Y >=1000) START_Y=1000-CNT_Y;
                    }
                    
                    this.Dispatcher.Invoke((Action)(() =>{
                       // Title="MATRIX_X,Y="+START_X+","+START_Y+ "/L_MOUSE="+XX+ ","+YY +"/R="+CIRCEL_R+"/SPEED"+SPEED +"/CNT_X,Y="+CNT_X+ ","+CNT_Y;

                        MainCanvas.InvalidateVisual(); 
                        MapCanvas.InvalidateVisual(); 
                        CrentA_CIRCLECanvas.InvalidateVisual();
                        CrentB_CIRCLECanvas.InvalidateVisual();
                    }));
                }
            });
        }
                       
        // 描画
        void MainPaintSurface(object sender, SKPaintSurfaceEventArgs args){
           
            var CAX=args.Info.Width;
            var CAY=args.Info.Height;

            int XX=10;
            int YY=10;
            int CAS_Y= 0;

            if (CIRCEL_R == 9) {
                XX=9;
                YY=9;
            }

            if (CIRCEL_R == 8) {
                XX=8;
                YY=8;
            }

            if (CIRCEL_R == 7) {
                XX=7;
                YY=7;
            }

            args.Surface.Canvas.Clear(SKColors.Black);
                           
            for (int y=START_Y;y<START_Y+CNT_Y;y++){
                for (int x = START_X; x < START_X+CNT_X; x++) {

                    if (x>=999){
                        FLG_X=true;
                        continue;
                    }
                    else FLG_X=false;

                    if (y>=999){
                        FLG_Y=true;
                        continue;
                    }
                    else FLG_Y=false;

                    CAS_Y=0;

                    if(CIRCEL_R <= 9) {
                        XX += 1;
                        CAS_Y=1;        
                    }

                    if(CIRCEL_R == 10) {
                        XX += 2;
                        CAS_Y=2;        
                    }
                    
                    if(CIRCEL_R == 11) {
                        XX += 4;
                        CAS_Y=4;        
                    }
                                        
                    if(CIRCEL_R == 12) {
                        XX += 6;
                        CAS_Y=6;        
                    }

                    if(CIRCEL_R == 13) {
                        XX += 8;
                        CAS_Y=8;        
                    }

                    if(CIRCEL_R == 14) {
                        XX += 10;
                        CAS_Y=10;        
                    }

                    if(CIRCEL_R == 15) {
                        XX += 12;
                        CAS_Y=12;        
                    }
                                
                    if ( mat[y,x] == 0 && D1_CHK.IsChecked == true) args.Surface.Canvas.DrawCircle (XX,YY+CAS_Y,CIRCEL_R,LV1_LINE);
                    if ( mat[y,x] == 1 && D2_CHK.IsChecked == true) args.Surface.Canvas.DrawCircle (XX,YY+CAS_Y,CIRCEL_R,LV2_LINE);
                    if ( mat[y,x] == 2 && D3_CHK.IsChecked == true) args.Surface.Canvas.DrawCircle (XX,YY+CAS_Y,CIRCEL_R,LV3_LINE);
                    if ( mat[y,x] == 3 && D4_CHK.IsChecked == true) args.Surface.Canvas.DrawCircle (XX,YY+CAS_Y,CIRCEL_R,LV4_LINE);
                   
                    if (CIRCEL_R==7)  XX+=15;
                    if (CIRCEL_R==8)  XX+=17;
                    if (CIRCEL_R==9)  XX+=19;
                    if (CIRCEL_R>=10) XX+=20;
                }
               
                if (CIRCEL_R ==7){
                    XX =7;
                    YY+=15+CAS_Y;
                }

                if (CIRCEL_R ==8){
                    XX =8;
                    YY+=17+CAS_Y;
                }

                if (CIRCEL_R ==9){
                    XX =9;
                    YY+=19+CAS_Y;
                }

                if (CIRCEL_R >=10){
                    XX =10;
                    YY+=20+CAS_Y;
                }                         
            }

            // MAIN格子
            args.Surface.Canvas.DrawLine ((int)(CAX/3),0,(int)CAX/3,CAY,MAIN_XY_LINE);
            args.Surface.Canvas.DrawLine ((int)(CAX/3*2),0,(int)CAX/3*2,CAY,MAIN_XY_LINE);
            args.Surface.Canvas.DrawLine (0,(int)(CAY/3),CAX,(int)CAY/3,MAIN_XY_LINE);
            args.Surface.Canvas.DrawLine (0,(int)(CAY/3*2),CAX,(int)(CAY/3*2),MAIN_XY_LINE);

        }
                
        // DisplayAreaMAP
        void MapPaintSurface(object sender, SKPaintSurfaceEventArgs args){
           
            args.Surface.Canvas.Clear(SKColors.Black);

            // ヘッダ文字
            MAP_NO.TextSize=16;
            args.Surface.Canvas.DrawText ("DisplayAreaMap",55,23,MAP_NO);

            // MAP枠
            args.Surface.Canvas.DrawRect (15,45,205,205,MAP_RECT);

            // XY中央線
            args.Surface.Canvas.DrawLine (18,150,218,150,MAP_CENTER);
            args.Surface.Canvas.DrawLine (115,47,115,248,MAP_CENTER);

            // 数値
            MAP_NO.TextSize=13;
            args.Surface.Canvas.DrawText ("1",10,40,MAP_NO);
            args.Surface.Canvas.DrawText ("1000",205,40,MAP_NO);
            args.Surface.Canvas.DrawText ("1000",0,265,MAP_NO);
            args.Surface.Canvas.DrawText ("500",105,40,MAP_NO);
            args.Surface.Canvas.DrawText ("500",105,40,MAP_NO);
            args.Surface.Canvas.DrawText ("500",5,165,MAP_NO);

            // XY補助線
            dashArray[0] = 0.21f;  //0.21 2.5 2.5
            dashArray[1] = 2.5f;
            args.Surface.Canvas.DrawLine (16,100,218,100,XY_ARAY);
            args.Surface.Canvas.DrawLine (16,200,218,200,XY_ARAY);
            args.Surface.Canvas.DrawLine (65,47,65,248,XY_ARAY);
            args.Surface.Canvas.DrawLine (167,47,167,248,XY_ARAY);
            
            // MAP赤丸
            int MX2=((CNT_X/2)+START_X)/5;
            int MY2=((CNT_Y/2)+START_Y)/5;

            if ((int)MainCanvas.ActualWidth < 500) {
                args.Surface.Canvas.DrawCircle(MX2+16, MY2+45, 6, MAP_MARK);
                return;
            }

            if ((int)MainCanvas.ActualWidth < 1000) {
                args.Surface.Canvas.DrawCircle (MX2+17,MY2+47,6,MAP_MARK);
                return;
            }
            
            if ((int)MainCanvas.ActualWidth < 1500) {
                args.Surface.Canvas.DrawCircle (MX2+15,MY2+47,6,MAP_MARK);
                return;
            }

            if ((int)MainCanvas.ActualWidth < 3000) {
                args.Surface.Canvas.DrawCircle (MX2+6,MY2+47,6,MAP_MARK);
                return;
            }
        }

        void TopPaintSurface(object sender, SKPaintSurfaceEventArgs args){
            args.Surface.Canvas.Clear(SKColors.Black);
            args.Surface.Canvas.DrawText ("RadiationExposure TDR System",args.Info.Width/2,38,TOP_TITLE);
        }

        // ALLDATA CIRCLE ALLCircle_PaintSurface
        void ALLCircle_PaintSurface(object sender, SKPaintSurfaceEventArgs args){
            args.Surface.Canvas.Clear(SKColors.Black);

            int code1=0,code2=0,code3=0,code4=0;
            for (int y=0;y<1000;y++){
                for(int x = 0; x < 1000; x++) {
                    if (mat[y,x] == 0) code1++;
                    if (mat[y,x] == 1) code2++;
                    if (mat[y,x] == 2) code3++;
                    if (mat[y,x] == 3) code4++;
                }
            }
                          
            int SS1=code1/10000*36;
            int SS2=code2/10000*36;
            int SS3=code3/10000*36;
      
            double  X4,Y4;

            for(int h = 00; h < SS1; h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV1_LINE);
            }
                        
            for(int h= SS1; h < SS1+SS2; h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV2_LINE);
            }
                        
            for(int h= SS1+SS2; h < SS1+SS2+SS3; h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV3_LINE);
            }

            for(int h = SS1+SS2+SS3; h < 3600; h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV4_LINE);
            }

            args.Surface.Canvas.DrawCircle (115,95,70,DATA_CIRCLE);
            MAP_NO.TextSize=16;
            args.Surface.Canvas.DrawText ("AllData",92,17,MAP_NO);


            NUM_NO.Color=new SKColor (0,255,0);
            args.Surface.Canvas.DrawText ("Alpha",47,190,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code1.ToString()+ "  "+(code1/10000).ToString()+"%",107,190,NUM_NO);

            NUM_NO.Color=new SKColor (0,0,255);
            args.Surface.Canvas.DrawText ("Beta",52,205,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code2.ToString()+ "  "+(code2/10000).ToString()+"%",107,205,NUM_NO);

            NUM_NO.Color=new SKColor (255,0,0);
            args.Surface.Canvas.DrawText ("Gamma",42,220,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code3.ToString()+ "  "+(code3/10000).ToString()+"%",107,220,NUM_NO);

            NUM_NO.Color=new SKColor (0,255,255);
            args.Surface.Canvas.DrawText ("Unknown",37,235,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code4.ToString()+ "  "+(code4/10000).ToString()+"%",107,235,NUM_NO);
           
            // 区切線
            args.Surface.Canvas.DrawLine (40,250,190,250,LV1_LINE    
        }
     
        // CRENT DATA CIRCLE [All]
        void CrentA_CirclePaintSurface(object sender, SKPaintSurfaceEventArgs args){
            
            int code1=0,code2=0,code3=0,code4=0;
            for (int y=START_Y ;y<START_Y+CNT_Y;y++){
                for(int x = START_X; x < START_X+CNT_X; x++) {
                    if (y<=999 && x<=999) {
                        if (mat[y,x] == 0 && D1_CHK.IsChecked == true) code1++;
                        if (mat[y,x] == 1 && D2_CHK.IsChecked == true) code2++;
                        if (mat[y,x] == 2 && D3_CHK.IsChecked == true) code3++;
                        if (mat[y,x] == 3 && D4_CHK.IsChecked == true) code4++;
                    }
                }
            }
                   
            double FD=CNT_X * CNT_Y;
       
            double SS1=code1 / FD * 3600;
            double SS2=code2 / FD * 3600;
            double SS3=code3 / FD * 3600;
            double SS4=code4 / FD * 3600;

            args.Surface.Canvas.Clear(SKColors.Black);
            double X4,Y4;
            
            for(int h = 00; h < (int)SS1; h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV1_LINE);
            }
    
            for(int h = (int)SS1; h < (int)(SS1+SS2); h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV2_LINE);
            }
            
            for(int h = (int)(SS1+SS2); h < (int)(SS1+SS2+SS3); h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV3_LINE);
            }

            for(int h = (int)(SS1+SS2+SS3); h < (int)(SS1+SS2+SS3+SS4); h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 96 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 96, (int)X4, (int)Y4, LV4_LINE);
            }
            
            args.Surface.Canvas.DrawCircle (116,96,70,DATA_CIRCLE);
            MAP_NO.TextSize=16;
            args.Surface.Canvas.DrawText ("DisplayData(All)",55,19,MAP_NO);

            int CN=CNT_X*CNT_Y;
            if (CN==0) return;

            double xp;
            xp=code1/(double)CN*100f;
            NUM_NO.Color=new SKColor (0,255,0);
            args.Surface.Canvas.DrawText ("Alpha",52,190,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code1.ToString("0000")+"  "+xp.ToString("00.0")+"%",110,190,NUM_NO);

            xp=code2/(double)CN*100.0;
            NUM_NO.Color=new SKColor (0,0,255);
            args.Surface.Canvas.DrawText ("Beta",56,205,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code2.ToString("0000")+ "  "+xp.ToString("00.0")+"%",110,205,NUM_NO);

            xp=code3/(double)CN*100.0;
            NUM_NO.Color=new SKColor (255,0,0);
            args.Surface.Canvas.DrawText ("Gamma",46,220,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code3.ToString("0000")+ "  "+xp.ToString("00.0")+"%",110,220,NUM_NO);

            xp=code4/(double)CN*100.0;
            NUM_NO.Color=new SKColor (0,255,255);
            args.Surface.Canvas.DrawText ("Unknown",43,235,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code4.ToString("0000")+ "  "+xp.ToString("00.0")+"%",110,235,NUM_NO);
     
            // 区切線
            args.Surface.Canvas.DrawLine (40,250,190,250,LV1_LINE);

        }

        // CRENT DATA CIRCLE [CHK.BOX SELECT]
        void CrentB_CirclePaintSurface(object sender, SKPaintSurfaceEventArgs args){
            
            int code1=0,code2=0,code3=0,code4=0;
            for (int y=START_Y ;y<START_Y+CNT_Y;y++){
                for(int x = START_X; x < START_X+CNT_X; x++) {
                    if (y<=999 && x<=999) {
                        if (mat[y,x] == 0 && D1_CHK.IsChecked == true) code1++;
                        if (mat[y,x] == 1 && D2_CHK.IsChecked == true) code2++;
                        if (mat[y,x] == 2 && D3_CHK.IsChecked == true) code3++;
                        if (mat[y,x] == 3 && D4_CHK.IsChecked == true) code4++;
                    }
                }
            }
             
            double FD=code1+code2+code3+code4;
       
            double SS1=code1 / FD * 3600;
            double SS2=code2 / FD * 3600;
            double SS3=code3 / FD * 3600;
            double SS4=code4 / FD * 3600;

            args.Surface.Canvas.Clear(SKColors.Black);
            double X4,Y4;
            
            for(int h = 00; h < (int)SS1; h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 102 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 102, (int)X4, (int)Y4, LV1_LINE);
            }
    
            for(int h = (int)SS1; h < (int)(SS1+SS2); h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 102 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 102, (int)X4, (int)Y4, LV2_LINE);
            }
            
            for(int h = (int)(SS1+SS2); h < (int)(SS1+SS2+SS3); h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 102 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 102, (int)X4, (int)Y4, LV3_LINE);
            }

            for(int h = (int)(SS1+SS2+SS3); h < (int)(SS1+SS2+SS3+SS4); h++) {
                X4 =116 + 70 * Math.Sin(h * Math.PI / 1800);
                Y4 = 102 - 70 * Math.Cos(h * Math.PI / 1800);
                args.Surface.Canvas.DrawLine(116, 102, (int)X4, (int)Y4, LV4_LINE);
            }
            
            args.Surface.Canvas.DrawCircle (116,102,70,DATA_CIRCLE);
            MAP_NO.TextSize=16;
            args.Surface.Canvas.DrawText ("DisplayData(Select)",46,25,MAP_NO);

          //  int CN=CNT_X*CNT_Y;
            //if (CN==0) return;

            double xp;
            xp=code1/(double)FD*100f;
            NUM_NO.Color=new SKColor (0,255,0);
            args.Surface.Canvas.DrawText ("Alpha",52,198,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code1.ToString("0000")+"  "+xp.ToString("00.0")+"%",110,198,NUM_NO);

            xp=code2/(double)FD*100.0;
            NUM_NO.Color=new SKColor (0,0,255);
            args.Surface.Canvas.DrawText ("Beta",56,213,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code2.ToString("0000")+ "  "+xp.ToString("00.0")+"%",110,213,NUM_NO);

            xp=code3/(double)FD*100.0;
            NUM_NO.Color=new SKColor (255,0,0);
            args.Surface.Canvas.DrawText ("Gamma",46,228,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code3.ToString("0000")+ "  "+xp.ToString("00.0")+"%",110,228,NUM_NO);

            xp=code4/(double)FD*100.0;
            NUM_NO.Color=new SKColor (0,255,255);
            args.Surface.Canvas.DrawText ("Unknown",43,243,NUM_NO);
            NUM_NO.Color=new SKColor (255,255,255);
            args.Surface.Canvas.DrawText (code4.ToString("0000")+ "  "+xp.ToString("00.0")+"%",110,243,NUM_NO);

            // 区切線
            args.Surface.Canvas.DrawLine (40,257,190,257,LV1_LINE);
      
            NUM_NO.TextSize=15;
            args.Surface.Canvas.DrawText ("StartingPoint X"+START_X.ToString() +" / Y"+START_Y.ToString(),30,285,NUM_NO);
            args.Surface.Canvas.DrawText ("X,Y COUNT X"+CNT_X.ToString()+" / Y"+CNT_Y.ToString(),30,300,NUM_NO);
            args.Surface.Canvas.DrawText ("TOTAL  "+(CNT_X * CNT_Y).ToString(),30,315,NUM_NO);

        }

        private void MainCanvas_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e) {
            if (e.Delta > 0  ){
                CIRCEL_R++;
                if (CIRCEL_R >=16 ) CIRCEL_R=15; 
            }

            if (e.Delta <0  ){
                CIRCEL_R--;
                if (CIRCEL_R <=7 ) CIRCEL_R=7;
            }

            CanvasWidthHighALU();
            MainCanvas.InvalidateVisual();
        }

        private void MainCanvas_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e) {
            MOUSE_IN=false;
        }
        
        private void MainCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            LEFT_BTN=true;

            if (RIGHT_BTN==true ) SPEED=25; 
            if (RIGHT_BTN==false) SPEED=50;
        }

        private void MainCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
            LEFT_BTN=false;

            if (RIGHT_BTN==false) SPEED=100;
            if (RIGHT_BTN==true ) SPEED=20;
        }

        private void MainCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e) {
            RIGHT_BTN=true;

            if (LEFT_BTN==false) SPEED=20;
            if (LEFT_BTN==true)  SPEED=25;
        }

        // MAP L-BUTTON ON
        private void MapCanvas_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            MAP_LEFT_BTN=true;
            MapCanvasGetMouseXY (sender,e);

            MainCanvas.InvalidateVisual();
            MapCanvas.InvalidateVisual();
            CrentA_CIRCLECanvas.InvalidateVisual();
            CrentB_CIRCLECanvas.InvalidateVisual();
        }

        void MapCanvasGetMouseXY(object sender, MouseEventArgs e) {
                
            var mainWindow = Application.Current.MainWindow;
              
            Matrix m = PresentationSource.FromVisual(mainWindow).CompositionTarget.TransformToDevice;
            var dpiScaleX = m.M11;
            var dpiScaleY = m.M22;
    
            var pixelPosition = e.GetPosition(sender as Canvas);
            var scaledPixelPosition = new System.Windows.Point(pixelPosition.X * dpiScaleX, pixelPosition.Y * dpiScaleY);
           
            // ローカルマウス現在位置
            XX=(int)scaledPixelPosition.X;
            YY=(int)scaledPixelPosition.Y-(int)H1.ActualHeight;

            if (XX-(int)MainCanvas.ActualWidth-13<=0) return;
           // if (XX-(int)MainCanvas.ActualWidth-13>=200) return;
            
            if ( (YY-46) <=0 ) return;
           // if ( (YY-46) >=196) return;
            
            //CanvasWidthHighALU();
            START_X=(XX-(int)MainCanvas.ActualWidth-13)*5;
            START_Y=(YY-46)*5;
            
            if (START_X+CNT_X >=1000) START_X=1000-CNT_X;
            if (START_Y+CNT_Y >=1000) START_Y=1000-CNT_Y;

        }

        // MAP移動
        private void MapCanvas_PreviewMouseMove(object sender, MouseEventArgs e) {
            
            if (MAP_LEFT_BTN==false) return;

            MapCanvasGetMouseXY (sender,e);
                          
            MainCanvas.InvalidateVisual(); 
            MapCanvas.InvalidateVisual();
            CrentA_CIRCLECanvas.InvalidateVisual();
            CrentB_CIRCLECanvas.InvalidateVisual();
        }

        // MAP 移動キャンセル
        private void MapCanvas_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
            MAP_LEFT_BTN=false;
        }

        private void D1_CHK_Click(object sender, RoutedEventArgs e) {
            MainCanvas.InvalidateVisual();
            CrentA_CIRCLECanvas.InvalidateVisual();
            CrentB_CIRCLECanvas.InvalidateVisual();
        }

        private void D3_CHK_Click(object sender, RoutedEventArgs e) {
            MainCanvas.InvalidateVisual();
            CrentA_CIRCLECanvas.InvalidateVisual();
            CrentB_CIRCLECanvas.InvalidateVisual();
        }

        private void D4_CHK_Click(object sender, RoutedEventArgs e) {
            MainCanvas.InvalidateVisual();
            CrentA_CIRCLECanvas.InvalidateVisual();
            CrentB_CIRCLECanvas.InvalidateVisual();
        }

        private void D2_CHK_Click(object sender, RoutedEventArgs e) {
            MainCanvas.InvalidateVisual();
            CrentA_CIRCLECanvas.InvalidateVisual();
            CrentB_CIRCLECanvas.InvalidateVisual();
        }

        private void MainCanvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e) {
            RIGHT_BTN = false;
            
            if (LEFT_BTN ==true  ) SPEED = 50;
            if (LEFT_BTN ==false ) SPEED =100;
        }

        private void MainCanvas_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e) {
            MOUSE_IN=true;
            MAP_LEFT_BTN=false;
        }

        // 表示させる個数の算出
        public void CanvasWidthHighALU() {

            if (CIRCEL_R >= 2 && CIRCEL_R<=6){
                CNT_X= (int)MainCanvas.ActualWidth /17;
                CNT_Y= (int)MainCanvas.ActualHeight /16;
            }

            if (CIRCEL_R == 7 ){
                CNT_X= (int)MainCanvas.ActualWidth /16;
                CNT_Y= (int)MainCanvas.ActualHeight /16;
            }

            if (CIRCEL_R == 8 ){
                CNT_X= (int)MainCanvas.ActualWidth /18;
                CNT_Y= (int)MainCanvas.ActualHeight /18;
            }

            if (CIRCEL_R == 9 ){
                CNT_X= (int)MainCanvas.ActualWidth /20;
                CNT_Y= (int)MainCanvas.ActualHeight /20;
            }

            if (CIRCEL_R == 10 ){
                CNT_X= (int)MainCanvas.ActualWidth /22;
                CNT_Y= (int)MainCanvas.ActualHeight /22;
            }

            if (CIRCEL_R == 11 ){
                CNT_X= (int)MainCanvas.ActualWidth /24;
                CNT_Y= (int)MainCanvas.ActualHeight /24;
            }     
      
            if (CIRCEL_R == 12 ){
                CNT_X= (int)MainCanvas.ActualWidth /26;
                CNT_Y= (int)MainCanvas.ActualHeight /26;
            }     

            if (CIRCEL_R == 13 ){
                CNT_X= (int)MainCanvas.ActualWidth /28;
                CNT_Y= (int)MainCanvas.ActualHeight /28;
            }     

            if (CIRCEL_R == 14 ){
                CNT_X= (int)MainCanvas.ActualWidth /30;
                CNT_Y= (int)MainCanvas.ActualHeight /30;
            }    

            if (CIRCEL_R == 15 ){
                CNT_X= (int)MainCanvas.ActualWidth /32;
                CNT_Y= (int)MainCanvas.ActualHeight /32;
            }    
        }

        private void MainCanvas_SizeChanged(object sender, SizeChangedEventArgs e) {
            
            // メインXY格子
            LAT_X1=(int)MainCanvas.ActualWidth /3;
            LAT_X2=LAT_X1*2;

            LAT_Y1= (int)MainCanvas.ActualHeight /3 ;
            LAT_Y2=LAT_Y1*2;

            // CNT_X CNT_Y算出
            CanvasWidthHighALU();
           
            // START_X が大きい時に画面左を左にリサイズしたらSTART_Xを順次補正して右側に表示を展開させる
            if (START_X+CNT_X >=1000) START_X=1000-CNT_X;
            
            // Y軸
            if (START_Y+CNT_Y >=1000) START_Y=1000-CNT_Y;

            MainCanvas.InvalidateVisual(); 
            CrentA_CIRCLECanvas.InvalidateVisual();
            CrentB_CIRCLECanvas.InvalidateVisual();

        }

        // ローカルマウス現在位置
        private void MainCanvas_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) {
       
            var mainWindow = Application.Current.MainWindow;
              
            Matrix m = PresentationSource.FromVisual(mainWindow).CompositionTarget.TransformToDevice;
            var dpiScaleX = m.M11;
            var dpiScaleY = m.M22;
    
            var pixelPosition = e.GetPosition(sender as Canvas);
            var scaledPixelPosition = new System.Windows.Point(pixelPosition.X * dpiScaleX, pixelPosition.Y * dpiScaleY);
           
            // ローカルマウス現在位置
            XX=(int)scaledPixelPosition.X;
            YY=(int)scaledPixelPosition.Y-(int)H1.ActualHeight;
        }

        private System.Drawing.Color GetPixelColorAt(UIElement visualElement,int x,int y){

            RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)visualElement.RenderSize.Width, (int)visualElement.RenderSize.Height, 96, 96, PixelFormats.Pbgra32);
            renderBitmap.Render(visualElement);
            byte[] pixels = new byte[4]; // BGRA format, 4 bytes
            renderBitmap.CopyPixels(new Int32Rect(x, y, 1, 1), pixels, 4, 0);

            System.Drawing.Color color = System.Drawing.Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]);
            return color;
        }
    }
}
```

<font COLOR="blue" >


#### 6.WPF XAML</FONT>

``` xml
<!-- ///////////////////////////////////////////////////////////////// -->
<!-- RadiationExposure VisualAid And RealTimeRenderingSystem TestType  -->
<!-- inf102 S.H 2025.                                                  -->
<!-- ///////////////////////////////////////////////////////////////// -->

<Window x:Class="SkiaSharpSample.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:SkiaSharpSample" 
        xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF" 
        xmlns:wpf="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF" mc:Ignorable="d" Title="RadiationExposure VisualAid And RealTimeRenderingSystem"
        Loaded="Window_Loaded" Height="1270" Width="1800" Background="Black">

    <Grid  >
        <Grid.RowDefinitions>
            <RowDefinition Height="35" x:Name="H1"/>
            <RowDefinition Height="271"/>
            <RowDefinition Height="260"/>
            <RowDefinition Height="252"/>
            <RowDefinition Height="318"/>

            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="250" x:Name="W2"/>

        </Grid.ColumnDefinitions>

        <wpf:SKElement x:Name="MainCanvas" PaintSurface="MainPaintSurface" Grid.Row="1"  Grid.Column="0"  MouseMove="MainCanvas_MouseMove" MouseWheel="MainCanvas_MouseWheel" SizeChanged="MainCanvas_SizeChanged" MouseLeave="MainCanvas_MouseLeave" MouseEnter="MainCanvas_MouseEnter"  MouseLeftButtonDown="MainCanvas_MouseLeftButtonDown" MouseLeftButtonUp="MainCanvas_MouseLeftButtonUp" MouseRightButtonDown="MainCanvas_MouseRightButtonDown" MouseRightButtonUp="MainCanvas_MouseRightButtonUp" Grid.RowSpan="5" />
        <wpf:SKElement x:Name="MapCanvas"  PaintSurface="MapPaintSurface" Grid.Row="1"  Grid.Column="1" PreviewMouseLeftButtonDown="MapCanvas_PreviewMouseLeftButtonDown" PreviewMouseMove="MapCanvas_PreviewMouseMove" PreviewMouseLeftButtonUp="MapCanvas_PreviewMouseLeftButtonUp" Grid.RowSpan="1" />
        <wpf:SKElement x:Name="TopCanvas"  PaintSurface="TopPaintSurface" Grid.Row="0"  Grid.Column="0" Grid.ColumnSpan="2" Margin="0,-10,0,0" />
     
        <wpf:SKElement x:Name="All_CIRCLECanvas"    PaintSurface="ALLCircle_PaintSurface"    Grid.Row="2"  Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="1" />
        <wpf:SKElement x:Name="CrentA_CIRCLECanvas" PaintSurface="CrentA_CirclePaintSurface" Grid.Row="3"  Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="1" />
        <wpf:SKElement x:Name="CrentB_CIRCLECanvas" PaintSurface="CrentB_CirclePaintSurface" Grid.Row="4"  Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="1" />

        <StackPanel Orientation="Vertical" Grid.Row="5" Grid.Column="1">
            <Label Content="                     Enable" Foreground="White" FontSize="16" />
            <StackPanel Orientation="Horizontal" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Center" Width="246" Height="80" VerticalAlignment="Top"  >
                <StackPanel VerticalAlignment="Center" HorizontalAlignment="Stretch" Margin="32,-20,2,2">
                    <CheckBox Foreground="#00FF00" IsChecked="True" FontSize="19" x:Name="D1_CHK"  Content="Alpha"  Margin="2,0,2,2" VerticalAlignment="Top"  Click="D1_CHK_Click"/>
                    <CheckBox IsChecked="True" FontSize="19" Foreground="#FF0000" x:Name="D3_CHK"  Content="Gamma"  Margin="2,0,2,2" VerticalAlignment="Center" Click="D3_CHK_Click"/>
                </StackPanel>

                <StackPanel VerticalAlignment="Center" HorizontalAlignment="Stretch" Margin="20,-20,2,2">
                    <CheckBox IsChecked="True" FontSize="19" Foreground="#0000FF" x:Name="D2_CHK"  Content="Beta"  Margin="2,0,2,2" VerticalAlignment="Top" Click="D2_CHK_Click"/>
                    <CheckBox IsChecked="True" FontSize="19" Foreground="#00FFFF" x:Name="D4_CHK"  Content="Unknown"  Margin="2,0,2,2" VerticalAlignment="Center" Click="D4_CHK_Click"/>
                </StackPanel>
                
            </StackPanel>
        </StackPanel>
    </Grid>
</Window>
```