А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
После того как траектория построена, ее можно отобразить или преобразовать. Мы не будем здесь перечислять все возможные операции с траекториями, остановимся только на преобразовании траектории в ломаную. Как уже отмечалось, все контуры траектории представляют собой набор отрезков прямых и кривых Безье. С другой стороны, при построении кривой Безье она аппроксимируется ломаной. Следовательно, вся траектория может быть аппроксимирована набором отрезков прямой. Функция FlattenPath
преобразует кривые Безье, входящие в состав траектории, в ломаные линии. Таким образом, после вызова этой функции траектория будет состоять из отрезков прямой.
Отметим также некоторые другие преобразование траектории, полезные для создания графических редакторов и подобных им программ. Функция PathToRegion
позволяет преобразовать траекторию в регион. Это может понадобиться, в частности, при определении того обстоятельства, попадает ли курсор мыши в область объекта, представляемого сложной фигурой. Функция WidenPath
превращает каждый контур траектории в два контура — внутренний и внешний. Расстояние между ними определяется толщиной текущего пера. Таким образом, траектория как бы утолщается. После преобразования утолщенной траектории в регион можно определить, попадает ли курсор мыши на кривую с учетом погрешности, определяемой толщиной пера.
Получить информацию о точках текущей траектории можно с помощью функции GetPath
. Для каждой точки траектории эта функция возвращает координаты и тип точки (начальная линии, замыкающая точка отрезка, точка кривой Безье, конец контура).
Таким образом, создав траекторию из кривой Безье ( BeginPath/PoliBezier/EndPath
), мы можем преобразовать эту траекторию в ломаную ( FlattenPath
), а затем получить координаты угловэтой ломаной ( GetPath
). А каждое звено этой ломаной мы можем нарисовать произвольным стилем, используя LineDDA
. Таким образом, задача построения кривой Безье сведена к уже решенной задаче построения отрезка.
В листинге 1.60 реализован метод DrawCurve
, выполняющий указанные действия. Здесь FCurve
— это поле формы типа TCurve
, в котором хранятся координаты четырех точек, образующих кривую.
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 контур содержит только отрезки прямых.
// Поэтому значения, записанные в TpBuf, будут в дальнейшем
// игнорироваться
GetPath(Canvas.Handle, PtBuf[0], TpBuf[0], Size);
FCounter := 0;
// Рисуем по отдельности каждый из отрезков, составляющих контур
for I := 1 to Size - 1 do
begin
// Вычисляем длину отрезка
L :=
Sqrt(Sqr(PtBuf[I - 1].X - PtBuf[I].X) +
Sqr(PtBuf[I - 1].Y - PtBuf[I].Y));
// Практика показала, что аппроксимированный контур может
// содержать отрезки нулевой длины - видимо, это издержки
// алгоритма аппроксимации. Так как в дальнейшем нам придется
Интервал:
Закладка: