unit Geometry; {$mode ObjFPC}{$H+} interface uses Classes, SysUtils; type { Вершины } Vertex = record x, y, z: Real; { Координаты вершины } end; { Ребра } Edge = record src, dest: Integer; { Индексы соединяемых вершин } end; Object3D = class public vertices: array of Vertex; { вершины } edges: array of Edge; { ребра } xc, yc, zc: Real; { координаты центра объекта } vx, vy, vz: Real; { значения составляющих его скорости } xa, ya, za: Real; { скорость вращения вокруг оси } constructor Create(var center, velocity, axis: Vertex); procedure MoveCenter(); end; Matrix = array[1..4, 1..4] of Real; { матрица 4x4 } Column = array[1..4] of Real; { столбец } function CopyObject3D(Shape: Object3D): Object3D; { умножение матрицы на матрицу } function MMMult(lhs, rhs: Matrix): Matrix; { умножение матрицы на столбец } function MCMult(lhs: Matrix; rhs: Column): Column; { матрица поворота модели } function RotateMatrix(xa, ya, za: Real): Matrix; function MoveMatrix(tx, ty, tz: Real): Matrix; function ResizeMatrix(sx, sy, sz: Real): Matrix; procedure RotateShape(Shape: Object3D); procedure MoveShape(Shape: Object3D; Width, Height: Real); procedure ResizeShape(var Shape: Object3D; sx, sy, sz: Real); implementation constructor Object3D.Create(var center, velocity, axis: Vertex); const size = 10; cubeVertices: array of Vertex = ( (x: -size; y: -size; z: -size), (x: -size; y: size; z: -size), (x: size; y: size; z: -size), (x: size; y: -size; z: -size), (x: -size; y: -size; z: size), (x: -size; y: size; z: size), (x: size; y: size; z: size), (x: size; y: -size; z: size) ); cubeEdges: array of Edge = ( (src: 0; dest: 1), (src: 1; dest: 2), (src: 2; dest: 3), (src: 3; dest: 0), (src: 4; dest: 5), (src: 5; dest: 6), (src: 6; dest: 7), (src: 7; dest: 4), (src: 0; dest: 4), (src: 1; dest: 5), (src: 2; dest: 6), (src: 3; dest: 7) ); begin vertices := cubeVertices; edges := cubeEdges; xc := center.x; yc := center.y; zc := center.z; vx := velocity.x; vy := velocity.y; vz := velocity.z; xa := axis.x; ya := axis.y; za := axis.z end; procedure Object3D.MoveCenter(); begin xc := xc + Vx; yc := yc + Vy; zc := zc + Vz end; function CopyObject3D(Shape: Object3D): Object3D; begin CopyObject3D.vertices := Copy(Shape.vertices, 0); CopyObject3D.edges := Copy(Shape.edges, 0); CopyObject3D.xc := Shape.xc; CopyObject3D.yc := Shape.yc; CopyObject3D.zc := Shape.zc end; function MMMult(lhs, rhs: Matrix): Matrix; var i, j, k: Integer; r: Matrix; s: Real; begin for i := 1 to 4 do for j := 1 to 4 do begin s := 0; for k := 1 to 4 do s := s + lhs[i, k] * rhs[k, j]; r[i, j] := s; end; MMMult := r; end; function MCMult(lhs: Matrix; rhs: Column): Column; var k, i: Integer; s: Real; r: Column; begin for i := 1 to 4 do { аналогично MMMult } begin s := 0; for k := 1 to 4 do s := s + lhs[i, k] * rhs[k]; r[i] := s; end; MCMult := r; end; function RotateMatrix(xa, ya, za: Real): Matrix; var xr, yr, zr: Matrix; begin { матрица поворота вокруг оси Ox } xr[1, 1] := 1; xr[1, 2] := 0; xr[1, 3] := 0; xr[1, 4] := 0; xr[2, 1] := 0; xr[2, 2] := Cos(xa); xr[2, 3] := -Sin(xa); xr[2, 4] := 0; xr[3, 1] := 0; xr[3, 2] := Sin(xa); xr[3, 3] := Cos(xa); xr[3, 4] := 0; xr[4, 1] := 0; xr[4, 2] := 0; xr[4, 3] := 0; xr[4, 4] := 1; { матрица поворота вокруг оси Oy } yr[1, 1] := Cos(ya); yr[1, 2] := 0; yr[1, 3] := Sin(ya); yr[1, 4] := 0; yr[2, 1] := 0; yr[2, 2] := 1; yr[2, 3] := 0; yr[2, 4] := 0; yr[3, 1] := -Sin(ya); yr[3, 2] := 0; yr[3, 3] := Cos(ya); yr[3, 4] := 0; yr[4, 1] := 0; yr[4, 2] := 0; yr[4, 3] := 0; yr[4, 4] := 1; { матрица поворота вокруг оси Oz } zr[1, 1] := Cos(za); zr[1, 2] := -Sin(za); zr[1, 3] := 0; zr[1, 4] := 0; zr[2, 1] := Sin(za); zr[2, 2] := Cos(za); zr[2, 3] := 0; zr[2, 4] := 0; zr[3, 1] := 0; zr[3, 2] := 0; zr[3, 3] := 1; zr[3, 4] := 0; zr[4, 1] := 0; zr[4, 2] := 0; zr[4, 3] := 0; zr[4, 4] := 1; RotateMatrix := MMMult(MMMult(xr, yr), zr) end; function MoveMatrix(tx, ty, tz: Real): Matrix; begin MoveMatrix[1, 1] := 1; MoveMatrix[1, 2] := 0; MoveMatrix[1, 3] := 0; MoveMatrix[1, 4] := tx; MoveMatrix[2, 1] := 0; MoveMatrix[2, 2] := 1; MoveMatrix[2, 3] := 0; MoveMatrix[2, 4] := ty; MoveMatrix[3, 1] := 0; MoveMatrix[3, 2] := 0; MoveMatrix[3, 3] := 1; MoveMatrix[3, 4] := tz; MoveMatrix[4, 1] := 0; MoveMatrix[4, 2] := 0; MoveMatrix[4, 3] := 0; MoveMatrix[4, 4] := 1 end; function ResizeMatrix(sx, sy, sz: Real): Matrix; begin ResizeMatrix[1, 1] := sx; ResizeMatrix[1, 2] := 0; ResizeMatrix[1, 3] := 0; ResizeMatrix[1, 4] := 0; ResizeMatrix[2, 1] := 0; ResizeMatrix[2, 2] := sy; ResizeMatrix[2, 3] := 0; ResizeMatrix[2, 4] := 0; ResizeMatrix[3, 1] := 0; ResizeMatrix[3, 2] := 0; ResizeMatrix[3, 3] := sz; ResizeMatrix[3, 4] := 0; ResizeMatrix[4, 1] := 0; ResizeMatrix[4, 2] := 0; ResizeMatrix[4, 3] := 0; ResizeMatrix[4, 4] := 1 end; procedure RotateShape(Shape: Object3D); var rm: Matrix; i: Integer; c: Column; begin rm := RotateMatrix(Shape.xa, Shape.ya, Shape.za); { сгенерировать матрицу вращения } c[4] := 1; { последний элемент столбца всегда равен единице } for i := 0 to High(Shape.vertices) do { цикл по всем вершинам } begin { High(a) возвращает верхний индекс массива a } c[1] := Shape.vertices[i].x; { инициализация столбца } c[2] := Shape.vertices[i].y; c[3] := Shape.vertices[i].z; c := MCMult(rm, c); { вызов преобразования } Shape.vertices[i].x := c[1]; { внесение изменений в модель } Shape.vertices[i].y := c[2]; { в соответствии с полученным } Shape.vertices[i].z := c[3] { результатом преобразования } end end; procedure MoveShape(Shape: Object3D; Width, Height: Real); begin if Shape.xc > Width then begin Shape.xc := Width; Shape.Vx := -Shape.Vx end; if Shape.xc < -Width then begin Shape.xc := -Width; Shape.Vx := -Shape.Vx end; if Shape.yc > Height then begin Shape.yc := Height; Shape.Vy := -Shape.Vy end; if Shape.yc < -Height then begin Shape.yc := -Height; Shape.Vy := -Shape.Vy end; if Shape.zc > 500 then begin Shape.zc := 500; Shape.Vz := -Shape.Vz end; if Shape.zc < 200 then begin Shape.zc := 200; Shape.Vz := -Shape.Vz end; end; procedure ResizeShape(var Shape: Object3D; sx, sy, sz: Real); var mm: Matrix; i: Integer; c: Column; begin mm := ResizeMatrix(sx, sy, sz); c[4] := 1; for i := 0 to High(Shape.vertices) do begin c[1] := Shape.vertices[i].x; c[2] := Shape.vertices[i].y; c[3] := Shape.vertices[i].z; c := MCMult(mm, c); Shape.vertices[i].x := c[1]; Shape.vertices[i].y := c[2]; Shape.vertices[i].z := c[3] end end; end.