![]() |
1. Заголовок темы должен быть информативным. В противном случае тема удаляется ...
2. Все тексты программ должны помещаться в теги [code=pas] ... [/code].
3. Прежде чем задавать вопрос, см. "FAQ", если там не нашли ответа, воспользуйтесь ПОИСКОМ, возможно такую задачу уже решали!
4. Не предлагайте свои решения на других языках, кроме Паскаля (исключение - только с согласия модератора).
5. НЕ используйте форум для личного общения, все что не относится к обсуждению темы - на PM!
6. Одна тема - один вопрос (задача)
7. Проверяйте программы перед тем, как разместить их на форуме!!!
8. Спрашивайте и отвечайте четко и по существу!!!
![]() |
Гersh |
![]()
Сообщение
#1
|
![]() Новичок ![]() Группа: Пользователи Сообщений: 31 Пол: Мужской Реальное имя: Игорь Репутация: ![]() ![]() ![]() |
Текст задачи:
"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 - 9.05.2006 14:08 Прикрепленные файлы ![]() ![]() |
![]() ![]() |
Lapp |
![]()
Сообщение
#2
|
![]() Уникум ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 6 823 Пол: Мужской Реальное имя: Лопáрь (Андрей) Репутация: ![]() ![]() ![]() |
Значит, все-таки в процедуре Border в строке dy:=Sqrt(dl2-dx*dx)*dy/Abs(dy)под корнем - отрицательное число... Моя ошибка, да. Конечно, сравнение (двумя строчками выше) нужно делать по модулю.. if Abs(s2)>=1.0 then dy:=-dy else begin { <-- здесь добавлена функция Abs } А чисто физически теперь ведь все нормально? Более-менее да.. Но я бы рекомендовал тебе делать те сравнения (новую и старую позицию с координатой границы в условии вызова процедуры Border) в реальных координатах, а не в координатах экрана Вообще все нужно делать в них, а в экранные координаты переводить только при выводе точки. (См. также замечание в конце поста). Кстати, а ты не объяснишь как твоя процедура действует? Как оно вообще просчитывается физчески и геометрически и как именно реализуется в алгоритме. Да это же все очевидно.. Когда обнаруживается пересечение границы, нужно изменить направление луча. 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. Видишь - все просто до безобразия.. -------------------- я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой |
![]() ![]() |
![]() |
Текстовая версия | 1.08.2025 18:38 |