Помощь - Поиск - Пользователи - Календарь
Полная версия: Крутящийся тор
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
SlazeR
Прошу помощи. Мне задали сделать тор крутящийся вокруг осей X, Y, Z. Я прочитал статью по 3д графике Altair'а и сделал, но вот проблема - у меня не только тор крутится, но и оси. То есть после поворотов по оси Z и к примеру Y, начинаешь крутить по Х, то он уже крутит под каким-то углом... Объяснить, как то очень сложно. Я говорил с Altair'ом по ICQ, он понял но так ничего и не выслал и не подсказал. Ещё раз прошу помощи, реально закон жизни и смерти, без этого курсовика мне не закрыть сессию.

Сама прога:

Program RotateTor;

uses
  Crt, Graph, Obj;

var
  GraphicDriver, GraphicMode, ErrorCode: Integer;
  rotate_x, rotate_y, rotate_z: Integer;
  Xan, Yan, Zan: Real;
  key: Char;
  Tor: TTor;

begin
  GraphicDriver:=InstallUserDriver('EGAVGA', @GraphicDriver);
  GraphicMode:=1;
  InitGraph(GraphicDriver, GraphicMode, '');
  ErrorCode:=GraphResult;
  if ErrorCode <> grOk then
  begin
    Writeln('Graphics error:');
    Writeln(GraphErrorMsg(ErrorCode));
    Writeln('Program aborted...');
    Halt(1);
  end;
  rotate_x:=0;
  rotate_y:=0;
  rotate_z:=0;
  Xan:=0;
  Yan:=0;
  Zan:=0;
  Tor.Create(GetMaxX div 2, GetMaxY div 2, 0, 80, 20);
  Tor.Draw(0,0,0);
  Flip;
  repeat
    if keypressed then
    begin
      key:=readkey;
      if key='z' then
        begin
	  if rotate_z=0 then
            rotate_z:=-1;
	  if rotate_z=1 then
            rotate_z:=0;
        end;
      if key='a' then
        begin
	  if rotate_z=0 then
            rotate_z:=1;
	  if rotate_z=-1 then
            rotate_z:=0;
        end;
      if key=#0 then
      begin
        key:=ReadKey;
        if key=#75 then
        begin
	  if rotate_y=0 then
            rotate_y:=-1;
	  if rotate_y=1 then
            rotate_y:=0;
        end;
        if key=#77 then
        begin
	  if rotate_y=0 then
            rotate_y:=1;
	  if rotate_y=-1 then
            rotate_y:=0;
        end;
        if key=#72 then
        begin
	  if rotate_x=0 then
            rotate_x:=-1;
	  if rotate_x=1 then
            rotate_x:=0;
        end;
        if key=#80 then
        begin
	  if rotate_x=0 then
            rotate_x:=1;
	  if rotate_x=-1 then
            rotate_x:=0;
        end;
      end;
    end;
    if rotate_y=-1 then
      if (Yan > 0) and (Yan <= 360) then
        Yan:=Yan-10
      else
        Yan:=350;
    if rotate_y=1 then
        if (Yan >= 0) and (Yan < 350) then
          Yan:=Yan+10
        else
          Yan:=0;
    if rotate_x=-1 then
      if (Xan > 0) and (Xan <= 360) then
        Xan:=Xan-10
      else
        Xan:=350;
    if rotate_x=1 then
      if (Xan >= 0) and (Xan < 350) then
        Xan:=Xan+10
      else
        Xan:=0;
    if rotate_z=-1 then
      if (Zan > 0) and (Zan <= 360) then
        Zan:=Zan-10
      else
        Zan:=350;
    if rotate_z=1 then
      if (Zan >= 0) and (Zan < 350) then
        Zan:=Zan+10
      else
        Zan:=0;
    Tor.Draw(Xan, Yan, Zan);
    OutTextXY(5, 5, 'To rotate on x press up, down cursor key. X Angle: '+IntToStr(Xan));
    OutTextXY(5, 20, 'To rotate on y press left, right cursor key. Y Angle: '+IntToStr(Yan));
    OutTextXY(5, 35, 'To rotate on z press "a", "z" key button. Z Angle: '+IntToStr(Zan));
    Flip;
    delay(3000);
  until key=#13;
  closegraph;
end.



Модуль Obj:

unit Obj;

interface

uses
  Graph;

const
  Rad=Pi/180;
  Page: Word=0;

  function IntToStr(I: Real): String;
  procedure Flip;

type
  TPixel = object
  private
    x, y, z: Integer;
    screen_x, screen_y, screen_z: Real;
  public
    constructor Create(x_, y_, z_: Integer);
    destructor Destroy; virtual;

    procedure Calc(Xan, Yan, Zan: Real); virtual;
    procedure Draw(Xan, Yan, Zan: Real); virtual;
  end;

  TTor = object(TPixel)
  private
    r, r_center: Real;
  public
    constructor Create(x_, y_, z_: Integer; r_, r_center_: Real);
    destructor Destroy; virtual;

    procedure Calc(Xan, Yan, Zan: Real); virtual;
    procedure Draw(Xan, Yan, Zan: Real); virtual;

    function GetRadius: Real;
  end;

implementation

  function IntToStr;
  var
    S: string[11];
  begin
    Str(I:3:0, S);
    IntToStr := S
  end;

  procedure Flip;
  begin
    SetVisualPage(Page);
    Page:=1-Page;
    SetActivePage(Page);
  end;

  constructor TPixel.Create;
  begin
    x:=x_;
    y:=y_;
  end;

  destructor TPixel.Destroy;
  begin
    {no code}
  end;

  procedure TPixel.Calc;
  var
    x_temp, y_temp, z_temp: Real;
  begin
    y_temp:=screen_y*cos(Xan*Rad)-screen_z*sin(Xan*Rad);
    z_temp:=screen_y*sin(Xan*Rad)+screen_z*cos(Xan*Rad);
    screen_y:=y_temp;
    screen_z:=z_temp;
    x_temp:=screen_x*cos(Yan*Rad)-screen_z*sin(Yan*Rad);
    z_temp:=screen_x*sin(Yan*Rad)+screen_z*cos(Yan*Rad);
    screen_x:=x_temp;
    screen_z:=z_temp;
    x_temp:=screen_x*cos(Zan*Rad)-screen_y*sin(Zan*Rad);
    y_temp:=screen_x*sin(Zan*Rad)+screen_y*cos(Zan*Rad);
    screen_x:=x_temp;
    screen_y:=y_temp;
  end;

  procedure TPixel.Draw;
  begin
    ClearDevice;
    Calc(Xan, Yan, Zan);
    putpixel(x,y,5);
  end;

  constructor TTor.Create;
  var
    i: Integer;
  begin
    x:=x_;
    y:=y_;
    z:=z_;
    r:=r_;
    r_center:=r_center_;
  end;

  destructor TTor.Destroy;
  begin
    {no code}
  end;

  procedure TTor.Calc;
  var
    x_temp, y_temp, z_temp: Real;
  begin
    y_temp:=screen_y*cos(Xan*Rad)-screen_z*sin(Xan*Rad);
    z_temp:=screen_y*sin(Xan*Rad)+screen_z*cos(Xan*Rad);
    screen_y:=y_temp;
    screen_z:=z_temp;
    x_temp:=screen_x*cos(Yan*Rad)-screen_z*sin(Yan*Rad);
    z_temp:=screen_x*sin(Yan*Rad)+screen_z*cos(Yan*Rad);
    screen_x:=x_temp;
    screen_z:=z_temp;
    x_temp:=screen_x*cos(Zan*Rad)-screen_y*sin(Zan*Rad);
    y_temp:=screen_x*sin(Zan*Rad)+screen_y*cos(Zan*Rad);
    screen_x:=x_temp;
    screen_y:=y_temp;
  end;

  procedure TTor.Draw;
  var
    i, Angle: Integer;
    r_temp: Real;
  begin
    ClearDevice;
    r_temp:=(r-r_center);
    for Angle:=0 to 90 do
    begin
      screen_x:=r_temp*(cos(Angle*4*Rad)-sin(Angle*4*Rad));
      screen_y:=r_temp*(sin(Angle*4*Rad)+cos(Angle*4*Rad));
      screen_z:=z;
      Calc(Xan, Yan, Zan);
      SetColor(5);
      circle(x+round(screen_x), y+round(screen_y), round(r_temp/2));
    end;
  end;

  function TTor.GetRadius;
  begin
    GetRadius:=r;
  end;

end.

volvo
Хорошо, а что ТЫ хочешь? Чтобы у тебя тор крутился ТОЛЬКО относительно одной оси? Тогда сбрасывай остальные в 0...

Ты объясни, чего добиваешься?
Гость
Смотри. представь оси X, Y, Z. Они раположены перепендикулярно друг другу, как и должно быть. так вот я хочу, чтобы если к примеру вокруг Х прокрутил на 90 градусов, то когда крутишь вокруг Y тор крутится вокруг Y той.
То есть тор, независимо на какой угол повернут по любой оси должен крутиться вокруг начальных.
Блин словами объяснить очень сложно, но Altair понял... хотя кто знает, может он меня так мягко отослал blink.gif
volvo
Ну, не знаю, по-моему у тебя так и крутится, как ты хочешь... Очень трудно что-либо сказать - все мелькает страшно blink.gif
SlazeR
А у меня нормально, попробуй delay поставить больше =)
По началу да нормально, кроме Y. А вот после поворотов по Z, начинает и X. Просто оси поворачиваются, а мне надо чтобы они стояли в начальном положении и тор крутился вокруг них =)
Lapp
Цитата(SlazeR @ 21.02.2006 1:31) *

По началу да нормально, кроме Y. А вот после поворотов по Z, начинает и X. Просто оси поворачиваются, а мне надо чтобы они стояли в начальном положении и тор крутился вокруг них =)

Я бегло посмотрел - извини, если невпопад отвечу. Мне кажется, что ты накапливаешь (складываешь) все углы по каждой отдельной оси, а потом производишь повороты - сначала вокруг одной оси на суммарный угол, потом вокруг другой, потом вокруг третьей. Это, конечно, неправильно, поскольку группа поворотов вокруг осей некоммутативна (иначе говоря, нельзя менять порядок слагаемых). Эффект должен получиться, по моим прикидкам, примерно такой, как ты говоришь.

Если я прав - напиши сюда, подумаем, как исправить..
SlazeR
Цитата(lapp @ 21.02.2006 9:43) *

Я бегло посмотрел - извини, если невпопад отвечу. Мне кажется, что ты накапливаешь (складываешь) все углы по каждой отдельной оси, а потом производишь повороты - сначала вокруг одной оси на суммарный угол, потом вокруг другой, потом вокруг третьей. Это, конечно, неправильно, поскольку группа поворотов вокруг осей некоммутативна (иначе говоря, нельзя менять порядок слагаемых). Эффект должен получиться, по моим прикидкам, примерно такой, как ты говоришь.

Если я прав - напиши сюда, подумаем, как исправить..


У меня углы задаются отдельно для каждой оси: переменные rotate_x, rotate_y, rotate_z, они передаются в процедурки отрисовки, и там в процедуру высчета углов =) Если ты не это имел ввиду, то поясни конкрейтней. Вот ща думаю на идейкой, как нибудь связать с невидимыми осями...
Lapp
Цитата(SlazeR @ 21.02.2006 23:07) *

У меня углы задаются отдельно для каждой оси: переменные rotate_x, rotate_y, rotate_z, они передаются в процедурки отрисовки, и там в процедуру высчета углов =) Если ты не это имел ввиду, то поясни конкрейтней. Вот ща думаю на идейкой, как нибудь связать с невидимыми осями...

Я имел в виду вот, что.
Допустим, ты повернул (кнопками) на угол 30 вокруг Y. После этого повернул на угол 90 вокруг X.
Как ты теперь строишь изображение?
Если ты в процессе построения...
1. берешь начальное положение,
2. сначала производишь второй поворот (на 90 вокруг X),
3. а потом первый
- то это в корне неверно и приведет к тому, что ты называешь "вращение осей". Мне показалось, что ты делаешь именно так. Я не прав?

Чтобы получить правильное изображение, нужно последовательно выполнять все повороты в том порядке, в котором они происходили. Типа: 30 вокруг Y, 90 вокруг Х, 20 вокруг Z, 10 вокруг Х, 10 вокруг Y....
В соответствии с этим, нельзя суммировать повороты по одной оси, если между ними были повороты вокруг другой. Накапливать (суммировать) можно только углы последовательных поворотов вокруг одной и той же оси.

Выходов, соответственно, два:
1. Держать в памяти всю цепочку углов и каждый раз вертеть от начала. Этот метод требует очень много расчетов на каждом шагу, особенно если прога работает долго.
2. После каждого преобразования изменять начальное положение, делая текущее начальным. Этот метод работает быстро, но более подвержен накоплению ошибок вычислений.
SlazeR
Вообщем я сегодня сдал крутящийся тор преподу так =) Огромное спасибо volvo и lapp'у за желание помочь. С прогой можете делать, что хотите =) Может я в свободное время доделаю и вышли нормальный вариант ;-)

Ещё раз спасибо и удачи.
Lapp
Цитата(SlazeR @ 23.02.2006 2:28) *

Вообщем я сегодня сдал крутящийся тор преподу так =) Огромное спасибо volvo и lapp'у за желание помочь. С прогой можете делать, что хотите =) Может я в свободное время доделаю и вышли нормальный вариант ;-)

Поздравляю!
Но проблема действительно интересная и поучительная, жаль, что не доделали.. Сомнительно, чтоб ты вернулся к сданной проге.. Время покажет! smile.gif
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.