Какова формула для получения координат x, y из кривой b-сплайна истинного типа? - PullRequest
0 голосов
/ 11 апреля 2011

Какова формула для рисования линии в пространстве x, y с заданными координатами b-сплайна в шрифте TrueType?

1 Ответ

2 голосов
/ 14 апреля 2011

Обратите внимание, что Truetype допускает кривые bspline И прямые в определении глифа.

Если вам нужно изменить эти команды на серию MoveTo и LineTo, вы можете использовать следующее:

  1. Преобразование данных TrueType в список подсказок координат. Это то, что ваша ОС может сделать для вас (следующий код использует API Windows).

  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;
    
...