七月,空白

On 2010年08月8日, in IT生活, 非技术, by antmanler

大项目中期检查还有一个星期就要开始了,实验室里大家都在紧张的准备着。今天打开自己的博客,发现居然没有七月的achieve。

七月,一个美好的月份就这么凭空消失了,至少在这里找不到它的踪迹,这多少然人感到沮丧,于是我开始寻找七月的记忆,在八月八日把他们记录下来,顺便提醒自己不要再错过其他的月份。

1号的下午,坐火车从杭州回北京,那天天气很热,不知是不是杭州用温度极力驱散我们这群过客换得一时清静,反正我是一刻不想在这火炉子里锻炼了。第二天早晨到的北京,正如我车上所想的那样,北方的早晨要凉爽些,我深吸了一口清晨的灰尘奔赴寝室。接下来几天比较清闲,换了个寝室,从18栋换到了6栋,条件也比以前好多了,离着实验室也更近了。那段时原本想上来写篇日志,想大多数人一样抒发下旅途的感想,但苦于不知从何谈起也就搁浅了,后来就一直到今天,如果再然我谈浙江之行的感觉,我已全然谈不出了,仿佛已经融入我的意识,它就在那里。

看上去,七月的开始是清闲的,但这不意味着整个七月就像我一直认为的那样是假期的日子。在一次中期动员后终于进入状态了:每天的作息差不多是9:00到00:00,13号27号分别去了趟西安和上海出差。上海那次是当天去当天回,据说我们的车路过SB园,不过显然那个时候我觉得睡觉比SB更吸引我,毕竟SB天天有。这段时间虽然忙,但忙的很规律,项目在那次动员会过后也神奇的前进了不少,中期在即各种问题似乎也都要解决了。

在做项目时写了一个插件框架,是个个人项目,我叫它Yaps(Yet Another Plugin System),也算是为项目后期个架构做个实验,目前版本已经比较稳定了,之后考虑开源,放出来溜一溜。Yaps是Header File Only的轻量级插件框架,目前就Windows平台上的编译器Msvc6~10、Mingw而言,编译出来的插件是可以公用:创建导出类的对象,以及对象生命周期的维护,基本达到了独立于编译器的目标,下一步准备着移植到linux下,当然,我并没有打算做的如DnyObj那样做到插件的跨平台,只是想在linux下使用而已。

在忙里偷闲的时候把Effective Go看完了,觉得Go的风格正是自己期盼和喜欢的那种,是个神奇的语言,但愿能长久,不要像D那样一闪而过。我也有考虑,用Go写点东西,应该至少要比C++来的快些。此外,编译和尝试了许多library:GLFWSDLJsonCppPyhonQtMyGUICEGUIglvHorde3D。特别值得一提的是Hord3D这个渲染引擎,很小巧,但却号称是下一代渲染引擎;更重要是他的philosophy只作一件事情,它的目标是作为其他项目的组件,你不必为使用Horde3D做其他额外的事情,拿来用就好,这也是我这么些年一直努力去做的事情,所以很有兴致的把它代码拿来读一读,如果拿读书来比喻,刚刚读完了它的序言,不过相比一些巨型项目来说还是读的完的,希望他能有更多引人入胜的情节。

好了,就写到者,去祭下五脏庙去。

Good day.

Tagged with:
 

VTK与Phantom

On 2010年05月12日, in 未分类, by antmanler

今天毕设代码暂时算告一段落了,在上次中期的基础上加入了Phantom desktop的接入,提供触力觉反馈。其中触力觉反馈使用的是OpenHaptic的HDAPI

为了提供Haptic的支持主要解决2个问题

  1. Phantom设备的ServoLoop 1khz的力渲染与VTK15~30帧的图形渲染
  2. Phantom设备坐标系与VTK世界坐标系的匹配

关于问题1有两种解决的方法:

  1. 由于VTK的对象实现了subject/observer的模式,所以可以添加一个observer
  2. 使用Timer每间隔一段时间同步设备状态,渲染图形

由于UI是用QT实现的,所以VTK并不能自己处理重绘事件,所以这里选择了第2种方法,设置timer。在此之前曾尝试使用单独的绘制线程,但是由于VTK和OpenHaptic单独管理各自线程并且机制不同,无法在合适的时间同步设备状态,所以便用timer,这样使得图形渲染在同意线程中执行,也符合逻辑。

关于问题2

通过HDAPI可以获得探针姿态变换矩阵,利用HDU里的

void hduMapWorkspaceModel(const HDdouble *modelMatrix,
                          const HDdouble *projMatrix,
                          HDdouble *wsModelMatrix);

可以获得设备坐标系到世界坐标的变换,唯一要注意的是VTK内部矩阵是左乘,而OpenHaptic和OpenGL一样是右乘。

下面的代码片段描述了获得变换矩阵的方法

// get current render window
vtkRenderer *ren = this->renderer_ ;

// calculate the aspect from render window
double aspect[2];
ren->ComputeAspect();
ren->GetAspect(aspect);

double aspect2[2];
ren->vtkViewport::ComputeAspect();
ren->vtkViewport::GetAspect(aspect2);
double aspectModification = aspect[0]*aspect2[1]/(aspect[1]*aspect2[0]);

// get view port
int viewport[4] ;
ren->GetTiledSizeAndOrigin(
	// width
	viewport + 2,
	// height
	viewport + 3,
	// lower left x
	viewport,
	// lower left y
	viewport+1
) ;

// get the projection matrix
vtkSmartPointer projection = vtkSmartPointer::New();
projection->DeepCopy(this->renderer_->GetActiveCamera()
		->GetProjectionTransformMatrix(
		aspectModification*(viewport[2]/viewport[3]), -1.0, 1.0)) ;
projection->Transpose() ;

// get model view matrix
vtkSmartPointer modelview = vtkSmartPointer::New();
modelview->DeepCopy(this->renderer_->GetActiveCamera() ->GetViewTransformMatrix()) ;
modelview->Transpose() ;

// Compute the transform for going from device coordinates to world
//   coordinates based on the current viewing transforms.
::hduMapWorkspaceModel(modelview->Element[0],
		projection->Element[0], this->workspace_model_) ;

下面的片段描述了如何利用获得的矩阵调整绘制视图中指针的姿态和位置。需要注意的是,变换之后会包换缩放的信息,如果不希望指针被莫名奇妙的缩放的话,需要去除缩放分量,可以使用vtkTransform类完成。

IHapticDevice::IHapticDeviceState *state =
    this->device_in_graphic_->getCurrentState() ;
vtkSmartPointer workspace_model = vtkSmartPointer::New() ;
workspace_model->DeepCopy(state->getParentCumulativeTransform()) ;
workspace_model->Transpose() ;

vtkSmartPointer device_transform = vtkSmartPointer::New() ;
device_transform->DeepCopy(state->getTransform()) ;
device_transform->Transpose() ;

vtkSmartPointer device2view = vtkSmartPointer::New() ;
// set to the post multiply
device2view->PostMultiply() ;

// transform in work space
device2view->Concatenate(device_transform) ;
// transform to VTK view
device2view->Concatenate(workspace_model) ;

// set user transform
this->cursor_->SetPosition(device2view->GetPosition()) ;
this->cursor_->SetOrientation(device2view->GetOrientation()) ;

(完)

毕设中期报告

On 2010年04月29日, in IT生活, by antmanler

做了一个多月的毕业设计,今天实验室例会上给老师做了个报告,同时悲痛的得知这个难得的暑假估计大半时间要贡献给实验室了

今天报告的PPT

视频演示 : 清晰版 (On youtube)

Tagged with:
 

静态方法做为友元的问题

On 2010年04月24日, in IT生活, by antmanler

在C++中一个类的友元函数或者友元类可以实现访问该类私有变量或者方法。但是对于静态方法使用声明友元类的方法却不能如愿,例如:

class Bar ;
class Foo {
public :
    // do some custom initialize
    static Bar *GetBar() { return new Bar() ;}
};

class Bar {
private:
    Bar(){ }
    // friend class Foo ;  will cause the compile error
    friend Bar *Foo::GetBar() ;
} ;

从上面的例子可以进一步理解类的静态成员的含义:属于类的上下文中,而不绑定于特定的对象(即无隐含的this指针)。

Tagged with:
 

关于在C++中使用this指针

On 2010年04月17日, in IT生活, by antmanler

好久没有更新博客了,最近比较忙,头绪也很多。

其实对于this指针的使用,我个人一直是倾向于对于成员函数以及成员变量都明确使用”this”指针。今天在阅读 unladen-swallowStyleGuide 时,项目也明确提出了Always use this的说法,并且用C++ 在名字查找时使用 two phase parse的方法引发的问题,很有针对性的指出了使用this指针的好处。下面直接引用过来,也好提醒自己继续保持这个习惯

[35.19] Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?
Perhaps surprisingly, the following code is not valid C++, even though some compilers accept it:

template<typename T>
class B {
public:
    void f() { }  //member of class B
};
template<typename T>
class D : public B <T> {
public:
    void g() {
        f();  //bad (even though some compilers erroneously (temporarily?) accept it)
    }
};

This might hurt your head; better if you sit down.

Within D::g(), the name f does not depend on template parameter T, so f is known as a nondependent name. On the other hand, B is dependent on template parameter T so B is called a dependent name.

Here’s the rule: the compiler does not look in dependent base classes (like B) when looking up nondependent names (like f).

This doesn’t mean that inheritance doesn’t work. Class D is still derived from class B, the compiler still lets you implicitly do the is-a conversions (e.g., D* to B*), dynamic binding still works when virtual functions are invoked, etc. But there is an issue about how names are looked up.

Workarounds:

Change the call from f() to this->f(). Since this is always implicitly dependent in a template, this->f is dependent and the lookup is therefore deferred until the template is actually instantiated, at which point all base classes are considered.
Insert using B::f; just prior to calling f().
Change the call from f() to B::f(). Note however that this might not give you what you want if f() is virtual, since it inhibits the virtual dispatch mechanism.

同时在9.4.2 Dependent Base Classes一节中也提到过这种dependent和nondependent的规则,其中一句话说到:

Hence, the C++ standard specifies that a nondependent name appearing in a template is looked up as soon as it is encountered.

Tagged with:
 

可以连接在一起的QSplitter

On 2010年03月30日, in IT生活, by antmanler

查了好久没有发现如何用QSplitter实现类似3Ds MAX的十字分割的窗口,于是自己动手从QSplitter继承出一个QConnectedSplitter,效果如图:

将两个QSplitter窗口连接起来,使得操作更像常见的cross window,当双击手柄时可以将连接的分开,就可以自由调整视口大小。

//************************************
// Method:    connectAnotherSplitter
// FullName:  QConnectedSplitter::connectAnotherSplitter
// Access:    public
// Returns:   void
// Qualifier: Make a 2-way connection of splitter
// Parameter: QConnectedSplitter * another
//************************************
void QConnectedSplitter::connectSplitter( QConnectedSplitter *another )
//************************************
// Method:    disconnectFromSplliter
// FullName:  QConnectedSplitter::disconnectFromSplitter
// Access:    public
// Returns:   void
// Qualifier: Disconnect from a bundled QConnectedSplitter
//************************************
void QConnectedSplitter::disconnectAnotherSplitter()

代码下载: QConnectedSplitter src

Tagged with:
 

POJ 3425

On 2009年08月9日, in Blogbus搬家过来, IT生活, by antmanler

心血来潮,在POJ上小试一题,结果不好: AC 224K 16ms…

/*
*@summery: POJ problem id : 3245
*@author: antmanler
*2009.08.09
*/

#include
#include <map>
using namespace std;
typedef map Questions ;

int main() {

  Questions qst ;
  int cnt = 0, total = 0, cans = 0;

  cin >> cnt ;

  for ( int i=0; i < cnt; i++ ){
    int q = -1, a =0 , x = 0 ;     cin >> q >> a >> x ;
    Questions::iterator pos = qst.find(q) ;
    if ( pos == qst.end() && a != 0 ) {
      qst.insert(make_pair(q, a)) ;
    } else {
      cans += a ;
    }
    total += (10 + (a ? (a *(10 + x*20)) : 0)) ;
  }
  total += 10 * cans;
  cout << total << endl ;

  return 0;
}

实在太不满意了,优化了一下,又提交了一次: AC 224K 0ms

*
*@summery: POJ problem id : 3245
*@author: antmanler
*2009.08.09
*/
#include
#include
using namespace std;
typedef set Questions ;
int main() {
  Questions qst ;
  int cnt = 0, total = 0, cans = 0, q = -1, a =0 , x = 0 ;
  cin >> cnt ;
  for ( int i=0; i < cnt; i++ ){ 
    cin >> q >> a >> x ;
    Questions::iterator pos = qst.find(q) ;
    if ( pos == qst.end() && a != 0 ) {
      qst.insert(q) ;
    } else {
      cans += a ;
    }
    switch ( (a<<1)|x ) {
      case 2 : total += 20; break;
      case 3 : total += 40; break;
      default : total += 10;
    }
  }
  total += 10 * cans;
  cout << total << endl ;
  return 0;
}
Tagged with:
 

cpsh – C++ shell

On 2009年08月8日, in Blogbus搬家过来, IT生活, by antmanler

cpsh 是 davber 开发的一个使用C++语言的 shell, 支持交互模式.
项目主页 http://code.google.com/p/cpsh

它的原理主要是利用系统中的C++编译器,将用户写的脚本插入到”代码模板”中编译执行的,作者开发这个的目的博客中如是说:”This tool works with common C++ compilers (such as GCC and VC 7.1) to leverage C++ constructs for scripts. It is simply beyond my grasp that one needs ’special script’ languages, like Perl, in order to do ’small’ tasks.”

正好这几天在看STL,cpsh提供的交互式执行环境可以方便的测试stl中的各种容器和算法,不过作者说不支持Linux,只有xcode和vs的工程文件,也没提供makefile,于是乎我用scons简单写了个脚本,编译了一番,果然有问题.
不够问题不严重,改了点源代码,就修复了,在Kubuntu下一切正常,只是启用boost支持时编译速度会很慢,这也情理之中.

好了,无图无真想
看看执行结果:

下一步工作:
觉得作者的想法很有意思,他并没有真正实现c++语法的脚本.发现作者两年没更新了,估计是不开发了,有点小bug还得咱自己修,另外他不支持添加新的头文件,内置支持的是stl和boost,所以改进之.
[8.10 更新] 修复了在Linux下的大部分bug,剩下的是我没发现的,加入了动态添加头文件的特性.在linux下编译时需要scons(或者你自己再写个makefile也行)
[源代码下载]
编译: scons
运行: ./cpsh -i
有图有真相2:

类似的项目:
CINT : 真正的c interpeter

 

 

Tagged with:
 

由于系统限制,代码贴不完整,需要请与我联系

PS:这几天抽空做一个写一个(linux读管道,从arp或者ifconfig匹配字符串等有2种方法,Windows下至少有4种方法,netbios, snmp, getmac, ipconfig, uuid, VBscript, JavaScript)所以比较乱,等都搞好了,再好好整理。
获取MAC地址有很多方法,总体都比较容易,今天抽了半个小时,先在Linux下实验了一下,其实方法很简单,就是通过ioctl从一个可用的socket中查询MAC地址就可以了。ioctl是设备驱动程序中对设备的I/O通道进行管理的函数, 是一个十分强大的函数,在linux下用gethostbyname获得不了本地的ip(返回是回环lo的地址)也可以用ioctl查询eth0,wlan0的ip(如果激活的话)
具体实现:
#include

#include
#include
#include
#include
#include
int
get_mac(unsigned char *mac, const char *ifname ){
/*
* This routine executes only in *nix, which support the “ioctl”
* mac : return the mac address of the device specified by ifname
* ifname : specify which device is to retrieve ( ect. eth0, wlan0 )
* Return :
* if succeed return 0, self nonzero is returned
* Author : Ant-man (Bin Zhao)
* */
int i = 0 ;

struct ifreq ifr ;
int sock_no ;
if ( (sock_no = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror(“error occurs when creating socket”) ;
return 2 ;
}
strcpy(ifr.ifr_name, ifname) ;
if (ioctl(sock_no, SIOCGIFHWADDR, &ifr, sizeof(ifr) ) < 0) {
perror(“error occurs when query the mac address”) ;
return 3 ;
}
close(sock_no) ;
for(; i<6; i++ ) {
sprintf( mac+2*i, “%02x”, (unsigned char)ifr.ifr_hwaddr.sa_data) ;
}
return 0 ;
}
------------------------------------------
在Python中更直接一点,虽然方法都一样
#!/usr/bin/python
import sys
import socket
import fcntl
import struct
def get_hw_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
info = fcntl.ioctl(s.fileno(), 0×8927, struct.pack(’16s16s’, ifname, ”))
hwaddr = []
s.close()
ignore1, ignore2, addr_high, addr_low = struct.unpack(‘>16sHHL8x’, info)
addr = (long(addr_high)<<32) + addr_low
b0 = addr & 0xFF
b1 = (addr >> 8) & 0xFF
b2 = (addr >> 16) & 0xFF
b3 = (addr >> 24) & 0xFF
b4 = (addr >> 32) & 0xFF
b5 = (addr >> 40) & 0xFF
return “%02X:%02X:%02X:%02X:%02X:%02X” % (b5, b4, b3, b2, b1, b0)
if __name__ == ‘__main__’ :
print get_hw_address( sys.argv[1] )

====================================================================================================
Windows中的方法已经说了有很多了
1 一种是通过外部调用getmac或者ipconfig来获得MAC地址,步骤如下:
首先CreateProcess一个进程(getmac或ipconfig),并且重定向其标准输出设备句柄(设置进程启动信息实现)
之后读入进程的输出信息,过滤字符串获得MAC地址。这种方法比较可靠(只要没人BT的把getmac和ipconfig和谐掉)
2 还有一种方法是COM组件产生UUID时(准确说是UUID1)会使用MAC地址,此方法也可以获得MAC地址
3 如果操作系统是Windows2000即以上,还可以使用SendARP来得到MAC地址。
===================================================================================================
4 另外可以通过调用NetBios的API获得系统MAC地址,缺点是系统要安装相应协议, 而且当网线被拔掉之后无法获得正确的MAC地址,所以不是很通用。
====================================================================================================
5 对于98-Vista以及NT SP4的系统如果只有TCP/IP协议,可以使用IP Helper API的方法,并且这个方法比较简单 :
IP Helper :The Internet Protocol Helper (IP Helper) API enables the retrieval andmodification of network configuration settings for the local computer.
The IP Helper API is applicable in any computing environment whereprogrammatically manipulating TCP/IP configuration is useful. Typicalapplications include IP routing protocols and Simple Network ManagementProtocol (SNMP) agents
GetAdaptersAddresses Function :The GetAdaptersAddresses function retrieves the addresses associated with the adapters on the local computer.ULONG WINAPI GetAdaptersAddresses(
__in ULONG Family,
__in ULONG Flags,
__in PVOID Reserved,
__inout PIP_ADAPTER_ADDRESSES AdapterAddresses,
__inout PULONG SizePointer
);
但是对于98的SDK还是使用的GetAdaptersInfo,所以为了兼容,还是选择GetAdaptersInfo实现
具体实现:

#include
#include
#include
#include
#include
int
get_mac(char *mac, const char *ifname )
{
PIP_ADAPTER_INFO pAdapterInfo;
PIP_ADAPTER_INFO pCurrAddresses = NULL;
pAdapterInfo=(IP_ADAPTER_INFO*)malloc(sizeof(IP_ADAPTER_INFO));
ULONG bufsize = sizeof(IP_ADAPTER_INFO);
/*save device type and number*/
char dname[32] ;
int type = 6 ;
int no = 0 ;
int count = 0 ;
/*Make an initial call to GetAdaptersAddresses to get the
*size needed into the outBufLen variable*/
if(GetAdaptersInfo(pAdapterInfo,&bufsize)!=ERROR_SUCCESS) {
free(pAdapterInfo);
pAdapterInfo=(IP_ADAPTER_INFO*)malloc(bufsize);
}
/* Make a second call to GetAdapters Addresses to get the
* actual data we want*/
if(GetAdaptersInfo(pAdapterInfo,&bufsize)==NO_ERROR) {
/*parse device type and no*/
strcpy(dname, ifname) ;
/*get number of get device*/
count = strlen(dname) ;
no = dname – ‘0′ ;
dname = ‘\0′ ;
/*get device type*/
if ( strcmp( dname, “eth” ) == 0 ) {
type = 6 ;
} else if ( strcmp( dname, “wlan”) == 0 ) {
type = 71 ;
}
count = 0 ;
pCurrAddresses = pAdapterInfo;
while (pCurrAddresses) {
if( pCurrAddresses->Type == type ) {
if ( no == count++ ) {
for(count = 0; count <6; count++ ) {
sprintf( mac+3*count, “%02x%c”, (unsigned char)pCurrAddresses->Address, count == 5 ? ‘\0′ : ‘:’) ;
}
free(pAdapterInfo) ;
return 0 ;
}
}
pCurrAddresses = pCurrAddresses->Next;
}
free(pAdapterInfo) ;
return -1 ;
}
free(pAdapterInfo) ;
return -2;
}

====================================================================================================
6 使用VBScript或者JavaScript + WMI,只有记事本就可以通过程序获得本机的Mac地址
具体实现:
随便在哪里建立一个文本文件,扩展名改成vbs,写入以下内容, 保存,之后双击那个文件,OK,you get it
————————————————————————————–
Set wmi = GetObject(“winmgmts://./root/cimv2″)
Set adapters = wmi.ExecQuery (“Select * from Win32_NetworkAdapterConfiguration where IPEnabled=TRUE”)
MacAdd = “”
LastGet = “” Rem : may get the same address more than once
For Each IP In adapters
If Not IsNull(IP.IPAddress) Then
For I = LBound(IP.IPAddress) To UBound(IP.IPAddress)
If LastGet <> IP.Macaddress(I) Then
MacAdd = MacAdd & Chr(10) & IP.Macaddress(I)
LastGet = IP.Macaddress(I)
End If
Next
End If
Next
If MacAdd<> “” Then
MsgBox( “Your MAC address is :”&MacAdd)
Else
MsgBox( “Can not find your MAC address”)
End If
—————————————————————————————————-
其实这个主要是利用了 WMI(Windows管理规范:Windows Management Instrumentation, 它是Windows标准的系统管理接口,通过它提供的类SQL查询语言,可以很方便的获得系统的一些信息。比如网络适配器的信息:”Win32 classes, such as Win32_NetworkAdapter or Win32_Process, monitor and manage system hardware and features. Generally, these classes are located in the rootcimv2 WMI namespace. The following table lists the Win32 class categories.”
具体的大家可以看下:http://msdn.microsoft.com/en-us/library/aa394582.aspx
上面的代码加入了些出错机制,所以使用了19行之多,主要防止重复的获得MAC地址,其实还可以再短些:
Set wmi = GetObject(“winmgmts://./root/cimv2″)
Set adapters = wmi.ExecQuery(“Select * from Win32_NetworkAdapterConfiguration where IPEnabled=TRUE”)
For Each IP In adapters
MsgBox( “Your MAC address is :”& IP.Macaddress(0))
Next
====================================================================================================
7 其实用批处理也可以

Tagged with: