找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 819|回复: 0

[ARX程序]:Cool helper classes for ARX part 2: ARX goes STL

[复制链接]

已领礼包: 145个

财富等级: 日进斗金

发表于 2002-2-13 02:46:15 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

  1. Cool helper classes for ARX part 2: ARX goes STL  
  2. ID    1696  
  3. Applies to:    AutoCAD 2000I
  4. AutoCAD 2002
  5. AutoCAD 2000

  6. Date    1/22/2002  

  7. This document is part of    AutoCAD Utilities     


  8. Question
  9. This solution is an extension of the helper classes presented in <Solution 1695>
  10. "ACAD: COOL HELPER CLASSES FOR ARX" which is a prerequisite for this solution
  11. and should be looked at first.
  12. Answer
  13. I generalized the template class Apply even more, which now works only with
  14. MSVC 6.0 now, as I'm using template member functions in template classes.)

  15. Up to now (version 1), Apply took a function pointer as an argument for the
  16. constructor. This function pointer had to be a pointer to a function that takes
  17. one argument.

  18. Now (version 2), Apply takes a template parameter as argument for the constructor.
  19. Valid is everything that can be applied a '()' operation on. This CAN be - of
  20. course - a function pointer, like before. But it also can be a class object
  21. of a class with in overloaded '()' operator.

  22. You can do really cool things with it. For example, I wanted to have an apply
  23. function which takes not only one argument, as in ...


  24. Adesk::Boolean applyFunc( AcDbEntity * );

  25. ... but two arguments, as in ...


  26. Adesk::Boolean transform( AcDbEntity *p, const AcGeMatrix3d& m )
  27. {
  28.     p->transformBy( m );
  29.     return Adesk::kTrue;
  30. }

  31. ... because I wanted to apply an user-supplied transformation matrix to each
  32. entity in a block.

  33. Instead of modifying the Apply class (which is what I didn't want to do because
  34. I wanted to keep this class as minimal as possible), you can solve this entirely
  35. by using Template helper classes and -functions.

  36. The name of the first template helper class is '_2', which makes it possible
  37. to apply a function that takes two arguments.

  38. The calling syntax is:


  39. AcGeMatrix3d mat;
  40.      mat.setToTranslation( AcGeVector3d( 5.0, 2.0, 0.0 ) );
  41.      Apply<BlockTableRecord>( pMs, _2( transform, mat ), kForWrite );

  42. Now how does this work?

  43. _2 has a constructor which takes two template arguments. (transform and mat).
  44. The constructor just stores these two objects as data members. Now comes the
  45. trick: _2 has an overloaded '()' operator, which takes one argument; because
  46. this is exactly what apply needs. The operator '()' in turn just calls it's
  47. constructor's argument #1, passing the constructor's argument #2 as an additional
  48. argument to the apply function (argument #1).

  49. Sample code:


  50. _2::_2( T t, S s ) : m_t( t ), m_s( s ) { }

  51. Adesk::Boolean _2::operator () (P* pEnt)
  52. {  return m_t( pEnt, s );  }

  53. That's it. It's really as simple as this. Still reading? :-)

  54. Another neat template helper class is 'If'. The If constructor takes (again)
  55. two arguments: the first one is a filter function, and the second one is the
  56. apply function. The apply function will be called only if a specific object
  57. passes the filter function. If you consider the following filter function:


  58. Adesk::Boolean isAcDbLine( AcDbEntity *pEnt )
  59. {
  60.     return pEnt->isKindOf( AcDbLine::desc() );
  61. }

  62. ... then the calling sequence


  63. Apply<BlockTableRecord>( pMs,
  64. If( isAcDbLine, applyFunc ), kForRead );
  65. ... calls applyFunc() only if the entity is an AcDbLine. The implementation
  66. of If is similar to _2:


  67. If::If( T t, S s ) : m_t( t ), m_s( s ) { }

  68. Adesk::Boolean If::operator () (P* pEnt)
  69. {  return m_s( pEnt ) ? m_t( pEnt ) : Adesk::kTrue;  }

  70. This code above calls the apply function (m_t) only if the object passes the
  71. filter (m_s). This means, the following code:


  72. Apply<BlockTableRecord>( pMs,
  73.          If( isAcDbLine, applyFunc ), kForRead );

  74. ... causes that applyFunc() is called for each Line in the model space. Of course,
  75. you can combine these two classes, as in:


  76. Apply<BlockTableRecord>( pMs,
  77.          If( isAcDbLine, _2( transform, mat ) ), kForWrite );

  78. This applies the transformation matrix 'mat' to each line in model space. But
  79. the first parameter to If (the filter function) is also templatized, so it can
  80. also be a class object instead of a function pointer. Which means: taken the
  81. following filter function (note that this one also takes TWO arguments [you
  82. guess what happens...?]):


  83. Adesk::Boolean hasColor( AcDbEntity *pEnt, int color )
  84. {
  85.     return pEnt->colorIndex() == color;
  86. }

  87. ..., if you use this like the following:


  88. Apply<BlockTableRecord>( pMs,
  89.          If( _2( hasColor, 4 ), _2( transform, mat ) ), kForWrite );

  90. ... causes each entity in model space with the colorIndex of 4 to be translated
  91. by 'mat'. On the other hand,


  92. Apply<BlockTableRecord>( pMs,
  93.          If( _2( hasColor, 6 ), _2( transform, mat2 ) ), kForWrite );

  94. ... will apply the matrix 'mat2' to each entity with the colorIndex of 6.

  95. Is this flexible? Is this cool? Or what?

  96. All this is done by only a few lines of code. Just a few minimal template classes:
  97. Apply, Filter and TwoArgs. It's completely customizable and extendible by users
  98. of these classes. (You can add helpers for functions with three parameters,
  99. and so on.) You can apply every complex operation you want on every object with
  100. every imaginable search-criteria in the database. Needless to say, Apply doesn't
  101. work only with entities, it works also with Dictionaries, and all other symbol tables.

  102. There's really no limit for improvements. Be creative! For example, the function
  103. 'isAcDbLine( AcDbEntity *pEnt )' above can be generalized to 'isKindOf( AcDbObject
  104. *pObj, AcRxClass *desc )', so the term


  105. Apply<BlockTableRecord>( pMs,
  106.      If( isAcDbLine, testFunc1 ), kForRead );

  107. ... can be also be formulated as ...


  108. Apply<BlockTableRecord>( pMs,
  109.      If( _2( isKindOf, AcDbLine::desc() ), testFunc1 ), kForRead );

  110. Or, what about two more classes 'And' and 'Or', which apply the following operation
  111. on their two parameters:


  112. Adesk::Boolean And::operator () ( P* p)
  113.     { return m_t( p ) && m_s( p ); }

  114.     Adesk::Boolean Or::operator () ( P* p)
  115.     { return m_t( p ) || m_s( p ); }

  116. ... so you can use them as boolean operations for the Apply class:


  117. Apply<BlockTableRecord>( pMs,
  118.          If( Or( _2( isKindOf, AcDbLine::desc() ),
  119.              _2( isKindOf, AcDbCircle::desc() ) ),
  120.          _2( transform, mat ) ),
  121.          kForWrite );

  122. This code above will apply the transformation matrix 'mat' to all circles and
  123. lines in the model space, while ...


  124. Apply<BlockTableRecord>( pMs,
  125.          If( And( _2( isColor, 3 ),
  126.               _2( isKindOf, AcDbCircle::desc() ) ),
  127.          _2( transform, mat ) ),
  128.          kForWrite );

  129. ... will apply 'mat' only to all circles with the color 3.

  130. If you're familiar with STL (the Standard Template Library), then the code presented
  131. here will be familiar to you as well: this is *exactly* how STL works. I mean,
  132. applying generic functions to all sort of containers, with all sort of combinations.

  133. Full source code is attached.

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2025-9-5 13:22 , Processed in 0.265536 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表