Программирование >>  Рекурсивные объекты и фрактальные узоры 

1 ... 4 5 6 [ 7 ] 8 9 10 ... 43


struct TMirror {

Idouble X, y; Idouble angle, k; Idouble b;

Idouble y above, y below; крайние ординаты зеркала bool prev iter reflected; отражало ли это зеркало

на предыдущей итерации

int pos; int length;

номер отразившего зеркала длина зеркала

vector <TMirror> mirrors; TLaser laser;

массив зеркал лазер

Функция-обработчик события OnClick кнопки B Initialize заполняет объекты laser и mirrors данными, считанными из полям Initialize:

void {

.fastcall TF Main::B InitializeClick(TObject *Sender)

очистка экрана

(рисование будет осуществляться прямо по канве формы) F Main->Canvas->FillRect(Rect(0, О, Width, Height));

считывание в поток нулевой строки из ТМешо; istringstream is(Il Initialize->Lines->Strings[0].c str());

инициализация лазера

is laser.х;

is laser.у;

is laser.angle;

ось ординат направлена вниз

laser.angle = (-1)*laser.angle*M PI/180.;

составляем уравнение прямой лазера

laser.к = tan(laser.angle);

laser.b = laser.у - laser.k*laser.x;

заполняем массив зеркал и выводим зеркала синим цветом F Main->Canvas->Pen->Color = clBlue; mirrors.clear(); TMirror mirr;

for (int i = 1; i < M Initialize->Lines->Count; i++)

istringstream is(M Initialize->Lines->Strings[i].c str())

is mirr.x;

is mirr.y;

is mirr.angle;

ось ординат направлена вниз

mirr.angle = -mirr.angle*M PI/180.;

is mirr.length;

mirr.к = tan(mirr.angle);

mirr.b = mirr.y - mirr.k*mirr.x;

рисуем зеркала

F Main->Canvas->MoveTo(mirr.x - mirr.length*cos(mirr.angle), mirr.y below = mirr.y - mirr.length*sin(mirr.angle))

F Main->Canvas->LineTo(mirr.x + mirr.length*cos(mirr.angle), mirr.y above = mirr.y + mirr.length*sin(mirr.angle))

mirr.prev iter reflected = false;

mirrors.push back(mirr);

laser.у - 4, laser.у + 4);

графически обозначим позицию и направление движения луча лазера

F Main->Canvas->Pen->Color = clRed; F Main->Canvas->Ellipse(laser.X - 4,

laser.X + 4, F Main->Canvas->Pen->Style = psDot; F Main->Canvas->MoveTo(laser.X, laser.у); F Main->Canvas->LineTo(laser.X + 50*cos(laser.angle),

laser.у + 50*sin(laser.angle)); F Main->Canvas->Pen->Style = psSolid;

Обработчик события OnClick кнопки B Step выводит очередной отрезок лазерного луча.

И зеркало, и луч представляют собой участки прямых, заданных линейными уравнениями Y = КХ + и У = КХ + В. Эти прямые либо пересекаются, и абсцисса точки пересечения равна (В, - B2)/(Kj - Kj), либо параллельны (К = Kj).

Существование точки пересечения прямых ещё не гарантирует встречи луча с зеркалом, потому что эта точка может лежать за пределами зеркала.

typedef long double Idouble;

struct TLaser {

Idouble X, y;

отрезок задается выражением вида у = к*х + b Idouble angle, к; Idouble b;



зеркало


лазер

Рнс 2.5. Проверка на 1ум9надпежносгъ зеркалу точки пересечения гцммых

Функция GetlntersectionPoint(int indx, TMirrors mirror) проверяет, попадает ли лазер в зеркало mirrors [ indx], записывает точку пересечения в поля х и у переданного объекта mirror и возвращает true в случае успеха:

bool GetlntersectionPoint(int indx, TMirror& mirror) {

mirror.x = (laser.b - mirrors [indx] .b) / (mirrors [indxl . к - laser.к); mirror .у = mirror. x*laser .к + laser-:b; return (mirror.у <= mirrors[indx].y below && mirror.у >= mirrors[indx].y above);

Эта йроверка не учитывает, во-первых, направление лазера (так, вызов GetlntersectionPoint О для зеркала, расположенного за лазерной пушкой, вернёт true), а во-вторых, что лазер изменит направление, встретившись с первым же зеркалом на своём пути.

Поиск ближайшего зеркала - задача простая. Определив набор точек пересечения, можно просто выбрать точку с ближайшей к лазеру абсциссой (этот критерий достаточен,-поскольку ордината точки пропорциональна её абсциссе - луч лазера ведь лежит на прямой линии).

С направлением же дело обстоит несколько сложнее, но здесь можно немного схитрить.

Важность зачёта направления луча иллюстрирует рис. 2.6. Если просто выбрать ближайшее к точке последнего отражения лазера зеркало, луч прожжёт только что отразившее его зеркало насквозь и устремится вверх.


Рис 2.6. Учат напрваленмя пуча лазера при поиске точек соприкосновения

Теперь - обещанная хитрость (там, где кончается наука - математика, начинается искусство - программирование). Всё, что надо сделать - это продолжить луч на небольшой отрезок и выяснить, приближается луч к зеркалу или удаляется от него. Если зеркало выбрано правильно, луч, конечно же, будет двигаться в его сторону.

Функция isDirectionCorrect (const TMirrors m) возвращает true, если зеркало m расположено по ходу луча:

bool isDirectionCorrect(const TMirror& m) {

return (sqrt( pow((laser.x + cos(laser.angle) - m.x), 2) + pow((laser.y + sin(laser.angle) - m.y), 2)) < sqrt( pow((laser.X - m.x), 2) + pow((laser.y - m.y), 2) ));

Здесь луч продолжается на отрезок единичной длины (можно продолжить и на меньшую длину, если зеркала расположены очень близко друг к другу). Затем расстояния между зеркалом и каждой из двух точек лазера (исходный конец луча, продолженный конец луча), вычисленные по формуле R = sqrt((X, - ХУ + (Y, - Yj)), сравниваются между собой.

К тому же при решении системы уравнений не учитывается направление лазерного луча.

Простую проверку на попадание лазера в зеркало можно организовать, сравнивая ординату найденной точки пересечения прямых с ординатами крайних точек зеркала (рис. 2.5).



TMirror ш; int i ;

static int rem index; номер зеркала, отразившего предыдущий

отрезок

bool allow - false; разрешение на отражение луча

собираем зеркала, которые луч пересекает

for (i = 0; i < mirrors.size(); i++)

если зеркалу можно отражать и уравнения имеют общую точку

it(mirrors 111.prev itGr reflccted && GctlntersectionPoint(i, m)) {

m.pos = i; запомнить позицию зеркала в

глобальном массиве

vm.push back(m); поместить зеркало во временный массив

F Main->Canvas->Ellipse(т.х - 4, т.у - 4, т.х + 4, т.у + 4);

if (vm.sizeO > 0) {

хотя бы одно зеркало пересе- кается прямой луча

на следующей итерации это зеркало уже будет доступно mirrors(rem index].prev iter reflected = false;

не забываем сбросить значение rem index Idouble delta, d;

for (delta = fabs(vm[rem index = i = 0].x - laser.x);

i < vm.sizeO; i + + )

ищем ближайшее удовлетворяющее направлению движения луча

if ( (d-= fabs(vm[i].x - laser.х)) <= delta &&

CorrectDirection(vm[i]))

delta = d;

rem index = i; запоминаем его номер во временном массиве

allow = true;/

if (allow) {

F Main->Canvas->Pen->Color = clRed; F Main->Canvas->MoveTo(laser.X, laser.у);

После того, как стало ясно, от какого зеркала отражать, выясним теперь куда, собственно, отражать. Как уже говорилось, угол отражения луча света в однородной среде равен злу падения. Для горизонтального зеркала формула очевидна: если угол падения равен а, то угол отражения вычисляется по формуле: а = 2?! - а.

Для угла mirror angle в диапазоне [О, п/2] угол очередного отрезка луча равен:

laser angle = 2*М Р1 - laser angle + 2*mirror angle

А для угла в диапазоне [п/2, п]:

laser angle = -laser angle - 2*(M PI - mirror angle)

Поскольку все зеркала в нашей системе покрыты отражающим слоем с обеих сторон, рассматривать углы наклона в диапазонах [п, Зп/2] и [Зтс/2,2п] не требуется. Таким образом, функция отражения луча будет выглядеть так:

void Reflect(Idoublefc laser angle, Idouble mirror angle) {

строки /*!*/, 1*2*I, I нужны для того, чтобы математически

/ / полученные формулы не изменили своего вида из-заразнонаправленности математической и экранной осей ординат /*1*/ laser angle = -laser angle; 1*2*1 mirror angle = -inirror angle;

if (inirror angle >= 0 && inirror angle <= M PI 2)

laser angle = (2*K PI - laser angle + 2*inirror angle) ;

else if (inirror angle >= M PI 2 && mirror angle <= M PI)

laser angle = (-laser angle - 2* (]У1 Р1 - mirror angle)) ;

else

Application->MessageBoxA(He соблюдён диапазон ,

Неверное значение*, МВ ОК);

return;

/*3*/ laser angle = -laser angle; }

Теперь займёмся основной функцией - вычерчиванием очередного отрезка луча:

void fastcall TF Main::B StepClick(TObject *Sender)

зеркала, уравнения прямых которых имеют общие точки с прямой лазера vector <TMirror> vm;



1 ... 4 5 6 [ 7 ] 8 9 10 ... 43

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика