Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 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 Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: 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

Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 19:35 [#2]:

Как построить луч "это я знаю" и отразить его от двух и более сторон в зависимости от длинны луча
Alexey6522

Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 19:37 [#3]:

смотреть прикрепленный файл
Егор

Егор (статус: 10-ый класс), 15 февраля 2010, 19:54 [#4]:

картинка, конечно.... шедевр :))))))
не так луч будет отражаться, не так. ну да ладно.

я не понял, в чём вопрос?
что ты хочешь узнать? вроде же сам всё написал, что делать надо, если тот или иной случай:

Цитата (Alexey6522):

рекрусивно вызываем себя, передав в качестве параметров X,Y конца линии и 180-Y если пересекаем по сторонам и 90-Y если по потолку/дну.


в чём сложность?
или просто хвастаемся, типа "это я знаю"? :)))
Опасайтесь багов в приведенном выше коде; я только доказал корректность, но не запускал его.
— Donald E. Knuth.
Alexey6522

Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 20:00 [#5]:

мне код нужен ))))
Хоть что нибудь, что может направить в нужное русло
IlluminatI

IlluminatI (статус: 2-ой класс), 15 февраля 2010, 22:14 [#6]:

юзай главный закон оптики - угол падения равен углу отражения =)

напиши в чем именно проблема, тогда и помогать будут, а то я так и не понял, что тебе нужно :)
Alexey6522

Alexey6522 (статус: 1-ый класс), 15 февраля 2010, 22:20 [#7]:

Я знаю этот закон, мне нужна подсказка как это реализовать в программе, а не в теории. Как говорят, теорию подгоняют под практику, ведь они всегда отличались ))))
vlsavkin

vlsavkin (статус: 2-ой класс), 16 февраля 2010, 14:50 [#8]:

Вечером пример накидаю, самому интересно написать, если еще актуально
Егор

Егор (статус: 10-ый класс), 16 февраля 2010, 15:05 [#9]:

я тоже заинтересовался :)
только фигня какая-то получается - не всегда луч отражается :)
иногда проходит насквозь...
результат потом выложу
Опасайтесь багов в приведенном выше коде; я только доказал корректность, но не запускал его.
— Donald E. Knuth.
Alexey6522

Alexey6522 (статус: 1-ый класс), 16 февраля 2010, 15:14 [#10]:

Конечно актуально, я над эти голову ломаю и sin и cos использовал, блин, а на уроке физике и геометрии все так просто было, взял транспортир и начертил

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:55
Выполнено за 0.03 сек.