您的位置:首页 > 编程语言 > MATLAB

Matlab与VC混合编程之三

2013-07-01 23:59 387 查看
Matlab与VC混合编程之三

1. 有没有优雅的使用方式?

在《Matlab与VC混合编程之二》中我们学会了如何使用向量或者矩阵在VC与Matlab
COM组件之间传递参数。在第二章的实现中,标量和向量的使用方式勉强可以接受,矩阵的使用方式简直令人发狂。而我们的大多数科学计算或者工程计算都需要用到矩阵,如何改进对矩阵(二维数组)的访问方式,是本章要回答的问题。在本章中,我们使用用C++的类来封装这种复杂性,把标量和向量作为矩阵的特殊情况,使用类来表达矩阵的概念。经过封装之后,以后再使用时就直接调用类的接口,实现了简单优雅访问Matlab生产的COM组件。首先讲解一些C++的类基本概念,之后讲解矩阵了matrix的实现方式,最后在附录中给出完整的源代码。

2. 基本概念

a.需要几个类来封装

使用类来表示概念和针对接口编程,是设计一个良好的类需要遵循的原则。在VC与Matlab
COM的访问中,我们需要“矩阵”这一概念。使用Matlab时会注意到matlab的几乎所有函数的输入输出参数都是矩阵,向量和标量只是矩阵的特殊形式,向量是只有一行(行向量)或者只有一列(列向量)的矩阵,标量是只有一行一列的矩阵。理解了这一点之后,我们就只需要一个概念,即矩阵。所以我们只需要实现或者定义一个类matrix。

b.类的接口有哪些

类的接口指类的共有方法(public函数)。类的接口有哪些,是由使用该类的客户的上下文(环境)来确定的。也就是说在定义类的接口时要站在客户(使用类的人或者代码)的角度去考虑问题。在这里,使用matrix时,我们需要能够将数据赋值到matrix中,能够将matrix作为输入参数传递给Matlab
COM的接口函数去完成计算,能够将matrix作为输出参数传递给Matlab
COM的接口函数从而获得计算的结果,能够将matrix中的数据获取出来。

如图1所示。





图1 matrix封装示意图
写成伪代码的形式如下:

double dx[2][2] = {1,2,3,4}; //客户需要计算的数据

matrix mx, my; //matrix变量的定义

mx.setMatrix(2,2,dx);//将客户数据赋值到matrix中

long varNum = 1;

pInterface->calcSin(varNum, &my,
mx); //matrix作为输入参数和输出参数,假定这里的COM函数是求正弦值

double dy[2][2] = {0}; //客户需要获取结果数据

my.getData(dy); //将matrix中的数据获取出来

站在客户的角度,才能设计出优良的类(抽象、概念)。

3. matrix的实现方式

a. matrix接口初步

根据第二节的分析,我们的matrix的接口应该是这样的:

class matrix

{

public:

matrix(); //默认构造函数

matrix(int nRows, int nCols); //构造nRows行、nCols列的矩阵,所有元素初始化为0

matrix(int nRows, int nCols, double*
pdArray);//构造nRows行、nCols列的矩阵,矩阵元素为数组的内容

matrix(const matrix& other);
//拷贝构造函数,允许使用matrix对象构造

void setMatrix(int nRows, int nCols, double* pdArray);
//设置矩阵的大小和数据

void setSize(int nRows, int nCols); //设置矩阵的大小,以后再设置数据

void setData(double* pdArray, ); //设置数据

Size getSize(); //返回矩阵的大小

void getData(double* pdArray); //获得矩阵的数据

operator VARIANT();
//类型转换运算符,允许在函数的输入参数中使用VARIANT的地方使用matrix

//matlab com的接口函数的输入参数都是VARIANT型的变量

VARIANT* operator&();
//取地址运算符重载,允许在函数的输出参数中使用VARIANT的地方使用matrix

//matlab com的接口函数的输出参数都是VARIANT型的变量的指针(取地址)

}

b.增加一维数组和二维数组的描述

i.一维数组和二维数组的区别

在《Matlab与VC混合编程之二》中我们提到了VARIANT存储数组时是按照列优先的顺序来存储的。如果是一维数据,不管是按照行优先原则还是列优先的原则,访问其内部元素的顺序是相同的。比如double
a[3]={1,2,3}。若按照行优先来存储,先存储第一行,那么在内存中的顺序是1,2,3.若按照列优先来存储,先存储第一列,1,再存储第二列2,最后存储第三列3,元素在内存中的顺序依然是1,2,3.所以对于一维数组,不需要进行数据转换。

对于二维数据(矩阵),则必须进行数据转换。仍然使用《Matlab与VC混合编程之二》中的例子。一个3行2列的数组(矩阵)

double array[3][2] = {1, 2,

3, 4,

5, 6};

按照行优先的顺序存储,在VC中是先存第1{1,2},再存第2{3,4},再存第3{5,6}。即在内存中的顺序是1,2,3,4,5,6.

如果直接将array的数据拷贝到VARIANT的SAFEARRAY中,那么SAFEARRAY在内存中的顺序仍然是1,2,3,4,5,6.但由于SAFEARRAY是按照列优先来存放和访问的。SAFEARRAY的第一维是列,列数是2,第二维是行,行数是3。SAFEARRAY在进行访问时,先访问第1{1,2,3},再访问第2{4,5,6}。即这时将SAFEARRAY写成矩阵的形式是
[1 4,
2
5,
3
6]。显然不是我们要传入的矩阵array.所以,在从二维数组到SAFEARRAY的赋值前必须进行转换。
现在首先对array取转置,得到二维数组b[2][3]={1,3,5,

2,4,6}。之后将b的内存直接拷贝到VARIANT的SAFEARRAY中。由于b在内存中的顺序是1,3,5,2,4,6.那么SAFEARRAY是按照列优先来访问,先访问第1列{1,3,5},再访问第2列{2,4,6}.写成矩阵的形式是
[1,2,
3,4,
5,6]。正好是我们所要传入的矩阵。所以转换的方法是,首先将二维数组array求转置得到新的二维数组,将该二维数组的数据直接拷贝到SAFEARRAY中。同时,在输出数据时,需要将SAFEARRAY的数据拷贝出来,经过转置,放置到接受输出数据的二维数组中。见图2.




图2 matrix实现示意图
为了区分一维数组和二维数组,定义了枚举enum ArrayType{Dim1, Dim2};
当使用matrix表示向量(行向量或者列向量,默认是列向量)或者标量时,使用Dim1,表示(Dimension
1,一维)。当使用matrix表示矩阵时,如果用户没有在外部对输入的二维数组使用转置,使用Dim2,matrix会在构造时进行装置;如果用户在外部自己实现了转置,那么使用Dim1,matrix不会再进行转置。即Dim1和Dim2的区别是Dim1构造时matrix时直接拷贝传入的数组的数据,Dim2将传入的数据转置后拷贝到内部的VARIANT。
ii.
数组维数的描述
使用了matrix的内部类struct
Size来描述数组的行数和列数。
class matrix {
public:
struct Size

{

int m_nRows; //矩阵的行数

int m_nCols; //矩阵的列数

Size() : m_nRows(0), m_nCols(0){ }

Size(int nRows, int nCols) : m_nRows(nRows), m_nCols(nCols){
}

};
};

c. 兼容已有的程序
为了兼容已有的程序,需要增加VARIANT和matrix互相赋值的接口。使用构造函数和setMatrix函数重载来用VARIANT构造和设置matrix;使用类型转换运算符来将matrix转换为VARIANT。
d.
完整接口的matirx
经过以上分析,具备较完备接口的matrix的定义如下:
class matrix

{

public:

//Dim1:一维数组,表示向量;Dim2:二维数组,表示矩阵。将标量看成是只有一个元素的向量或者矩阵。

enum ArrayType{Dim1, Dim2};

struct Size

{

int m_nRows; //矩阵的行数

int m_nCols; //矩阵的列数

Size() : m_nRows(0), m_nCols(0){ }

Size(int nRows, int nCols) : m_nRows(nRows), m_nCols(nCols){
}

};

public:

matrix();

matrix(int nRows, int nCols); //构造nRows行、nCols列的矩阵,所有元素初始化为0

//构造nRows行、nCols列的矩阵,所有元素初始化为一维数组或二维数组的内容

matrix(int nRows, int nCols, double* pdArray, ArrayType
arrType);

matrix(const VARIANT& var); //用VARIANT构造

matrix(const matrix& other);
//拷贝构造函数,允许使用matrix对象构造

void setMatrix(int nRows, int nCols, double* pdArray, ArrayType
arrType); //设置矩阵的大小和数据

void setMatirx(const VARIANT& var);
//用VARIANT设置矩阵

void setSize(int nRows, int nCols); //设置矩阵的大小,默认构造后再设置数据

void setData(double* pdArray, ArrayType arrType);
//默认构造后再设置数据

Size getSize(); //返回矩阵的大小

void getData(double* pdArray, ArrayType arrType); //获得矩阵的数据

public: //matrix 与 VARIANT的转换

operator VARIANT(); //类型转换运算符,允许在函数的输入参数中使用VARIANT的地方使用matrix

//matlab com的接口函数的输入参数都是VARIANT型的变量

VARIANT* operator&();
//取地址运算符重载,允许在函数的输出参数中使用VARIANT的地方使用matrix

//matlab com的接口函数的输出参数都是VARIANT型的变量的指针(取地址)

matrix& operator=(const matrix&
other); //重载赋值运算符,允许matrix之间相互赋值

virtual ~matrix();

};

4. 优雅的使用matrix类

为了演示matrix的使用,这里使用matrix重写了《Matlab与VC混合编程之二》中的OnButtonTest()。

void CTestMyCalcDlg::OnButtonTest()

{

::CoInitialize(NULL);
//a.初始化COM。

IMyCalc *pICalc; //声明一个接口

//b.创建COM接口。

HRESULT hr =
::CoCreateInstance(CLSID_MyCalc,
//你使用的COM对象的ID(CLaSs ID)

NULL,

CLSCTX_ALL,

IID_IMyCalc,
//你使用的COMCOM对象接口的ID(Interface ID)

(LPVOID*)&pICalc);//这里用&pIdraw使pIdraw指向接口的地址

if (FAILED(hr)) //错误检查并处理

{

//。。。

return;

}

//c.使用COM接口,这一段使用的数据类型是VARIANT

long nvar = 1; //输出变量的个数

//i. 使用mycross

matrix ca,cb,cy;
//ca,cb输入参数,cy输出参数初始化在默认构造函数已经完成

//对向量ca,cb赋值,以double型为例

//...Action_1

double array1[3] = {1, 0,
0};
//待存入的一维数组

double array2[3] = {0, 1,
0};
//带存入的一维数组

ca.setMatrix(1,3,array1,
matrix::Dim1); //数组维数定义和数据变换自动完成,行向量

cb.setMatrix(1,3,array2,
matrix::Dim1);
//这里也可以将ca、cb定义成列向量,setMatrix(3,1,...);

hr = pICalc->mycross(nvar,
&cy, ca, cb);
//输出变量使用&cy形式才能得到返回值。

//从cy获取计算结果

//...Action_2

double array3[3] = {0};

cy.getData(array3, matrix::Dim1);

matrix::Size s1 = cy.getSize();

//array3结果是{0,0,1},结果正确。

//ii. 使用mydet

matrix dx,dy; //dx输入参数,dy输出参数, 默认构造函数完成初始化

//对向量dx赋值,以double型为例

//...Action_3

double array4[2][2] = {1, 0, 0, 4};

dx.setMatrix(2,2,(double*)array4,
matrix::Dim2); //数组维数定义和数据变换自动完成

hr = pICalc->mydet(nvar,
&dy, dx);
//输出变量使用&dy形式才能得到返回值。

//从dy获取计算结果

//...Action_4

double dresult = 0;

dy.getData(&dresult,
matrix::Dim1);

matrix::Size s2 = dy.getSize();

//dresult = 4,结果正确

//iii. 使用myinv

matrix ix,iy;
//ix输入参数,iy输出参数。ix,iy在默认构造函数已经被初始化

//对向量ix赋值,以double型为例

//Action_5

double array5[3][3] = {1, 0, 0, 0, 1, 0, 0, 0,
1};

ix.setMatrix(3, 3, (double*)array5,
matrix::Dim2); //数组维数定义和数据变换自动完成

hr = pICalc->myinv(nvar,
&iy, ix);
//输出变量使用&iy形式才能得到返回值。

//从iy获取计算结果

//...Action_6

double array6[3][3] = {0};

iy.getData((double*)array6, matrix::Dim2);

matrix::Size s3 = iy.getSize();

//array6结果是{{1,0,0}, {0,1,0}, {0,0,1}},结果正确。

//d.退出COM。

CoUninitialize();

}

