|
Вопрос # 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 использовал, блин, а на уроке физике и геометрии все так просто было, взял транспортир и начертил
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|