Персональная страничка
Диканева Тараса
Викторовича

Главная \ Преподавательское \ Программирование для начинающих

13. Графика в Паскале

Предыдущий раздел:

Следующий раздел:

Задание 13: Графика в Паскале

Примечание: При выполнении заданий в среде Borland Pascal следует слово «графическое окно» заменить на «экран». То есть вместо «нарисуйте в центре графического окна» следует читать «нарисуйте в центре экрана» и т.п.

1. Войдя в графический режим, определите ширину и высоту графического окна в пикселях. Выведите ее на экран, не выходя из графического режима.

2. Нарисуйте окружности радиусом 20 пикселов (а) в центре графического окна, (б) по углам окна.

3. С помощью процедур рисования линий нарисуйте квадрат со стороной 200 пикселов так, чтобы он отображался по центру окна.

4. Создайте процедуру, рисующую квадрат заданной величины по центру окна.

5. Отобразите в графическом окне 1000 точек (а) со случайными координатами, (б) со случайными координатами и лежащими внутри квадрата из предыдущей задачи.

Усложненный вариант: со случайными координатами, лежащими внутри заданной окружности.

6. Воспроизведите орнаменты, оформив рисование их отдельных элементов в виде процедур:

7. Нарисуйте домик, над которым светит солнышко.

Усложненный вариант: (а) Солнышко имеет лучики, (б) солнышко движется по небу: картинка рисуется процедурой, параметрами которой является координаты солнышка.

8. Воспроизведите рисунки, полученные с помощью поворотов треугольника и окружности:

9. Нарисуйте график функции y=a\sin\omega t. Параметрами процедуры должны быть интервал значений t, амплитуда a, частота \omega и количество точек, выводимых на график.

Следующий раздел:

Предыдущий раздел:

1 комментарий

  1. Константин

    Солнышко движется по небу o_O

  2. Taras

    А еще, хорошо бы, оно при этом лучилось! Как-то так:

  3. Константин

    Я думал, что Паскаль не настолько развит :D

  4. Андрей

    Здравствуйте! Не могли бы вы показать решение восьмого задания, где требуется воспроизвести рисунки с помощью окружности (про треугольники не надо). Заранее премного благодарен.

  5. оксана

    Не могу сделать задание 1, у меня выводятся только стандартные ширина и высота, что изменить?:
    uses
    GraphABC;
    var
    ww,wh: integer;
    begin
    ww:= WindowWidth;
    wh:= WindowHeight;
    write(ww,’ ‘,wh);
    end

  6. Taras

    Так, в общем, все правильно. Создалось графическое окно, ширина и высота которого, действительно 640х480.

  7. оксана

    а как узнать ширину и высоту если растянуть окно?
    а в задании 6 переплетающиеся круги рисовать кругами или дугами? Кругами пробовала, но они накладываются друг на друга.

  8. Taras

    WindowWidth и WindowHeight возвращают ширину и высоту в момент выполнения программы. Если ты растягиваешь окно, то это, очевидно, происходит уж после того, как твой код выполнился. Узнать размер после растягивания все-таки можно, но для этого надо, чтобы какая-то часть программы выполнялась не сразу, а в ответ на возникновение события. Прочитать про них можно в справке по F1 (раздел Уроки PascalABC.NET \ Примеры \ Простейшие события).

    Для примера:

      uses
        GraphABC;
    
      procedure PressEnter(ch: char);
      var
        ww, wh: integer;
      begin
        if ord(ch) = VK_Enter then
        begin
          ww:= WindowWidth;
          wh:= WindowHeight;
          writeln(ww,', ',wh);
        end;
      end;
    
      begin
        // OnKeyPress - переменная процедурного типа, описанная как
        // OnKeyPress: procedure (ch: char);
        // Присвоенное ей значение-процедура будут вызываться при нажатии любой 
        // клавиши на клавиатуре
        OnKeyPress := PressEnter;
      end.
    

    Можно растянуть окно, нажать Enter и получить его текущие размеры.

    В 6 — и, правда, накладываются. Надо использовать процедуру DrawCircle. Рисует только окружность без заливки.

  9. оксана

    задание 5б:

    Был текст программы

  10. Taras

    5б — OK

  11. оксана

    6 задание так получилось, (не стала точно соблюдать все пропорции):

    Был текст программы

  12. оксана

    а лучики у солнца надо процедурой Line рисовать? а как выполнять заливку?

  13. Taras

    Выглядит хорошо )

    По стилю реализации приходит в голову следующее:

    1) Напрашивается разбиение программы на три части (круги и линии по краям, узор, круги в середине). Соответствующие части можно было бы поместить в отдельные процедуры или, хотя бы, отделить друг от друга пустыми строками. Нужно чтобы структура программы была очевидна сразу, а не становилась понятна после нескольких минут внимательного вглядывания.

    2) Явное использование числовых констант, как, например, в

      x := 320 - (12 * (2 * r + 4)) div 2;
      y := 240 - 20;

    это не хорошо. Было бы гораздо лучше, если бы соответствующие значения были присвоены переменным с говорящими названиями. А уже из этих переменных составлялись бы выражения. Что такое 320 и 240 понятно сразу (хотя, конечно, использовать WindowWidth в выражении было бы правильней). А вот узнать, что есть 12, 4 и 20, без анализа программы целиком невозможно. И это плохо. Хорошая с точки зрения стиля программа не должна требовать «забегания вперед» для своего понимания.

    3) Помню, когда еще работал преподавателем, требовал от студентов делать количество шагов спиралек в узоре параметром процедуры. Как раз, чтобы всю спиральку отдельными line’ми не рисовали. Злой был.

    Но, в целом, все очень неплохо.

    >> а лучики у солнца надо процедурой Line рисовать? а как выполнять заливку?

    Лучики — да, это линии.
    Цвет заливки:

      procedure SetBrushColor(c: Color);

    Процедура Circle как раз и рисовала тебе залитую окружность. Просто цвет заливки по умолчанию белый.
    Вообще, за разнообразными графическими процедурами можно сходить в справку по F1, раздел Стандартные модули \ Модуль GraphABC \ GraphABC: графические примитивы

  14. оксана

    временно один комп в семье на троих, поэтому над солнышком зависла на несколько дней)) правда у меня домик стирается и чтобы солнце лучилось ничего не придумывается, и мерцает оно сильно, подскажите, пожалуйста, что-нибудь))

    Был текст программы

  15. оксана

    забыла про знаки, в конце после r1:=20 до ClearWindow идет кусок:
    Solnce(x2,y2,r1);
    while x2 меньше 640 do
    begin
    Solnce(x2,y2,r1);
    x2:=x2+1;
    ClearWindow;
    end;
    while x2 больше 0 do
    begin
    Solnce(x2,y2,r1);
    x2:=x2-1;

  16. Taras

    Рисование средствами PascalABC происходит очень медленно. Пока оно идет, картинка на экране успевает много раз обновиться. Отсюда мерцание. То есть, мы видим не окончательную картинку, а процесс ее рисования. Окончательную картинку в общем-то не видим — как только она построилась, мы ее тут же стираем и начинаем новый цикл рисования. Для борьбы с этим эффектом придумали двойную буферизацию. Идея в том, чтобы сначала построить картинку в памяти (не выводя на экран), а затем отобразить новый кадр на экране целиком, без промежуточных вариантов, где не хватает половины лучиков.

    В PascalABC оказывается есть поддержка двойной буферизации. Для этого в начале программы вызываем процедуру

      LockDrawing;

    После этого все команды рисования будут создавать картинку в памяти (в так называемом вторичном буфере). Непосредственно на экране ничего рисоваться не будет. После того, как очередной кадр анимации полностью отрисован (то есть перед ClearWindow), нужно вызвать процедуру

      Redraw;

    которая, собственно, и вызовет перерисовку всей картины.

    На счет, чтобы лучилось, это скорее математическое творчество. Надо придумать формулу для изменения длины лучиков. Подсказывать не хочу — пусть у тебя по-своему лучиться ))

  17. оксана

    спасибо за комментарии, к сожалению так и не придумала формулу для лучения((( С процедурой LockDrawing действительно картинка не мерцает. А вот частично задание 8 (с треугольниками решила не заморачиваться):

    uses
    GraphABC;
    var
    x,y,r,i,z,z1,k: integer;
    a,b: real;

    procedure BolshoiKrug(x1,y1,r1: integer);
    begin
    DrawCircle(x1,y1,r1);
    end;

    begin
    x:= 320;
    y:=240;
    r:=200;
    a:=1.26;
    BolshoiKrug(x,y,r);
    for k:=1 to 5 do
    begin
    b:=a;
    z:=x+round(r div 2 *cos(a));
    z1:=y-round(r div 2*sin(a));
    b:=b+0.04;
    for i:=1 to 9 do
    begin
    z:=x+round(r div 2 *cos(b));
    z1:=y-round(r div 2*sin(b));
    DrawCircle(z,z1,r div 2);
    b:=b+0.04;
    end;
    a:=a+1.26;
    end;
    end.

  18. Taras

    Замечания такие:

    1) По возможности следует избегать явного использования числовых констант. Мысль стоящая, например, за операцией

      a := a + 1.26;

    по крайней мере, сходу не очевидна. Стоило бы ввести параметр для числа групп окружностей и выразить эту прибавку через него. Например,

      N := 5; // Количество групп
      da := 2*pi/N; // то самое 1.26

    2) Присваивание в начале

      a := 1.26;

    есть не что иное как задание угла поворота всей конструкции. Однако при повороте на 1.26 радиан картинка как раз не изменится. То есть это то же самое, что

      a := 0;

    3) Операции

      z  := x + round(r div 2 * cos(a));
      z1 := y - round(r div 2 * sin(a));

    во внешнем цикле бессмысленны, так как присвоенные значения нигде не используются.

    4) Напрашивается замена

      b := a;
      ...
      b := b + 0.04;

    во внешнем цикле одной операцией. Впрочем, после такой замены становится очевидным, что прибавление 0.04 к b эквивалентно прибавлению его же к начальному значению a. То есть это просто еще один способ повернуть всю конструкцию теперь уже на 0.04 радиана. Думаю, этого не следует делать вовсе.

    Ну, а в целом — да, задача решена.

  19. Darkhan

    program N13_6;{орнаменты}
    uses
    GraphABC;
    const
    r = 17;
    x0 = 5;
    ww = WindowWidth-1;
    y0 = 5;
    wh = WindowHeight-1;
    var
    x, y:integer;

    procedure Rectangle1(x, y:integer);{прямоугольник внешний}
    begin
    x:=x0+2; y:=y0+2; MoveTo(x, y);
    x:=ww-10; y:=y0+2; LineTo(x, y); {вправо}
    x:=ww-10; y:=wh-4; LineTo(x, y);{вниз}
    x:=x0+2; y:=wh-4; LineTo(x, y);{влево}
    x:=x0+2; y:=y0+2; LineTo(x, y);{вверх}
    end;

    procedure Rectangle2(x, y:integer);{прямоугольник внутренний}
    begin
    x:=x0+round(2.5*r); y:=y0+round(2.5*r); MoveTo(x, y);
    x:=ww-round(3.1*r); y:=y0+round(2.5*r); LineTo(x, y); {вправо}
    x:=ww-round(3.1*r); y:=wh-round(2.7*r); LineTo(x, y); {вниз}
    x:=x0+round(2.5*r); y:=wh-round(2.7*r); LineTo(x, y);{влево}
    x:=x0+round(2.5*r); y:=y0+round(2.5*r); LineTo(x, y);{вверх}
    end;

    procedure Circle(x, y, r:integer);
    begin
    DrawCircle(x, y, r);
    end;

    procedure PerimetrCircle(x, y, r:integer);{по периметру}
    var
    i:integer;
    begin
    x:=r+10; y:=r+10;
    for i:=1 to 34 do {вправо}
    begin
    x:=x+r;
    Circle(x, y, r);
    end;

    for i:=1 to 25 do {вниз}
    begin
    y:=y+r;
    Circle(x, y, r);
    end;

    for i:=1 to 34 do {влево}
    begin
    x:=x-r;
    Circle(x, y, r);
    end;

    for i:=1 to 25 do {вверх}
    begin
    y:=y-r;
    Circle(x, y, r);
    end;
    end;

    procedure Meandr(x, y:integer);
    var
    i, x1:integer;
    begin
    x1:=x0;
    for i:=1 to 10 do
    begin
    x:=x1+68; y:=y0+120; MoveTo(x, y);
    x:=x1+68; y:=y0+78; LineTo(x, y);
    x:=x1+110; y:=y0+78; LineTo(x, y);
    x:=x1+110; y:=y0+114; LineTo(x, y);
    x:=x1+80; y:=y0+114; LineTo(x, y);
    x:=x1+80; y:=y0+90; LineTo(x, y);
    x:=x1+98; y:=y0+90; LineTo(x, y);
    x:=x1+98; y:=y0+102; LineTo(x, y);
    x:=x1+92; y:=y0+102; LineTo(x, y);
    x:=x1+92; y:=y0+96; LineTo(x, y);
    x:=x1+86; y:=y0+96; LineTo(x, y);
    x:=x1+86; y:=y0+108; LineTo(x, y);
    x:=x1+104; y:=y0+108; LineTo(x, y);
    x:=x1+104; y:=y0+84; LineTo(x, y);
    x:=x1+74; y:=y0+84; LineTo(x, y);
    x:=x1+74; y:=y0+120; LineTo(x, y);
    x:=x1+116; y:=y0+120; LineTo(x, y);
    x1:=x1+48;
    end;
    end;

    procedure BigCircle(x, y, r:integer);
    var
    i, x1, y1, r1, r2, r3:integer;
    begin
    r1:=67;
    r2:=60;
    r3:=7;
    x1:=trunc(1.95*r1);
    y1:=wh-3*r1;
    for i:=1 to 6 do
    begin
    Circle(x1, y1, r1);
    Circle(x1, y1, r2);
    Circle(x1, y1, r3);
    x1:=x1+r1+r3;
    end;
    end;

    begin
    Rectangle1(x, y);
    Rectangle2(x, y);
    PerimetrCircle(x, y, r);
    Meandr(x, y);
    BigCircle(x, y, r);
    end.

  20. Helene

    program N13_6;{орнаменты}
    uses
    GraphABC;
    const
    z=50;
    var
    ww,wh, a, b, r, r2, r3, c: integer;
    Procedure Ramka (x1, y1, m, n: integer); //Прямоугольник (координаты левого верхнего угла и длина ширины, высоты)
    var
    x2, y2, x, y: integer;
    begin
    x2:=x1+m;
    y2:=y1+n; // координаты правого нижнего угла
    { Нижняя и верхняя сторона: }
    for x := x1 to x2 do begin //здесь изменяется x
    PutPixel(x, y1, clBlack);
    PutPixel(x, y2, clBlack)
    end;
    { Левая и правая сторона: }
    for y := y1 to y2 do begin //здесь изменяется y
    PutPixel(x1, y, clBlack);
    PutPixel(x2, y, clBlack)
    end;
    end;
    Procedure Krugi (x1, y1: integer); //круги, которые идут по рамке (координаты первого круга)
    begin
    b:=ww-a;
    repeat
    DrawCircle(x1, y1, r);
    x1:=x1+r;
    until x1>=b;
    b:=wh-a;
    x1:=x1-r;
    repeat
    DrawCircle(x1, y1, r);
    y1:=y1+r;
    until y1>=b;
    b:=a;
    y1:=y1-r;
    repeat
    DrawCircle(x1, y1, r);
    x1:=x1-r;
    until x1<=b;
    b:=a;
    x1:=x1+r;
    repeat
    DrawCircle(x1, y1, r);
    y1:=y1-r;
    until y1<=b;
    end;
    Procedure Krugi2 (x1, y1: integer);
    var
    i: integer;
    begin
    for i:= 1 to 10 do
    begin
    DrawCircle(x1, y1, r);
    DrawCircle(x1, y1, r2);
    DrawCircle(x1, y1, r3);
    x1:=x1+(r3+r);
    end;
    end;
    Procedure Sp(x, y: integer);
    begin
    a:=z;
    MoveTo(x,y);
    begin
    y:=y-a;
    LineTo(x,y);
    a:=a-6;
    x:=x+a;
    LineTo(x,y);
    a:=a-6;
    y:=y+a;
    LineTo(x,y);
    a:=a-6;
    x:=x-a;
    LineTo(x,y);
    a:=a-6;
    y:=y-a;
    LineTo(x,y);
    a:=a-6;
    x:=x+a;
    LineTo(x,y);
    a:=a-6;
    y:=y+a;
    LineTo(x,y);
    a:=a-8;
    x:=x-a;
    LineTo(x,y);
    end;
    end;
    Procedure Sp2(x,y: integer);
    var
    x1, y1, i: integer;
    begin
    for i:= 1 to c-1 do
    begin
    x1:=x+(z+3)*i;
    y1:=y;
    Sp(x1,y1);
    end;
    end;
    Procedure Sp3 (x, y: integer);
    begin
    a:=z-3;
    MoveTo(x,y);
    begin
    x:=x-a;
    LineTo(x,y);
    a:=a-3;
    y:=y-a;
    LineTo(x,y);
    a:=a-11;
    x:=x+a;
    LineTo(x,y);
    a:=a-7;
    y:=y+a;
    LineTo(x,y);
    a:=a-6;
    x:=x-a;
    LineTo(x,y);
    a:=a-7;
    y:=y-a;
    LineTo(x,y);
    a:=a-6;
    x:=x+a;
    LineTo(x,y);
    a:=a-1;
    y:=y+a;
    LineTo(x,y);
    end;
    end;
    Procedure Sp4(x,y: integer);
    var
    x1, y1, i: integer;
    begin
    for i:= 1 to c-1 do
    begin
    x1:=x+(z+3)*i;
    y1:=y;
    Sp3(x1,y1);
    end;
    end;
    Procedure Spiral(x,y:integer); // начало координат спирали(нижний левый угол)
    var
    x1: integer;
    begin
    Sp(x,y);
    Sp2(x,y);
    x1:=x+z+3;
    Sp3(x1,y);
    Sp4(x1,y);
    end;

    begin
    //2 квадрата,создающие рамку
    begin
    ww:=WindowWidth;
    wh:=WindowHeight;
    Ramka(2, 2, ww-4, wh-4); //внешний квадрат рамки
    Ramka(62, 62, ww-124, wh-124); //внутренний квадрат рамки
    end;
    //круги в рамке по периметру
    begin
    a:=27;
    r:=20;
    Krugi (30, 30);
    end;
    //разновеличинные круги внутри рисунка
    begin
    r:=5;
    r2:=33;
    r3:=38;
    Krugi2 (130, 270);
    end;
    //спирали
    begin
    c:=8; // c — количество витков спирали
    Spiral (110,200);
    end;
    end.

  21. Helene

    program N13_7b;{домик, солнышко движется по небу}
    uses
    GraphABC;
    var
    a: integer;
    Procedure Dom (x,y: integer); //левый нижний угол дома
    var
    P:array of Point;
    P1:array of Point;
    P2:array of Point;
    P3:array of Point;
    begin
    {стены}
    SetLength(P,4); //количество вершин многоугольника массива P
    SetPenWidth(3);
    SetPenColor(clBlue);
    SetBrushColor(clYellow);
    p[0].x:=x; p[0].y:=y;
    p[1].x:=x; p[1].y:=y-250;
    p[2].x:=x+200; p[2].y:=y-250;
    p[3].x:=x+200; p[3].y:=y;
    Polygon(P);

    {крыша}
    SetLength(P1,3);
    SetPenWidth(3);
    SetPenColor(clBlue);
    SetBrushColor(clBrown);
    p1[0].x:=x+100; p1[0].y:=y-400;
    p1[1].x:=x; p1[1].y:=y-250;
    p1[2].x:=x+200; p1[2].y:=y-250;
    Polygon(P1);

    {дверь}
    SetLength(P2,4);
    SetPenWidth(1);
    SetPenColor(clBlue);
    SetBrushColor(clBrown);
    p2[0].x:=x+15; p2[0].y:=y;
    p2[1].x:=x+15; p2[1].y:=y-160;
    p2[2].x:=x+85; p2[2].y:=y-160;
    p2[3].x:=x+85; p2[3].y:=y;
    Polygon(P2);

    {окно}
    SetLength(P3,4);
    SetPenWidth(1);
    SetPenColor(clBlue);
    SetBrushColor(clRed);
    p3[0].x:=x+115; p3[0].y:=y-125;
    p3[1].x:=x+115; p3[1].y:=y-210;
    p3[2].x:=x+175; p3[2].y:=y-210;
    p3[3].x:=x+175; p3[3].y:=y-125;
    Polygon(P3);
    Line(x+115,y-168, x+175, y-168);
    Line(x+145,y-168, x+145, y-125);
    end;
    Procedure Solnce (x, y:integer);//центр солнца
    var
    n, i, x1, y1, x2, y2, r, r1, r2, r3, z: integer;
    a,a1: real;
    P:array of Point;
    begin
    r:=50;//радиус солнца
    r1:=r+5;//радиус круга начала лучиков
    r2:=r1+55;//радиус круга конца коротких лучиков
    r3:=r1+70;//радиус круга конца длинных лучиков
    SetPenWidth(3);
    SetPenColor(clBlue);
    SetBrushColor(clOrange);
    Circle(x,y,r);
    SetPenWidth(2);
    SetPenColor(clOrange);
    n:=50; // кол-во лучиков
    a1:=360/n;
    a:=a1;
    z:=1;

    for i:= 1 to n div 2 -1 do
    begin
    x1:= x+round(r1*cos(a));
    y1:= y+round(r1*sin(a));
    x2:= x+round(r2*cos(a));
    y2:= y+round(r2*sin(a));
    a:=a+a1;
    MoveTo(x1,y1);
    LineTo(x2,y2);
    z:=z+1;
    x1:= x+round(r1*cos(a));
    y1:= y+round(r1*sin(a));
    x2:= x+round(r3*cos(a));
    y2:= y+round(r3*sin(a));
    a:=a+a1;
    MoveTo(x1,y1);
    LineTo(x2,y2);
    end;
    end;
    begin
    Dom(50,470);
    repeat
    a:=350;
    repeat
    Solnce (a,120);//центр солнца
    sleep(100);
    ClearWindow;
    Dom(50,470);
    a:=a+5;
    until a>=750;
    until false;
    end.

Добавить комментарий