Помощь - Поиск - Пользователи - Календарь
Полная версия: Реализовать программу, строящую двумерное изображение заданной фигуры.
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
GrukhvinEV
Реализовать программу, строящую двумерное изображение заданной фигуры. Необходимо выполнить 2D преобразования и отобразить новое положение фигуры.
TarasBer
Задаёшь массив из 8 точек.
Для поворота на 45 градусов для каждой точки делаешь так:

x_нов := (x+y)/sqrt(2)
y_нов := (x-y)/(sqrt(2)

Для относительно оси икс заменяешь все x на -x
GrukhvinEV
Спасибо! Да мне бы всю картину решения задачи увидеть это мой первый опыт работы над графикой =))
TarasBer

uses Graph;
var
gd,gm: integer;
begin
gd:=0; // автоматический выбор режима
gm:=0;
InitGraph(gd,gm,''); // файлы BGI должны быть в одной папке с программой
Line(GetMaxX div 4, GetMaxY div 4, GetMaxX * 3 div 4, GetMaxY * 3 div 4); // нарисовали линию
ReadLN; // ждём нажатия ентера
CloseGraph;
end.

GrukhvinEV
Угу вот за это спасибо! Щас время нет, но завтро думаю разбирусь! Еще вот вопросик есть,
InitGraph(gd,gm,''); // файлы BGI должны быть в одной папке с программой 

у меня вообще файлов с расширением bgi нету, пользуюсь FreePascal 2.4.2 однако все работает нормально, так и должно быть ?
IUnknown
Да, при использовании FPC это нормально. Его модулю Graph не нужны дополнительные драйверы.

P.S. Обновись, вышла уже 2.4.4 давно, чего на старой версии сидеть?
GrukhvinEV
Спасибо. Посдскажите пожалуйста изменить положение осей x и y. Всю голову уже сломал.
У нас ось:
_______________ x
|
|
|
|
y

А чтоб удобно было строить надо сделать их как всегда, как в школе было!
TarasBer
x переводишь в GetMaxX div 2+x
y переводишь в GetMaxY div 2-y
GrukhvinEV
Наверно даже надо писать за место y GetMaxY/2-y, а за место х GetMaxX/2-x. чтоб экран на 4 части разбить. Верно ?
TarasBer
> Наверно даже надо писать за место y GetMaxY/2-y, а за место х GetMaxX/2-x. чтоб экран на 4 части разбить.
> Верно ?

Не понял, я чем ваш вариант отличается от моего, кроме того, что вы добавили две ошибки?
/2 не нужно, нужно div 2, вещественные вычисления привлекать не надо.
икс нужно не вычитать, а прибавлять, потому что ориентацию по иксу менять не надо
GrukhvinEV
А точно, извини просто уже крыша едет от pascala =))

Добавлено через 13 мин.
Короче я уже сбился походу с верного пути, мне кажется что эту программу можно намного проще написать чем она у меня есть, подскажите где что можно упрастить и что исправить. Спасибо!

Program Zadanie_1;
uses Graph, Crt;
const k=7; n=1;
z:array [0..k,0..n] of
integer= ((320,000),(427,160),(640,240),(427,320),
(320,480),(213,320),(000,240),(213,160));
var
gd,gm :integer;
t :integer;
x1,y1,x2,y2 :integer;
xc,yc :real;
begin
gd:=detect;
initgraph(gd,gm,'');
xc:=GetMaxX/640/2;
yc:=GetMaxY/480/2;
t:=0;
while t<=k do begin
x1:=round(-z[0+t,0]*xc+GetMaxX/2);
y1:=round(-z[0+t,1]*yc+GetMaxY/2);
x2:=round(-z[(1+t) mod 8,0]*xc+GetMaxX/2);
y2:=round(-z[(1+t) mod 8,1]*yc+GetMaxY/2);
line(x1,y1,x2,y2);

inc(t);
end;
readln;
t:=0;
while t<=k do begin
x1:=round((-z[0+t,0]*xc+GetMaxX/2-z[0+t,1]*yc+GetMaxY/2)/sqrt(2));
y1:=round((-z[0+t,0]*xc+GetMaxX/2+z[0+t,1]*yc+GetMaxY/2)/sqrt(2));
x2:=round((-z[(1+t) mod 8,0]*xc+GetMaxX/2-z[(1+t) mod 8,1]*yc+GetMaxY/2)/sqrt(2));
y2:=round((-z[(1+t) mod 8,0]*xc+GetMaxX/2+z[(1+t) mod 8,1]*yc+GetMaxY/2)/sqrt(2));
setcolor(2);
line(x1,y1,x2,y2);
inc(t);
end;
readln;
t:=0;
while t<=k do begin
x1:=round((-z[0+t,0]*xc+GetMaxX/2-z[0+t,1]*yc+GetMaxY/2)/sqrt(2));
y1:=round((-z[0+t,0]*xc+GetMaxX/2+z[0+t,1]*yc+GetMaxY/2)/sqrt(2));
x2:=round((-z[(1+t) mod 8,0]*xc+GetMaxX/2-z[(1+t) mod 8,1]*yc+GetMaxY/2)/sqrt(2));
y2:=round((-z[(1+t) mod 8,0]*xc+GetMaxX/2+z[(1+t) mod 8,1]*yc+GetMaxY/2)/sqrt(2));
setcolor(14);
line(-x1,y1,-x2,y2);
inc(t);
end;
readln;
closegraph;
end.

TarasBer
Да не, всё чётко.
Кроме того, что вместо

t:=0;
while t<=k do begin
...
inc(t);
end;


Нагляднее и короче так:

for t :=0 to k do begin
...
end;



Но можно и ещё попридираться.

Вот например:


const k=7; n=1;
z:array [0..k,0..n] of


Сейчас k и n несут очень мало геометрического смысла, они что-то типа "номер максимального элемента" или "количество точек минус один". Не лучше ли сразу сделать их количеством точек?

Предпочтительнее так:

const k=8; n=2;
z:array [0..k-1, 0..n-1] of


Перебор от 0 до эн минус 1 - это стандартно в программировании.

Что ещё можно найти.
А, ты вот k раз считаешь две точки, по сути у тебя все точки считаются по два раза.

Короче, можно оптимизировать.
У тебя пока так:

t:=0;
while t<=k do begin
x1:=round((-z[0+t,0]*xc+GetMaxX/2-z[0+t,1]*yc+GetMaxY/2)/sqrt(2));
y1:=round((-z[0+t,0]*xc+GetMaxX/2+z[0+t,1]*yc+GetMaxY/2)/sqrt(2));
x2:=round((-z[(1+t) mod 8,0]*xc+GetMaxX/2-z[(1+t) mod 8,1]*yc+GetMaxY/2)/sqrt(2));
y2:=round((-z[(1+t) mod 8,0]*xc+GetMaxX/2+z[(1+t) mod 8,1]*yc+GetMaxY/2)/sqrt(2));
setcolor(14);
line(-x1,y1,-x2,y2);
inc(t);
end;


Я бы заранее посчитал k раз новые точки, и потом уже обращался к готовым точкам, не считая каждую 2 раза.


// считаем координаты
for t:=0 to k do begin
scrx[t] :=round((-z[t,0]*xc+GetMaxX/2-z[t,1]*yc+GetMaxY/2)/sqrt(2));
scry[t] :=round((-z[t,0]*xc+GetMaxX/2+z[t,1]*yc+GetMaxY/2)/sqrt(2));
end;
// рисуем ломаную
for t := 0 to k do begin
t1 := (t+1) mod (k+1); // никаких mod 8, если по смыслу у нас k!
setcolor(14);
line(-scrx[t ],scry[t ],
-scrx[t1],scry[t1]);
end;


Ещё вроде есть готовая процедура для рисования ломаных.
IUnknown
Цитата
Ещё вроде есть готовая процедура для рисования ломаных.
Есть, DrawPoly называется, в справке есть пример ее использования.
GrukhvinEV
Цитата(TarasBer @ 15.12.2011 13:33) *

Задаёшь массив из 8 точек.
Для поворота на 45 градусов для каждой точки делаешь так:

x_нов := (x+y)/sqrt(2)
y_нов := (x-y)/(sqrt(2)

Для относительно оси икс заменяешь все x на -x

Ошибка тут, верно будет вот так:
x_нов := (x-y)/sqrt(2)
y_нов := (x+y)/(sqrt(2)
И относительно оси икс надо менять y на -y

Добавлено через 4 мин.
Вот написал я программу дня за 3 )))) Зато сколько возможностей )))
Program Zadanie_2;
uses graph;
function arccos(r:real):real;
begin
if r=0 then arccos:=pi/2
else arccos:=arctan(sqrt(1-sqr®)/r)+pi*byte(r<0)
end;
procedure Figura(x11,y11,x111,y111,d,m,u,c:integer);
{x11,y11 - Є®®а¤Ё­ вл 業ва  ­®ўле ®бҐ©, x111,y111-Є®®а¤Ё­ вл 業ва  дЁЈгал
®в­®бЁвҐ«м­®Ј® ­®ў®Ј® 業ва  ®бҐ©, d - а ¤Ёгб дЁЈгал, m - ¤Ґ«ЁвҐ«м а ¤Ёгб 
дЁЈгал зҐаҐ§ Є ¦¤лҐ 90 Ја ¤гб®ў,u - гЈ®« Ї®ў®а®в  ®в­®бЁвҐ«м­® ­®ў®© ®бЁ,
c - 梥в дЁЈгал}
var
i,d1,a,x1,y1:integer;
l,f:real;
p:array[1..9] of pointtype;
begin
d1:=d div m;
a:=u;
x1:=x11+x111;
y1:=y11-y111;
//write(y11,' ',y1);
l:=(x111)/sqrt(sqr(x111)+sqr(y111));
f:=arccos(l);
x1:=round(x11+sqrt(sqr(x111)+sqr(y111))*cos(u*pi/180+f));
if (y111>=0) then
y1:=round(y11-sqrt(sqr(x111)+sqr(y111))*sin(u*pi/180+f))
else
y1:=round(y11+sqrt(sqr(x111)+sqr(y111))*sin(u*pi/180+f));
for i:=1 to 8 do
begin
if i mod 2=0 then
begin
p[i].x:=x1+round(d1*cos(a*pi/180));
p[i].y:=y1-round(d1*sin(a*pi/180));
end
else
begin
p[i].x:=x1+round(d*cos(a*pi/180));
p[i].y:=y1-round(d*sin(a*pi/180));
end;
a:=a+45;
end;
p[9].x:=p[1].x;
p[9].y:=p[1].y;
SetColor©;
drawpoly(9,p);
end;
var gd,gm,xc,yc:integer;
begin
gd:=0;
initgraph(gd,gm,'');
xc:=getmaxX div 2;
yc:=getmaxY div 2;
line(0,yc,getmaxX,yc);
line(xc,0,xc,getmaxY);
outtextXY(xc+100,50,'Press Enter');
Figura(xc,yc,100,100,80,3,0,15);
readln;
Figura(xc,yc,100,100,80,3,45,10);
readln;
Figura(xc,yc,100,-100,80,3,45,5);
readln
end.

GrukhvinEV
Вот, мб кому пригодится!
Program Zadanie_2; {Имя программы}
uses graph; {Команда подключения модулей}
function arccos(r:real):real; {Так как в языке pascal отсутствует оператор arccos, создадим функцию нахождения arccos через arctan. Данная функция потребуется для определения начального угла поворота относительно новой системы координат}
begin
if r=0 {Если переменная r равна нулю, то переходим к выполнению оператора после then, иначе выполняем оператор после else}
then
arccos:=pi/2 {Присваиваем функции arсcos значение pi/2, где pi – число пи. Расчет ведем в радианах}
else
arccos:=arctan(sqrt(1-sqr®)/r)+pi*byte(r<0) {Находим значение функции arcos через arctan}
end;
procedure Figura(x11,y11,x111,y111,d,m,u,c:integer);
{Процедура построения фигуры с параметрами: x11,y11 – координаты осей для новой системы координат, x111,y111- координаты центра построения фигуры относительно новой системы координат
, d – радиус фигуры, m – отношение радиуса d к радиусу d1, u – угол сдвига фигуры относительно начала новой системы координат, c – цвет фигуры, для наглядности преобразований}
var {Секция описания переменных}
i,d1,a,x1,y1:integer; {Переменные целого типа, где i – порядковый номер точки, d1- радиус каждой второй точки, х1,y1 – координаты центра фигуры относительно начальной системы координат}
l,f:real;{Переменные вещественного типа, где l – расстояние от начала новой системы координат до центра фигуры, f – угол между осью x` и отрезком l, т.е. начальный угол на котором расположен центр фигуры относительно начала новой системы координат}
p:array[1..9] of pointtype; {Массив из 9 элементов имеющих тип точка}
begin
d1:=d div m;{Переменной d1 присвоить значение d деленного на m без остатка, т.е. находим радиус для каждой второй точки через радиус фигуры поделенного на заданное значение m}
a:=u;{Присваиваем вспомогательной переменной a значение u (угол сдвига фигуры относительно начала новой системы координат)}
// Находим координаты центра фигуры относительно начальной системы координат, переменным x1,y1 присваиваем найденные значения
x1:=x11+x111;
y1:=y11-y111;
// Находим расстояние от начала новой системы координат до центра фигуры
l:=(x111)/sqrt(sqr(x111)+sqr(y111));
// Находим угол между осью х` и отрезком l
f:=arccos(l);
//Находим центр построения фигуры относительно начальной системы координат, с учетом угла сдвига фигуры относительно начала новой системы координат
x1:=round(x11+sqrt(sqr(x111)+sqr(y111))*cos(u*pi/180+f));
//Следующая операция необходима для правильного нахождения центра фигуры относительно новой системы координат при отрицательных значениях y111
if (y111>=0) {Если переменная y111>=0 то переходим к выполнению оператора после then, иначе выполняем оператор после else}
then
//Находим значение координаты центра фигуры по оси y` при положительной переменной y111
y1:=round(y11-sqrt(sqr(x111)+sqr(y111))*sin(u*pi/180+f))
else
//Находим значение координаты центра фигуры по оси y` при отрицательной переменной y111
y1:=round(y11+sqrt(sqr(x111)+sqr(y111))*sin(u*pi/180+f));
for i:=1 to 8 do {Для всех i от 1 до 8 выполняем оператор после do}
//Находим координаты точек для построения фигуры с учетом того, что точка, имеющая четный порядковый номер должна находится на расстоянии d1 от цетра фигуры
begin
if i mod 2=0 then {Если при делении количества точек остаток равен нулю, то выполняем оператор после then, иначе выполняем оператор после else}
begin
p[i].x:=x1+round(d1*cos(a*pi/180));
p[i].y:=y1-round(d1*sin(a*pi/180));
end
else
begin
p[i].x:=x1+round(d*cos(a*pi/180));
p[i].y:=y1-round(d*sin(a*pi/180));
end;
a:=a+45; {Т.к. точки построения фигуры находятся под углом 45 градусов к друг другу, в конце каждого цикла увеличиваем угол на 45 градусов}
end;
//Присваиваем координаты последней точки девятому элементу массива, это необходимо для замыкания фигуры.
p[9].x:=p[1].x;
p[9].y:=p[1].y;
SetColor©; {задаем цвет линий фигуры}
drawpoly(9,p); {Строим фигуру, т.е. последовательно соединяем все наши точки отрезками}
end;
var
gd,gm,xc,yc:integer;
begin
gd:=0; {Тип драйвера адаптера определяется автоматически, значение gm после команды gd:=detect или gd:=0 определяется автоматически}
initgraph(gd,gm,''); {Инициализация графики. В кавычках указывается путь к программе драйверу с расширением bgi, т.к. мы используем FreePascal у нас нет необходимости указывать путь к дополнительным драйверам, т.к. он в них не нуждается}
//Определяем разрешающую способность для текущего графического режима функциями, возвращающими максимальные значения координат экрана
xc:=getmaxX div 2;
yc:=getmaxY div 2;
//Рисуем по центру экрана экран линии, т.е. оси соответствующие новым системам координат
line(0,yc,getmaxX,yc);
line(xc,0,xc,getmaxY);
//Выводим на экран надпись 'Press Enter', для информативности
outtextXY(xc+100,50,'Press Enter');
// С помощью процедуры Figura строим требуемую фигуру.
Figura(xc,yc,100,100,80,3,0,15); {Начальное положение фигуры}
readln;
Figura(xc,yc,100,100,80,3,45,10); {Поворачиваем фигуру относительно центра новой системы координат на 45 градусов}
readln;
Figura(xc,yc,100,-100,80,3,45,5);{Отражение относительно оси х`}
readln
end.

TarasBer
> Ошибка тут, верно будет вот так:
> x_нов := (x-y)/sqrt(2)
> y_нов := (x+y)/(sqrt(2)

А, ну может быть, это тоже поворот на 45, но в другую сторону.

> И относительно оси икс надо менять y на -y

А, ну да. Я прочитал как "вдоль оси икс".

gm:=0 тоже проинициализируй

> Figura(xc,yc,100,100,80,3,0,15); {Начальное положение фигуры}

Тут привязка к фиксированному разрешению, лучше пересчитать через GetMaxX, GetMaxY
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.