20200530のC#に関する記事は7件です。

C# ディスプレイサイズを表示する

やりたいこと

ディスプレイサイズを取得して表示する

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace myDisplay
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            int disp_width = Screen.PrimaryScreen.Bounds.Width;
            int disp_height = Screen.PrimaryScreen.Bounds.Height;

            txtDispWidth.Text = disp_width.ToString();
            txtDispHeight.Text = disp_height.ToString();
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityでマウスの位置に画像(guiのimage)を表示させる

Unityでマウスの位置に画像(guiのimage)を表示させる

guiのimageを使ってマウスポインターの代わりに画像を表示させる

画像からアニメーションにも応用できるはず

用意するもの

・Windows PC
・Unity (制作時に使用したバージョンは2019)
・マウスの位置に表示させたい画像

作りたいもの

Rec_20181224_181408_20200530_175000.gif
黒い丸がマウスポインタ—に追従している。
これはわかりやすくするためにマウスポインターを表示している。

作りたかた

1.HierarchyのプラスボタンからUI > ImageからCanvasとImageオブジェクトを作る。
2.Imageに入れる画像をTexture TypeをSprite(2D and UI)にし、ImageのSource Imageに入れる。
3.Imageのオブジェクト名を「MouseImage」に変更する。
4.HierarchyのプラスボタンからCreate Emptyで空のオブジェクトを作る、オブジェクト名を「MouseManager」に変更する。
5.下記のスクリプトをC#のファイルで作り、MouseManagerオブジェクトに入れる。
完成

image.PNG
manager.PNG

スクリプト

MousePointerpos.C#
    //画像
    public Image Mouse_Image;
    //Canvasの変数
    public Canvas canvas;
    //キャンバス内のレクトトランスフォーム
    public RectTransform canvasRect;
    //マウスの位置の最終的な格納先
    public Vector2 MousePos;

    // Start is called before the first frame update
    void Start()
    {
        //マウスポインター非表示
        Cursor.visible = false;

        //HierarchyにあるCanvasオブジェクトを探してcanvasに入れいる
        canvas = GameObject.Find("Canvas").GetComponent<Canvas>();

        //canvas内にあるRectTransformをcanvasRectに入れる
        canvasRect = canvas.GetComponent<RectTransform>();

        //Canvas内にあるMouseImageを探してMouse_Imageに入れる
        Mouse_Image = GameObject.Find("MouseImage").GetComponent<Image>();
    }

    // Update is called once per frame
    void Update()
    {
        /*
         * CanvasのRectTransform内にあるマウスの位置をRectTransformのローカルポジションに変換する
         * canvas.worldCameraはカメラ
         * 出力先はMousePos
         */
        RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRect,
                Input.mousePosition, canvas.worldCamera, out MousePos);

        /*
         * Mouse_Imageを表示する位置にMousePosを使う
         */
        Mouse_Image.GetComponent<RectTransform>().anchoredPosition
             = new Vector2(MousePos.x, MousePos.y);
    }

参考文献

ぐーるらいふ 遊びのunityのメモ帳。敗北者の末路。
【Unity】タッチした位置にuGUI(RectTransform)を表示する
https://ghoul-life.hatenablog.com/entry/2018/11/13/000955
2020年5月30日閲覧

Unity DOCUMENTATION
RectTransformUtility .ScreenPointToLocalPointInRectangle
https://docs.unity3d.com/ScriptReference/RectTransformUtility.ScreenPointToLocalPointInRectangle.html
2020年5月30日閲覧

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AzureとLINEとVue.jsで投稿画像のHappiness数値判定Botを作ってみた

はじめに

エンジニアが披露宴の余興を頼まれたら

こちらの記事に感化されて、Microsoft Azure で作成してみました。

コードは、Github に置いてあります。

HappinessChecker

動作

【LINEとランキングページ】

line01.png

【ダウンロード機能】

line02.png

参加者で投稿画像を共有できるように、ダウンロード機能を設けています

【リアルタイム通信】

line03.gif

上記わかりづらいですが、異なるブラウザでランキングページを表示して、スマホから更新している状態です。

ランキングページでは「新しい画像が投稿」された場合と「いいね!ボタン」が押下されたときに、

ブラウザを更新なしで、変更がリアルタイムで反映されるようにしています

ちなみに、「いいね!ボタン」はユーザ管理をしていないので、いいね!と思った分だけ押下可能です。

アーキテクチャ図

architecture.png

LINEとの連携部分はDurable Functions を使い、Vue.js との連携部分はAzureFunctionsで使っています。

工夫した点

IHttpClientFactory

LINE との連携部分では、HttpClient で通信を行っています。

このクラスでは IDisposable が実装されますが、これを using ステートメント内で宣言およびインスタンス化することはお勧めできません。その理由は、HttpClient オブジェクトが破棄されても、基になるソケットがすぐに解放されず、ソケットの枯渇の問題が発生する可能性があるということにあります。

ドキュメントによるとHttpClient のインスタンスは使いまわしを行うことがベストプラクティスのため、IHttpClientFactory を DI して使うようにしました。

Startup.cs
using HappinessFunctionApp.Common;
using HappinessFunctionApp.Extension;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System;

[assembly: FunctionsStartup(typeof(HappinessFunctionApp.Startup))]
namespace HappinessFunctionApp
{
    public class Startup : FunctionsStartup
    {
        // 依存関係
        public override void Configure(IFunctionsHostBuilder builder)
        {
            // IHttpClientFactory を使用する
            builder.Services.AddHttpClient<HttpClientService>();
            builder.Services.AddSingleton(provider =>
            {
                ConnectionPolicy ConnectionPolicy = new ConnectionPolicy
                {
                    ConnectionMode = ConnectionMode.Direct,
                    ConnectionProtocol = Protocol.Tcp
                };

                return new DocumentClient(new Uri(AppSettings.Instance.COSMOSDB_ENDPOINT), AppSettings.Instance.COSMOSDB_KEY, ConnectionPolicy);
            });
        }
    }
}

  • キーとして文字列を使用する必要なしに、名前付きクライアントと同じ機能を提供します。
  • クライアントを使用するときに、IntelliSense とコンパイラのヘルプが提供されます。
  • 特定の HttpClient を構成してそれと対話する 1 つの場所を提供します。 たとえば、単一の型指定されたクライアントは、次のために使用 される場合があります。
    • 単一のバックエンド エンドポイント用。
    • エンドポイントを処理するすべてのロジックをカプセル化するため。
  • DI に対応しており、アプリ内の必要な場所に挿入できます。

今回の用途的に「型指定されたクライアント」で実装しました。

HttpClientService
using HappinessFunctionApp.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HappinessFunctionApp.Extension
{
    public class HttpClientService
    {
        private readonly HttpClient _client;

        public HttpClientService(HttpClient client)
        {
            _client = client;
        }
        public async Task<HttpResponseMessage> PostJsonAsync<T>(string requestUri, T value)
        {
            _client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json;");
            return await _client.PostAsJsonAsync(requestUri, value, CancellationToken.None).ConfigureAwait(false);
        }

        public async Task<HttpResponseMessage> PostLineJsonAsync<T>(string requestUri, T value)
        {
            _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AppSettings.Instance.LINE_CHANNEL_ACCESS_TOKEN);
            _client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json;");
            return await _client.PostAsJsonAsync(requestUri, value, CancellationToken.None).ConfigureAwait(false);
        }

        public async Task<Stream> GetStreamAsync(string requestUri)
        {
            var response = await _client.GetAsync(requestUri);
            return response.Content.ReadAsStreamAsync().Result;
        }

        public async Task<string> GetAsync(string requestUri)
        {
            var response = await _client.GetAsync(requestUri);
            return response.Content.ReadAsStringAsync().Result;
        }
    }
}


DocumentClient

各 DocumentClient インスタンスと CosmosClient インスタンスはスレッドセーフであり、直接モードで動作しているときには効率的な接続管理とアドレスのキャッシュが実行されます。 効率的な接続管理と SDK クライアントのパフォーマンス向上を実現するために、アプリケーションの有効期間中は、AppDomain ごとに単一のインスタンスを使用することをお勧めします。

DocumentClient インスタンスを使いまわすことが、ベストプラクティスのため、こちらも DI して使います。

Startup.cs
using HappinessFunctionApp.Common;
using HappinessFunctionApp.Extension;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System;

[assembly: FunctionsStartup(typeof(HappinessFunctionApp.Startup))]
namespace HappinessFunctionApp
{
    public class Startup : FunctionsStartup
    {
        // 依存関係
        public override void Configure(IFunctionsHostBuilder builder)
        {
            // IHttpClientFactory を使用する
            builder.Services.AddHttpClient<HttpClientService>();
            builder.Services.AddSingleton(provider =>
            {
                ConnectionPolicy ConnectionPolicy = new ConnectionPolicy
                {
                    ConnectionMode = ConnectionMode.Direct,
                    ConnectionProtocol = Protocol.Tcp
                };

                return new DocumentClient(new Uri(AppSettings.Instance.COSMOSDB_ENDPOINT), AppSettings.Instance.COSMOSDB_KEY, ConnectionPolicy);
            });
        }
    }
}

Azure Functions Proxy

投稿された画像を保存しているストレージアカウントのエンドポイントを表示したくなかったので、
Azure Functions Proxy 経由で画像表示を行うようにした。

従量課金の AppService Plan だとコールドスタートなので、初回は画像表示に遅延が発生してしまうので、プラン変更を行うか、他の方法で実装すべきだったなと少し思っています。

Proxies.json

{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "img": {
      "matchCondition": {
        "methods": [ "GET" ],
        "route": "/image/{filename}"
      },
      "backendUri": "https://<your Strage Account endpoint>.blob.core.windows.net/uploadimage/{filename}"
    }
  }
}

Azure SignalR

今回、リアルタイムでのコンテンツ更新を行いたかったので Azure SignalR を使いました。

ランキング情報の json をそのまま配信したかったので、シンプルにデフォルトで実装しています。

SignalRFunction.cs
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace HappinessFunctionApp.Functions
{
    public static class SignalRFunction
    {
        [FunctionName("negotiate")]
        public static SignalRConnectionInfo GetSignalRInfo(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
        [SignalRConnectionInfo(HubName = "chat")] SignalRConnectionInfo connectionInfo)
        {
            return connectionInfo;
        }

        [FunctionName("SendMessage")]
        public static async Task SendMessage(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest req,
        [SignalR(HubName = "chat")]IAsyncCollector<SignalRMessage> signalRMessages, ILogger log)
        {

            var data = await req.ReadAsStringAsync();

            await signalRMessages.AddAsync(new SignalRMessage
            {
                Target = "newMessage",
                Arguments = new[] { data }
            });
        }
    }
}


Vue側で、negotiate にリクエストを送信して接続情報を取得して、受け取った json を表示するだけ

Happiness.vue
 mounted () {
    // SignalRとコネクションを作成
    this.connection = new signalr.HubConnectionBuilder()
      .withUrl(process.env.VUE_APP_HOST)
      .configureLogging(signalr.LogLevel.Information)
      .build()
    console.log('connecting...')

    // SignalR Serviceへの接続
    this.connection
      .start()
      .then(() => console.log('connected!'))
      .catch(console.error)

    // SignalR Serviceへの接続
    this.connection.on('newMessage', (data) => {
      this.items = JSON.parse(data).images
      this.sumcnt = JSON.parse(data).images.length
      this.isLoading = false
      this.errored = false
      this.$emit('sumpicter', this.sumcnt)
      console.log(this.sumcnt)
      console.log(this.items)
    })
    // 切断
    this.connection.onclose(() => console.log('disconnected'))

動かすためにやること

LINE Developers に登録

以下を参照して、登録を行う

チャンネルの作成が完了したら「Channel secret」と「Channel access token」を控えておく

Azureポータル上の操作

Microsoft Azure で以下を作成する

  • Azure Functions
  • Azure Cosmos DB
  • SignalR
  • Cognitive Services Face
  • Storage Account

作成をしたら「キー」や「エンドポイント」を控えておく

storage01.png

ストレージアカウントの「BLOB」を使い、「uploadimage」というコンテナーを作成しておく

storage02.png

以降の local.settings.json の項目を AzureFunctions のアプリケーション設定に登録する

その際、SIGNALR_URL は Azure 上に作成した AzureFunctions のエンドポイントを設定する

applicationsetting.png

Happiness Function (C#)

local.settings.json

前述の作業で控えた「キー」と「エンドポイント」を設定する

ローカル実行する場合は、localhost の記載はそのままにしておく

※HOSTの記載は変更しない
 ローカルデバック時の vue.js との連携のため

local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "AzureSignalRConnectionString": "<your SignalR endpoint>",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "FACE_SUBSCRIPTION_KEY": "<your faceApi subscription key>",
    "FACE_ENDPOINT": "https://<your faceApi endpoint>.cognitiveservices.azure.com/",
    "STORAGE_ACCOUNT_NAME": "<your storage account name>",
    "STORAGE_ACCESS_KEY": "<your storage subscription key>",
    "BLOB_NAME": "uploadimage",
    "COSMOSDB_ENDPOINT": "https://<your cosmos db endpoint>.documents.azure.com:443/",
    "COSMOSDB_KEY": "<your cosmos db subscription key>",
    "DATABASE_ID": "LineBotDb",
    "COLLECTION_ID": "HappinessInfo",
    "LINE_CHANNEL_ACCESS_TOKEN": "<your LINE Messaging API Access Token>",
    "LINE_CHANNEL_SECRET": "<your LINE Messaging API Channel Secret>",
    "LINE_POST_LIST": "https://<your Storage Static web site endpoint>.z11.web.core.windows.net/",
    "BLOB_URL": "https://<your Strage Account endpoint>.blob.core.windows.net/uploadimage/",
    "PROXY_URL": "https://<your azure function endpoint>.azurewebsites.net/image/",
    "SIGNALR_URL": "http://localhost:7071/api/SendMessage"
  },
  "Host": {
    "LocalHttpPort": 7071,
    "CORS": "http://localhost:8080",
    "CORSCredentials": true
  }
}

Proxies.json

投稿画像を保存するストレージアカウントのエンドポイントに書き換え

Proxies.json
{
  "$schema": "http://json.schemastore.org/proxies",
  "proxies": {
    "img": {
      "matchCondition": {
        "methods": [ "GET" ],
        "route": "/image/{filename}"
      },
      "backendUri": "https://<your Strage Account endpoint>.blob.core.windows.net/uploadimage/{filename}"
    }
  }
}

happiness_app (Vue.js)

prod.env.js

VUE_APP_HOST の書き換え

prod.env.js
'use strict'
module.exports = {
  NODE_ENV: '"production"',
  VUE_APP_HOST: '"https://<your azure function endpoint>.azurewebsites.net/api"'
}

ビルド方法

# install dependencies
npm install

# serve with hot reload at localhost:8080
npm run dev

# build for production with minification
npm run build

# build for production and view the bundle analyzer report
npm run build --report

Azure Storage にデプロイ

Azure Storage コンテナー に VScode からデプロイを行う

スクリーンショット (2).png

LINEにエンドポイントを設定する

Azure にデプロイした「LineBotHttpStart」のエンドポイントを設定すれば完了

Linesetting.png

所感

今回初めて、LINE Messaging API や Durable Function 、Cosmos DB 、SignalR 、Vue.js を使ってみました。

まだまだ Durable Function や vue.js の実装方法など今後も引き続き、勉強していくしかないなと感じました。

しかし、この個人プロジェクトかなり学びが多い!楽しかった!

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# 基礎

参照:https://www.runoob.com/csharp/csharp-encapsulation.html

a++; ++a; a--; --a

b = a++: 先将 a 赋值给 b,再对 a 进行自增运算。
b = ++a: 先将 a 进行自增运算,再将 a 赋值给 b。
b = a--: 先将 a 赋值给 b,再对 a 进行自减运算。
b = --a: 先将 a 进行自减运算,再将 a 赋值给 b


using System;

namespace OperatorsAppl
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 1;
            int b;

            // a++ 先赋值再进行自增运算 a = 2, b = 1
            b = a++;
            Console.WriteLine("a = {0}", a);
            Console.WriteLine("b = {0}", b);
            Console.ReadLine();

            // ++a 先进行自增运算再赋值 a = 2, b = 2
            a = 1; // 重新初始化 a
            b = ++a;
            Console.WriteLine("a = {0}", a);
            Console.WriteLine("b = {0}", b);
            Console.ReadLine();

            // a-- 先赋值再进行自减运算 a = 0, b = 1
            a = 1;  // 重新初始化 a
            b= a--;
            Console.WriteLine("a = {0}", a);
            Console.WriteLine("b = {0}", b);
            Console.ReadLine();

            // --a 先进行自减运算再赋值 a = 0; b = 0
            a = 1;  // 重新初始化 a
            b= --a;
            Console.WriteLine("a = {0}", a);
            Console.WriteLine("b = {0}", b);
            Console.ReadLine();
        }
    }
}

Factorial

在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法。
  递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
  (1) 递归就是在过程或函数里调用自身。
  (2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
  (3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
  (4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。在实际编程中尤其要注意栈溢出问题。

  借助递归方法,我们可以把一个相对复杂的问题转化为一个与原问题相似的规模较小的问题来求解,递归方法只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。但在带来便捷的同时,也会有一些缺点,也即:通常用递归方法的运行效率不高。

using System;
namespace Test {
    class Dummy {
        public int loop(int i) {
            int result;
            Console.WriteLine("i: {0}", i);
            if (i == 10)
            {
                return 10;
            }
            else {
                result = loop(i + 1) + i;
                return result;
            }
        }
        static void Main(string[] args) {
            Dummy d = new Dummy();

            Console.WriteLine("result: {0}", d.loop(6)); // result: 40
        }
    }
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityの標準機能だけでTexturePackerを作ってテクスチャアトラスを用意する

動作環境

  • Windows10
  • Unity2018.4.22f1

記事の作成にあたり使用したアセット(無料)

Asset StoreからSunny Landという2Dのプレイヤー画像を使用させていただきました。
0.PackingTargets.jpg
こちらのかわいい複数枚のキツネをUnityの標準機能だけでテクスチャアトラスにします。

処理を始める前に…

画像をパックする前に対象となるテクスチャアセットのRead/Write Enabledにチェックを入れておく必要があります。
この項目にチェックが入っていないとTexture2D 関数からテクスチャデータにアクセスができないので画像をパックできません。
2.Checkit.jpg

実装内容

TexturePacker.cs
    private static void Pack(string filename, Texture2D[] resources, int maxsize)
    {
        // 1.複数枚の画像を1つにパックする
        var texture = new Texture2D(maxsize, maxsize, TextureFormat.RGBA32, false);
        var rect = texture.PackTextures(resources, 4, maxsize, false);
        File.WriteAllBytes(Application.dataPath + filename, texture.EncodeToPNG());
        AssetDatabase.ImportAsset("Assets" + filename);

        // 2.SpriteのMultiple設定をパックした画像から作成
        var spritesheets = new List<SpriteMetaData>();
        for (var index = 0; index < resources.Length; index++)
        {
            var data = new SpriteMetaData();
            data.name = resources[index].name;
            var x = rect[index].x * texture.width;
            var y = rect[index].y * texture.height;
            var w = rect[index].width * texture.width;
            var h = rect[index].height * texture.height;
            data.rect = new Rect(x, y, w, h);
            spritesheets.Add(data);
        }

        // 3.作成した情報をもとに画像をAtlas化
        var importer = AssetImporter.GetAtPath("Assets" + filename) as TextureImporter;
        importer.textureType = TextureImporterType.Sprite;
        importer.spriteImportMode = SpriteImportMode.Multiple;
        importer.spritesheet = spritesheets.ToArray();
        AssetDatabase.ImportAsset("Assets" + filename);
    }

解説

1. 複数枚の画像を1つにパックする

動的に画像を生成してPackTextures関数にTexture2D 配列を渡すことで自動的にパックしてくれます。
ただ、ここまでだと1枚の画像を作っただけです。テクスチャアトラスとして使うためには戻り値のRect型が必要になります。
1.PackingTexture.jpg

2. SpriteのMultiple設定をパックした画像から作成

画像をMultipleに設定することでパックした画像の配置とサイズを設定できます。
そのためにSpriteMetaDataクラスへPackTextures関数から返ってきたRect型の情報を割り当てて配列を用意しておきます。

3. 作成した情報をもとに画像をアトラス化

ここからがパックした画像をアトラス化する方法です。
まずTextureImporterクラスで生成したパック画像をエディターで読み込みます。
※画像を読み込むためにAssetDatabase.ImportAsset関数で画像を生成した後にインポートしておく必要があります。
読み込むことができたらTexture TypeをSpriteに、Sprite ModeをMultipleにします。
最後に、用意しておいたSpriteMetaData型の配列をspritesheetに設定したら完成です。
3.TextureAtlas.jpg

おわりに

Unityの標準機能だけでテクスチャアトラスを用意することができました。
ここまでならTexturePackerを使わなくてもいいのでは?とも思われそうですが、Unityで画像を作成するからこそ発生するデメリットがあります。
そのデメリットとはTexture2Dで指定できる最大サイズが限定的なので、必ず画像に余白ができることです。
x32.jpg
PackingTexture関数が画像をパッキングするタイミングで自動的に32のべき乗のサイズが設定されます。
その点、TexturePackerを使うと画像サイズは最適化されて余白が生まれません。
Unityを使用しないプロジェクトであればTexturePackerだけでいいのかもしれないですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

.Net Coreネイティブのネットワークフレームワーク Sockety

Sockety

.NET Coreで書いたネットワークフレームワークです。
MagicoOnionにインスパイアを受け開発しました。

開発経緯

.Net Coreで利用しマルチプラットフォームで通信を行う必要があり、MagicOnionを用いて通信を行っていました。
MagicOnionは通信コアにgRPCを使っており、ネイティブコードを利用しています。マルチプラットフォームで通信を行う場合、残念ながらARM版Windowsでは利用できないこと画面しました。
※ARM版Windowsでの動作はあまり必要ないと思いますがHololens2で利用するためです。
そこで一念発起しネットワークフレームワークを作成した次第です。
ですので、目指したところは"通信をラッピングし相手のメソッドを簡単に呼ぶ"です。まだ速度までは至っていません。

概要

SocketyはTCPとUDPを利用することが出来ます。
UDPはHolePunchingでNATを回避しています

Client.Connect("localhost",11000,"MyApp",this);

これでクライアントは接続を開始しますが、この時にTCPとUDPを張ります。
ですので、高速通信を行いたい場合はUDPを利用することも、大事なデータはTCPで送ることも出来ます
クライアント(呼ぶ側)

client.Send("Join", DateTime.Now.ToString());

とやるとサーバのメソッド(この場合はJoin)を呼び、引数である現在時刻を渡すことが出来ます。

サーバ(呼ばれる側)

public void Join(ClientInfo sendclientInfo,string JoinDate)

サーバの受け側はこんな感じです。
ClientInfo→送信元のクライアント情報
JoinDate→client.Sendの第2引数

パッケージ

dotnet add package Sockety

で取得してください
現状はバグがあることからGithubからソースをCloneしプロジェクトに追加することをお勧めします。

使い方

詳細な使い方は追って記述しますが、まずはExampleを参照してください。
・Sockety(本体)
・Example/SocketyServer(サンプルサーバ)
・Example/SocketyClient(サンプルクライアント)
・Example/SocketyClientUWP(サンプルクライアント版)

問題点

C#での利点である型チェックやメソッド名などを参照することが出来ず、相手のメソッドを呼ぶ時に文字列していとなっています。MagicOnionではこの点が解消されていて素晴らしいライブラリとなっています。
まだまだ至らない点はたくさんありますが、皆さんの熱いプルリクをお待ちしております。

Github リポジトリ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「有限要素法入門」を読んでみた

EYq0hgKU8AAZbMt.png
1978年発行という古い本。入門の名にふさわしく、基礎から順序だてて体系的に説明しており、高校数学程度の前提知識だけで理解できる。大部分が基本的な数学と力学の説明で、有限要素法自体の内容は少ない。最後に第二部として応用的な内容が紹介されているが詳細な説明はなく、次のステップへの道しるべのようになっている。

論理は明解で、混乱を招くような定義漏れや誤字脱字などもなく整っており、自分のような初学者も安心して読める。素晴らしい良書だった!古くから読み継がれている本というのは洗練されている。

構成

最初の1/3は基本的な線形代数のみ。大学数学でやるような抽象的なベクトルの定義からのスタートではなく、数のセットとしてベクトルを定義するやり方。分かりやすさに重点を置いている。

線形代数の後は複数のバネからなる系を表す剛性マトリクスの説明。一見 有限要素法と関係ない話のように見えるのだが、実は有限要素法はこの理論から発祥したものらしい。そのことが後になって分かる。

剛体マトリクスの次は弾性体力学の解説。基本的なことから明解に解説しており、弾性体力学を学んだことがない自分でもすんなりと理解することが出来た。

ここまでが本書の半分を占めるのだが、有限要素法の説明はまだ始まらない。この本では有限要素法を理解するための前提知識の解説に多くの紙面を費やしている。有限要素法の理論自体はとても単純なので、このやり方はとても良いと思う。

次でようやく有限要素法の開始。かと思いきや、剛性マトリクスを利用した骨組構造解析の手法の解説が始まる。棒からなる構造物を考えるとき、棒を一つのバネ要素とみなし、バネ要素一つ一つに剛性マトリクスを求め、それらを合成した行列を作る。その行列からなる連立方程式を解くことで力やひずみの解析が出来る。

その後 本当に有限要素法が始まる。有限要素法は骨組構造解析を一般化しただけのもの。計算のやり方は全く同じ。結局のところ、有限要素法としての説明は、紙面上はわずか15ページほどにしか過ぎない。拍子抜けするほど簡単で、入門としてはとても分かりやすい。
EYjXtYUUEAA7VP-.jfif

このあとは第II部 応用編となっており、説明は大雑把で結論しか載ってない。詳細説明は他の書籍に譲るといったところか。Fotranによる具体的な解析例も記載されているが、今となってはいささか古いので参考として読み流してもいいと思う。自分の好きな言語で実装してみると良い勉強になる。

本書の特徴

もともと有限要素法はこのように骨組み構造解析から生まれたものだそうである。しかしこれを一般の物理現象を表す微分方程式を解く手法として一般化することが出来る。初めから一般化して数学的に有限要素法を説明している本もあるようだが、この本では歴史的な道筋の通りに説明している。最初から抽象的な説明を受け入れるのはなかなか難しい。初心者にとっては、たとえ特殊な一つの例にすぎなかったとしても、具体的なものから導入して説明された方がずっと分かりやすい。
この本を読んだことで有限要素法の全てが分かるわけではないが、入門書としては間違いなく良書であると思う。

C#で実装してみた

この基礎理論に基づいて2次元弾性解析を実装してみた。
EZMpXaeUEAAtb6Y.png

それっぽい変位・ひずみ・応力の分布が得られた。やっていることは単に小さい三角形ごとに行列を作って、それらを重ね合わせた行列がなす連立方程式を解いているだけ。こんなシンプルなプログラムでこんな凄いことが出来る。結果が出ると楽しいし、数値計算や画像表示のプログラミングのいい練習にもなる。

ここでは規則正しく並んだ要素からなる正方形という簡単な形状を解析対象としているが、これは単に入力の形状データを作る作業を楽にしたかったためである。有限要素法の凄いところはどんな複雑な形状をしていようと全く同じ方法で計算出来るところである。自分で適当に節点を設定して細かい三角形に分割してその座標を入力するだけで、どんな問題も同じように解ける。

任意形状に対する分割データの作成作業自体もプログラム化することは出来るが有限要素法の本質と関係ないので今回は実装しなかった。それはまた別の機会に考えよう。

コードはGitHubに置いた。WindowsFormsApp2/WindowsFormsApp2/Form1.csがメインのコード。
https://github.com/MhageGH/FEM-exmaple

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む