5. 优雅的背后,matrix封装类

在第4节,我们使用matrix类的接口重写了《Matlab与VC混合编程之二》中VC与Matlab
COM的接口函数进行交互的程序。可以明显看到,使用了matrix后,程序代码和程序逻辑得到很大的改善。那么,matrix的接口是怎么实现的。附录8给出优雅的背后,matrix的完整实现代码。

6. 有没有完整的说明matlab COM?

我们采用COM组件方式的matlab与VC混合编程给予了详细的介绍。这里距离完整还差一点,就是我们的程序怎么发布。在Matlab7.0及以下版本中,在Matlab
COM Builder窗口中点击菜单Component->Package
component;在在Matlab2007b及以上版本中,点击工具栏Build后面的Package按钮。弹出Package
Files对话框(Matlab 7.0版本),见图3,将“Include
MCR”选中,点击左下方的Create,等待几十秒,完成COM组件封装。在Matlab的当前目录Current
Directary窗口下,找到distrib文件夹下的组件名的可执行程序YourComName.exe,将该文件复制出来,跟你的VC程序编译链接生成的可执行程序.exe放在一起打包发布就行了。





图3 matlab com package 窗口
7.其他的VC和Matlab混合编程的方式呢?

对于matlab与VC混合编程的实现方法之一“采用COM组件方式”,我们给予了完整而详细的介绍。根据存在必有其意义的想法,其他的混合编程方式一定有其存在的意义。那么其他方式是怎么实现的,有没有优点,接下来的章节会继续探讨。
8.附录

// matrix.h: interface for the matrix class and
matrix-related functions.


// 头文件

//////////////////////////////////////////////////////////////////////

#ifndef MATRIX_H_H

#define MATRIX_H_H

//封装了与matlab com进行交互的数据。可以把所有matlab的函数的输入参数和返回值看成是矩阵形式。

//作者:张坤

//时间:2013.06.06

class matrix

{

public:

//Dim1:一维数组,表示向量;Dim2:二维数组,表示矩阵。将标量看成是只有一个元素的向量或者矩阵。

enum ArrayType{Dim1,
Dim2};

struct Size

{

int
m_nRows;
//矩阵的行数

int
m_nCols;
//矩阵的列数

Size() : m_nRows(0),
m_nCols(0){ }

Size(int nRows, int nCols) :
m_nRows(nRows), m_nCols(nCols){ }

};

public:

matrix();

matrix(int nRows, int nCols);
//构造nRows行、nCols列的矩阵,所有元素初始化为0

//构造nRows行、nCols列的矩阵,所有元素初始化为一维数组或二维数组的内容

matrix(int nRows, int nCols, double* pdArray,
ArrayType arrType);

matrix(const VARIANT&
var); //用VARIANT构造

matrix(const matrix& other);
//拷贝构造函数,允许使用matrix对象构造

void setMatrix(int nRows, int nCols, double*
pdArray, ArrayType arrType); //设置矩阵的大小和数据

void setMatirx(const VARIANT&
var); //用VARIANT设置矩阵

void setSize(int nRows, int
nCols); //设置矩阵的大小,默认构造后再设置数据

void setData(double* pdArray, ArrayType
arrType); //默认构造后再设置数据

Size
getSize(); //返回矩阵的大小

void getData(double* pdArray, ArrayType
arrType); //获得矩阵的数据

public: //matrix 与 VARIANT的转换

operator VARIANT()
//类型转换运算符,允许在函数的输入参数中使用VARIANT的地方使用matrix

{
//matlab com的接口函数的输入参数都是VARIANT型的变量

return m_varMatrix;

}

VARIANT*
operator&()
//取地址运算符重载,允许在函数的输出参数中使用VARIANT的地方使用matrix

{
//matlab com的接口函数的输出参数都是VARIANT型的变量的指针(取地址)

return
&m_varMatrix;

}

matrix& operator=(const
matrix& other);
//重载赋值运算符,允许matrix之间相互赋值

virtual ~matrix();

private: //注意:私有函数不属于类的接口,属于类的实现部分

Size
m_matrixSize;
//矩阵的大小,包括行和列

VARIANT m_varMatrix; //变体类型,与matlab的接口

//私有函数,将nRow行、nCols列的pdin矩阵转置成pdout矩阵

inline void transpose(int nRows, int nCols,
double* pdin, double* pdout);

inline void copy(const matrix&
other); //复制other到this对象

inline void getVariantSize(Size&
varSize, const VARIANT& var); //获得该var的大小

};

#endif

// matrix.cpp: implementation of the matrix
class.


//源文件

//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "matrix.h"

// 功能:构造0行、0列的空矩阵

// 输入:无

// 输出:无

// 影响:matrix为空矩阵

// 作者:张坤

// 时间:2013.06.06

matrix::matrix()

{

VariantInit(&m_varMatrix);
//一定要初始化

}

// 功能:析构

// 输入:无

// 输出:无

// 影响:无

// 作者:张坤

// 时间:2013.06.06

matrix::~matrix()

{

VariantClear(&m_varMatrix);

}

// 功能:构造nRows行、nCols列的矩阵,所有元素初始化为0

// 输入:nRows, 矩阵的行数; nCols,矩阵的列数

// 输出:无

// 影响:matrix所有元素初始化为0

// 作者:张坤

// 时间:2013.06.06

matrix::matrix(int nRows, int nCols)

{

setSize(nRows, nCols);

}

// 功能:拷贝构造函数,允许使用matrix构造

// 输入:matrix对象

// 输出:无

// 影响:matrix大小和所有元素与输入参数相同

// 作者:张坤

// 时间:2013.06.06

matrix::matrix(const matrix& other)

{

copy(other);

}

// 功能:重载赋值运算符,允许matrix之间相互赋值

// 输入:matrix对象

// 输出:无

// 影响:matrix大小和所有元素与输入参数相同

// 作者:张坤

// 时间:2013.06.06

matrix& matrix::operator=(const
matrix& other)

{

if (this == &other )
//判断是否自身赋值给自身

{

return *this;

}

else

{

copy(other);

return *this;

}

}

// 功能:拷贝另一个matrix对象到this对象

// 输入:matrix对象

// 输出:无

// 影响:matrix大小和所有元素与输入参数相同

// 作者:张坤

// 时间:2013.06.06

void matrix::copy(const matrix& other)

{

m_matrixSize.m_nRows =
other.m_matrixSize.m_nRows;

m_matrixSize.m_nCols =
other.m_matrixSize.m_nCols;

VariantCopy(&m_varMatrix,
(VARIANT*)&other.m_varMatrix);

}

// 功能:用指定的var构造矩阵

// 输入:var:VARIANT型的数据

// 输出:无

// 影响:将matrix的大小和所有元素初始化为var的大小和元素

// 作者:张坤

// 时间:2013.06.12

matrix::matrix(const VARIANT& var)

{

setMatirx(var);

}

// 功能:构造nRows行、nCols列的矩阵,所有元素初始化为一维数组或二维数组的内容

// 输入:nRows, 矩阵的行数; nCols,矩阵的列数,pdArray一维数组或二维数组强制转换的结果,

// arrType,一维数组或二维数组的标识

// 输出:无

// 影响:matrix所有元素初始化为一维数组或二维数组的内容

// 注意:如果matrix表示一个向量,使用一维数组构造,arrType设为matrix::Dim1

//
若干matrix表示一个矩阵,使用二维数组构造,arrType设为matrix::Dim2

// 作者:张坤

// 时间:2013.06.06

matrix::matrix(int nRows, int nCols, double* pdArray, ArrayType
arrType)

