尺寸標註的文字應該繪製在哪裏?

問題引入

在標註尺寸時,我們會在雙向箭頭中心處的旁邊,繪製對應的文本提示。要繪製的文字位置看起來自然舒服,文本的繪製位置並不是簡單地從線段中心點偏移固定值。

計算過程分析

 這裏,提供一種計算標註文本位置的計算方式。

    

 如上圖,綠色的點是文本位置的起點,經觀察發現,文本左側中心點相對於線段中心點的位置遵循一定的規律:

 

 線段起點終點向量角度 V 爲 (0,180]:  

[提示文字左側中心點 P1 ]、[線段中點]、[P1在V在中點法向量投影點]成直角三角形:  
短直角邊 a  = text height
長直角邊 b  = text length/2  
直角斜邊 c                             

向量 V 右側法向量角度 Vf=(V-90)
a 和 c 的動態角度 k = (V-90)/90 * atan(b/a)   注:這裏k值粗略按等比計算

直角斜邊c =a/cos(k)

文字左側中心點 P1 向量 Vt = Vf + k

----k值初步分析----
V 爲 (0,90]     時,k <= 0
V 爲 (90,180] 時,k > 0
----特殊值驗證----
V 爲 90           時,k=0,   Vt=Vf,  c=a
V 爲 180         時,k= atan(b/a), Vt=Vf+atan(b/a),  c=a/cos(atan(b/a))

最終座標:
P1.x = mx + cos(Vt)*c
P1.y = my + sin(Vt)*c

文字繪製座標:
Ptext.x = P1.x
Ptext.y = P1.y - a/2

代碼實現(參考)

//計算繪製文本時相對於線段(x1,y1),(x2,y2)中點的偏移點
void calculateTextOffsetForMiddlePt(double x1, double y1, double x2, double y2, int textLength, int textHeight, int& ptOffsetX, int& ptOffsetY)
{
    /*
    線段起點終點向量角度 V 爲 (0,180]:  

[提示文字左側中心點 P1 ]、[線段中點]、[P1在V在中點法向量投影點]成直角三角形:  
短直角邊 a  = text height
長直角邊 b  = text length/2  
直角斜邊 c                             

向量 V 右側法向量角度 Vf=(V-90)
a 和 c 的動態角度 k = (V-90)/90 * atan(b/a)   注:這裏k值粗略按等比計算

直角斜邊c =a/cos(k)

文字左側中心點 P1 向量 Vt = Vf + k

----k值初步分析----
V 爲 (0,90]     時,k <= 0
V 爲 (90,180] 時,k > 0
----特殊值驗證----
V 爲 90           時,k=0,   Vt=Vf,  c=a
V 爲 180         時,k= atan(b/a), Vt=Vf+atan(b/a),  c=a/cos(atan(b/a))

最終座標:
P1.x = mx + cos(Vt)*c
P1.y = my + sin(Vt)*c

文字繪製座標:
Ptext.x = P1.x 
Ptext.y = P1.y - a/2
    
    */

    //特殊情況
    if (ZMath_IsEqual(x1, x2) && ZMath_IsEqual(y1, y2))
        x2 -= 1.0; //重合時,把 (x1,y1),(x2,y2) 作爲 180度線段來計算

    //確保:線段起點終點向量角度 V 爲(0, 180]:
    double V = 0.0;
    ZMath_GetVectorAngle(x1, y1, x2, y2, &V);
    if (ZMath_IsEqual(V, 0.0) || (V > 180.0 && !ZMath_IsEqual(V, 180.0)))
        std::swap(x1, x2), std::swap(y1, y2);

    ZMath_GetVectorAngle(x1, y1, x2, y2, &V);

    double Vradian = ZMath_AngleToRadian(V);

    //短直角邊 a  = text height ;長直角邊 b = text length / 2
    double a = textHeight;
    double b = textLength / 2;

    //向量 V 右側法向量角度 Vf=(V-90)
    double Vf = V - 90.0;
    double Vfradian = ZMath_AngleToRadian(Vf);

    //a 和 c 的動態角度 k = (V-90)/90 * atan(b/a)   注:這裏k值粗略按等比計算
    double k = (V - 90) / 90 * atan(b / a);

    //直角斜邊c =a/cos(k)
    double c = a / cos(k);

    //文字左側中心點 P1 向量 Vt = Vf + k
    double Vtarget = Vfradian + k;

    //最終座標:
    //P1.x = mx + cos(Vt)*c
    //P1.y = my + sin(Vt)*c
    //所以偏移值爲
    double offsetX = cos(Vtarget) * c;
    double offsetY = sin(Vtarget) * c * -1; /* 繪製時是以左上角爲原點,向上Y爲負,向下Y爲正,所以這裏 Y 值乘以 -1 */

    //文字繪製座標:
    //Ptext.x = P1.x 
    //Ptext.y = P1.y - a/2
    ptOffsetX = (int)offsetX;
    ptOffsetY = (int)(offsetY + a / 2); /* 繪製時是以左上角爲原點,向上Y爲負,向下Y爲正,所以這裏 Y 值加上 a/2 */
}

上述代碼中:

ZMath_IsEqual 爲判斷兩個浮點數是否相等,精度爲 0.01

ZMath_GetVectorAngle 爲獲得線段的向量角度

ZMath_AngleToRadian 爲角度轉弧度

 


 

本文地址:https://www.cnblogs.com/BensonLaur/p/16916827.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章