Таким образом, создав траекторию из кривой Безье ( BeginPath/PoliBezier/EndPath
), мы можем преобразовать эту траекторию в ломаную ( FlattenPath
), а затем получить координаты угловэтой ломаной ( GetPath
). А каждое звено этой ломаной мы можем нарисовать произвольным стилем, используя LineDDA
. Таким образом, задача построения кривой Безье сведена к уже решенной задаче построения отрезка.
В листинге 1.60 реализован метод DrawCurve
, выполняющий указанные действия. Здесь FCurve
— это поле формы типа TCurve
, в котором хранятся координаты четырех точек, образующих кривую.
Листинг 1.60. Работа с траекторией на основе кривой Безье
type
// Тип TCurve хранит координаты кривой в следующем порядке: начало,
// первую промежуточную точку, вторую промежуточную точку, конец
TCurve = array[0..3] of TPoint;
// Функция обратного вызова для LineDDA
procedure LineDrawFunc(X, Y: Integer; Canvas: TCanvas); stdcall;
begin
case CurveForm.RGroupType.ItemIndex of
// Разноцветные шарики
0: if CurveForm.FCounter mod 10 = 0 then
begin
Canvas.Pen.Style := psSolid;
Canvas.Pen.Width := 1;
Canvas.Brush.Style := bsSolid;
if CurveForm.FCounter mod 15 = 0 then Canvas.Pen.Color := clBlue
else if CurveForm.FCounter mod 15 = 5 then Canvas.Pen.Color := сlLime
else Canvas.Pen.Color := clRed;
Canvas.Brush.Color := Canvas.Pen.Color;
Canvas.Ellipse(X - 2, Y - 2, X + 3, Y + 3);
end;
// Поперечные полосы
1: it CurveForm.FCounter mod 5 = 0 then
begin
Canvas.Pen.Style := psSolid;
Canvas.Pen.Width := 1;
Canvas.Pen.Color := clBlue;
Canvas.MoveTo(X - CurveForm.FDX, Y - CurveForm.FDY);
Canvas.LineTo(X + CurveForm.FDX, Y + CurveForm.FDY);
end;
// Плакатное перо
2: begin
Canvas.Pen.Style := psSolid;
// Предположим, некоторая точка прямой имеет координаты (X, Y),
// а соседняя с ней - координаты (Х+1, Y-1). Тогда при проведении
// через эти точки наклонной линии одинарной ширины между ними
// останутся незаполненные точки, как на шахматной доске.
// Поэтому потребовалось увеличить толщину пера
Canvas.Pen.Width := 2;
Canvas.Pen.Color := clBlack;
Canvas.MoveTo(X - 5, Y - 5);
Canvas.LineTo(X + 6, Y + 6);
end;
// Цепочка
3: begin
case CurveForm.FCounter mod 15 of
0: begin
Canvas.Pen.Style := psSolid;
Canvas.Pen.Width := 1;
Canvas.Pen.Color := clBlack;
Canvas.Brush.Style := bsClear;
Canvas.Ellipse(X - 5, Y - 5, X + 6, Y + 6);
end;
2..13: Canvas.Pixels[X, Y] := clBlack;
end;
end;
end;
Inc(CurveForm.FCounter);
end;
procedure TCurveForm.DrawCurve(Canvas: TCanvas);
var
LCurve: TCurve;
I, Size: Integer;
PtBuf: array of TPoint;
TpBuf: array of Byte;
L: Extended;
begin
// LCurve хранит координаты начала и конца кривой и ее
// опорных точек. Если включен режим рисования по опорным
// точкам, LCurve совпадает с FCurve, если включен режим
// рисования по точкам кривой, опорные точки LCurve[1]
// и LCurve[2] рассчитываются по приведенным в книге
// формулам на основании точек FCurve
LCurve := FCurve;
if RGroupDrawMethod.ItemIndex = 1 then
begin
LCurve[1].X :=
Round((-5 * FCurve[0].X + 18 * FCurve[1].X -
9 * FCurve[2].X + 2 * FCurve[3].X) / 6);
LCurve[1].Y :=
Round((-5 * FCurve[0].Y + 18 * FCurve[1].Y -
9 * FCurve[2].Y + 2 * FCurve[3]-Y) / 6);
LCurve[2].X :=
Round((2 * FCurve[0].X - 9 * FCurve[1].X +
18 * FCurve[2].X - 5 * FCurve[3].X) / 6);
LCurve[2].Y :=
Round((2 * FCurve[0].Y - 9 * FCurve[1].Y +
18 * FCurve[2].Y - 5 * FCurve[3].Y) / 6);
end;
// Создаем траекторию на основе кривой
BeginPath(Canvas.Handle);
Canvas.PolyBezier(LCurve);
EndPath(Canvas.Handle);
// Аппроксимируем траекторию отрезками прямых
FlattenPath(Canvas.Handle);
// Получаем число точек траектории. Так как сами точки никуда
// пока не копируются, в качестве фиктивного буфера можно указать
// любую переменную. В данном случае - переменную I
Size := GetPath(Canvas.Handle, I, I, 0);
// Выделяем память для хранения координат и типов точек траектории
SetLength(PtBuf, Size);
SetLength(TpBuf, Size);
// Получаем координаты и типы точек. Типы точек нас в данном случае
// не интересуют: у первой точки будет тип PT_MOVETO,
// а у остальных - PT_LINETO. Появление PT_MOVETO у других точек
// невозможно, т.к. траектория содержит только один замкнутый
// контур, состояний из кривой и соединяющей ее концы прямой.
// Появление точек типа PT_BEZIERTO также исключено, т.к. после
// вызова FlattenPath контур содержит только отрезки прямых.
Читать дальше
Конец ознакомительного отрывка
Купить книгу