| 
| 
 | Вопрос # 3 774/ вопрос открыт / | 
 |  Как построить луч "это я знаю" и отразить его от двух и более сторон в зависимости от длинны луча:1) Определить начало луча: X,Y
 2) Начиная от позиции начала "движете" переменной
 X:=X+cos;
 Y:=Y+sin;
 , пока не:
 А - не вылезем за пределы формы
 Б - длина луча не станет равной = MaxLineLenght
 3) рисуем линию
 4) если условие Б то exit;
 5) рекрусивно вызываем себя, передав в качестве параметров X,Y конца линии и 180-Y если пересекаем по сторонам и 90-Y если по потолку/дну.
 К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса) 
|  |   Вопрос задал: Alexey6522 (статус: 1-ый класс)Вопрос отправлен: 15 февраля 2010, 18:02
 Состояние вопроса: открыт, ответов: 1.
 |  Ответ #1. Отвечает эксперт: Егор Здравствуйте, Alexey6522!На форму кидаем:
 1) Метка (Label - отображать туда информацию о пройденном расстоянии)
 2) Кнопка (Button) - очистка графика
 3) Компонент SpinEdit (на вкладке Samples) - будет отображать максимальную длину линии
 4) Самый главный компонент - PaintBox - на нём всё и будет рисоваться
 
 В принципе, единственным реально нужным компонентом является PaintBox. Впрочем, можно и без него обойтись - рисовать прямо на канве формы.
 
 Теперь пишем код - новые поля к объекту формы и обработчики нажатий на кнопку и PaintBox:
 
 ...
type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
...
  private
    count : integer;             // количество точек
    x1, y1, x2, y2 : integer;    // координаты точек
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  count:=0;               // изначально ни одна точка не выбрана
  SpinEdit1.Value:=10000; // макс длина - 10 тыс
  Label1.Caption:='';     // очистим метку
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin  //очистка графика
  PaintBox1.Repaint;   // очистка
  count:=0;            // выбранных точек нет
  label1.Caption:='';  // очистка метки
end;
 
procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  s, smax, ds, alpha, dx, dy, sx : extended;
  ymax, xmax : integer;
begin  // обработчик нажатия мыши
  SpinEdit1.Enabled:=false; // сначала запретим изменять длину линии
  Button1.Enabled:=false;   // и запретим чистить рисунок
  if count=0 then   // если это первая выбранная точка, то...
  begin
    x1:=X; y1:=Y;   // запоминаем координаты точки
    count:=1;       // запоминаем, что одна точка уже выбрана
    exit;           // больше пока делать ничего не нужно - выходим
  end;
  xmax:=PaintBox1.Width-1;   // максимальное значение по х
  ymax:=PaintBox1.Height-1;  // максимальное значение по у
  smax:=SpinEdit1.Value;     // считываем максимальную длину линии
  x2:=X; y2:=Y;              // запоминаем координаты второй точки
  if (x2=x1) or (y2=y1) then // вертикальные/горизонтальные линии
       exit;                 // строить не будем - не интересно :)))
 
  s:=0;                      // пока длина всех линий =0
  dx:=x2-x1; dy:=y2-y1;
  ds:=sqrt( dx*dx + dy*dy ); // длина участка между двумя выбранными точками
  alpha:=arctan( dy/dx );    // вычислим угол
  if dx<0 then alpha:=alpha+pi;       // скорректируем угол
 
  // начертим линию (жирную, красную) между двумя выбранными точками:
  PaintBox1.Canvas.Pen.Width:=3;
  PaintBox1.Canvas.Pen.Color:=clRed;
  PaintBox1.Canvas.MoveTo(x1,y1);
  PaintBox1.Canvas.LineTo(Round(x1+ds*cos(alpha)), Round(y1+ds*sin(alpha)) );
 
  // остальные линии будут тонкими
  PaintBox1.Canvas.Pen.Width:=1;
  while s<smax do   // пока длина меньше максимальной, будем рисовать
  begin
    // вычислим координаты точки, которая находится на расстониии 30 на луче,
    // выходящем под углом альфа из точки 1 (х1, у1)
    x2:=Round(x1+30*cos(alpha));
    y2:=Round(y1+30*sin(alpha));
    PaintBox1.Canvas.MoveTo(x1,y1);     // сделаем активной точку 1
 
    // у точки 2 пересчитаем координаты
    if y2>y1 then y2:=ymax else y2:=0;
    if x2>x1 then x2:=xmax else x2:=0;
 
    // с учётом известной координаты у2 (или ноль, или уmax) найдём
    // координату х:
    sx:=x1+(y2-y1)/tan(alpha);
    // если эта координата лежит на границе прямоугольника, то она корректна
    // и её и будем присваивать переменной х2 вместо старого значения
    if (sx<xmax) and (sx>0) then
        x2:=Round(sx)
    else // значит, sx некорректна, а значит, у2 некорректно - пересчитываем:
        y2:=Round(y1+(x2-x1)*(tan(alpha)));
 
    // всё, на этом этапе имеем нормальные координаты х2 и у2
    PaintBox1.Canvas.Pen.Color:=Random(clWhite); // задаём случайный цвет линии
    PaintBox1.Canvas.LineTo(x2,y2);              // рисуем линию
    Application.ProcessMessages;                 // точно нарисуем
 
    // определим новый угол, с учётом отражения:
    if (x2>=xmax) or (x2<=0) then
       alpha:=pi-alpha;
    if (y2>=ymax) or (y2<=0) then
       alpha:=-alpha;
 
    // рассчитаем длину нарисованного отрезка:
    dx:=x2-x1; dy:=y2-y1;
    ds:=sqrt( dx*dx + dy*dy );
    x1:=x2;
    y1:=y2;
    // прибавим длину отрезка к общей длине:
    s:=s+ds;
    // выведем длину линии:
    Label1.Caption:=IntToStr('s=' + Round(s));
  end; // конец выводу линии
  count:=0;   // говорим, что ни одна точка не выбрана
  SpinEdit1.Enabled:=true;  // разрешим изменять макс длину
  Button1.Enabled:=true;    // разрешим чистить рисунок
end;
 
end.Работа программы - щёлкаем на PaintBox в одном месте, затем - другом.
 
 ...а если установить значение SpinEdit-a равным примерно так миллиону (или больше), а размер PaintBox-a на весь экран, то можно потихоньку медитировать....
 :))))))))))))))
 
|  | Ответ отправил: Егор (статус: 10-ый класс)Время отправки: 17 февраля 2010, 09:34
 Оценка за ответ: 5
 Комментарий к оценке: Вот это класс!!!!! Мне понравилось |  
 Мини-форум вопросаВсего сообщений: 10; последнее сообщение — 16 февраля 2010, 15:14; участников в обсуждении: 5. 
|   | Ерёмин А.А. (статус: *Администратор), 15 февраля 2010, 18:48 [#1]:А в чём вопрос? |  
|   | Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 19:35 [#2]:Как построить луч "это я знаю" и отразить его от двух и более сторон в зависимости от длинны луча |  
|   | Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 19:37 [#3]:смотреть прикрепленный файл |  
|   | Егор (статус: 10-ый класс), 15 февраля 2010, 19:54 [#4]:картинка, конечно.... шедевр  ))))) не так луч будет отражаться, не так. ну да ладно.
 
 я не понял, в чём вопрос?
 что ты хочешь узнать? вроде же сам всё написал, что делать надо, если тот или иной случай:
 
 Цитата (Alexey6522): рекрусивно вызываем себя, передав в качестве параметров X,Y конца линии и 180-Y если пересекаем по сторонам и 90-Y если по потолку/дну. 
 в чём сложность?
 или просто хвастаемся, типа "это я знаю"?
  )) Опасайтесь багов в приведенном выше коде; я только доказал корректность, но не запускал его.— Donald E. Knuth.
 |  
|   | Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 20:00 [#5]:мне код нужен )))) Хоть что нибудь, что может направить в нужное русло
 |  
|   | IlluminatI (статус: 2-ой класс), 15 февраля 2010, 22:14 [#6]:юзай главный закон оптики - угол падения равен углу отражения =) 
 напиши в чем именно проблема, тогда и помогать будут, а то я так и не понял, что тебе нужно
   |  
|   | Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 22:20 [#7]:Я знаю этот закон, мне нужна подсказка как это реализовать в программе, а не в теории. Как говорят, теорию подгоняют под практику, ведь они всегда отличались  )))) |  
|   | vlsavkin (статус: 2-ой класс), 16 февраля 2010, 14:50 [#8]:Вечером пример накидаю, самому интересно написать, если еще актуально |  
|   | Егор (статус: 10-ый класс), 16 февраля 2010, 15:05 [#9]:я тоже заинтересовался  только фигня какая-то получается - не всегда луч отражается
  иногда проходит насквозь...
 результат потом выложу
 Опасайтесь багов в приведенном выше коде; я только доказал корректность, но не запускал его.— Donald E. Knuth.
 |  
|   | Alexey6522 (статус: 1-ый класс), 16 февраля 2010, 15:14 [#10]:Конечно актуально, я над эти голову ломаю и sin и cos использовал, блин, а на уроке физике и геометрии все так просто было, взял транспортир и начертил |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |