Министерство общего и профессионального образования Российской Федерации Уфимский государственный авиационный технически...
6 downloads
173 Views
286KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Министерство общего и профессионального образования Российской Федерации Уфимский государственный авиационный технический университет Кафедра технической кибернетики
МЕТОДИЧЕСКИЕ УКАЗАНИЯ для курсового проектирования по курсу "Информатика" для подготовки инженеров по специальностям 210100 "Управление и информатика в технических системах" и 210300 "Роботы и робототехнические системы"
Уфа 1996
2 Составитель: О.В. Трушин УДК 681.3 Методические указания для курсового проектирования по курсу "Информатика" для подготовки инженеров по специальностям 210100 "Управление и информатика в технических системах" и 210300 "Роботы и робототехнические системы" /Уфимск. гос. авиац. техн. ун-т; Сост. О.В. Трушин. Уфа. 1996, - 39 с.
Приведены типовые задания для курсового проектирования с ориентацией на решение основных проблем при составлении и программировании вычислительных и демонстрационно-обучающих алгоритмов. Рассмотрен ряд методик и принципов создания программ с визуализацией, в том числе и динамической, перерабатываемой в программе информации. Приводимые алгоритмы реализованы на языке Turbo-Pascal_7 и могут быть легко адаптированы для других систем программирования. Библ.: 14 наимен.
Рецензенты:
А. Ю. Хасанов М. Е. Сидоров
3
Содержание Стр. Общие сведения .......................................................................... 4 1. Построение графиков функций и траекторий движения .............. 7 1.1. Построение графика функции Y=F(X) с масштабированием по осям координат ..................................................................... 7 1.2. Построение графика функции, заданной в параметрической форме Y=FY( t), X=FX( t) ........................................................ 10 1.3. Построение траекторий движения ............................................. 10 Перечень тем курсового проектирования по разделу № 1 ......... 13 2. Приемы создания динамичных графических образов ................. 14 2.1. Перерисовывание объекта ........................................................ 14 2.2. Плавная модификация контурного изображения ..................... 15 2.3. Мультипликация с запоминанием части экрана ...................... 16 2.4. Мультипликация с чередованием видеостраниц ..................... 18 2.5. Управление движением образа ................................................. 19 Перечень тем курсового проектирования по разделу № 2 .......... 20 3. Численные методы в вычислительных расчетах ........................... 21 3.1. Численное решение уравнений .................................................. 21 3.2 Численный расчет интегралов ................................................... 22 3.3. Сортировка одномерных массивов ........................................... 23 Перечень тем курсового проектирования по разделу № 3 .......... 25 4. Аффинные преобразования координат при моделировании динамики объектов ...................................................................... 26 Перечень тем курсового проектирования по разделу № 4 .......... 40 Список литературы ...................................................................... 41
4 Общие сведения Предлагаемые в пособии задания ориентированы на освоение приемов и методов визуального отображения значимой информации, перерабатываемой в типовых программах. Графика применяется практически во всех серьезных программных разработках, так как позволяет отобразить сущность решаемой задачи и увидеть результаты расчетов в виде чертежей, графиков, иллюстраций в движении. Приводимые ниже алгоритмы реализованы с использованием библиотеки графических функций Borland в среде Turbo-Pascal. Используются следующие типовые графические процедуры и функции: InitGraph(Gd,Gm,'way') - переход к графическому режиму (инициализация графики), где Gd - имя графического драйвера, Gm - номер графического режима монитора , 'way' - дорожка DOS к файлам с графическими драйверами ( * .bgi). Обычно драйверы подключаются в режиме автоопределения используемого монитора ПК. Для этого перед инициализацией графики задается Gd:= Detect (или Gd:= 0). В этом случае по умолчанию устанавливается режим с наибольшим числом точек на экране, а значение параметра "Gm" игнорируется. Номер наибольшего режима для текущего драйвера возвращает функция GetMaxMode. Изменить режим можно процедурой SetGraphMode(Gm). Экран при этом очищается. Разрешающую способность для текущего графического режима можно определить функциями, возвращающими максимальные значения координат экрана: GetMaxX - по оси Х; GetMaxY - по оси Y. Для возврата из графического режима в текстовый можно использовать операторы: CloseGraph - полное прекращение работы графической системы; RestoreCrtMode - переключение в текстовый режим с возможностью возврата к текущим установкам графического режима (оператором SetGraphMode). Очистить графический экран можно процедурой ClearDevice (без изменения установленных параметров) либо GraphDefaults (устанавливаются параметры, принятые по умолчанию).
5 Процедуры рисования. SetBkColor( N) - установить цвет N для пикселов фона. SetColor( N) - установить цвет N для выводимых линий. PutPixel(X, Y, N) - высветить цветом N пиксель с координатами X,Y. GetPixel(X, Y) - определить цвет пиксела с координатами X, Y. Circle(X, Y, R) - окружность с центром X, Y радиуса R. Arc(X,Y, A1,A2, R) - дуга окружности. Ellipse(X,Y, A1,A2, RX,RY) - сектор эллипса с полуосями RX,RY. A1, A2 - начальный и конечный углы (в градусах), отсчитываемые против часовой стрелки относительно оси Х. Line(X1,Y1, X2,Y2) - отрезок прямой от точки с координатами X1,Y1 к точке с координатами X2,Y2. LineTo(X, Y) - отрезок прямой от текущего положения курсора до точки X,Y. LineRel(dX, dY) - отрезок прямой от текущего положения курсора до точки, смещенной на расстояние dX,dY. В отличие от процедуры Line процедуры LineTo и LineRel при своем исполнении перемещают текущий указатель. Перемещать курсор без рисования можно процедурами MoveTo(X, Y) и MoveRel(dX,dY). В графическом режиме курсор невидим, а его положение можно определить функциями, возвращающими значения координат: GetX - по оси Х, GetY - по оси Y. Rectangle(X1,Y1, X2,Y2) - прямоугольник с левым верхним углом в точке X1,Y1 и правым нижним углом в точке X2,Y2 (стороны параллельны краям экрана ). Процедуры построения заполненных фигур Граница заполняемых фигур рисуется текущим цветом для линий. Цвет N и стиль заполнения P (орнамент) можно устанавливать из стандартного набора BGI или определять самим процедурой SetFillStyle(P, N). Bar(X1,Y1, X2,Y2) - прямоугольник; Bar3d(X1,Y1, X2,Y2, d, t) - параллелепипед с заполненной передней гранью (координаты углов грани X1,Y1, X2,Y2) глубиной d.
6 Переменная t типа boolean задает вывод верхней грани. При t=TopOn (true) верхняя грань показывается, при t=TopOff (false) - нет. FillEllipse(X,Y, RX,RY) - заполненный эллипс; Sector(X,Y, A1,A2, RX,RY) - заполненный сектор эллипса; PieSlice(X,Y, A1,A2, R) - заполненный сектор круга. FillPoly(N, M) - заполнить произвольную плоскую фигуру с границей, описанной массивом N точек границы. М - параметр типа PointType ( Var M: array[1..N] of PointType).
7 1. Построение графиков функций и траекторий движения Проведение расчетов желательно сопровождать визуализацией результатов на экране монитора. Это позволяет избежать ошибок, контролировать результаты расчета и оптимизировать алгоритм. Графики функций строятся обычно в декартовой системе координат (XoY). Функция может быть задана в явном виде типа Y=F(X), в неявном: F(X, Y)=0, в параметрическом: X=Fx( t), Y=Fy( t). 1.1. Построение графика функции Y=F(X) с масштабированием по осям координат. При построении графиков функций на экране монитора необходимо преобразовывать расчетные координаты в графические с соблюдением определенных пропорций, а также предусмотреть возможность масштабирования графика по осям координат. Для этого необходимо создать процедуры, обеспечивающие универсальность программирования графических изображений. Ниже приводится алгоритм построения графиков в правой системе координат, расположенной в заданной области экрана, с возможностью автоматического масштабирования. left up
right Y X
A
Пусть задана непрерывная функция F(X) в диапазоне изменения аргумента X=[A.B].
0
B
Требуется построить по N точкам график функции Y=F(X) в прямоугольной области экрана left, up, right, down.
down Алгоритм построения графика функции Y=F(X). 1). Определяем массивы значений аргумента и функции: X[i], Y[i]=F( X[i] ), где i= 1...N. При равномерном разбиении интервала [A..B] массивы можно задавать операторами: Dx:= (B-A) /(N-1); { шаг разбиения по X } for i:=1 to N do begin X[i]:= A + round( Dx * (i-1)); Y[i]:= F( X[i] ) end; 2). Определяем наибольшее (Y_max) и наименьшее (Y_min) значения функции в заданном интервале изменения аргумента:
8 Y_max:= Y[1]; Y_min:= Y[1]; for i:= 1 to N do begin IF Y_max < Y[i] THEN Y_max:= Y[i]; IF Y_min > Y[i] THEN Y_min:= Y[i]
end;
В случае явного задания функции для аргумента X наибольшее значение X_max:= B и наименьшее X_min:= A. Эти значения необходимо определить для полного размещения графика в расчетной области. 3). Определяем коэффициенты масштабирования при построении графика в заданной области экрана: Kx:= ( right - left) /(X_max - X_min); Ky:= (down - up ) /(Y_max - Y_min); Если X и Y имеют одинаковую размерность или оба безразмерны, то появится искажение естественной формы кривой вследствие разного масштабирования по осям координат (растяжение или сжатие по одной из осей). Для вывода графика без искажения формы кривой следует переназначить координаты области экрана так, чтобы получить Ky=Kx. Пример операторов для автомасштабирования: Пусть заданы нижняя, верхняя и левая границы области построения графика: down, up, left. Необходимо найти значение right при условиях: Ky=Kx и right<=GetMaxX. Если условие ограничения графика по длине экрана не выполняется, то полагается right:=GetMaxX, и значение up корректируется (уменьшается). Ky:= (down - up ) /(Y_max - Y_min); Kx:= Ky; right:= left + Round( Kx * (X_max - X_min)); If right > GetMaxX then begin right:= GetMaxX; Kx:= ( right-left) /(X_max - X_min); up:= down - Round( Ky * (Y_max - Y_min)) end;
Ky=Kx;
4). Определяем координаты точек для построения графика в системе координат экрана: XG[ i]:= left + round( Kx * ( X[ i] -X_min)); YG[ i]:= down - round( Ky * ( Y[ i] -Y_min));
9 Здесь Kx * (X[i] -X_min) и Ky * (Y[i] -Y_min) - смещения координат точек по соответствующим осям относительно границ области left и down. Разные знаки перед смещениями по осям X и Y получаются из-за необходимости "переворота" оси Y, которая в координатах монитора направлена сверху вниз. 5). Строим график в виде последовательных отрезков: moveto( XG[1], YG[1] ); for i:=2 to N do lineto( XG[ i], YG[ i] ); 6). Строим оси координат, предварительно задав начало координат X0 , Y0 (обычно X0 = 0, Y 0 = 0 ) и вычислив: XG0:= left + round( Kx * (X0 - X_min)); YG0:= down - round( Ky * (Y0 - Y_min)); Оси координат целесообразно строить лишь с случае их попадания в соответствующие диапазоны X_min...X_max, Y_min...Y_max: if X_min * X_max<=0 then line( XG0, up, XG0, down); if Y_min * Y_max<=0 then line( left, YG0, right, YG0); Доработать методику для совместного построения нескольких графиков несложно. Необходимо для всех функций определить дискретные координаты Y[i] и найти наибольшее и наименьшее значения для всех функций в заданных диапазонах изменения аргументов. Наибольшим значениям присвоить Y_max и X_max, а наименьшим - Y_min и X_min. Затем определить область для построения графика и координаты точек кривых. Кривые для разных функций желательно рисовать разным цветом с указанием вида функции. 1.2. Построение графика функции, заданной в параметрической форме Y=FY( t), X=FX( t). 1). Определяем массивы значений параметра t[i] , а также функций X[i]=FX( t[i] ), Y[i]=FY( t[i] ), где i= 1...N. При равномерном разбиении интервала [A..B] изменения параметра массивы можно задать операторами: Dt:= (B-A) /(N-1);
{ шаг разбиения по t }
10 for i:=1 to N do begin t[ i]:=A+round( Dt * (i-1)); X[ i]:=FX( t[i] ); Y[i]:=FY( t[i] ) end; 2). Аналогично п.2 алгоритма построения графика функции Y=F(X) определяем наибольшее (Y_max) и наименьшее (Y_min) значения функции Y=FY(t) в заданном интервале изменения параметра t и аналогично X_max, X_min для функции X=FX(t). Далее следуем по.п. 3..5 алгоритма построения графика функции Y=F(X). Параметрическая форма задания функций позволяет значительно разнообразить виды графических кривых. Наиболее часто используется представление в полярных координатах в виде зависимости длины радиус-вектора R от его направления (alfa - угол между вектором и осью X, - используется в качестве параметра): R=F( alfa), X=R* sin( alfa), Y=R * cos( alfa). 1.3. Построение траекторий движения При расчете физических процессов составляется математическая модель - система уравнений, описывающая зависимости между физическими величинами при некоторых упрощающих допущениях. Физические процессы описываются обычно системой дифференциальных уравнений, для решения которой применяют различные численные методы (модели). Широко используется метод конечных разностей, в котором бесконечно малые приращения переменных заменяют малыми (конечными) приращениями. Рассмотрим задачу определения траектории точки, движущейся в некоторой плоскости под действием различных сил. Например, необходимо вычислить траекторию движения снаряда с учетом сопротивления воздуха или ракеты с учетом изменения ее массы, движущихся в поле тяготения Земли. Координаты точки X( t), Y( t) в некоторый момент времени t можно определить, зная ее координаты X( t-dt), Y( t-dt) в предыдущий момент времени t-dt и изменение координат dX,dY: X( t) = X( t-dt) + dX( t), Y( t) = Y( t-dt) + dY( t). Если временной интервал выбрать достаточно малым, то можно полагать, что скорость точки на этом интервале не изменяется и приращения координат определяются по формулам:
11
dX( t) = Vx( t) * dt, dY( t) = Vy( t) * dt. Здесь Vx(t), Vy(t) - проекции скорости на оси координат. Составляющие скорости Vx(t) и Vy(t) можно вычислить по формулам: Vx( t) = Vx( t-dt) + Ax( t) * dt, Vy( t) = Vy( t-dt) + Ay( t) * dt. Здесь Ax( t), Ay( t) - проекции ускорения на оси координат. Ускорение определяется силами, действующими на точку - оно равно равнодействующей силе, деленной на массу точки. Силы могут зависеть от координат и скорости точки, а также от времени. Например, ускорение ракеты в поле тяготения планеты обратно пропорционально квадрату расстояния до центра планеты. При включении двигателя ракеты ускорение зависит от времени (программы работы двигателя). При движении в плотных слоях атмосферы на ракету действуют силы сопротивления воздуха, зависящие от скорости движения. Алгоритм расчета траектории движения точки: 1). Определяем силы, действующие на точку, и находим проекции ускорения на оси координат. В общем случае ускорение точки зависит от многих факторов и в момент времени t задается как функция от скорости, координат и времени : Ax:= Fx(Vx, Vy, X, Y, t), Ay:= Fy(Vx, Vy, X, Y, t), где Vx,Vy, Ax,Ay - проекции скорости и ускорения. 2). Задаем начальное положение точки - координаты X[1], Y[1] и начальные скорость и ускорение в виде проекций на оси координат: X[1]:= X0; Y[1]:= Y0; Vx[1]:= V* cos( fi); Vy[1]:= V * sin( fi); Ax[1]:= Fx( Vx[1], Vy[1], X[1], Y[1], t[1] ); Ay[1]:= Fy( Vx[1], Vy[1], X[1], Y[1], t[1] ); где V - начальная скорость, fi - угол наклона вектора скорости к оси Х.
12 3). Задаем временной шаг dt и разбиваем весь временной интервал на N участков. При равномерной разбивке приращение времени определяется по формуле: dt:= (t[N]-t[1]) /(N-1);
где t[N]-t[1] - время движения точки.
Выбор величины dt определяется необходимой точностью расчета, возможностями вычислительной техники, и может уточняться при решении задачи. 4). Вычисляем массивы скоростей, ускорений и координат точки: For i:= 2 to N do begin Vx[ i]:=Vx[i-1] + Ax[i-1] * dt; Vy[ i]:=Vy[i-1] + Ay[i-1] * dt; X[ i]:= X[i-1] + 0.5 * (Vx[i-1] + Vx[ i] ) * dt; Y[ i]:= Y[i-1] + 0.5 * (Vy[i-1] + Vy[ i] ) * dt; Ax[ i]:= Fx( Vx[ i], Vy[ i], X[ i], Y[ i], t[ i] ); Ay[ i]:= Fy( Vx[ i], Vy[ i], X[ i], Y[ i], t[ i] ); { уточнение скорости точки в расчетном месте } VX[ i]:= VX[i-1] + 0.5 * (Ax[i-1] + Ax[ i]) * dt; VY[ i]:= VY[i-1] + 0.5 * (Ay[i-1] + Ay[ i]) * dt; end; Для уменьшения погрешностей расчетной схемы скорость и ускорение на участке интерполируются средними значениями. 5). Строим траекторию движения по найденным наборам координат X[i], Y[i], определив предварительно расчетную область и область рисования траектории на экране. Перечень тем курсового проектирования по разделу № 1. Создать демонстрационную программу: 1. Влияние параметров a, b, c, d на вид функции Y=aX3 +bX2 +cX+d. 2. Тригонометрические функции и их производные. 3. Степенная функция Y=XA и ее свойства при различных A. 4. Показательная (Y=aX ) и логарифмическая (Y=log AX ) функции. 5. Графики функций в полярных координатах.
13
6. Графики функций в параметрической форме. 7. Построение касательных и нормалей к кривой. 8. Алгебраические уравнения второго порядка. 9. Циклоида: характеристики кривой и ее свойства. 10. Розы - периодические функции в полярных координатах. 11. Спирали: классические кривые, заданные в полярных координатах. 12. Гиперболические функции (Sh, Ch, Th, Cth) и их свойства. 13. Функции ArcSin, ArcCos, ArcTg и области их определения 14. Графическое отображение разложения функции в ряд Фурье. 15. Траектории движения тел в поле тяготения планеты. 16. Полет снаряда с учетом сопротивления воздуха. 17. Траектория баллистической ракеты с учетом уменьшения ее массы. 18. Траектории заряженной частицы в электромагнитном поле. 19. Затухающие колебания. 20. Вынужденные колебания. Резонанс.
14 2. Приемы создания динамичных графических образов. 2.1. Перерисовывание объекта. Наиболее простой метод моделирования движущегося объекта состоит в многократном его перерисовывании со смещением координат - на текущем шаге по текущим координатам объект рисуется, запоминаются старые и определяются его новые координаты, задается задержка (ее величина определит скорость объекта). Затем следует рисование цветом фона по старым координатам и повторение процесса на следующем шаге. Этот метод применим для вывода не слишком сложных объектов небольшого размера, прорисовывать которые можно достаточно быстро. К тому же цвет фона во всей области движения должен быть одним и тем же. Пример подобного алгоритма: { "снег" - движение массива пикселов с остановкой на преградах. } Gx:=GetmaxX; Gy:=GetmaxY; for i:=1 to 200 do begin X[i]:= random( Gx); Y[i]:= random( Gy div 2); PutPixel( X[i], Y[i], 15) end; Repeat for i:=1 to 200 do begin if ( Y[i] < Gy ) and ( GetPixel( X[i],Y[i]+1 ) = 0 ) { анализ границы } { и цвета пиксела } then begin PutPixel( X[i],Y[i], 0); Y[i]:= Y[i]+1; PutPixel( X[i],Y[i],15) end { движение пикселов } else begin { образование новых пикселов } Y[i]:= random(Gy div 10); X[i]:= random(Gx); PutPixel( X[i],Y[i], 15) end end Until keypressed; В примере сначала генерируется набор координат X[i],Y[i] в верхней половине экрана и выводятся белые точки (снежинки). Затем каждая точка гасится, смещается по оси Y на один пиксел и высвечивается вновь. Если точка по ходу движения достигнет нижнего края экрана или встретит "преграду" (точку не черного цвета), то она не гасится и генерируются новые координаты этой точки в верхней части экрана. 2.2. Плавная модификация контурного изображения.
15
Метод используется для анимации образов, задаваемых набором координат узловых точек. Этапы реализации метода: а). задается массив координат узловых точек исходного (начального) контурного изображения X1[1..N], Y1[1..N]. Соединяя определенным образом эти точки отрезками прямых, получаем изображение. б). задается массив координат узловых точек целевого (конечного) контурного изображения X2[1..N], Y2[1..N]. Количество точек одинаково для обоих массивов. в). плавной модификацией исходного образа получаем целевое изображение. Для этого последовательно находятся наборы координат X[1..N], Y[1..N] промежуточных образов. Каждую i точку этого образа выбирают на отрезке прямой между соответствующими точками исходного и целевого контуров, т.е. между точкой X1[i], Y1[i] и точкой X2[i], Y2[i] (отрезок делится на m частей, где m - количество промежуточных образов, включая целевой). Промежуточные образы перерисовывают, постепенно удаляясь от исходного образа. X1[ i] Y1[ i]
X[ i] Y[ i]
X2[ i] Y2[ i]
В случае равномерного деления отрезков координаты узловых точек промежуточных образов можно рассчитать по формулам: x[ i]:= x1[ i] + ( x2[ i] - x1[ i] ) * k /m; y[ i]:= y1[ i] + ( y2[ i] - y1[ i] ) * k /m; где k - номер образа, m - количество делений отрезка. Перерисовку образов удобно делать двойным рисованием в режиме SetWriteMode(1). Задержка видимости образа (delay) определяет скорость преобразования. В приведенном ниже фрагменте программы задается исходный контур из 12 точек X1[i], Y1[i] координат узлов квадрата, а целевой контур из 12 точек X2[i], Y2[i] координаты вершин звезды. SetWriteMode( 1); { координаты узлов исходной фигуры: } for i:=7 to 10 do begin x1[ i]:= 10; y1[ i]:= 10+( i-7) * 40 end; for i:=1 to 4 do begin x1[ i]:=130; y1[ i]:=130-( i-1) * 40 end;
16 x1[11]:=50; x1[12]:=90; y1[11]:=130; y1[12]:=130; x1[ 6]:= 50; x1[ 5]:= 90; y1[ 5]:= 10; y1[ 6]:= 10; { координаты узлов звезды - целевой фигуры: } xc:= 500; yc:= 300; { центр звезды } for i:=1 to 12 do begin alfa:= (1-i) * (2 * pi) /12; if (i mod 2)=0 then r:=30 else r:=100; x2[ i]:= xc + round( r * cos(alfa)); y2[ i]:= yc + round( r * sin( alfa)) end; m:= 60; { координаты узлов на промежуточных образах: } for k:=0 to m do begin for i:=1 to 12 do begin x[i]:=x1[ i] + round( (x2[ i]-x1[ i] ) * k /m ); y[i]:=y1[ i] + round( (y2[ i]-y1[ i] ) * k /m ) end; for j:=1 to 2 do begin { перерисовка промежуточных образов } MoveTo(x[12],y[12]); for i:= 1 to 12 do LineTo(x[ i ], y[ i ] ); if j=1 then delay(40) end end; Координаты точек промежуточных образов можно определять не только равномерным разбиением прямых линий между исходным и целевым изображениями, но и соединяя соответствующие точки исходного и целевого контуров по кривым линиям с неравномерной разбивкой. 2.3. Мультипликация с запоминанием части экрана Метод применяется для сложных объектов, которые заранее запоминаются как массив пикселей части графического экрана. Прежде чем сохранить фрагмент экрана, под него нужно отвести память, размер которой определяют с помощью функции ImageSize( X1,Y1, X2,Y2), параметры которой определяют границу прямоугольной области графического экрана подобно процедуре Rectangle. Функция определяет число байт для хранения области. Этот размер можно также вычислить по формуле (X2-X1+1) * (Y2-Y1+1). Размер отводимой памяти должен быть меньше 64 Кбайт. Далее определяем параметр P (типа pointer), который будет содержать начальный адрес области памяти ( буфера) размером Size, отводимый для хранения двоичного образа прямоугольной области экрана процедурой:
17 GetMem( P, Size ). Сохраняем двоичный образ прямоугольной области в ОЗУ (буфере) процедурой: GetImage( X1,Y1, X2,Y2, P^ ). Сохраненный массив пикселов можно выводить на экран из буфера процедурой: PutImage( X, Y, P^, N ); Здесь X,Y - позиция вывода верхнего левого угла прямоугольной области, P^ обозначает содержимое буфера с начальным адресом Р. N - режим вывода, соответствующий логическим операциям с битами, определяющими цвет пикселов на экране и соответствующих значений цвета пикселов, выводящихся из буфера: N=0 (CopyPut) - замена изображения на экране изображением из буфера. N=1 (XorPut) - "исключающее ИЛИ" (результат равен 1, если значения битов различны), N=2 ( OrPut) - "ИЛИ" (результат равен 1, если один из битов равен 1), N=3 ( AndPut) - "И" (результат равен 1, если оба бита равны 1), N=4 ( NotPut) - "НЕ" (замена изображения на экране инверсным изображением из буфера). Последовательный вывод в режиме XorPut удобно использовать при создании движущихся изображений, поскольку при первом выводе получаем изображение из буфера, а при втором восстанавливаем изображение на экране. Для создания движущегося изображения в буфер помещают, как правило, несколько различных образов, например, рисунок человечка с различным положением рук и ног. На экран выводится первое изображение в режиме XorPut, затем следует задержка выполнения программы, снова выводится первое изображение в режиме XorPut в том же месте (происходит восстановление изображения на экране), далее выводится (обычно в другой позиции) второе изображение в режиме XorPut и т. д. Пример программы - мультипликации с использованием процедур GetImage / PutImage в режиме вывода XorPut: uses Graph, Crt; var Gd, Gm, i, j, k, Size, x, y: Integer; P1,P2: Pointer; { тип указатель } Begin Gd:=VGA; Gm:=2; InitGraph(Gd, Gm, 'c:\tp7\bgi');
18 Size := ImageSize( 0,0, 20,100); { размер области } SetLineStyle( 0,0,3); { первый образ } { второй образ }
PieSlice(10, 10, 0, 360, 10); FillEllipse(10, 40, 10, 20); Line(8, 60, 0, 100); Line(12, 60, 20, 100); PieSlice(60, 10, 0, 360, 10); FillEllipse(60, 40, 10, 20); Line(60, 60, 60, 100);
GetMem( P1, Size); { P1 - указатель адреса хранения первого образа } GetImage(0,0, 20,100, P1^);{P1^ - содержимое (двоичный код) образа } GetMem( P2, Size); GetImage(50, 0, 70,100, P2^); x:=0; y:=200; { координаты начальной точки } Readln; ClearDevice; Line( 0, 300, 600, 300); { "дорога" } Repeat { имитация движения чередованием образов со смещением } PutImage( x, y, P1^, 1); delay(50); PutImage( x, y, P1^, 1); x:=x+10; { смещаем позицию на полшага } PutImage( x, y, P2^, 1); delay(50); PutImage( x, y, P2^, 1); x:=x+10 Until (x > GetmaxX -20) or ( KeyPressed ); FreeMem( P1, Size); FreeMem( P2, Size); {освободить память} CloseGraph End. 2.4. Мультипликация с чередованием видеостраниц Для изменения всего изображения на экране необходимо быстро заменять рисунок на экране другим рисунком. Этого можно достичь рисованием на невидимой видеостранице. При этом во время просмотра одной видеостраницы на другой (невидимой, но активной) странице происходит процесс рисования. Затем страницы переключают, и невидимая страница активизируется для рисования. Страницы переключаются для просмотра на экране процедурой: SetVisualPage( N), где N - номер страницы. По умолчанию видна и активна страница с N=0. Страница активизируется для рисования процедурой: SetActivePage( N) Переключение для просмотра выполняется очень быстро, что важно при создании движущихся изображений.
19 Пример фрагмента программы - мультипликации с чередованием кодовых страниц (режим двух видеостраниц). k:= 2; { количество кодовых страниц } REPEAT for i:=1 to 100 do begin j:= i mod k; { j - номер кодовой страницы } SetActivePage( j); { активизируем страницу без ее показа } ClearDevice; { стираем старый рисунок } SetfillStyle(1, i div 15 +1); { изменение цвета через 15 стр. } Bar(1, 1, i+10, i+5); { строим новый рисунок } SetVisualPage( j); delay(40) { показываем страницу } end UNTIL KeyPressed; В программе на активной странице рисуется заполненный прямоугольник, затем страница включается для просмотра на экране и активизируется другая страница, на которой рисуется заполненный прямоугольник увеличенного размера. Процесс повторяется в цикле. 2.5. Управление движением образа. Определяя смещение вновь выводимого образа в зависимости от кода нажатой клавиши, можно управлять движением. Обычно используют клавиши перемещения курсора. Приведем пример операторов, демонстрирующих принципы управляемого перемещения (для образа из программы п. 2.3): dx:=1; dy:=1; x:=100; y:=100;
{ пошаговые перемещения по осям X и Y } { начальные координаты смещаемого образа } REPEAT PutImage(x, y, P1^, 1); { выводим образ (запомненный ранее в P1^) } xold:= x; yold:= y; { запоминаем координаты } c:= readkey; { считываем код клавиши } if c=#0 then c:= readkey; case c of { анализируем код нажатой клавиши } #72: if y>1 then y:= y-dy; { смещение вверх } #75: if x>2 then x:= x-dx; { смещение влево } #80: if y
20 Перечень тем курсового проектирования по разделу № 2. Создать демонстрационно-обучающую программу по теме: 1. Броуновское движение. 2. Испарение жидкости. 3. Диффузия. 4. Электролиз растворов солей. 5. Изопроцессы в идеальных газах. 6. Строение газообразных, жидких и твердых тел. 7. Первый закон Ньютона. 8. Закон сохранения импульса. 9. Виды равновесия тела. 10. Силы упругости. 11. Силы трения. 12. Гармонические колебания математического маятника. 13. Равномерное движение точки по окружности. 14. Режимы вывода графических образов процедурой PutImage. 15. Основные принципы и приемы анимации. 16.Управляемое перемещение образа на экране. 17. Фазовые превращения твердых тел. 18. Удар, виды удара, коэффициент восстановления. 19. Движение тела переменной массы. Уравнение Циолковского. 20. Закон распределения молекул по скоростям Максвелла.
21 3. Численные методы в вычислительных расчетах. 3.1. Численное решение уравнений Для определения корней алгебраических и трансцендентных уравнений разработаны численные методы, основанные на уточнении значения корня в предположении, что на отрезке [A...B] функция Y=F(x) непрерывна и имеет только один корень. В этом случае значения функции на концах отрезка имеют разные знаки. Чаще всего применяется метод половинного деления (дихотомии) - он состоит в последовательном делении пополам отрезка, где находится корень. При этом анализируется изменение знака функции на половинах отрезка, и одна из границ отрезка [A...B] переносится в его середину. Переносится та граница, со стороны которой функция на половине отрезка знака не меняет. Процесс повторяется до тех пор, пока длина интервала [A...B] не станет меньше заданной погрешности E нахождения корня: REPEAT x:= (A + B) /2; { x - середина отрезка [A, B] } y := F(x); { значения функции в середине } yA:=F(A); { и на конце отрезка } { если знаки функции в точках A и x совпадают } if y * yA > 0 then A:=x else B:=x { то, перенос границы "A", иначе - "В" } UNTIL ABS(B-A) < E ; Для повышения надежности метода при анализе знаков функции желательно вычислять не y * yA (при перемножении малых чисел можно потерять точность), а знаковые эквиваленты (-1, 0, 1). В ряде случаев более эффективны другие методы нахождения корней, например, метод секущих или метод простых итераций. Если на исследуемом интервале [A1...B1] функция имеет несколько корней x1[1..m], то для их нахождения можно разбить этот интервал на N малых интервалов и выбрать из них те, где функция меняет знак. Здесь полагается, что на каждом малом интервале функция имеет не более одного корня. Затем следует на каждом выбранном малом интервале применить метод дихотомии (или какойнибудь другой). dx:=(b1-a1) /N; { длина отрезков } m:= 0 { счетчик корней } for k:=1 to N do begin a:= a1+(k-1) * dx; b:= a+dx; if F(a) * F(b) <= 0
22 then begin m:=m+1;
REPEAT << метод дихотомии >> UNTIL ABS(b-a)< E; x1[m]:=x; { корень номер m } end end; 3.2 Численный расчет интегралов Если отрезок интегрирования разбить на малые отрезки dx i , на которых значение функции f(x i ) можно принять постоянным, то b
S = ∫ f(x)dx = f(x 1 ) * dx 1 + f(x 2 ) * dx 2 + f(x 3 ) * dx 3 + ... + f(x N) * dx N; a
где dx 1 +dx 2 +dx 3 +... +dx N = b-a. Вычисление определенного интеграла по приведенной выше формуле называется численным интегрированием. Оно применяется, например, при определении площадей сложных геометрических фигур, нахождении работы сил, расчете длины траектории точки и в других случаях, когда подынтегральная функция f(x) задана по точкам, или ее первообразная не определяется аналитически. Сущность численных методов интегрирования состоит в замене (интерполяции) подынтегральной функции на малых отрезках простой функцией, либо в представлении функции в виде ряда. Метод прямоугольников основан на интерполяции постоянным значением. Кривую f(x) на каждом малом интервале h заменяют горизонтальной линией, пересекающей кривую в середине отрезка. Интеграл вычисляется по формуле: S =( f(x 1 ) + f(x 2 ) + ...+ f(x M) ) * h, где h = (b-a) /N; xi=a -h /2+h * i;
i = 1, 2,...N.
В методе трапеций функцию на каждом малом интервале h заменяют отрезком прямой, соединяющим точки кривой f(x) на краях этого интервала. Интеграл можно вычислить как: S = ((f(x A) + f(x B)) /2 + f(x 1 ) + f(x 2 ) +...+ f(x N-1 ) ) * h, где h = (b-a)/N; xi = a + h * i; i = 1, 2,...N-1. Более сложны метод Симпсона (интерполяция квадратичной параболой) и метод "трех восьмых" (интерполяция кубической параболой), но в ряде случаев они более эффективны. Представление подынтегральной функции в виде сходящегося ряда применяется при расчете интегралов, не выражающихся через элементарные функции (интегрирование членов такого ряда обычно сложностей не представляет). Например:
23 x
S= ∫ e-X dx= x- x 3 /(3 * 1!)+...+ (-1) N* x (2*N+1) /((2 * N+1) * N!); N=0, 1, 2,... 0
При расчете суммы степенного ряда очередной член ряда аN можно получить умножением предыдущего члена ряда a N-1 на коэффициент k=f( N,x). Приближенное значение функции находится как частичная сумма членов ряда. Погрешность вычисления зависит от количества членов ряда и значения х, поэтому расчет заканчивается при |aN| < eps, где eps - допустимая погрешность расчетов, например: Writeln( 'Вычисление y=sin(x) с использованием разложения в ряд' ); n:= 0; a:= x; { a - первый член ряда } y1:= a; { y1 - первая частичная сумма ряда } While abs(a) > eps do begin n:=n+1; k:= -x * x /(2 * n * (2 * n+1)); a:=a * k; y1:=y1+a; Writeln( 'Приближенное значение: ', y1:-11:8, ' при n=', n ) end; 3.3. Сортировка одномерных массивов Сортировка заключается в перестановке элементов массива в порядке возрастания или убывания их значений. Известно несколько методов сортировки, обладающих различной эффективностью при решении конкретных задач. Сортировка выбором основана на определении наибольшего (наименьшего) элемента, который переносится в начало или конец массива в зависимости от вида сортировки ( по возрастанию или по убыванию). Затем эта процедура применяется ко всем оставшимся элементам, кроме уже перемещенных элементов, всего N-1 раз. Пример операторов для сортировки массива Х по возрастанию: for j:=1 to N-1 do begin { цикл по числу "проходов" } k:=N-j+1; { последний элемент в проверяемой части массива } m:= k; { m - номер элемента с наибольшим значением } for i:=1 to N-j do {сравнение элементов оставшейся части массива} if x[i]>x[m] then m:=i; { запоминаем значение m } b:=x[k]; x[k]:=x[m]; x[m]:=b { переставляем элементы } end; Здесь полагается, что последний элемент, расположенный в сортируемой части массива, имеет наибольшее значение. Это условие проверяется для оставшейся части массива и запоминается
24 номер элемента с действительно наибольшим значением. Затем производится перестановка наибольшего элемента с последним элементом в проверяемой части массива. Далее процесс повторяется с уменьшением числа рассматриваемых элементов на единицу. Сортировка обменом (метод пузырька) основана на последовательном сравнении пары соседних элементов x[ i] и x[i+1]. Если пара расположена не в требуемом порядке, то элементы переставляются. Например, при сортировке по возрастанию после первого "прохода" массива от первого до последнего элемента на последнем месте окажется наибольший элемент массива. Далее сортируется оставшаяся часть массива. С каждым очередным "проходом" наибольший элемент массива в оставшейся части массива будет занимать последнее место в проверяемой части массива. Наибольшее число проходов равно N-1, причем число проверок при очередном проходе уменьшается на единицу: for j:=1 to N-1 do { цикл по числу "проходов" } for i:=1 to N-j do { сравнение элементов в оставшейся части массива } if x[i] > x[i+1] then begin { запоминаем значение x[i] и } b:=x[i]; x[i]:=x[i+1]; x[i+1]:=b end; { переставляем элементы } Сортировка вставками основана на внедрении в отсортированную часть массива элемента, следующего за этой частью, если он удовлетворяет условию сортировки. На первом шаге сортировки второй элемент сравнивается с первым, на втором шаге третий элемент сравнивается с двумя первыми и т. д. Среди уже отсортированных i-1 элементов массива вставляют i-й элемент без нарушения порядка, т.е. при вставке i-го элемента на j-е место ( jx[ j] do j:=j+1; { определение номера j для вставки элемента} for k:=i downto j+1 do x[k]:=x[k-1]; { увеличение индексов элементов} x[ j]:= b { вставка значения b на место j-го элемента } end; Перечень тем курсового проектирования по разделу № 3. Создать демонстрационно-обучающую программу по теме:
25 1. Метод половинного деления при нахождении корней уравнений. 2. Метод хорд при нахождении корней уравнений. 3. Метод Ньютона при нахождении корней уравнений. 4. Метод секущих при нахождении корней уравнений. 5. Метод простых итераций при нахождении корней уравнений. 6. Комбинированный метод хорд и касательных. 7. Численное решение уравнения, имеющего несколько корней. 8. Интегрирование методом прямоугольников. 9. Интегрирование методом трапеций. 10. Интегрирование методом Симпсона. 11. Интегрирование методом "трех восьмых". 12. Интегрирование функции с представлением ее в виде ряда. 13. Интегральные показательные функции различного порядка. 14. Интегралы вероятности. 15. Интегралы Френеля. 16. Функции Бесселя первого рода. 17. Интеграл с бесконечными пределами. 18. Сортировка массивов методом обмена. 19. Сортировка массивов методом вставок. 20. Сортировка массивов методом выбора.
26 4. Аффинные преобразования координат при моделировании динамики объектов. Преобразования координат графических объектов используются весьма широко. Основные случаи: - объект описан не в декартовой координатной системе, - изображение типовых или повторяющихся деталей объекта, - построение проекций трехмерных объектов, - направленная деформация при синтезе новых форм, - мультипликация. Различают двумерные ( 2D ) и трехмерные ( 3D) преобразования координат. Видов преобразований много, рассмотрим только так называемые аффинные преобразования, когда в получаемом изображении объекта сохраняется прямолинейность и параллельность прямых, а также деление отрезков в заданных соотношениях. Общий вид формул двумерных аффинных преобразований: x* = a11 x + a12 y + a13 y* = a21 x + a22 y + a23 Здесь x, y - координаты исходного, а x*, y* - преобразованного объекта. Коэффициенты преобразований a I J сохраняют в виде матрицы, расширенной до квадратной, при этом a11 a12 a13 очень просто вычисляются коэффициенты какого-либо a21 a22 a23 сложного преобразования, если известны коэффициенты 0 0 1 преобразований, его составляющих. Для этого просто перемножают соответствующие матрицы коэффициентов. Примеры типовых преобразований и соответствующие им матрицы: ( Ф - исходная фигура, Ф* - преобразованная ) Y dx
Ф*
Параллельный перенос
dy Ф X
1 0 dx 0 1 dy 0 0 1
27
Y Ф*
Масштабирование M = x*/x = y*/y
Ф
M 0 0
0 0 M 0 0 1
X Y
Зеркальное отображение:
Ф*
Ф
относительно оси Y
-1 0 0 0 1 0 0 0 1
относительно оси X
1 0 0 0 -1 0 0 0 1
X Ф* Y
Ф* Y=Х относительно оси Y=Х
0 1 0 1 0 0 0 0 1
относительно начала координат
-1 0 0 0 -1 0 0 0 1
Ф X Ф* Y
Ф* Поворот относительно начала координат Ф
cos a -sin a 0 sin a cos a 0 0 0 1
α X Y a
Y*
Ф*
Ф
X*
Деформация сдвига : в направлении X - a в направлении Y - b
1 tg a 0 tg b 1 0 0 0 1
β X Прочие преобразования обычно представляют в виде комбинаций перечисленных выше простейших преобразований.
28 Например, поворот относительно произвольной точки можно представить как комбинацию трех преобразований: - параллельный перенос, переводящий центр поворота в начало координат, - поворот относительно начала координат, - параллельный перенос, противоположный первоначальному. Перемножение матриц выполняется следующим образом: b 11 b 12 b 13 c11 c12 c13 a11 a12 a13 a21 a22 a23 * b 21 b 22 b 23 = c21 c22 c23 b 31 b 32 b 33 c31 c32 c33 a31 a32 a33 где c I J = a I 1 * b 1 J + a I 2 * b 2 J + a I 3 * b J 3 , то есть для расчета элемента матрицы, расположенного в I-строке и J-столбце, вычисляется сумма произведений элементов этой строки в матрице A на соответствующие элементы этого столбца в матрице B. При нахождении матрицы коэффициентов сложного преобразования координат важен порядок перемножения: матрицы перемножают последовательно от последней к первой. Для приведенного выше примера первому преобразованию соответствует матрица В, второму - А. В приведенной ниже программе линейчатая фигура задается в виде массивов координат ее вершин xa, ya на чертеже ( x, y - в системе координат экрана ). Эти координаты подвергаются аффинным преобразованиям, коэффициенты преобразования хранятся в двумерном массиве R. Начальному положению фигуры соответствует единичная матрица R (единицы на главной диагонали, остальные члены - нули). При очередном преобразовании коэффициенты матрицы R пересчитываются путем умножения на нее матрицы этого преобразования (А), получаемая матрица (В) снова записывается в R. Новые координаты x, y высчитываются в процедуре NEW_XY, которая вызывается непосредственно при выводе фигуры на экран процедурой PICT. Причем если установить для рисования цвет фона, то пересчет координат производиться не будет, что приведет к стиранию старого изображения фигуры - это удобно при имитации движения. Все простые преобразования координат (перенос, вращение, масштабирование, сдвиг) , а также некоторые типовые преобразования как комбинации простых оформлены в виде процедур.
29
uses Graph, Crt; var Gd, Gm, n, i, j, k, xc, yc: integer; xa, ya: array[1..50] of real; { координаты фигуры на чертеже } x , y : array[1..50] of integer; { координаты фигуры на экране } } a, b, r: array[1..3, 1..3] of real; { массивы членов матриц 3 * 3 {-----------------------------------------------------------------------------------------} PROCEDURE I_R; { присвоение матрице R значения единичной } var i, j: integer ; begin for i:=1 to 3 do begin { 1 0 0 } for j:=1 to 3 do r[ i, j]:=0; { 0 1 0 } r[ i, i]:=1; end; end; { 0 0 1 } {-----------------------------------------------------------------------------------------} PROCEDURE MULT; { умножение матриц А и R, результат (матр. В) записывается в R } var z: real; i, j, k: integer; begin for i:=1 to 3 do for j:=1 to 3 do begin z:=0; for k:=1 to 3 do z:=z+a[ i, k] * r[ k, j]; b[i, j]:=z end; for i:=1 to 3 do for j:=1 to 3 do r[ i, j]:=b[ i, j] end; {-----------------------------------------------------------------------------------------} PROCEDURE NEW_XY; { вычисление новых координат фигуры по базовым коорд. XA, YA с использованием матрицы преобразования R } var i: integer ; begin for i:=1 to n do begin x[ i]:=round( xa[ i]* r[1, 1]+ ya[ i]* r[1, 2]+ r[1, 3] ); y[ i]:=round( xa[ i]* r[2, 1]+ ya[ i]* r[2, 2]+ r[2, 3] ) end; end; {-----------------------------------------------------------------------------------------} PROCEDURE TRAN( dx, dy: real); { расчет матриц А и R для переноса объекта на dx, dy } var i, j: integer ; begin for i:=1 to 3 do begin { 1 0 dx } for j:=1 to 3 do a[i, j]:=0; { 0 1 dy } a[ i, i]:=1 end; { 0 0 1 }
30 a[1, 3]:=dx; a[2, 3]:=dy; MULT; end; PROCEDURE SCALE( sx, sy: real ); { расчет матриц А и R для масштабирования объекта: по оси Х - умножение на sx, по оси Y - на sy } var i, j: integer; begin { sx 0 0 } for i:=1 to 3 do { 0 sy 0 } for j:=1 to 3 do a[i, j]:=0; { 0 0 1 } a[1, 1]:=sx; a[2, 2]:=sy; a[3, 3]:=1; MULT; end; {-----------------------------------------------------------------------------------------} PROCEDURE ROTATE( alfa: real ); { расчет матриц А и R для поворота объекта на угол alfa(рад): } var c, s: real; i, j: integer; begin { cos(alfa) -sin(alfa) 0 } for i:=1 to 3 do { sin(alfa) cos(alfa) 0 } for j:=1 to 3 do a[ i, j]:= 0; { 0 0 1 } a[3, 3]:= 1; c:=cos( alfa); a[1, 1]:= c; a[2, 2]:=c; s:=sin( alfa); a[1, 2]:=-s; a[2, 1]:=s; MULT; end; {-----------------------------------------------------------------------------------------} PROCEDURE LOOK( alfa, dx, dy, sx, sy: real); { перевод объекта из локальной системы координат (на чертеже) в систему координат экрана: - поворот объекта на угол alfa(рад), - перенос на dx,dy, - масштабирование sx,sy, - пересчет базовых координат xa,ya. } var xx, yy: real; i: integer; begin I_R; ROTATE( alfa); TRAN( dx, dy); SCALE( sx, sy); for i:=1 to n do begin xx:=xa[ i] * r[1, 1]+ya[ i] * r[1, 2] + r[1, 3]; yy:=xa[ i] * r[2, 1]+ya[ i] * r[2, 2] + r[2, 3]; xa[ i]:=round( xx); ya[ i]:=round( yy); end; I_R; end; {-----------------------------------------------------------------------------------------}
31 PROCEDURE PICT( color: word ); { рисование фигуры по координатам X,Y } var i: integer; begin setcolor( color); if(color>0) then NEW_XY; { Вычисление новых координат фигуры: пересчет не производится при рисовании черным цветом } moveto( x[n], y[n] ); for i:=1 to n do lineto( x[ i], y[ i] ); end; PROCEDURE RS( beta, kx, ky: real ); { поворот фигуры относительно ее центра xm, ym на угол beta, а также ее масштабирование (kx - коэффициент для оси x, ky - для y) без смещения центра фигуры } var xm, ym: real; i: integer; begin xm:=0; ym:=0; for i:=1 to n do begin xm:=xm+x[ i]; ym:=ym+y[ i]; end; xm:=xm /n; ym:=ym /n; { координаты центра фигуры } TRAN(-xm, -ym); { Перенос центра фигуры в начало координат: } ROTATE( beta); { центр поворота и центр масштабирования } SCALE(kx, ky); { совпадают с центром фигуры. } TRAN(xm, ym); { Обратный перенос фигуры } end; {-----------------------------------------------------------------------------------------} PROCEDURE ROT_XY( xc, yc, beta: real); { поворот фигуры относительно точки хс, ус на угол beta } begin TRAN(-xc, -yc); { Смещение фигуры так, чтобы ее новое положение относительно начала координат было таким же, как старое положение относительно xc, yc. } ROTATE( beta); { поворот относительно начала координат } TRAN(xc, yc); { обратное смещение фигуры } end; {-----------------------------------------------------------------------------------------} PROCEDURE AXES( alfa, beta: real); { расчет матриц А и R cмещения осей координат (деформация сдвига) ось x смещается на угол alfa, ось y - на угол beta } var i, j: integer; begin for i:=1 to 3 do begin { 1 tg(beta) 0 } for j:=1 to 3 do a[i, j]:=0; { tg(alfa) 1 0 } a[i, i]:=1 end; { 0 0 1 } a[1, 2]:=sin(beta) /cos( beta); a[2, 1]:=sin( alfa) /cos( alfa); MULT; end; {-----------------------------------------------------------------------------------------}
32 PROCEDURE MIRROR( delta: real; index: byte); { расчет матриц А и R зеркального отображения фигуры относительно оси , параллельной одной из осей координат: при index=1: относительно оси, -1 0 2 * delta параллельной оси Y 0 1 0 и проходящей через точку (delta, 0). 0 0 1 при index=2: относительно оси, 1 0 0 параллельной оси X 0 -1 2 * delta и проходящей через точку (0, delta). 0 0 1 } var i, j: integer; begin for i:=1 to 3 do begin for j:=1 to 3 do a[i, j]:=0; a[i, i]:=1 end; a[ index, index]:=-1; a[ index, 3]:=2 * delta; MULT; end; {-----------------------------------------------------------------------------------------Определяем плоскую фигуру : } begin n:=4; { число вершин фигуры } xa[1]:= 5; ya[1]:= 5; { координаты вершин фигуры на чертеже } xa[2]:=70; ya[2]:=20; xa[3]:= 5; ya[3]:=35; xa[4]:=20; ya[4]:=20; Gd:= Detect; InitGraph(Gd, Gm, ' ' ); LOOK( 0, 0, -70, 1, -1); { переход к координатам экрана } PICT( 9); { показ начального положения фигуры --------- Примеры аффинных преобразований плоской фигуры ---------} SCALE( 4, 2); { увеличение по оси х в 4 раза, по оси у в 2 раза } TRAN( 10,60); { смещение по оси х на 10 пикселей, по оси у - на 60} PICT( 14); readln; {--------------------Вращение с увеличением и смещением ------------------} for i:=1 to 100 do begin PICT( 13); { вывод фигуры } RS( 0.04, 1.01, 1.01); { поворот на 0.04 рад. и увеличение на 1%} TRAN( 4, 0); delay(20); { смещение фигуры } PICT( 0); { стирание фигуры - черным по старым координатам } end; PICT( 13); readln; ClearDevice; I_R;
33 {---------------- Вращение вокруг смещающегося центра -------------------} for i:=1 to 60 do begin PICT(14); xc:=xc+3; yc:=yc+2; putpixel(xc, yc, 12); { смещение центра xc,yc } TRAN(3, 2); { перенос фигуры соответственно смещению центра } ROT_XY(xc, yc, -0.3); { поворот на 0.3 рад относительно xc,yc } delay(20); PICT( 0); end; readln; ClearDevice; I_R; SCALE( 2, 4); PICT(14); {-------------- Смещения осей координат (деформация сдвига) ---------} AXES( 1, 0); { сдвиг оси х } PICT( 10); readln; AXES(-1, 0); { возврат } PICT( 11); AXES( 0, 1); { сдвиг оси у } PICT( 12); readln; AXES( 0, -1); { возврат } PICT( 13); for i:=1 to 100 do begin AXES( 0.01, 0.01); { постепенный сдвиг обеих осей } PICT( 0); PICT(14); delay(10); end; readln; ClearDevice; I_R; SCALE( 4, 4); PICT(14); {------------------- Зеркальные отображения фигуры ------------------------} MIRROR(250, 1); PICT(10); { отображение относительно вертикали } MIRROR(150, 2); PICT(11); { отображение относительно горизонтали} readln; CloseGraph; end. Аналогичный набор подпрограмм несложно составить и для трехмерных аффинных преобразований, где будут перерабатываться матрицы 4 * 4 соответственно для трех координат - X, Y, Z. На экране при этом можно отображать либо прямую проекцию объекта ( X,Y без преобразований), либо с масштабированием по Z, имитируя перспективу (зрительный конус). При этом приходится решать задачу удаления невидимых линий при построении проекций. В приведенной ниже программе трехмерный объект кодируется координатами вершин и принадлежностью этих вершин граням объекта перебором их против часовой стрелки при условии видимости грани. Если при показе грани ее ориентация меняется ( что определяется знаком векторного произведения двух первых ребер на этой грани ), то ребра, принадлежащие этой грани, не показываются.
34 Реализована только часть различных аффинных преобразований, позволяющая перемещать объект в пространстве, вращать его и масштабировать. Кодировки объекта считываются из файла, структура которого приведена в конце программы. Uses Graph, Crt; var Gd,Gm, i, j, i_n, j_n, k,kg, stop, d: integer; fl: text; c: char; xa,ya,za: { координаты фигуры на чертеже } array[1..50] of real; x , y , z, { расчетные координаты фигуры } xp, yp: { координаты фигуры на экране с учетом перспективы } array[1..50] of longint; a, b, r: { массивы членов матриц 4*4 } array[1..4, 1..4] of real; f: { номера вершин на определенных гранях фигуры } array[1..8, 1..50] of integer; h: { число вершин на одной грани } array[1..50] of integer; {-----------------------------------------------------------------------------------------} PROCEDURE I_R_3; { присвоение матрице R значения единичной} begin { 1 0 0 0 } for i:=1 to 4 do begin { 0 1 0 0 } for j:=1 to 4 do r[i, j]:=0; { 0 0 1 0 } r[i, i]:=1; end; end; { 0 0 0 1 } {-----------------------------------------------------------------------------------------} PROCEDURE MULT_3; { умножение матриц А и R, результат (матрица В) записывается в R } var z: real; begin for i:=1 to 4 do for j:=1 to 4 do begin z:=0; for k:=1 to 4 do z:=z +a[i, k] * r[k, j]; b[i, j]:=z end; for i:=1 to 4 do for j:=1 to 4 do r[i, j]:=b[i, j] end; {-----------------------------------------------------------------------------------------} PROCEDURE NEW_XYZ; {вычисление новых координат фигуры по базовым координатам XA,YA,ZA с использованием матрицы R } begin for i:=1 to i_n do begin x[i]:=round( xa[i]* r[1,1] + ya[i]* r[1,2] + za[i]* r[1,3] + r[1,4] ); y[i]:=round( xa[i]* r[2,1] + ya[i]* r[2,2] + za[i]* r[2,3] + r[2,4] );
35 z[i]:=round( xa[i]* r[3,1] + ya[i]* r[3,2] + za[i]* r[3,3] + r[3,4] ); end; end; {-----------------------------------------------------------------------------------------} PROCEDURE TRAN_3( dx, dy, dz: real ); { расчет матриц А и R для переноса трехмерного обьекта на dx,dy,dz } begin for i:=1 to 4 do begin { 1 0 0 dx } for j:=1 to 4 do a[ i, j]:=0; { 0 1 0 dy } a[ i, i]:=1 end; { 0 0 1 dz } a[1, 4]:=dx; a[2, 4]:=dy; a[3, 4]:=dz; { 0 0 0 1 } MULT_3; end; {-----------------------------------------------------------------------------------------} PROCEDURE SCALE_3(sx,sy,sz: real); { расчет матриц А и R для масштабирования трехмерного обьекта: по оси Х - умножение на sx, по оси Y - на sy, по оси Z - на sz } begin for i:=1 to 4 do { sx 0 0 0 } for j:=1 to 4 do a[ i, j]:=0; { 0 sy 0 0 } a[1, 1]:=sx; a[3, 3]:=sz; { 0 0 sz 0 } a[2, 2]:=sy; a[4, 4]:=1; { 0 0 0 1 } MULT_3; end; {-----------------------------------------------------------------------------------------} PROCEDURE ROTATE_3( alfa: real; index: byte ); { расчет матриц А и R для поворота обьекта на угол alfa(рад) относительно одной из осей X, Y, Z. 1 0 0 0 Повороту относительно оси Х 0 cos(alfa) -sin(alfa) 0 соответствует матрица: 0 sin(alfa) cos(alfa) 0 0 0 0 1 cos(alfa) 0 sin(alfa) 0 Повороту относительно оси Y 0 1 0 0 соответствует матрица: -sin(alfa) 0 cos(alfa) 0 0 0 0 1 cos(alfa) -sin(alfa) 0 0 Повороту относительно оси Z sin(alfa) cos(alfa) 0 0 соответствует матрица: 0 0 1 0 0 0 0 1 необходимая матрица генерируется по значению index: 1 - для оси X, 2 - для оси Y, 3 - для оси Z. }
36 var c,s: real; ax1,ax2: byte; begin for i:=1 to 4 do for j:=1 to 4 do a[i, j]:=0; a[4, 4]:=1; a[ index,index]:=1; ax1:=index+1; if(ax1=4) then ax1:=1; ax2:= ax1 +1; if(ax2=4) then ax2:=1; c:=cos( alfa); a[ax1,ax1]:= c; a[ax2,ax2]:=c; s:=sin( alfa); a[ax1,ax2]:=-s; a[ax2,ax1]:=s; MULT_3; end; {-----------------------------------------------------------------------------------------} PROCEDURE LOOK_3( alfa, beta, teta, dx,dy,dz, sx, sy, sz: real ); { перевод обьекта из локальной системы координат (на чертеже) в систему координат экрана: 1.- повороты обьекта на углы alfa - относительно оси Х, beta - относительно оси Y, teta - относительно оси Z, 2.- перенос на dx,dy,dz 3.- масштабирование sx, sy, sz 4.- пересчет базовых координат xa, ya, za. } var xx, yy, zz: real; begin I_R_3; ROTATE_3( alfa, 1); ROTATE_3( beta, 2); ROTATE_3( teta, 3); TRAN_3( dx,dy,dz ); SCALE_3( sx, sy, sz ); for i:=1 to i_n do begin xx:=xa[i]* r[1,1] + ya[i]* r[1,2] + za[i]* r[1,3] + r[1,4]; yy:=xa[i]* r[2,1] + ya[i]* r[2,2] + za[i]* r[2,3] + r[2,4]; zz:=xa[i]* r[3,1] + ya[i]* r[3,2] + za[i]* r[3,3] + r[3,4]; xa[i]:=round( xx); ya[i]:=round( yy); za[i]:=round( zz); end; I_R_3; end; {-----------------------------------------------------------------------------------------} FUNCTION VISION( J: byte ): boolean; { определение, является ли грань фигуры с номером "J" видимой } var i1, i2, i3: integer; x1,x2, y1,y2: real; begin x 3 ,y 3 { номера координат при обходе вершин грани } i1:=f[1, J]; i2:=f[2, J]; i3:=f[3, J]; J x 2 ,y 2 x1:=xp[i2] -xp[i1]; x2:=xp[i3] -xp[i2]; y1:=yp[i2] -yp[i1]; y2:=yp[i3] -yp[i2]; x 1 ,y 1 if(x1 * y2 - x2 * y1>=0) { если произведение векторов обхода положительно, то } then VISION:=true else VISION:=false; end;
37 {-----------------------------------------------------------------------------------------} PROCEDURE PICT_3( color: word ); { рисование фигуры по координатам X,Y с учетом перспективы по координатам Z, d - расстояние от глаз до монитора (в пикселах)} begin setcolor(color); d:=1500; if(color<>GetBkColor) then NEW_XYZ; for i:=1 to i_n do begin { без учета перспективы d /z[i] = 1 } xp[i]:=round( x[i] * d /z[i] ); yp[i]:=round( y[i] * d/ z[i] ) end; for j:=1 to j_n do begin if VISION( j)=true then begin i:=f [ h[ j], j]; moveto( xp[i],yp[i] ); for k:=1 to h[ j] do begin i:=f[k, j]; lineto( xp[i],yp[i] ) end; end; end; end; {-----------------------------------------------------------------------------------------} PROCEDURE RS_3( alfa, beta, teta, kx, ky, kz: real ); { поворот фигуры относительно ее центра xm, ym, zm на углы alfa (ось X), beta (ось Y), teta (ось Z), а также ее масштабирование ( kx - коэффициент для оси X, ky - для оси Y, kz - для оси Z) без смещения центра фигуры } var xm, ym, zm: real; begin xm:=0; ym:=0; zm:=0; for i:=1 to i_n do begin xm:=xm+x[i]; ym:=ym+y[i]; zm:=zm+z[i]; end; xm:=xm /i_n; ym:=ym /i_n; zm:=zm /i_n; {координаты центра фигуры} TRAN_3(-xm,-ym,-zm); {Перенос центра фигуры в начало координат:} ROTATE_3( alfa, 1); {при этом центр поворота и масштабирования} ROTATE_3( beta, 2); {совпадают с центром фигуры. } ROTATE_3( teta, 3); SCALE_3( kx, ky, kz ); TRAN_3( xm, ym, zm); { Обратный перенос фигуры } end; {-----------------------------------------------------------------------------------------} PROCEDURE ROT_3( xc, yc, zc, alfa, beta, teta: real ); { поворот фигуры относительно точки с координатами хс, ус, zc на углы alfa (ось X), beta (ось Y), teta (ось Z) } begin TRAN_3( -xc, -yc, -zc ); { Смещение фигуры так, чтобы ее новое положение относительно начала координат было таким же, как старое положение относительно xc, yc, zc. }
38 ROTATE_3( alfa, 1); { поворот относительно начала координат по Х } ROTATE_3( beta,2); { поворот относительно начала координат по Y } ROTATE_3( teta, 3); { поворот относительно начала координат по Z } TRAN_3( xc, yc, zc); { обратное смещение фигуры } end; {------------------------------------------------------------------------------------------} begin clrscr; { считываем координаты фигуры из файла } assign( fl,'data.pas'); reset( fl); readln( fl, i_n); readln( fl); writeln( 'Число вершин фигуры ', i_n ); for i:=1 to i_n do readln( fl, xa[i], ya[i], za[i] ); writeln( 'Координаты вершин X Y Z' ); for i:=1 to i_n do writeln( i:10, ' -->', xa[i]:7:1, ya[i]:7:1, za[i]:7:1); readln( fl, j_n, kg); readln( fl); writeln( 'Число граней: ', j_n, ' вершин на грани: не более ', kg ); for j:=1 to j_n do begin for k:=1 to kg do read( fl, f[k, j] ); readln( fl, h[j] ); end; close( fl); writeln('Порядок обхода вершин на гранях / число вершин'); for j:=1 to j_n do begin write( j:2, '-я грань -> '); for k:=1 to kg do write( f[k, j]:4 ); writeln( h[j]:10 ); end; readln; LOOK_3(0,1,1, 30,80,1000, 2,2,2); { переход к координатам экрана } Gd:=Detect; InitGraph(Gd, Gm, 'c:\tp7\bgi'); PICT_3(9); { показ начального положения фигуры } stop:=0; { признак прекращения управляющих воздействий } REPEAT c:=readkey; PICT_3(0); { стирание предшествующего изображения } case c of { анализируем код нажатой клавиши } #72: TRAN_3(0, -5, 0); { смещение вверх } #80: TRAN_3(0, 5, 0); { смещение вниз } #77: TRAN_3( 5, 0, 0); { смещение вправо } #75: TRAN_3(-5, 0, 0); { смещение влево } #79: TRAN_3(0, 0, 50); { удаление (End) } #43: TRAN_3(0, 0, -50); { приближение (плюс) } #73: RS_3(pi/30, 0, 0, 1, 1, 1); { вращение вокруг оси Х ( PgUp) } #81: RS_3(0, pi/30, 0, 1, 1, 1); { вращение вокруг оси Y ( PgDn) } #71: RS_3(0, 0, pi/30, 1, 1, 1); { вращение вокруг оси Z ( Home) } #82: RS_3(0, 0, 0, 1.1, 1.1, 1.1); { увеличение ( Ins) } #83: RS_3(0, 0, 0, 0.9, 0.9, 0.9); { уменьшение ( Del) }
39 #27: stop:=1; { при нажатии Esc прекращаем } end; PICT_3(14); UNTIL stop=1; CloseGraph; end. {------------------------------------------------------------------------------------------} Структура файла с кодировками координат трехмерного обьекта ( комментарии обязательными не являются ): 5 - число вершин фигуры (i_n) 5 X Y Z - координаты вершин 0 0 10 ---- 1 0 30 10 ---- 2 1 40 30 10 ---- 3 40 0 10 ---- 4 0 0 60 ---- 5 2 5 4 - число граней фигуры (j_n) и макс. число вершин (Kg) порядок обхода грани число вершин 1 4 3 2 4 1 2 5 0 3 2 3 5 0 3 3 4 5 0 3 1 5 4 0 3
Перечень тем курсового проектирования по разделу № 4. Создать демонстрационно-обучающую программу по теме: 1. Линейные деформации и деформации сдвига. 2. Перспективная проекция, зрительный конус. 3. Стереометрия: пирамида, виды пирамид и их свойства. 4. Стереометрия: параллелепипеды, их виды и свойства. 5. Стереометрия: клин и его характеристики. 6. Двугранные, многогранные и телесные углы 7. Правильные выпуклые многогранники. Теорема Эйлера.
4 3
40 8. Цилиндрические поверхности - виды и их свойства. 9. Однополостный гиперболоид. 10. Конусы - виды и их свойства. 11. Октаэдр и его свойства. 12. Додекаэдр и его свойства. 13. Икосаэдр и его свойства. 14. Деформации сдвига по осям при синтезе трехмерных форм. 15. Трехмерные симметричные отображения. 16. Удаление невидимых линий в проекциях выпуклого объекта. 17. Динамика вращательного движения: моменты силы и инерции. 18. Гироскоп. Прецессия и гироскопический момент. 19. Механические колебания. Виды маятников. 20. Поступательное и вращательное движение твердого тела.
41 Список литературы 1. Бронштейн И.Н., Семендяев К.А. Справочник по математике.М.: Наука, 1986. 2. Епанешников А.М., Епанешников В.А. Программирование в среде Turbo Pascal 7.0. - М.: Диалог - МИФИ, 1995. 3. Епанешников А.М., Епанешников В.А. Turbo Vision 2.0. Основы практического использования. - М.: ”ДИАЛОГ-МИФИ ”, 1995. 4. Иванов В.М., Батраков А.С. Трехмерная компьютерная графика. - М.: Радио и связь, 1995. 5. Котов В.Ю., Павлова А.А. Основы машинной графики. - М.: Просвещение, 1993. 6. Котов Ю.В. Как рисует машина. - М.: Наука, 1988. 7. Лапшин Е. Графика для IBM PC. - М.: Солон, 1995. 8. Мудров А.Е. Численные методы для ПЭВМ на языках бейсик, фортран и паскаль. - Томск, 1991. 9. Райхмист А.Б. Графики функций: справочное пособие для вузов. - М.: Высш. шк., 1991. 10. Фаронов В.В. Турбо Паскаль ( в 3-х книгах ). Практика программирования. - М.: УНЦ ”МВТУ ФЕСТО ДИДАКТИК”, 1993. 11. Д. Хирн, М. Бейкер. Микрокомпьютерная графика. Пер. с англ. - М.: Мир, 1987. 12. Цимринг Ш.Е. Специальные функции и определенные интегралы. Алгоритмы. Программы для микрокалькуляторов: Справочник. - М.: Радио и связь, 1988. 13. Шикин Е.В., Борисов А.В., Зайцев А.А. Начала компьютерной графики. - М.: Диалог- МИФИ, 1993. 14. Яворский Б.М., Детлаф А.А. Справочник по физике. - М.: Наука, 1977.
42 Составитель: ТРУШИН Олег Владимирович
Методические указания для курсового проектирования по курсу "Информатика" для подготовки инженеров по специальностям 210100 "Управление и информатика в технических системах" и 210300 "Роботы и робототехнические системы"
Редактор
Ю.Р. Егорова
ЛР № 020258 от 30.10.91
Подписано к печати Формат 60 Х 84 Бумага оберточная. Печать плоская. Усл. печ. л. 2,3 Усл. кр. - отт. 2,2 Уч. изд. л. 2,2. Тираж 150 Заказ Бесплатно Уфимский государственный авиационный технический университет Уфимская типография № 2 Министерства печати и массовой информации Республики Башкортостан 450000, Уфа - центр, ул. К. Маркса, 12.