代码图元反向引用支持

初一听,这个词,还不知道是怎么回事,且听我慢慢道来。
所有的一切的一切,都是由需求引起的。
所谓代码图元,就是不用鼠标画,而是用编写代码直接画出图,这样,图的效果可达到绝美的境界。
下面是一些系统中已支持例子,可简单设置各元件对象的颜色达到各种效果。
已有效果
其中,圆柱体代码为
PenData.Style  =   5 ;                     //  无画笔
BrushData.BrushStyle  =   1 ;              //  渐变效果
BrushData.Color1  =  Color1;             //  渐变起始颜色
BrushData.Color2  =  Color2;             //  渐变结束色
Rectangle( - a,  0 , a, h);                   //  画出矩形
Ellipse( 0 , h, a, b);                      //  画出底部椭圆
BrushData.BackgroundStyle  =   2 ;          //  渐变底纹效果
BrushData.GradientIndex  =   1 ;            //  渐变变形效果
Ellipse( 0 0 , a, b);                      //  画出顶部椭圆
 
长方体代码为
PenData.Style  =   5 ;                  //  无画笔
double  x[ 4 ],y[ 4 ];                 //  4个坐标点分量
double  sqrt3  =   0.866 ;             //  其实是sqrt(3) / 2
BrushData.BrushStyle  =   1 ;          //  渐变效果
BrushData.Color1  =  Color1;          //  渐变起始颜色
BrushData.Color2  =  Color2;          //  渐变结束色
BrushData.BackgroundStyle  =   3 ;      //  渐变底纹效果:副对角线
BrushData.GradientIndex  =   1 ;     //  渐变变形效果
x[ 0 =   0 ; y[ 0 =   0 ; x[ 1 =  a; y[ 1 =   0 ; x[ 2 =  a; y[ 2 =  h; x[ 3 =   0 ; y[ 3 =  h; 
Polygon(x, y, 
4 );                 //  画出正面矩形
BrushData.BackgroundStyle  =   1 ;      //  渐变底纹效果:水平
BrushData.GradientIndex  =   0 ;      //  渐变变形效果
x[ 0 =  a  +  b  /   2 ; y[ 0 =   -  sqrt3  *  b;   x[ 3 =  a  +  b  /   2 ; y[ 3 =  h  -  sqrt3  *  b;
Polygon(x, y, 
4 );                 //  画出侧面矩形
BrushData.BackgroundStyle  =   0 ;      //  渐变底纹效果:垂直
BrushData.Degree  =   10 ;             //  旋转画刷10度
x[ 2 =   0 ; y[ 2 =   0 ; x[ 3 =  b  /   2 ; y[ 3 =   -  sqrt3  *  b;
Polygon(x, y, 
4 );                 //  画出顶面矩形
 
椭球代码为
PenData.Style  =   5 ;                  //  无线条颜色
BrushData.BrushStyle  =   1 ;          //  渐变效果
BrushData.Color1  =  Color1;          //  渐变起始颜色
BrushData.Color2  =  Color2;          //  渐变结束色
BrushData.BackgroundStyle  =   2 ;      //  底纹样式: 对角线
BrushData.GradientIndex  =   1 ;     //  渐变变形效果
BrushData.Degree  =   - 10 ;             //  旋转画刷-10度
Ellipse( 0 0 , a, b);                 //  画出椭圆
PenData.Style  =   2 ;                  //  画笔为虚线
PenData.Color  =  Color1;             //  画笔颜色
Ellipse( 0 0 , a, b  /   5 )             //  画出小椭圆
 
各代码可以在库文件CodeObject.lib中看到。
具体的代码含义及效果设置代码请参阅我写的组态说明书,说明书在 www.drgraph.com可以下载,当然,可能最新的技术还没有更新,不过,大体如此。
现在,系统已能支持相当多的组态效果了,但更进一步,新的需求又来了,如下面的效果。
更深层次的组态要求
 
第一个是个碗,碗口简单,用一个椭圆即可画出,剩下的呢?
第二个是一个锥体,底部亦可用一个椭圆画出,锥体呢?
当然,这些效果可以通过区域处理的方式来实现,但让用户操作起来将很是不便。
为此,我计划将借鉴正则表达式中的反向引用技术来完成这项工作,即用户可以让程序记下刚画的图,如上面所说的椭圆,然后,取出该图的边界上的一些点,附加上其余的点,构成一个多边形的点,最后,画出这个多边形即可。
这种思路好象可行。
1.       首先,设计数据类型BackReference,其中向量类型设计为MetaType
头文件代码
class  TCbwMetaType :  public  TObject
{
   TFloatPoint CentralPoint;
   
int Type;
   TPoint 
* Points;
   
int Number;
public:
   __fastcall TCbwMetaType(
int t, TPoint * p, int n);
   __fastcall 
~TCbwMetaType();
}
;

class  TCbwBackReference :  public  TObject
{
   vector
<TCbwMetaType *> FObjects;
   
void __fastcall Clear();   

   
bool FRecord;
public:
   __fastcall TCbwBackReference() 
{}
   __fastcall 
~TCbwBackReference()  {  Clear(); }
   
void __fastcall Add(int type, TPoint * DrawPoints, int PointNumber);
__published:
    __property 
bool Record = { read = FRecord, write = FRecord };
}

源文件代码:

__fastcall TCbwMetaType::TCbwMetaType( int  t, TPoint  *  p,  int  n)
{
   Type 
= t;
   Points 
= new TPoint[n];
   
for(int i = 0; i < n; ++i)
      Points[i] 
= p[i];
}


__fastcall TCbwMetaType::
~ TCbwMetaType()
{
   delete [] Points;
}


void  __fastcall TCbwBackReference::Clear()
{
   FlushVector(FObjects, 
true);
}


void  __fastcall TCbwBackReference::Add( int  type, TPoint  *  DrawPoints,  int  PointNumber)
{
   TCbwMetaType 
* object = new TCbwMetaType(type, DrawPoints, PointNumber);
   FObjects.push_back(
object);
}

 

2.       下来就应该在代码图元中加上相应支持了,简单声明发布属性TCbwBackReference * BackReference即可。然后在画图过程中进行处理
void  __fastcall TCbwCodeObject::GdiDraw(CbwDrawType type,  bool  reloadGdiFlag)
{
   
if(FBackReference->Record)
      FBackReference
->Add(type, DrawPoints, PointNumber);
   inherited::GdiDraw(type, reloadGdiFlag);
}
 
则,记录过程完成。
3.       剩下的就应该获取期望的点数了,怎么调用呢?设计一个系统函数支持,即
void GetPoints(int index, int beginTheta, int endTheta, double x[], double y[], int startIndex);
该函数中的各参数含义:
index: 反向引用下标值,自0开始,即取得对应的画法
beginTheta, endTheta: 即自对应画法的中心点,按角度取得边界的范围
x[], y[]:取得点的保存目标处
startIndex: x[], y[]的保存起始下标
该函数的含义是应该清楚了吧,可能说得不是很清楚,待后续具体示例进行说明。
比如,要画出上面的锥体,可写代码先画出
PenData.Style  =   5 ;                     //  无画笔
BrushData.BrushStyle  =   1 ;              //  渐变效果
BrushData.Color1  =   0x4080ff ;           //  渐变起始颜色
BrushData.Color2  =  clWhite;            //  渐变结束色
BrushData.BackgroundStyle  =   2 ;            //  底纹样式: 对角线
BrushData.GradientIndex  =   0 ;           //  渐变变形效果
BackReference.Record  =   true ;
Ellipse(
0 0 80 30 );                   //  画出椭圆
BackReference.Record  =   false ;
 
其运行效果为
简单效果
OK ,现在加入取点函数
PenData.Style  =   5 ;                     //  无画笔
BrushData.BrushStyle  =   1 ;              //  渐变效果
BrushData.Color1  =   0x4080ff ;           //  渐变起始颜色
BrushData.Color2  =  clWhite;            //  渐变结束色
BrushData.BackgroundStyle  =   2 ;            //  底纹样式: 对角线
BrushData.GradientIndex  =   0 ;           //  渐变变形效果
BackReference.Record  =   true ;
Ellipse(
0 0 80 30 );                   //  画出椭圆
double  x[ 181 ], y[ 181 ];
GetPoints(
0 0 180 , x, y,  0 );             //  取点函数,取得上面椭圆0~180度的点
BackReference.Record  =   false ;
 
为支持这些用法,还得一步步解决。
4.       首先得在编译处理时取得这些参数,这个简单
int  backReferenceIndex  =  AnsiString(function -> Realize -> Parameters[index ++ ] -> Variable -> Value).ToInt();
int  startTheta  =  AnsiString(function -> Realize -> Parameters[index ++ ] -> Variable -> Value).ToInt();
int  endTheta  =  AnsiString(function -> Realize -> Parameters[index ++ ] -> Variable -> Value).ToInt();
TSentence_Declare_Variable 
*  xValues  =  function -> Realize -> Parameters[index ++ ];
TSentence_Declare_Variable 
*  yValues  =  function -> Realize -> Parameters[index ++ ];
int  startIndex  =  AnsiString(function -> Realize -> Parameters[index ++ ] -> Variable -> Value).ToInt();

然后调用函数

FBackReference->GetPoints(index, startTheta, endTheta, xValues, yValues, startIndex);

需要在反向引用类中支持又得需要在模型类中处理 

void  __fastcall GetPoints( int  index,  int  beginTheta,  int  endTheta,
      TSentence_Declare_Variable 
*  x,
      TSentence_Declare_Variable 
*  y,
      
int  startIndex);

其实现源代码

void  __fastcall TCbwBackReference::GetPoints(
      
int  index,
      
int  beginTheta,
      
int  endTheta,
      TSentence_Declare_Variable 
*  x,
      TSentence_Declare_Variable 
*  y,
      
int  startIndex)
{
   
if(index >= 0 && index < FObjects.size())
   
{
      TCbwMetaType 
* object = FObjects[index];
      
for(int i = beginTheta; i <= endTheta; ++i)
      
{
         TPoint p 
= object->GetPointAt(i);
         x
->SetValueAt(i + startIndex, p.x);
         y
->SetValueAt(i + startIndex, p.y);
      }

   }

}

 

TPoint __fastcall GetPointAt( int  index);
TPoint __fastcall TCbwMetaType::GetPointAt(
int  index)
{
   …
}

5.       到此,只剩下数学问题了,即已知一个函数,求其与一条射线的交点。

函数为记录下的画法函数,以椭圆为例,椭圆的画法函数为
Ellipse(x0, y0, a, b)
其中,(x0,y0)为中心点坐标,a,b分别为长短半轴
其对应的数学函数为(x-x0)^2/a^2 + (y-y0)^2/b^2 = 0
射线为由x0, y0出发,角度为theta的射线,好象该用什么点斜式,赶快查书。稍等。
《数学实用手册》确实是一本好书,一查就查到,倾角为theta,则斜率为tg(theta),在计算机里面该表示为tan(theta),则射线方程为y-y0=tan(theta)(x-x0)
这两个方程联立求解,其实需要先将射线方程代入数学函数中
得x = x0±sqrt((ab)^2/(b^2 + (a tan(theta))^2),根据theta确定正负号
再求得y = y0 ± sqrt((ab)^2/(b^2 + (a tan(theta))^2)tan(theta)
则实现椭圆版的求解代码为
TPoint __fastcall TCbwMetaType::GetPointAt( int  theta)
{
   
while(theta < 0)  theta += 360;
   
while(theta >= 360) theta -= 360;
   
bool negativeFlag = (theta > 90 && theta < 270);

   
double x0 = Points[0].x, y0 = Points[0].y;
   
double a = Points[1].x, b = Points[1].y;
   
double k = tan(theta * PI / 180.0);
   
double v = sqrt( a*a*b*/ (b*+ a*a*k*k));
   
double x = x0 + v;
   
if(negativeFlag)
      x 
= x0 - v;
   v 
*= k;
   
double y = y0 - v;
   
if(negativeFlag)
      y 
= y0 + v;
   
return TPoint(x, y);
}

现在,试试画出效果 

运行,看下结果
锥体
 
OK,目标实现,剩下的事就是调一下画刷填充效果。
顺带把上面的碗也画出来
代码
PenData.Style  =   5 //  无画笔
BrushData.BrushStyle  =   1 //  渐变效果
BrushData.Color1  =   0x4080ff //  渐变起始颜色
BrushData.Color2  =  clWhite;  //  渐变结束色
BrushData.BackgroundStyle  =   2 //  底纹样式: 对角线
BrushData.GradientIndex  =   0 ;      //  渐变变形效果
BackReference.Record  =   true ;
Ellipse(
0 0 80 30 );  //  画出椭圆
double  x[ 381 ], y[ 381 ];
GetPoints(
0 180 0 , x, y,  0 );  //  取点函数,取得上面椭圆0~180度的点
Arc( 0 20 80 80 - 10 200 );
GetPoints(
1 - 10 190 , x, y,  180 ); 
Polygon(x, y, 
381 );
BackReference.Record 
=   false ;

碗

效果与示例可到http://www.drgraph.com/viewthread.php?tid=22&extra=page%3D1下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值