IPB
ЛогинПароль:

> Прочтите прежде чем задавать вопрос!

1. Заголовок темы должен быть информативным. В противном случае тема удаляется ...
2. Все тексты программ должны помещаться в теги [code=pas] ... [/code], либо быть опубликованы на нашем PasteBin в режиме вечного хранения.
3. Прежде чем задавать вопрос, см. "FAQ", если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Паскаля (исключение - только с согласия модератора).
5. НЕ используйте форум для личного общения, все что не относится к обсуждению темы - на PM!
6. Одна тема - один вопрос (задача)
7. Проверяйте программы перед тем, как разместить их на форуме!!!
8. Спрашивайте и отвечайте четко и по существу!!!

> Преломление и полное внутренне отражение
сообщение
Сообщение #1


Новичок
*

Группа: Пользователи
Сообщений: 31
Пол: Мужской
Реальное имя: Игорь

Репутация: -  0  +


Текст задачи:
"197. Экран разделен горизонтальной линей, изображающей границу раздела воды и воздуха. Изобразите траекторию светового луча, выходящего из произвольной точки и распространяющего по законам геометрической оптики. Считайте, что от границ луч отражается зеркально, учтите также возможность полного внутреннего отражения. (Это должна быть анимация – луч должен лететь из произвольной (заданной) точки под произвольным (заданным) углом. – Авт.)"

А Вот, собственно программа... Только в ней нехватет основной процедуры Border:
Код

program zadacha197; {Гершенович Игорь}
Uses Crt, Graph, Gersh;
const
     n1 = 1;
     n2 = 1.33;
     X0 : Integer = 100;
     Y0 : Integer = 100;
     a : Real = 45;
     pause : Integer = 1000;
var
   x, y : Integer;
   x1, y1, dx, dy : Real;

procedure Env;
var i, x, y : Integer;
begin
     SetColor (15);
     Rectangle (0,0,GetMaxX,GetMaxY);
     SetColor (11);
     Line (0,GetMaxY div 2, GetMaxX, GetMaxY div 2);
     Randomize;
     for i:=1 to 100 do PutPixel (Random(GetMaxX),Random(GetMaxY div 2),7);
     SetColor (3);
     for i:=1 to 50 do begin
         x:=Random(GetMaxX);
         y:=Random(GetMaxY div 2)+GetMaxY div 2;
         Line (x,y,x+5,y);
     end;
end; {Env}

procedure Border;
begin
     if dy=n1/n2 then if dx>0 then a:=3*Pi/2 else a:=Pi/2 else
        begin
            {????????????????????????????????
                а сдесь должон быть расчет угла после преломления
                (если я, конечно правильно сделал критический угол)
             ??????????????????????????????? }
        end;
end; {Border}

procedure adge;
begin
     if (x=GetMaxX) or (x=0) then dx:=-dx;
     if (y=GetMaxY) or (y=0) then dy:=-dy;
end; {adge}

procedure control;
var ch : char;
begin
     repeat Ch:= Readkey  until Ch<>#0;
     case Ord (Ch) of
          43 : if pause>1 then dec(pause,100);
          45 : inc(pause,100);
          27 : halt;
     end;
end; {control}

BEGIN
     GraphBegin('');
     Env;
     x1:=X0; y1:=Y0;
     a:=a*Pi/180;
     dx:=cos(a);
     dy:=sin(a);
     repeat
           PutPixel (x,y,14);
           Delay (pause);
           PutPixel (x,y,15);
           x1:=x1+dx;
           y1:=y1+dy;
           x:=Round(x1);
           y:=Round(y1);
           MoveTo (x,y);
           if GetPixel(x,y)=11 then Border;
           if GetPixel(x,y)=15 then adge;
           if KeyPressed then control;
     until KeyPressed;
END.

Помоите эту процедуру написать!
(В программе используется мой модуль - Gersh (процедура GraphBegin('')))

Сообщение отредактировано: Гersh -


Прикрепленные файлы
Прикрепленный файл  GERSH.PAS ( 652 байт ) Кол-во скачиваний: 260
Прикрепленный файл  GERSH.PAS ( 652 байт ) Кол-во скачиваний: 253
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
 
 Ответить  Открыть новую тему 
Ответов
сообщение
Сообщение #2


Уникум
*******

Группа: Пользователи
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


Цитата(volvo @ 10.05.2006 21:07) *

Значит, все-таки в процедуре Border в строке
	   dy:=Sqrt(dl2-dx*dx)*dy/Abs(dy)
под корнем - отрицательное число...

Моя ошибка, да. Конечно, сравнение (двумя строчками выше) нужно делать по модулю..
    if Abs(s2)>=1.0 then dy:=-dy else begin  { <-- здесь добавлена функция Abs }
dx:=dl*s2;
dy:=Sqrt(dl2-dx*dx)*dy/Abs(dy)

Цитата(Гersh @ 10.05.2006 16:11) *

А чисто физически теперь ведь все нормально?

Более-менее да.. Но я бы рекомендовал тебе делать те сравнения (новую и старую позицию с координатой границы в условии вызова процедуры Border) в реальных координатах, а не в координатах экрана Вообще все нужно делать в них, а в экранные координаты переводить только при выводе точки. (См. также замечание в конце поста).
Цитата(Гersh @ 10.05.2006 16:11) *

Кстати, а ты не объяснишь как твоя процедура действует? Как оно вообще просчитывается физчески и геометрически и как именно реализуется в алгоритме.

Да это же все очевидно.. Когда обнаруживается пересечение границы, нужно изменить направление луча.

1. определяем текущее направление (синус угла, s1). Для этого сначала высчитываем длину вектора перемещения dl (dl2 - это ее квадрат, сохраняем ее, поскольку пригодится в будущем) и вычисляем синус как катет на гипотенузу: s1=dx/dl .

2. по знаку dy определяем, куда мы движемся: из среды с n1 в n2 или из n2 в n1. Соответственно результирующий коэффициент преломления будет либо n2/n2, либо n1/n2. Домножаем его на синус входного угла и получаем синус выходного s2 (закон преломления).

3. Если синус получается по модулю больше 1, то вместо преломления делаем полное внутреннее отражение.

4. Если модуль синуса меньше 1, то по нему рассчитываем новое dx. Модуль dy находим по т.Пифагора (используем сохраненный квадрат перемещения), а знак dy делаем такой же, как был (домножаем на dy и делим на Abs(dy) ).

Замечание: величину dl я оставляю постоянной, что не совсем верно с точки зрения физики. Если считать, что скорость рисования луча представляет собой скорость распространения света в текущей среде, то желательно при переходе из одной среды в другую делить ее на коэффициент преломления. То есть
dl:=dl/n
Тут n равно либо n2/n1, либо n1/n2, как сказано выше. Соответственно, запоминать dl2 в этом случае не имеет смысла, поскольку все равно пересчитывать.

Далее луч летит с новыми dx и dy. Видишь - все просто до безобразия..


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

Сообщений в этой теме


 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 29.04.2024 1:55
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name