首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

C++ Builder GDI實現儀表盤指針旋轉與透明繪制

     編輯:VC 教學

需求背景

工業儀表盤虛擬化需實現指針平滑旋轉、刻度盤縮放漫游、背景透明疊加。傳統逐像素旋轉效率低,利用GDI世界變換(World Transform)可硬件加速實現仿射變換。

核心數學原理

GDI使用XFORM結構體表示2D仿射變換矩陣:

typedef struct tagXFORM {
    FLOAT eM11;  // 水平縮放/旋轉余弦
    FLOAT eM12;  // 水平傾斜/旋轉正弦
    FLOAT eM21;  // 垂直傾斜/-旋轉正弦
    FLOAT eM22;  // 垂直縮放/旋轉余弦
    FLOAT eDx;   // 水平平移
    FLOAT eDy;   // 垂直平移
} XFORM;

坐標變換公式:

x' = x * eM11 + y * eM21 + eDx
y' = x * eM12 + y * eM22 + eDy

指針旋轉實現步驟

1. 準備指針位圖資源

  • 設計指針圖片(含透明通道),中心點對齊旋轉中心
  • 使用TBitmap載入,設置Transparent = true、TransparentColor = clFuchsia (或Alpha通道)

2. 設置世界變換

void DrawRotatedNeedle(TCanvas* Canvas, TBitmap* NeedleBmp, 
                       TPoint Center, float AngleDeg, float Scale = 1.0f) {
    // 1. 保存原始圖形模式
    int oldMode = SetGraphicsMode(Canvas->Handle, GM_ADVANCED);
    
    // 2. 構建變換矩陣:平移到原點 → 旋轉 → 縮放 → 平移回目標中心
    XFORM xform = { 0 };
    float rad = AngleDeg * M_PI / 180.0f;
    float cosA = cos(rad) * Scale;
    float sinA = sin(rad) * Scale;
    
    xform.eM11 = cosA;
    xform.eM12 = sinA;
    xform.eM21 = -sinA;
    xform.eM22 = cosA;
    xform.eDx = Center.x - (NeedleBmp->Width / 2.0f) * cosA + (NeedleBmp->Height / 2.0f) * sinA;
    xform.eDy = Center.y - (NeedleBmp->Width / 2.0f) * sinA - (NeedleBmp->Height / 2.0f) * cosA;
    
    // 3. 應用變換
    SetWorldTransform(Canvas->Handle, &xform);
    
    // 4. 繪制位圖(相對原點(0,0)繪制,變換會自動映射)
    Canvas->Draw(0, 0, NeedleBmp);
    
    // 5. 恢復身份變換
    XFORM identity = { 1, 0, 0, 1, 0, 0 };
    SetWorldTransform(Canvas->Handle, &identity);
    SetGraphicsMode(Canvas->Handle, oldMode);
}

3. 雙緩衝防閃爍

void __fastcall TForm1::PaintBox1Paint(TObject *Sender) {
    TRect rect = PaintBox1->ClientRect;
    TBitmap* backBuf = new TBitmap();
    backBuf->SetSize(rect.Width(), rect.Height());
    backBuf->Canvas->Brush->Color = clWhite;
    backBuf->Canvas->FillRect(rect);
    
    // 繪制刻度盤背景
    backBuf->Canvas->Draw(0, 0, BackgroundBmp);
    
    // 繪制旋轉指針
    float angle = CalculateAngle(currentValue);  // 數值映射到角度
    DrawRotatedNeedle(backBuf->Canvas, NeedleBmp, CenterPoint, angle);
    
    // 一次性輸出到屏幕
    PaintBox1->Canvas->Draw(0, 0, backBuf);
    delete backBuf;
}

進階優化技巧

抗鋸齒與高質量縮放

SetGraphicsMode(hdc, GM_ADVANCED);
SetWorldTransform(hdc, &xform);
// 啟用高質量模式 (Windows Vista+)
SetStretchBltMode(hdc, HALFTONE);
SetBrushOrgEx(hdc, 0, 0, NULL);

指針軌跡拖尾效果

保存歷史幀位圖,按時間衰減Alpha值疊加繪製,模擬機械儀表慣性。

座標系統適配

GDI坐標原點左上角,Y軸向下;數學坐標Y軸向上。旋轉角度需按順時針方向為正,或通過eM12/eM21符號調整。

完整類封裝建議

class TGaugeNeedle {
    TBitmap* FNeedleBmp;
    TPoint FCenter;
    float FMinAngle, FMaxAngle;  // 量程對應角度范圍
    float FZeroAngle;            // 零點角度偏移
public:
    void SetValue(float value, float minVal, float maxVal);
    void PaintTo(TCanvas* Canvas);
    // 內部處理角度插值、變換矩陣構建、雙緩衝
};
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved