从truetype b样条曲线中获取x,y坐标的公式是什么?

时间:2011-04-11 15:06:59

标签: formula true-type-fonts

在给定的TrueType字体中的b样条坐标的情况下,在x,y空间中绘制直线的公式是什么?

1 个答案:

答案 0 :(得分:2)

请注意,Truetype允许在字形定义中使用bspline曲线和直线。

如果您需要将这些命令更改为一系列MoveTo和LineTo,您可以使用以下内容:

  1. 将TrueType数据转换为提示坐标列表。这是您的操作系统可以为您做的事情(以下代码使用Windows API)。

  2. 遍历所有坐标并将曲线转换为直线(请参阅下面的代码片段):

    procedure TGlyphEvaluator.EvaluateFromBuffer( Action: TGlyphEvaluatorAction );
    var
        H                                   : TTPOLYGONHEADER;
        C                                   : TTPOLYCURVE;
        Points                              : array of TPointFX;
        P, PE                               : DWORD;
        i, j                                : Integer;
        F                                   : Double;
        PA, PB, PC                          : TPoint;
    begin
        SetLength( Points, 10 );
        P := 0;
        repeat
            // Eat the polygon header
            Move( FBuffer[ P ], H, sizeof( H ) );
            if H.dwType <> TT_POLYGON_TYPE then Break;          // Sanity check!
            PE := P + H.cb;
            Inc( P, sizeof( H ) );
            Points[ 0 ] := H.pfxStart;
            // Eat all the curve records
            while P < PE do begin
                // Get the curve record
                Move( FBuffer[ P ], C, sizeof( C ) - sizeof( TPointFX ) );
                Inc( P, sizeof( C ) - sizeof( TPointFX ) );
    
                // Get the points from the curve record
                if Length( Points ) < C.cpfx + 1 then Setlength( Points, C.cpfx + 1 );
                Move( FBuffer[ P ], Points[ 1 ], sizeof( TPointFX ) * C.cpfx );
                Inc( P, sizeof( TPointFX ) * C.cpfx );
    
                case C.wType of
                    TT_PRIM_LINE: begin
                            MoveTo( Action, Points[ 0 ].x.value, Points[ 0 ].y.value );
                            for i := 1 to C.cpfx do
                                LineTo( Action, Points[ i ].x.value, Points[ i ].y.value );
                        end;
                    TT_PRIM_QSPLINE: begin
                            MoveTo( Action, Points[ 0 ].x.value, Points[ 0 ].y.value );
                            PA.X := Points[ 0 ].x.value;
                            PA.Y := Points[ 0 ].y.value;
                            for i := 1 to C.cpfx - 1 do begin   // DrawQSpline is called C.cpfx - 1 times
                                PB.X := Points[ i ].x.value;
                                PB.Y := Points[ i ].y.value;
                                PC.X := Points[ i + 1 ].x.value;
                                PC.Y := Points[ i + 1 ].y.value;
                                if i < C.cpfx - 1 then begin
                                    PC.X := ( PC.X + PB.X ) div 2;
                                    PC.Y := ( PC.Y + PB.Y ) div 2;
                                end;
                                for j := 1 to 8 do begin
                                    F := j / 8;
                                    LineTo( Action, Round( ( PA.x - 2 * PB.x + PC.x ) * Sqr( F ) + ( 2 * PB.x - 2 * PA.x ) * F + PA.x ),
                                        Round( ( PA.y - 2 * PB.y + PC.y ) * Sqr( F ) + ( 2 * PB.y - 2 * PA.y ) * F + PA.y ) );
                                end;
                                PA := PC;
                            end;
                        end;
                end;
                // Update last point.
                Points[ 0 ] := Points[ C.cpfx ];
            end;
            MoveTo( Action, Points[ 0 ].x.value, Points[ 0 ].y.value );
            LineTo( Action, H.pfxStart.x.value, H.pfxStart.y.value );
        until P >= Longword( Length( FBuffer ) );
    end;