Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Диметрическая проекция Pascal  (Прочитано 6646 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Viwwna
Интересующийся

ru
Offline Offline

« : 19-05-2012 10:03 » 

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

Код: (Pascal)
uses Graph,crt;
const                              {объявляю константы}
coord: array[0..6,0..2] of real =  {матрица координат вершин гексаэдра}
 ((60,0,60),
 (85.98,0,45),
 (85.98,0,15),
 (60,0,0),
 (34.02,0,15),
 (34.02,0,45),
 (60,150,30));

side: array[0..11,0..1] of integer = {матрица ребер гексаэдра}  
((0,1),(0,5),(1,2),(2,3),(3,4),(4,5),(0,6),(1,6),(2,6),(3,6),(4,6),(5,6));

pl:array[0..5,0..2] of integer =      {матрица граней гексаэдра}
((0,1,6),(1,2,6),(2,3,6),(3,4,6),(4,5,6),(0,5,6));

MatrOb: array[0..3,0..3] of real =     {обратная матрица видового преобразования}
 ((0.631,0.078,0.784,0),
 (0.452,0.772,-0.452,0),
 (-0.64,0.64,0.64,0),
 (0,0,0,1));

E:array[0..3] of integer = (0,0,-1,0); {вектор с координатами пробной точки}
f:real=45*Pi/180;                      {угол поворота вокруг оси OY}
q:real=35.26*Pi/180;                   {угол поворота вокруг оси OX}

Type st =set of 1..9;                  {объявляю тип множество целых чисел}

{объявляю переменные}
var corner :real;                      {угол поворота вокруг оси OY}
    s: real;                           {вспомогательные переменные}
    sx,sy,sx1,sy1,gd,gm,i,j,p: integer; {вспомогательные переменные}
    coordIz: array[0..6,0..2] of real; {матрица изометрических координат}
    V,V1: array[0..3,0..5] of real;    {матрицы коэффициентов уравнений плоскостей граней гексаэдра – матрица тела}
    N: array[0..1,0..2] of real;       {матрица вектора нормали к плоскости}
    o: array[0..3] of real;            {вектор координат точки, лежащей внутри гексаэдра}
    L: array[0..7] of integer;         {матрица координат вершин изометрических плоскостей гексаэдра – используется в функции Паскаля FillPoly}
    Hidden : st;                       {множество для хранения номеров невидимых вершин гексаэдра}
    Zn:array[0..6] of integer;         {вектор хранения знаков плоскостей граней}
    tX,tZ:real;                        {вспомогательные переменные}
    flag: Boolean;                     {переменная логического типа, определяет как проходит гексаэдр – за или перед осью OY}

{процедура нахождения изометрических координат гексаэдра}
Procedure Izometr;
Begin
   tX:=coordIz[0,0];             {запоминаем координату нулевой точки предыдущего местоположения гексаэдра}
   for p:=0 to 6 do              {в цикле от 0 до 6 находим изометрические координаты}
   begin
        coordIz[p,0]:=coord[p,0]*cos(f)+coord[p,2]*sin(f);
        coordIz[p,2]:=0;
        coordIz[p,1]:=coord[p,0]*sin(f)*sin(q)+coord[p,1]*cos(q)-coord[p,2]*cos(f)*sin(q);
   end;
{если координаты нулевой точки предыдущего хода меньше, чем текущего, то
переменной флаг присваиваем значение false, иначе - true}
   if tX<coordIz[0,0] then flag:=false else flag:=true;
End;

{процедура рисования контура гексаэдра} procedure draw(color:byte);
begin
    for p:=0 to 11 do         {в цикле от 0 до 11 соединяем точки вершин гексаэдра по номерам ребер. Точки строим относительно середины экрана}
    begin
       {если вершина не принадлежит множеству Hidden, т.е. если она видимая}        if (not (side[p,0] in Hidden)) and (not (side[p,1] in Hidden)) then
       begin
          sx:=round(coordIz[side[p,0],0]+getmaxx div 2);
          sx1:=round(coordIz[side[p,1],0]+getmaxx div 2);
          sy:=round(getmaxy div 2-coordIz[side[p,0],1]);
          sy1:=round(getmaxy div 2-coordIz[side[p,1],1]);
          setcolor(color);               {задаем цвет рисования ребер}
          line(SX,SY,sx1,sy1);           {проводим линии ребер}
     end;
end;
end;

{процедура поворота вокруг оси OY} procedure rotateOY;
begin
   for i:=0 to 6 do    {в цикле от 0 до 6 находим новые координаты гексаэдра}
   begin
     tX:= coord[i,0] * COS(corner) + coord[i,2] * SIN(corner);
     tZ:=-coord[i,0] * SIN(corner) + coord[i,2] * COS(corner);
     coord[i,0]:=tX;
     coord[i,2] :=tZ;
  end;
end;

{процедура, реализующая алгоритм Робертса} procedure Roberts;
begin
   o[0]:=0;
   o[1]:=0;
   o[2]:=0;
   o[3]:=1;
 {путем усреднения координат вершин находим координаты точки, лежащей внутри
 гексаэдра}
  for i:=0 to 2 do  
   begin
      for j:=0 to 6 do o[i]:=o[i]+coord[j,i];
      o[i]:=o[i]/7;
   end;

   for p:=0 to 5 do {в цикле от 0 до 5 ищем уравнения плоскостей граней гексаэдра}
   begin
      {поиск нормали к плоскости}   for i:=0 to 1 do
         for j:=0 to 2 do
            N[i,j]:=coord[pl[p,i+1],j]-coord[pl[p,i],j];
      {находим коэффициенты a,b,c,d уравнения плоскости}       V[0,p]:=N[0,1]*N[1,2]-N[0,2]*N[1,1];  
      V[1,p]:=-(N[0,0]*N[1,2]-N[0,2]*N[1,0]);
      V[2,p]:=N[0,0]*N[1,1]-N[0,1]*N[1,0];
      V[3,p]:=-V[0,p]*coord[p,0]-V[1,p]*coord[p,1]-V[2,p]*coord[p,2];
      s:=0;
{проверяем знак уравнения плоскости умножением уравнения плоскости на точку О}       for i:=0 to 3 do s:=s+o[i]*V[i,p];
{если скалярное произведение меньше нуля, то меняем знак уравнения плоскости}       if s<0 then
         for i:=0 to 3 do V[i,p]:=-V[i,p];
   end;
   {перемножаем обратную матрицу видового преобразования на матрицу тела}    for i:=0 to 3 do            
       for j:=0 to 5 do          
       begin                    
         s:=0;                  
         for p:=0 to 3 do
             s:=s+MatrOb[i,p]*V[p,j];
             V1[i,j]:=s;       {V1 – итоговая матрица тела}
       end;
    {вычисляем скалярное произведение (s) пробной точки на матрицу тела}
    for p:=0 to 5 do
    begin
      s:=0;
      for i:=0 to 3 do s:=s+V1[i,p]*E[i];
      {заполняем вектор Zn, хранящий знаки s}       if s=0 then Zn[p]:=0;
      if s<0 then Zn[p]:=-1;
      if s>0 then Zn[p]:=1;
   end;
   Hidden:=[];            {обнуляем множество}
{если два рядом стоящие элемента множества отрицательны, то данная вершина
невидима – заносим ее номер в множество Hidden}
     for p:=0 to 4 do            
        if (Zn[p]<0) and (Zn[p+1]<0) then
            Hidden:=Hidden+[p+1];
     if (Zn[0]<0) and (Zn[5]<0) then Hidden:=Hidden+[0];
end;

{процедура закраски граней гексаэдра в разный цвет}
Procedure color(col:byte);
Begin
{в цикле ищем координаты изометрических координат каждой грани гексаэдра. Точки
строим относительно середины экрана}
   for j:=0 to 5 do
   begin
     {если вершина не принадлежит множеству Hidden, т.е. если она видимая}      if (not (pl[j,0] in Hidden)) and (not (pl[j,1] in Hidden)) then
     begin
        i:=0;
        for p:=0 to 2 do
        begin
           L[i]:=round(coordIz[pl[j,p],0]+getmaxx div 2);
           L[i+1]:=round(getmaxy div 2-coordIz[pl[j,p],1]);
           if i=0 then
           begin
              L[6]:=round(coordIz[pl[j,p],0]+getmaxx div 2);
              L[7]:=round(getmaxy div 2-coordIz[pl[j,p],1]);
           end;
           i:=i+2;
        end;
{если входящий параметр col равен 0, то закрашиваем грани в разный цвет, иначе
закрашиваем грани цветом фона}
        if col=0 then SetFillStyle(1,j+1) else SetFillStyle(1,0);
        fillPoly(4,L);        {закрашиваем грань}
    end;
  end;
end;

{процедура рисования изометрических осей}
Procedure Axis;
var l:integer;
Begin
   setColor(15);                      {задаем цвет}
   l:=GetMaxY div 2;
   {рисуем ось OY – вертикально вверх}
   line(GetMaxX div 2,GetMaxY div 2,GetMaxX div 2,0);
   {рисуем ось OX – под углом 1200 к оси OY}   line(GetMaxX div 2,GetMaxY div 2,GetMaxX div 2 + round(0.866*l),GetMaxY div 2 + round(0.5*l));
   {рисуем ось OX – под углом -1200 к оси OY}   line(GetMaxX div 2,GetMaxY div 2,GetMaxX div 2 - round(0.866*l),GetMaxY div 2 + round(0.5*l));
   setColor(0);                    
end;

{основная программа} begin
gm:=VgaHi;                      {определяю графический режим}
gd:=detect;                     {определяю графический драйвер}
initgraph(gd,gm,'c:\TP7\BGI');  {инициализируем графику}
corner := 0.05;                 {задаю угол поворота}
{вывожу надпись "y" около оси OY}
OutTextXY(getmaxx div 2 + 10,10,'Y');
{вывожу надпись "x" около оси OX}        
OutTextXY(GetMaxX div 2 + round(0.866*(GetMaxY div 2)) + 10,GetMaxY div 2 + round(0.5*(GetMaxY div 2))-10,'X');
{вывожу надпись "z" около оси OZ}
OutTextXY(GetMaxX div 2 - round(0.866*(GetMaxY div 2))-10,GetMaxY div 2 + round(0.5*(GetMaxY div 2))-10,'Z');

{цикл с постусловием} repeat
   Roberts;                 {вызываю процедуру Roberts}
   Izometr;                 {вызываю процедуру Izometr}
   draw(15);                {вызываю процедуру draw с параметром 15 (белый цвет)}
   Color(0);                {вызываю процедуру color c параметром 0)}
   {если логическая переменная flag равна true, то вызываем процедуру Axis}    if flag=true then Axis;
   delay(5000);             {задержка 5000 мс}
   draw(0);                 {вызываю процедуру draw с параметром 15 (черный цвет)}
   color(1);                {вызываю процедуру color c параметром 1}
   {если логическая переменная flag равна false, то вызываем процедуру Axis}    if flag=false then Axis;