:
m_matrixSize(nRows, nCols)

{

setMatrix(nRows, nCols, pdArray, arrType);

}

// 功能:设置nRows行、nCols列的矩阵,元素为一维数组或二维数组的内容

// 输入:nRows, 矩阵的行数; nCols,矩阵的列数,pdArray一维数组或二维数组强制转换的结果,

// arrType,一维数组或二维数组的标识

// 输出:无

// 影响:matrix所有元素初始化为一维数组或二维数组的内容

// 注意:如果matrix表示一个向量,使用一维数组构造,arrType设为matrix::Dim1

//
若干matrix表示一个矩阵,使用二维数组构造,arrType设为matrix::Dim2

// 作者:张坤

// 时间:2013.06.06

void matrix::setMatrix(int nRows, int nCols, double* pdArray,
ArrayType arrType) //默认构造后再设置数据

{

setSize(nRows, nCols);

setData(pdArray, arrType);

}

// 功能:获得指定var的大小

// 输入:varSize引用:var的大小,是返回值;var:欲获得大小的VARIANT

// 输出:无

// 影响:无

// 作者:张坤

// 时间:2013.06.12

void matrix::getVariantSize(Size& varSize, const
VARIANT& var) //获得该var的大小

{

//var是标量

if (var.vt == VT_R8)

{

varSize.m_nRows = 1;

varSize.m_nCols = 1;

}

else if (var.vt == (VT_R8|VT_ARRAY)

&&
var.parray->cDims == 1)
//一维数组,相当于列向量

{

varSize.m_nRows = 1;

varSize.m_nCols =
var.parray->rgsabound[0].cElements;

}

else //二维数组,矩阵

{

varSize.m_nRows =
var.parray->rgsabound[1].cElements;

varSize.m_nCols =
var.parray->rgsabound[0].cElements;

}

}

// 功能:用指定的var设定矩阵

// 输入:var:VARIANT型的数据

// 输出:无

// 影响:将matrix的大小和所有元素设置为var的大小和元素

// 作者:张坤

// 时间:2013.06.12

void matrix::setMatirx(const VARIANT& var)
//用VARIANT设置矩阵

{

getVariantSize(m_matrixSize, var);

VariantCopy(&m_varMatrix,
(VARIANT*)&var);

}

// 功能:设置矩阵的所有元素为一维数组或二维数组的内容

// 输入:nRows, 矩阵的行数; nCols,矩阵的列数

// 输出:无

// 影响:matrix为空,只是定义了大小,必须之后再调用setData()

// 注意:这里用一维数组构造时,形参的格式必须按照列优先的顺序构造。

// 作者:张坤

// 时间:2013.06.06

void matrix::setSize(int nRows, int nCols)
//默认构造后再设置数据

{

m_matrixSize.m_nRows = nRows;

m_matrixSize.m_nCols = nCols;

SAFEARRAYBOUND rgsabound[2]; //2 dim array
二维数组的标识

rgsabound[0].lLbound =
0;
//初始下标从0开始

rgsabound[0].cElements =
m_matrixSize.m_nRows; //1st dim size 第一维的大小

rgsabound[1].lLbound =
0;
//初始下标从0开始

rgsabound[1].cElements =
m_matrixSize.m_nCols; //2nd dim size 第二维的大小

m_varMatrix.vt =
VT_R8|VT_ARRAY;
//double型的二维数组类型的声明

m_varMatrix.parray = SafeArrayCreate(VT_R8, 2,
rgsabound); //double型的二维数组数据的声明

//初始化为全0

double* pdBuf = NULL;
//指针用来指向m_varMatrix.parray的数据区

::SafeArrayAccessData(m_varMatrix.parray, (void
**)&pdBuf);

memset((void*)pdBuf, 0,
m_matrixSize.m_nRows*m_matrixSize.m_nCols*sizeof(double));
//直接设置数据区为全0,也可用循环实现

::SafeArrayUnaccessData(m_varMatrix.parray);

}

// 功能:设置矩阵的所有元素为一维数组或二维数组的内容

// 输入:pdArray一维数组或二维数组强制转换的结果,

// arrType,一维数组或二维数组的标识

// 输出:无

// 影响:matrix所有元素设置为一维数组或二维数组的内容

// 注意:这里用一维数组构造时,形参的格式必须按照列优先的顺序构造。

// 作者:张坤

// 时间:2013.06.06

void matrix::setData(double* pdArray, ArrayType
arrType) //默认构造后再设置数据

{

double* pdBuf = NULL;
//指针用来指向m_varMatrix.parray的数据区

::SafeArrayAccessData(m_varMatrix.parray, (void
**)&pdBuf);

if (arrType ==
Dim1) //这里一定要注意pdArray
是存储矩阵元素的一维数组,其排列顺序必须是列优先的。

{

memcpy((void*)pdBuf, pdArray,
m_matrixSize.m_nRows*m_matrixSize.m_nCols*sizeof(double));
//直接赋值pdArray指向的数据区

}

else // arrType == Dim2

{

//由于C++二维数组是按行优先顺序来存储的,所以需要转置为列优先的顺序。

transpose(m_matrixSize.m_nRows,
m_matrixSize.m_nCols, pdArray, pdBuf);

}

::SafeArrayUnaccessData(m_varMatrix.parray);

}

// 功能:获得矩阵的数据, 返回值矩阵可以为一维数组或二维数组

// 输入:pdArray一维数组或二维数组强制转换的结果,

// arrType,一维数组或二维数组的标识

// 输出:无

// 影响:无

// 注意:这里用一维数组构造时,形参的格式是按照列优先的顺序排列的。

// 作者:张坤

// 时间:2013.06.07

void matrix::getData(double* pdArray, ArrayType
arrType) //获得矩阵的数据

{

getSize(); //获取数组的大小

if (m_varMatrix.vt == VT_R8)
//特殊情况,标量值,不是VT_R8|VT_ARRAY

{

pdArray[0] =
m_varMatrix.dblVal;

return;

} //特殊情况处理结束

double* pdBuf = NULL;

::SafeArrayAccessData(m_varMatrix.parray, (void
**)&pdBuf);

if (arrType == Dim1)

{

memcpy(pdArray, pdBuf,
m_matrixSize.m_nRows*m_matrixSize.m_nCols*sizeof(double));

}

else //arrType == Dim2

{
//从列优先的存储转换为行优先的存储

transpose(m_matrixSize.m_nCols,
m_matrixSize.m_nRows, pdBuf, pdArray);

}

::SafeArrayUnaccessData(m_varMatrix.parray);

}

// 功能:获得矩阵的维数

// 输入:pdArray一维数组或二维数组强制转换的结果,

// arrType,一维数组或二维数组的标识

// 输出:无

// 影响:无

// 注意:这里用一维数组构造时,形参的格式是按照列优先的顺序排列的。

// 作者:张坤

// 时间:2013.06.07

matrix::Size matrix::getSize()

{

//若还未获取作为返回值的matrix封装的m_varMatrix的大小,获取之

if (m_matrixSize.m_nRows == 0 ||
m_matrixSize.m_nCols == 0)

{

getVariantSize(m_matrixSize,
m_varMatrix);

}

//已经获取作为返回值的matrix封装的m_varMatrix的大小,或者是作为输入变量的matrix。

//直接返回m_matrixSize

return m_matrixSize;

}

// 功能:将nRow行、nCols列的pdin矩阵转置成pdout矩阵

// 输入:pdin待转置的矩阵,nRows、nCols为pdin的行数和列数

// pdout为转置的结果,
pdout为nCols行、nRows列.

// 输出:无

// 影响:无

// 注意:该函数可以实现行优先与列优先访问时的数据变换,在getData,setData

// 和构造函数中使用。

// 作者:张坤

// 时间:2013.06.11

void matrix::transpose(int nRows, int nCols, double* pdin,
double* pdout)

{

for (int i = 0; i < nRows;
++i) //第i行

{

for (int j = 0; j
< nCols; ++j)//第j列

{

pdout[j*nRows
+ i] = pdin[i*nCols + j];

}

}

}



本文是作者原创,转载必须保证文章的完整性并标明出处(blog.sina.com.cn/zhangkunhn),请尊重作者,支持原创。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: