利用c++实现数值坐标刻度生成,并利用GDI绘制

给定两个数值如(3001,5020),如何做到均匀地标注刻度?

研究matlab图形刻度会发现,在matlab中,图像无论如何缩放,坐标刻度间隔都是以1,2,5为基数,按照10倍或者0.1倍的幂进行放大或缩小也即,刻度间隔为:

…0.1  0.2  0.5 ; 1 2  5;  10 20  50;  100 200  500;  1000 2000  5000….

负刻度也类似:

…-0.1  -0.2  -0.5 ; -1 -2  -5;  -10  -20  -50;  -100  -200  -500;  -1000  -2000  -5000….


在matlab图像放大中,还会发现,坐标轴刻度个数都在4个到10个之间。当数值超过1000或小于0.001,则会采用科学计数法。  

从上面的刻度看,无论正刻度还是负刻度,相邻刻度最大倍数为2.5。如果把绘制的刻度最小个数控制为4,则最大个数为4*2.5=10;这即是为什么matlab绘制的刻度个数为什么不会超出4个到10个这个范围。

根据上面的分析,回到最初的问题,如何计算(3001,5020)均匀刻度,让刻度符合matlab的刻度规律。

首先确定寻找的刻度范围,限制最小刻度数4个,则最大刻度数为10个:

(5020-3001)/4=504.75

(5020-3001)/10=201.9

因而,201.9-504.75之间只有500这个刻度值符合matlab规律。下面是C++编程实现的刻度生成器CLabelGenerator类

LabelGenerator.h:

#ifndef _LABELGENERATOR_H
#define _LABELGENERATOR_H
#pragma once

class CLabelGenerator
{
public:
    CLabelGenerator(void);
    ~CLabelGenerator(void);
	bool GenerateLabel(float x1,float x2,int minlabelnum,int &reallabelnum,float *&label,CStringArray &labelArr,int &order,int _interal=0,int limitorder=3);     // 产生坐标刻度
    CString StringCutZeros(CString str);   //  对标注字符串进行去零处理
};
#endif

LabelGenerator.cpp:

//****************************     LabelGenerator.cpp     *****************************
// 包含功能:坐标刻度生成
//
// 作者:    jiangjp2812   1034378054@qq.com
// 单位:    中国地质大学(武汉)
// 日期:    2016/10/01
//*************************************************************************************

#include "StdAfx.h"
#include "LabelGenerator.h"
#include "math.h"

CLabelGenerator::CLabelGenerator(void)
{
}


CLabelGenerator::~CLabelGenerator(void)
{
}

bool CLabelGenerator::GenerateLabel(float x1,float x2,int minlabelnum,int &reallabelnum,
                  float *&label,CStringArray &labelArr,int &order,int _interal,int limitorder) 
                  //  生成坐标刻度
                  //  x1,x2 :需要计算刻度的数值范围,minlabelnum:最小刻度数目。reallabelnum:得到的刻度个数。
                  //  label:刻度的数值位置。labelArr:刻度字符串。order:刻度数值采用科学计数法的阶次
                  //  _interal:指定刻度间隔,默认采用计算值。limitorder:超过此阶次采用科学计数,默认为3
{
    labelArr.RemoveAll();
    float labelInterval=0;                         //  标注间隔

    float leftx=(x2-x1)/((float)minlabelnum*2.5);  // 求标注间隔范围  

    if(leftx<0.000001)                             //  刻度产生失败
        return false;

    float rightx=leftx*2.5;

    int kx=0,ky=0;
    float a=0;

    float DOne=0;                         // 1,2,5 不断乘以10判断是否在标注间隔范围内,如果在则终止循环,
    float DTwo=0;
    float DFive=0;
    //----------------- 计算x方向大于1刻度 ----------------------------------------------------------------------
    while(a<=(x2-x1))                     // 如果没有找到合适的标度,当超出最大数也终止
    {
        DOne=1*pow((float)10,(float)kx);  // 1,2,5 不断乘以10判断是否在标注间隔范围内,如果在则终止循环,
        DTwo=2*pow((float)10,(float)kx);
        DFive=5*pow((float)10,(float)kx);
        if( DOne>=leftx  &&  DOne<=rightx)
        {
            labelInterval=DOne;
            break;
        }
        if(DTwo>=leftx && DTwo<=rightx)
        {
            labelInterval=DTwo;
            break;
        }
        if(DFive>=leftx && DFive<=rightx)
        {
            labelInterval=DFive;
            break;
        }
        kx++;
        a=DFive;                          // 每循环一次是1,2,5同时按倍数扩大,即判断的数扩大到a=DOne
    }
    //-----------  x方向如果没有大于1刻度则计算小于1刻度 --------------------------------------
    kx=0;
    a=1;
    if(labelInterval==0)
    {
        while(a>0.000001)                 // 如果没有找到合适的标度,当小于最小数也终止
        {
            DOne=1*pow((float)0.1,(float)kx);  // 1,2,5 不断乘以0.1判断是否在标注间隔范围内,如果在则终止循环,
            DTwo=2*pow((float)0.1,(float)kx);
            DFive=5*pow((float)0.1,(float)kx);
            if( DOne>=leftx  &&  DOne<=rightx)
            {
                labelInterval=DOne;
                break;
            }
            if(DTwo>=leftx && DTwo<=rightx)
            {
                labelInterval=DTwo;
                break;
            }
            if(DFive>=leftx && DFive<=rightx)
            {
                labelInterval=DFive;
                break;
            }
            kx++;
            a=DOne;                           // 每循环一次是1,2,5同时按倍数缩小,即判断的数扩大到a=DOne
        }	
    }
    //-----------------------------------------------------------------------------------
    if(labelInterval==0 ) return false;
    if(_interal!=0) labelInterval=_interal;  // 如果指定间隔,则使用指定的间隔

    float startx,endx;
    float temstartx/*,temendx*/;

    temstartx=x1/labelInterval-(int)(x1/labelInterval);
    if(temstartx==0)                //  如果x1正好位于刻度上,则其实点从x1开始
    {
        startx=labelInterval*(int)(x1/labelInterval);
    }
    else                            //  如果x1不位于刻度上,则起始点从x1之后某点开始
    {
        if(x1>=0)
            startx=labelInterval*((int)(x1/labelInterval)+1);
        else
            startx=labelInterval*((int)(x1/labelInterval)-1+1);    //  当出现负数时,取整向0靠拢,正半轴需加1,负半轴不需要
    }
    if(x2>=0)
        endx=labelInterval*(int)(x2/labelInterval);
    else 
        endx=labelInterval*((int)(x2/labelInterval)-1);            //  当出现负数时,取整向0靠拢,正半轴需加1,负半轴不需要

    reallabelnum=(endx-startx)/labelInterval+0.5+1; //  真实需要绘制的坐标刻度个数
    //  此处(endx-startx)/labelInterval计算得到的数值应为整数,但浮点型计算得不到精确值
    //  会略小于理论整数,因此需要加上0.5后再取整

    label=new float[reallabelnum];                  //  开辟坐标位置容器

    int valueorder=0,intervalorder=0;               //  采用科学计数法进行刻度标注,绝对值最大值阶数,标注间隔值阶数
     float loop=abs(endx);


    float valueabs=abs(startx)>abs(endx) ? abs(startx) : abs(endx) ;    //  获取最大值,求取阶数


    int limitvmax=pow(10.0,limitorder);
    float limitvmin=pow(10.0,limitorder*-1);
    if(valueabs>=limitvmax)                             //  求取最大刻度值大于1000的阶次,正阶
    {
        while(loop>=10)
        {
            loop=loop/10;
            valueorder++;
        }
    }else if(valueabs<=limitvmin)                      //  求取最大刻度值小于0.001的阶次,负阶
    {
        while(loop<=1) //0.1
        {
            loop=loop*10;
            valueorder++;
        }
    }
    for(int i=0;i<reallabelnum;i++)
    {
        label[i]=startx+i*labelInterval;
        CString str;
        if(valueorder==0)                         //  如果绝对值最大值阶次为0,则直接将坐标值输出字符串
        {
            str.Format(_T("%.4f"),label[i]);
        }
        else if(valueabs>=limitvmax)                   //  如果绝对值最大值阶次大于3,则除以对应阶数量级
        {
            str.Format(_T("%.4f"),label[i]/pow(10.0,valueorder));
        }
        else if(valueabs<=limitvmin)                  //  如果绝对值最大值阶次小于-3,则除以对应阶数量级
        {
            str.Format(_T("%.4f"),label[i]*pow(10.0,valueorder));
        }

        str=StringCutZeros(str);                  //  对标注字符串进行尾部去零
        labelArr.Add(str);
    }

    if(valueorder==0)  order=0;                   //  输出阶次
    if(endx>=limitvmax)  order=valueorder;
    if(endx<=limitvmin) order=-valueorder;

    return true;
}

CString CLabelGenerator::StringCutZeros(CString str)
        //  对标注字符串进行去零处理
{
    CString FinalStr;        
    FinalStr.Empty();
    int Length=str.GetLength();             // 字符串长度
    int pos=0;
    bool IsDot=false;
    for(int i=0;i<Length;i++)
    {
        if(str.GetAt(Length-1-i)=='0')      // 反向查找‘0’字符点位,直到找到非‘0’或‘.’点位
        {
            pos++;
        }
        else if(str.GetAt(Length-1-i)=='.') // 反向查找‘.’字符点位,如果出现直接终止
        {
            IsDot=true; break;
        }
        else                                //  只要出现非'0'字符点,直接终止
            break;
    }
    if(pos>0)
    {
        if(IsDot)
            FinalStr=str.Left(Length-1-pos);
        else
            FinalStr=str.Left(Length-1-(pos-1));
    }

    else
        FinalStr=str;

    return FinalStr;
}


类中有两个成员函数

boolGenerateLabel(float x1,float x2,int minlabelnum,int &reallabelnum,float*&label,CStringArray &labelArr,int &order,int _interal=0,intlimitorder=3);     // 产生坐标刻度

CStringStringCutZeros(CString str);   //  对标注字符串进行去零处理

GeneraterLabel函数产生坐标刻度,其中x1,x2是输入的数值,minlabelnum是需要指定的最小刻度个数。如果生成Matlab类似刻度则该数值为4,当然也可以设置其他值。reallabelnum是实际得到刻度个数(注意引用变量,通过引用变量把得到的数据输出),label是该处刻度的数值,labelArr是该处刻度对应的字符串,order是采用科学计数法输出的幂值,_interal是指定刻度值,给定初始值为0,即采用matlab相同刻度。如果不想采用此刻度,可以直接指定_interal值,则会采用指定的刻度生成标注值。Limitorder是指定的科学计数法限制阶数,超过此阶数采用科学计数法。默认为3,即超过1000则采用科学计数法。

StringCutZeros是去除标注字符串尾部的0。因为生成的标注可能尾部有0,如0.3000或1.0。在matlab中就不会出现这样的显示方式。

函数调用:

int xlabelnum;
float *pxlabel;
CStringArray xlabelArr;
int orderx;
CLabelGenerator LabelGenerator;3001,5020
bool sucx=LabelGenerator.GenerateLabel(3001,5020,4,xlabelnum,pxlabel,xlabelArr,orderx);   //  产生x刻度和值刻度
if(pxlabel!=NULL)              //  清空数组
    {
        delete m_pxlabel;
        pxlabel=NULL;
    }
bool sucy=LabelGenerator.GenerateLabel(200001,5340000,5,xlabelnum,pxlabel,xlabelArr,orderx,0,4);
       坐标绘制采用GDI编写,被封装成CLabelDrawer类

LabelDrawer.h

#ifndef LABELDRAWER_H
#define LABELDRAWER_H
#pragma once
class CLabelDrawer
{
public:
    CLabelDrawer(void);
    ~CLabelDrawer(void);
public:
    bool DrawLabelHor(CDC *pDC,
        int xlabelnum,float *pxlabel,CStringArray &xlabelArr,int xorder,
        float Desx1,float Desx2,float Desy1,float x1,float x2,CString xtitle,
        bool IsUpper=true,COLORREF rgb=RGB(0,0,0));
    bool DrawLabelVer(CDC *pDC,
        int ylabelnum,float *pylabel,CStringArray &ylabelArr,int yorder,
        float Desy1,float Desy2,float Desx1,float y1,float y2,CString ytitle,
        bool IsLeft=true,COLORREF rgb=RGB(0,0,0));
};
#endif

LabelDrawer.cpp

//****************************     LabelDrawer.cpp     *****************************
// 包含功能:坐标刻度绘制(配合CLabelGenerator类)
//
// 作者:    jiangjp2812   1034378054@qq.com
// 单位:    中国地质大学(武汉)
// 日期:    2016/10/01
//**********************************************************************************

#include "StdAfx.h"
#include "LabelDrawer.h"
#include <math.h> 

CLabelDrawer::CLabelDrawer(void)
{
}


CLabelDrawer::~CLabelDrawer(void)
{
}

bool CLabelDrawer::DrawLabelHor(CDC *pDC,
    int xlabelnum,float *pxlabel,CStringArray &xlabelArr,int xorder,
    float Desx1,float Desx2,float Desy1,float x1,float x2,CString xtitle,
    bool IsUpper,COLORREF rgb)
    //  绘制水平刻度
    //  pDC: 绘图句柄。xlabelnum: 刻度数目。pxlabel:刻度真实数值。xlabelArr:刻度数值对应的字符串。
    //  xorder: 采用科学计数法阶次。Desx1,Desx2:标注绘制在窗口中的横坐标。Desy1:水平刻度在窗口中的纵坐标。
    //  xtitle: 坐标轴名称字符串。IsUpper:若为true,刻度位于刻度线上方,否则位于刻度线下方
    //  rgb:刻度颜色。
{	
    if(abs(Desx2-Desx1) <0.0001) return false;
    if(pxlabel==NULL) return false;

    pDC->SetBkMode(TRANSPARENT);
    pDC->SetTextColor(rgb);
    CFont font,fontunit,*oldfont;                   //  创建Times New Roman字体
    font.CreatePointFont(100,_T("Times New Roman"),pDC);
    fontunit.CreatePointFont(120,_T("Times New Roman"),pDC);

    CPen pen(0,1,rgb),*oldpen;
    oldpen=pDC->SelectObject(&pen);
    float posx,posy;
    oldfont=pDC->SelectObject(&font);
    TEXTMETRIC tm;
    pDC->GetTextMetrics(&tm);
    LONG TW=tm.tmAveCharWidth;             // 获取输出字符信息,主要是为了使得短线标注对准字符串中间位置
    LONG TH=tm.tmHeight;                   // 用于计算字符相对短线输出位置

    double k=(Desx2-Desx1)/(x2-x1);
    if(IsUpper==true)                      //  标注在上边
    {
        pDC->SelectObject(&font);
        pDC->SetTextAlign(TA_CENTER | TA_BOTTOM);
        for(int i=0;i<xlabelnum;i++)
        {
            posx=k*(pxlabel[i]-x1)+Desx1;
            pDC->MoveTo(posx,Desy1);
            pDC->LineTo(posx,Desy1-TW);
            pDC->TextOutW(posx,Desy1-TW-1,xlabelArr.GetAt(i));
        }

        posx=k*((x1+x2)/2.0-x1)+Desx1;
        pDC->SelectObject(&fontunit);
        pDC->TextOutW(posx,Desy1-TW-TH,xtitle);    // 绘制x方向坐标单位
    }
    else{                                  //  标注在下边
        pDC->SelectObject(&font);
        pDC->SetTextAlign(TA_CENTER | TA_TOP);
        for(int i=0;i<xlabelnum;i++)
        {
            posx=k*(pxlabel[i]-x1)+Desx1;
            pDC->MoveTo(posx,Desy1);
            pDC->LineTo(posx,Desy1+TW);
            pDC->TextOutW(posx,Desy1+TW+1,xlabelArr.GetAt(i));
        }

        posx=k*((x1+x2)/2.0-x1)+Desx1;
        pDC->SelectObject(&fontunit);
        pDC->TextOutW(posx,Desy1+TW+TH,xtitle);  // 绘制x方向坐标单位
    }

    if(xorder!=0)                               // 绘制x方向阶次
    {
        CFont font1,font2;                            
        font1.CreatePointFont(100,_T("Times New Roman"),pDC);
        font2.CreatePointFont(70,_T("Times New Roman"),pDC);
        float fontrate=100.0/70.0;
        CString tenstr("×10"),orderstr;         // ×10字符和阶次字符
        orderstr.Format(_T("%d"),xorder);

        if(IsUpper==true)
        {		
            pDC->SelectObject(&font1);	
            pDC->SetTextAlign(TA_BOTTOM | TA_RIGHT);	
            pDC->TextOutW(Desx2-TW/fontrate*2,Desy1-TW-TH,tenstr);		
            pDC->SelectObject(&font2);
            pDC->SetTextAlign(TA_BOTTOM | TA_LEFT);
            pDC->TextOutW(Desx2-TW/fontrate*2,Desy1-TW-TH-TH/2.0,orderstr);  
        }
        else
        {
            pDC->SelectObject(&font1);	
            pDC->SetTextAlign(TA_TOP | TA_RIGHT);	
            pDC->TextOutW(Desx2-TW/fontrate*2,Desy1+TW+TH+TH/2.0,tenstr);		
            pDC->SelectObject(&font2);
            pDC->SetTextAlign(TA_TOP | TA_LEFT);
            pDC->TextOutW(Desx2-TW/fontrate*2,Desy1+TW+TH,orderstr);  
        }
    }
    pDC->SelectObject(oldfont);
    pDC->SelectObject(oldpen);
    return true;
}

bool CLabelDrawer::DrawLabelVer(CDC *pDC,
    int ylabelnum,float *pylabel,CStringArray &ylabelArr,int yorder,
    float Desy1,float Desy2,float Desx1,float y1,float y2,CString ytitle,
    bool IsLeft,COLORREF rgb)
    //  绘制垂直刻度
    //  pDC: 绘图句柄。ylabelnum: 刻度数目。pylabel:刻度真实数值。ylabelArr:刻度数值对应的字符串。
    //  yorder: 采用科学计数法阶次。Desy1,Desy2:标注绘制在窗口中的纵坐标。Desx1:垂直刻度在窗口中的横坐标。
    //  ytitle: 坐标轴名称字符串。IsLeft:若为true,刻度位于刻度线左边,否则位于刻度线右边
    //  rgb:刻度颜色。
{
    if(abs(Desy2-Desy1)<0.0001) return false;
    if(pylabel==NULL) return false;

    pDC->SetBkMode(TRANSPARENT);
    pDC->SetTextColor(rgb);
    CFont font,fontunit,*oldfont;                   //  创建Times New Roman字体
    font.CreatePointFont(100,_T("Times New Roman"),pDC);
    fontunit.CreatePointFont(120,_T("Times New Roman"),pDC);

    CPen pen(0,1,rgb),*oldpen;
    oldpen=pDC->SelectObject(&pen);
    float posx,posy;
    oldfont=pDC->SelectObject(&font);
    TEXTMETRIC tm;
    pDC->GetTextMetrics(&tm);
    LONG TW=tm.tmAveCharWidth;             // 获取输出字符信息,主要是为了使得短线标注对准字符串中间位置
    LONG TH=tm.tmHeight;                   // 用于计算字符相对短线输出位置

    int charlength=0;
    for(int i=0;i<ylabelArr.GetCount();i++)
    {
        if(ylabelArr.GetAt(i).GetLength()>charlength) charlength=ylabelArr.GetAt(i).GetLength();
    }	

    charlength=charlength+1;

    double k=(Desy2-Desy1)/(y2-y1);

    if(IsLeft==true)                      //  标注左边
    {
        pDC->SelectObject(&font);
        pDC->SetTextAlign(TA_BOTTOM | TA_RIGHT);
        for(int i=0;i<ylabelnum;i++)
        {
            posy=k*(pylabel[i]-y1)+Desy1;
            pDC->MoveTo(Desx1,posy);
            pDC->LineTo(Desx1-TW,posy);
            pDC->TextOutW(Desx1-TW-1,posy+TH/2.0,ylabelArr.GetAt(i));
        }

        pDC->SetTextAlign(TA_BOTTOM | TA_CENTER);    //  纵向字体按纵向的bottom和left设置,即和横向颠倒
        posy=k*((y1+y2)/2.0-y1)+Desy1;

        LOGFONT logfont;
        fontunit.GetLogFont(&logfont);
        logfont.lfEscapement =900;
        CFont fontemp;
        fontemp.CreateFontIndirect(&logfont); 
        pDC->SelectObject(&fontemp);

        pDC->TextOutW(Desx1-TW*charlength-TW,posy,ytitle);
    }
    else{

        pDC->SelectObject(&font);
        pDC->SetTextAlign(TA_BOTTOM | TA_LEFT);
        for(int i=0;i<ylabelnum;i++)
        {
            posy=k*(pylabel[i]-y1)+Desy1;
            pDC->MoveTo(Desx1,posy);
            pDC->LineTo(Desx1+TW,posy);
            pDC->TextOutW(Desx1+TW+1,posy+TH/2.0,ylabelArr.GetAt(i));
        }

        pDC->SetTextAlign(TA_TOP | TA_CENTER); 
        posy=k*((y1+y2)/2.0-y1)+Desy1;

        LOGFONT logfont;
        fontunit.GetLogFont(&logfont);
        logfont.lfEscapement =900;
        CFont fontemp;
        fontemp.CreateFontIndirect(&logfont); 
        pDC->SelectObject(&fontemp);
        pDC->TextOutW(Desx1+TW*charlength+TW,posy,ytitle);
    }

    if(yorder!=0)
    {
        CFont font1,font2;                             //  创建Times New Roman字体
        font1.CreatePointFont(100,_T("Times New Roman"),pDC);
        font2.CreatePointFont(70,_T("Times New Roman"),pDC);
        float fontrate=100.0/70.0;
        CString tenstr("×10"),orderstr;
        orderstr.Format(_T("%d"),yorder);

        if(IsLeft==true)
        {	
            pDC->SelectObject(&font1);	   
            pDC->SetTextAlign(TA_BOTTOM | TA_RIGHT);				
            pDC->TextOutW(Desx1-charlength*TW-TW-TW/fontrate*2,Desy2,tenstr);
            pDC->SelectObject(&font2);
            pDC->SetTextAlign(TA_BOTTOM | TA_LEFT);
            pDC->TextOutW(Desx1-charlength*TW-TW-TW/fontrate*2,Desy2-TH/2.0,orderstr);

        }
        else
        {
            pDC->SelectObject(&font1);	   
            pDC->SetTextAlign(TA_BOTTOM | TA_LEFT);				
            pDC->TextOutW(Desx1+charlength*TW+TW,Desy2,tenstr);
            pDC->SelectObject(&font2);
            pDC->SetTextAlign(TA_BOTTOM | TA_LEFT);
            pDC->TextOutW(Desx1+charlength*TW+TW+(tenstr.GetLength()+1)*TW,Desy2-TH/2.0,orderstr);
        }
    }

    pDC->SelectObject(oldfont);
    pDC->SelectObject(oldpen);
    return true;
}

CLabelDrawer类中有两个成员函数,DrawLabelHor用于绘制水平刻度,DrawLabelVer用于绘制垂直刻度。函数参数在代码中有说明,这个类必须配合上边的CLabelGenerator类使用。下面是使用实例。

首先利用vs生成一个MFC单文档程序,为了方便说明,直接把数据放在了OnDraw函数中:

void CLabelTestView::OnDraw(CDC* pDC)
{
	CLabelTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码

    int labelnum;
    float *plabel=NULL;
    CStringArray labelArr;
    int order;

    float v1=-0.0005,v2=-0.0003;
    float Desx1=100,Desx2=500,Desy1=100,Desy2=500;
    // 生成数值(-0.0005 -0.0003)范围
    CLabelGenerator labelgen;
    labelgen.GenerateLabel(v1,v2,4,labelnum,plabel,labelArr,order);

    CLabelDrawer labeldraw;
    // 绘制数值(-0.0005 -0.0003)范围上刻度
    labeldraw.DrawLabelHor(pDC,labelnum,plabel,labelArr,order,Desx1,Desx2,Desy1,v1,v2,_T("upper label"));
    // 绘制数值(-0.0005 -0.0003)范围下刻度
    labeldraw.DrawLabelHor(pDC,labelnum,plabel,labelArr,order,Desx1,Desx2,Desy2,v1,v2,_T("lower label"),false,RGB(0,0,255));
    // 绘制数值(-0.0005 -0.0003)范围左刻度
    labeldraw.DrawLabelVer(pDC,labelnum,plabel,labelArr,order,Desy1,Desy2,Desx1,v1,v2,_T("left label"));
    // 绘制数值(-0.0005 -0.0003)范围右刻度
    labeldraw.DrawLabelVer(pDC,labelnum,plabel,labelArr,order,Desy1,Desy2,Desx2,v1,v2,_T("right label"),false,RGB(255,0,0));
    //  绘制矩形框
    pDC->SelectStockObject(NULL_BRUSH);
    pDC->Rectangle(Desx1,Desy1,Desx2,Desy2);
 
    v1=30; v2=803;
    Desx1=650;Desx2=950;Desy1=100;Desy2=500;
    if(plabel!=NULL)  delete plabel;
    // 绘制数值(30 803)范围刻度
    labelgen.GenerateLabel(v1,v2,5,labelnum,plabel,labelArr,order);       
    // 绘制数值(30 803)范围水平上刻度
    labeldraw.DrawLabelHor(pDC,labelnum,plabel,labelArr,order,Desx1,Desx2,Desy1,v1,v2,_T("hor axis"),true,RGB(0,0,255));
    pDC->MoveTo(Desx1,Desy1); pDC->LineTo(Desx2,Desy1);  
    // 绘制数值(30 803)范围水平上逆向刻度
    labeldraw.DrawLabelHor(pDC,labelnum,plabel,labelArr,order,Desx2,Desx1,Desy1+50,v1,v2,_T("reverse hor axis"),true,RGB(0,0,255));
    pDC->MoveTo(Desx1,Desy1+50); pDC->LineTo(Desx2,Desy1+50);  

    Desx1=700;Desx2=1000;Desy1=200;Desy2=550;   
    // 绘制数值(30 803)范围垂直左刻度
    labeldraw.DrawLabelVer(pDC,labelnum,plabel,labelArr,order,Desy1,Desy2,Desx1,v1,v2,_T("ver axis"),true,RGB(255,0,255));
    pDC->MoveTo(Desx1,Desy1); pDC->LineTo(Desx1,Desy2);  
    // 绘制数值(30 803)范围垂直左逆向刻度
    labeldraw.DrawLabelVer(pDC,labelnum,plabel,labelArr,order,Desy2,Desy1,Desx1+100,v1,v2,_T("reverse ver axis"),true,RGB(255,0,255));
    pDC->MoveTo(Desx1+100,Desy1); pDC->LineTo(Desx1+100,Desy2);  
}
生成的效果如图









  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值