rotateOY;                {вызываем процедуру rotateOY}
until keypressed;           {пока не нажата любая клавиша}
closegraph;                 {закрываем графический режим}
end.
« Последнее редактирование: 19-05-2012 10:08 от viwwna » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 19-05-2012 15:31 » 

viwwna, ага, разбежались твою простыню изучать и за тебя задание делать, да ещё и нахаляву.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Viwwna
Интересующийся

ru
Offline Offline

« Ответ #2 : 19-05-2012 15:38 » 

Dimka, я тогда конкретизирую.....
Интересует, как записать при диметрии угол поворота вокруг оси:
Код: (Pascal)
f:real=45*Pi/180;                      {угол поворота вокруг оси OY}
q:real=35.26*Pi/180;                   {угол поворота вокруг оси OX}

и процедура нахождения диметрических координат фигуры:
Код: (Pascal)
Procedure Izometr;
Begin
   tX:=coordIz[0,0];             {запоминаем координату нулевой точки предыдущего местоположения гексаэдра}
   for p:=0 to 6 do              {в цикле от 0 до 6 находим изометрические координаты}
   begin
        coordIz[p,0]:=coord[p,0]*cos(f)+coord[p,2]*sin(f);
        coordIz[p,2]:=0;
        coordIz[p,1]:=coord[p,0]*sin(f)*sin(q)+coord[p,1]*cos(q)-coord[p,2]*cos(f)*sin(q);
   end;

В данном примере приведена изометрия.
« Последнее редактирование: 19-05-2012 17:29 от viwwna » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 19-05-2012 16:29 » new




Поворачивать ничего не надо - это не изометрия - проецируй: X и Z идут как есть, Y проецируется на X и Z:

X' = X - sin(PI / 4) * Y
Z' = Z - sin(PI / 4) * Y


Причем выражение - sin(PI / 4) можно вынести из формулы (и вычислений) для ускорения работы и для лучшей читаемости.

k = - sin(PI / 4)
X' = X + k * Y
Z' = Z + k * Y

« Последнее редактирование: 19-05-2012 16:39 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines