Вступление
В этой статье я постараюсь максимально полно и пошагово рассказать, как связать MATLAB с С#.NET и сделать приложение с интерфейсом на примере построения 3D-плоскости.
Зачем это нужно?
Очень часто перед программистом встает задача вычисления сложной математики. MATLAB в свою очередь является отличным средством для решения, но слаб в создании полноценного пользовательского приложения (можно воспользоваться инструментами GUI MATLAB'a, но это меня не устроило).
Инструменты
- Microsoft Visual Studio 2008 SP1
- MATLAB 2010a
- MATLAB Component Runtime
Шаг 1. Настройка линкера
Чтобы собрать dll-библиотеку MATLAB'а для интеграции в C#.NET, нужно настроить линкер, т.е. какой средой мы будем собирать проект. Для начала нужно установить среду выполнения MCR (MATLAB Component Runtime). Это набор dll-библиотек для полной поддержки языка MATLAB. Установочный файл можно найти: ...\MATLAB\R2011b\toolbox\compiler\deploy\win32\MCRInstaller. Установка типовая, жмем next.
Для настройки линкера в командном окне MATLAB'а набираем
mbuild -setup
. Со всем соглашаемся и выбираем нужную нам среду, в нашем случае это MVS 2008 SP1. Получаем что-то похожее:Please choose your compiler for building standalone MATLAB applications:
Would you like mbuild to locate installed compilers [y]/n? y
Select a compiler:
[1] Lcc-win32 C 2.4.1 in C:\PROGRA~1\MATLAB\R2010a\sys\lcc
[2] Microsoft Visual C++ 2008 SP1 in C:\Program Files\Microsoft Visual Studio 9.0
[0] None
Compiler: 2
Please verify your choices:
Compiler: Microsoft Visual C++ 2008 SP1
Location: C:\Program Files\Microsoft Visual Studio 9.0
Are these correct [y]/n? y
Получаем радостное
Done
. Все — линкер настроен.Шаг 2. Пишем m-функцию
Напишем функцию построения 3D-плоскости в заданных граничных условиях, для большего интереса вернем дескриптор функции.
function res=plane(strfunc,vx0,vx1,vy0,vy1,h)
vx=vx0:h:vx1;
vy=vy0:h:vy1;
figure(1)
res=ezsurfc(strfunc,vx,vy);
end
Как видно функция состоит из шести строчек кода, однако выполняет все вышеуказанные действия: в качестве входных параметров принимает символьную функцию (
strfunc
), начальные и конечные значения векторов границ плоскости (vx0,vx1,vy0,vy1
), шаг сетки (h
) и возвращает дескриптор (res
). Сохраняем данный код как plane.m.
Важно: компилятор MATLAB'а понимает только функции т.е., каждый сценарий должен начинаться с
function
(желательно заканчиваться end
) и быть отдельным m-файлом.Шаг 3. Получаем динамическую библиотеку
Набираем в командном окне MATLAB'a
deploytool
. Создаем новый .NET Assembly проект MATLABplane, указываем размещение.![image](https://habrastorage.org/getpro/habr/post_images/6b6/28e/eea/6b628eeeab6a205029f65e62abf06be5.png)
Далее создаем класс planeClass, добавляем в него plane.m и нажимаем кнопку build
![image](https://habrastorage.org/getpro/habr/post_images/978/b21/a7d/978b21a7d73b286f1621582275a71f09.png)
После успешной компиляции создается интересующая нас библиотека MATLABplane.dll, находиться она будет здесь: ...MATLABplane\distrib\MATLABplane.dll.
Шаг 4. Создаем приложение C#.NET
В MVS 2008 SP1 создаем приложение Windows Forms на С#.
Добавляем ссылки на библиотеки
Перед использованием методов проекта, необходимо добавить ссылки на скомпилированную библиотеку MATLABplane.dll и на библиотеку MWArray.dll, найти ее можно по адресу ...\MATLAB\R2010a\toolbox\dotnetbuilder\bin\win32\v2.0. После добавления должно получиться:
![image](https://habrastorage.org/getpro/habr/post_images/c9a/b8b/4d9/c9ab8b4d9458e714b31ecd74d3e298c9.png)
Для использования библиотек в проекте необходимо добавить описание пространства имен:
using MathWorks.MATLAB.NET.Utility;
using MathWorks.MATLAB.NET.Arrays;
using MATLABplane;
Создаем форму
С помощью панели инструментов в конструкторе создаем форму будущего приложения.
![image](https://habrastorage.org/getpro/habr/post_images/751/bc1/279/751bc1279f90b9fd21e3613a1932c336.png)
Для создания формы были использованы следующие блоки: Label, TextBox, RichBox, Button.
Пишем код
Для взаимодействия языков программирования C# и MATLAB создан соответствующий типу MATLAB тип данных MWArray C#. MWArray — это массив массивов, он может состоять из переменных, скаляров, векторов, матриц, строк, структур, объектов и т.д. Для получения каких-либо значений из MWArray нужно использовать приведение типов.
Алгоритм работы приложения должен быть следующим:
- Получение функции в символьном виде и значений с текстовых полей
- Вызов метода plane из класса planeClass
- Получение выходного массива descriptor (тип MWNumericArray)
- Вывод массива descriptor в RichBox
Ниже представлен полный код с комментариями:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MathWorks.MATLAB.NET.Utility;
using MathWorks.MATLAB.NET.Arrays;
using MATLABplane;
namespace planeApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += new EventHandler(button1_Click);//инициализация событий
button2.Click += new EventHandler(button2_Click);
}
double x0, x1, y0, y1, h; //объявление переменых
string func, s_x0, s_x1, s_y0, s_y1, s_h;
MWArray[] res = null; //выходной массив метода plane
MWNumericArray descriptor = null; //массив возвращаемого параметра
private void button1_Click(object sender, EventArgs e)//событие
{
try
{
func = textBox1.Text; //считывание с TextBox
s_x0 = textBox2.Text;
s_x1 = textBox3.Text;
s_y0 = textBox4.Text;
s_y1 = textBox5.Text;
s_h = textBox6.Text;
MWCharArray mw_func = new MWCharArray(func);//преобразование строки функции в тип MWCharArray
x0 = Convert.ToDouble(s_x0); //преобразоване string в double
x1 = Convert.ToDouble(s_x1);
y0 = Convert.ToDouble(s_y0);
y1 = Convert.ToDouble(s_y1);
h = Convert.ToDouble(s_h);
planeClass obj_plane = new planeClass(); //экземпляр класса компонента
res = obj_plane.plane(1, mw_func, x0, x1, y0, y1, h);//обращение к методу plane, первый параметр - это кол-во возвращаемых аргументов
descriptor = (MWNumericArray)res[0]; //выбор первого элемента из массива MWArray и преобразование в числовой тип MWNumericArray
double[,] d_descriptor = (double[,])descriptor.ToArray(MWArrayComponent.Real);//преобразование массива MWNUmericArray к масииву типа double
for (int i = 0; i < d_descriptor.Length; i++)//вывод массива d_descriptor в RichBox
{
richTextBox1.Text += i.ToString() + '\t';
richTextBox1.Text += d_descriptor[i, 0].ToString("0.000") + '\n';//преобразование элеметна массива double в string
}
}
catch (Exception ex)//обработка исключения
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
private void button2_Click(object sender, EventArgs e)
{
richTextBox1.Text = string.Empty;//очистка RichBox
res = null;//обнуление массивов
descriptor = null;
}
}
}
Как видим, активно используется приведение типов, по схеме MWArray->MWNUmericArray->тип C#.
Компилируем проект и видим результат:
![image](https://habrastorage.org/getpro/habr/post_images/4bc/72d/3fe/4bc72d3fe706ee43b877d8ec4da41657.jpg)
Литература
- MATLAB. Программирование на Visual С#, Borland JBuilder, VBA — Н. К. Смоленцев
- С# и платформа .NET — Э. Троелсен