Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Задачи _ З-х звенный манипулятор

Автор: Ametist 1.07.2008 16:40

От теоретической части, я перешел к решению задачи. Сначала я сделал просто три линии, которые были связаны между собой, и каждая из которых вращалась в полярной системе координат, но такую работу у меня не приняли и приходится начинать все сначала.
И я поставил себе такую задачу: "Построить три октаэдра, которые бы произвольно вращались относительно любых трех осей координат и были свзяны между собой". Пока вопрос такой, у меня не получается построить сам октаэдр..
Код вот...

 
Program izknigi;
uses crt,graph;
type
Vertex=record
x,y,z:real;
End;

Edge=record
src,dest:integer;
End;
Object3D=record
vertices:array [0..5] of Vertex;
edges:array [0..11] of Edge;
xc,yc,zc:real;
End;
Var
model:object3d;
gm,gd:integer;

Procedure LoadObject3D(var X: Object3D);
var
ff:text;
Nv,Ne:integer;
Shape:Object3D;
i:integer;
Begin
Assign(ff,'D:\oct');
Reset(ff);
Readln(ff,Nv);
For i:=1 to NV do
Readln(ff, Shape.vertices[i].x , Shape.vertices[i].y , Shape.Vertices[i].z);
Readln(ff, Ne);
For i:=1 to Ne do
Readln(ff, Shape.edges[i].src, Shape.edges[i].dest);
Close(ff);
X:=Shape;
End;

procedure ShowShape(Shape: Object3D);
var
i,Xs,Ys:integer;
x,y,z:real;
const n=300;
Begin
For i:=0 to High(Shape.edges) do
Begin
x:=Shape.vertices[Shape.edges[i].src].x + Shape.xc;
y:=Shape.vertices[Shape.edges[i].src].y + Shape.yc;
z:=Shape.vertices[Shape.edges[i].src].z + Shape.zc;
If abs(z)<0.01 then z:=0.01;
Xs:= Round(GetMaxX div 2 + N*x/z);
Ys:= Round(GetMaxY div 2 + N*y/z);
MoveTo(Xs, Ys);
x:=Shape.vertices[Shape.edges[i].dest].x + Shape.xc;
y:=Shape.vertices[Shape.edges[i].dest].y + Shape.yc;
z:=Shape.vertices[Shape.edges[i].dest].z + Shape.zc;
If abs(z)<0.01 then z:=0.01;
Xs:= Round(GetMaxX div 2 + N*x/z);
Ys:= Round(GetMaxY div 2 + N*y/z);
LineTo(Xs,Ys);
End;
End;
Begin
gm:=detect; gd:=1;
InitGraph(gm,gd,'');
LoadObject3D(model);
ShowShape(Model);
CloseGraph;
End.



Xs:= Round(GetMaxX div 2 + N*x/z);
Ys:= Round(GetMaxY div 2 + N*y/z);
Все дело умирает на этих вдух строчках, пишет "error 205 Floating point overflow". Вопрос как это исправить, чтобы все работало?
Внутренность тхт файла выглядит вот так...
6
-100 -100 0
-100 100 0
100 100 0
100 -100 0
0 0 -141.42
0 0 141.42
12
0 1
1 2
2 3
3 0
4 0
4 1
4 2
4 3
5 0
5 1
5 2
5 3

Автор: volvo 1.07.2008 17:02

Цитата
Все дело умирает на этих вдух строчках, пишет "error 205 Floating point overflow".
Умирает у тебя все гораздо раньше, просто труп показывается тебе на этих 2-х строчках... Смотри:

Цитата
Object3D=record
vertices:array [0..5] of Vertex; { <--- Заметь, индексы 0 .. 5, а не 1 .. 6 }
edges:array [0..11] of Edge;
xc,yc,zc:real;
End;

, а дальше?

(процедура LoadObject3D)
Цитата
For i:=1 to NV do
Readln(ff, Shape.vertices[i].x , Shape.vertices[i].y , Shape.Vertices[i].z);

Ну, и куда ты читаешь 6-ую вершину? "На деревню, дедушке"? А вершина с индексом = 0 вообще не заполняется...

Автор: Ametist 1.07.2008 17:26

Переделал на вот так...


Program izknigi;
uses crt,graph;
type
Vertex=record
x,y,z:real;
End;

Edge=record
src,dest:integer;
End;
Object3D=record
vertices:array [1..6] of Vertex;
edges:array [1..12] of Edge;
xc,yc,zc:real;
End;
Var
model:object3d;
gm,gd:integer;

Procedure LoadObject3D(var X: Object3D);
var
ff:text;
Nv,Ne:integer;
Shape:Object3D;
i:integer;
Begin
Assign(ff,'D:\oct');
Reset(ff);
Readln(ff,Nv);
For i:=1 to NV do
Readln(ff, Shape.vertices[i].x , Shape.vertices[i].y , Shape.Vertices[i].z);
Readln(ff, Ne);
For i:=1 to Ne do
Readln(ff, Shape.edges[i].src, Shape.edges[i].dest);
Close(ff);
X:=Shape;
End;

procedure ShowShape(Shape: Object3D);
var
i,Xs,Ys:integer;
x,y,z:real;
const
n=300;
Begin
For i:=1 to High(Shape.edges) do
Begin
x:=Shape.vertices[Shape.edges[i].src].x + Shape.xc;
y:=Shape.vertices[Shape.edges[i].src].y + Shape.yc;
z:=Shape.vertices[Shape.edges[i].src].z + Shape.zc;
If abs(z)<0.01 then z:=0.01;
Xs:= Round(GetMaxX div 2 + N*x/z);
Ys:= Round(GetMaxY div 2 + N*y/z);
MoveTo(Xs, Ys);
x:=Shape.vertices[Shape.edges[i].dest].x + Shape.xc;
y:=Shape.vertices[Shape.edges[i].dest].y + Shape.yc;
z:=Shape.vertices[Shape.edges[i].dest].z + Shape.zc;
If abs(z)<0.01 then z:=0.01;
Xs:= Round(GetMaxX div 2 + N*x/z);
Ys:= Round(GetMaxY div 2 + N*y/z);
LineTo(Xs,Ys);
End;
End;
Begin
gm:=detect; gd:=1;
InitGraph(gm,gd,'');
LoadObject3D(model);
ShowShape(Model);
CloseGraph;
End.


Ничего не поменялась.. опять таже ошибка на том же самом месте. Или опять я что-то не так сделал?

Автор: volvo 1.07.2008 19:44

Цитата
Переделал на вот так...
Это ничего не дает... У тебя из файла читаются индексы (в Edges), начиная с 0, а не с 1-цы, и следовательно, при попытке обратиться к
x:=Shape.vertices[Shape.edges[i].src].x + Shape.xc;

(когда Shape.edges[i].src = 0) произойдет ни что иное, как выход за пределы массива... Зайди уже в меню Options -> Compiler, и включи там Range Checking (и больше никогда не отключай, если хочешь бОльшую часть времени писать программы, а не заниматься отловом глюков)

Надо было менять вот так:
...
Reset(ff);
Readln(ff,Nv);
For i:=0 to pred(NV) do
Readln(ff, Shape.vertices[i].x , Shape.vertices[i].y , Shape.Vertices[i].z);
Readln(ff, Ne);
For i:=0 to pred(Ne) do
Readln(ff, Shape.edges[i].src, Shape.edges[i].dest);
Close(ff);
...


Но и это тебе ничего не даст... Программа все равно нерабочая. По одной простой причине: у тебя не инициализируются поля xc, yc, zc в структуре. А при вычислении X, Y и Z они используются... Все бы ничего, НО...

Ты не заполняешь сразу структуру, переданную, в Var параметр, а сначала заполняешь локальную, и только потом присваиваешь выходной структуре ее значения. Разница в твоем случае - катастрофическая: если в глобальной структуре Турбо Паскаль инициализирует все числовые значения нулем, то в локальной - ничего не инициализируется, остаются те значения, которые были в памяти на момент создания структуры...

Вот, например, при просмотре поля zc я вижу там число 4.087277324625618E+129 - представляешь, что получится в результате?

Автор: Ametist 1.07.2008 19:52

Огромное спасибо. Сейчас буду разбираться...

Автор: Ametist 2.07.2008 23:21

Отрисовать и завертеть параллелепипед я сумел. Спасибо еще раз Volvo, очень мне помог.


Program izknigi;
uses crt,graph;
type
Vertex=record
x,y,z:real;
End;

Edge=record
src,dest:integer;
End;
Object3D=record
vertices:array [1..8] of Vertex;
edges:array [1..12] of Edge;
xc,yc,zc:real;
End;
Matrix=array[1..4,1..4] of Real;
Column=array[1..4] of Real;
Var
model:object3d;
l,gm,gd:integer;
buf:matrix;
t:char;

Procedure MMMult(lhs,rhs:Matrix; var r: Matrix);
var
I,j,k:integer;
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;
End;
Procedure MCMult(lhs:matrix; rhs:column;var r:column);
Var
k,i:integer;
s:real;
Begin
For i:=1 to 4 do
Begin
s:=0;
For k:=1 to 4 do
s:=s+lhs[i,k]*rhs[k];
r[i]:=s;
end;
End;

Procedure RotateMatrix( xa,ya,za:real;var r:Matrix);
var
xr,yr,zr: Matrix;
v:Matrix;
Begin
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;

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;

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;
MMMult(xr,yr,v);
MMMult(v,zr,r);
End;

Procedure RotateShape(xa,ya,za:real; var Shape:Object3D);
var
rm:matrix;
i:integer;
c:column;
Begin
RotateMatrix(xa,ya,za,rm);
c[4]:=1;
For i:=1 to High(Shape.vertices) do
Begin;
C[1]:= shape.vertices[i].x;
C[2]:= shape.vertices[i].y;
C[3]:= shape.vertices[i].z;

McMult(rm,c,c);

shape.vertices[i].x:=c[1];
shape.vertices[i].y:=c[2];
shape.vertices[i].z:=c[3];
End;
End;

Procedure LoadObject3D(var Shape: Object3D);
var
ff:text;
Nv,Ne:integer;
i:integer;
Begin
Assign(ff,'D:\oct');
Reset(ff);
Readln(ff,Nv);
For i:=1 to NV do
Readln(ff, Shape.vertices[i].x , Shape.vertices[i].y , Shape.Vertices[i].z);
Readln(ff, Ne);
For i:=1 to Ne do
Readln(ff, Shape.edges[i].src, Shape.edges[i].dest);
Shape.xc:=200; Shape.yc:=200;Shape.zc:=0;
Close(ff);
End;

procedure ShowShape(Shape: Object3D);
var
i:integer;Xs,Ys:real;
x,y,z:real;
const
n=300;
Begin
For i:=1 to High(Shape.edges) do
Begin
x:=Shape.vertices[Shape.edges[i].src].x+Shape.xc;
y:=Shape.vertices[Shape.edges[i].src].y+Shape.yc;
z:=Shape.vertices[Shape.edges[i].src].z+Shape.zc;
If abs(z)<0.01 then z:=0.01;
Xs:=320+x-y*cos(pi/4);
Ys:=240+y*sin(pi/4)-z;
MoveTo(Round(Xs/2),Round(Ys/2));
x:=Shape.vertices[Shape.edges[i].dest].x + Shape.xc;
y:=Shape.vertices[Shape.edges[i].dest].y + Shape.yc;
z:=Shape.vertices[Shape.edges[i].dest].z + Shape.zc;
If abs(z)<0.01 then z:=0.01;
Xs:=320+x-y*cos(pi/4);
Ys:=240+y*sin(pi/4)-z;
LineTo(Round(Xs/2),Round(Ys/2));
End;
End;
Begin
LoadObject3D(model);
gm:=detect; gd:=1;
InitGraph(gm,gd,'');
ShowShape(Model);
Repeat
T:=readkey;
case t of
#49: Begin
ClearDevice;
RotateShape(pi/24,0,0,model);
ShowShape(Model);
End;
#50: Begin
ClearDevice;
RotateShape(0,pi/24,0,model);
ShowShape(Model);
End;
#51: Begin
ClearDevice;
RotateShape(0,0,pi/24,model);
ShowShape(Model);
End;
End;
until t=#27;
CloseGraph;
End.


Содержимое файла для считывания выглядит вот так:
8
-10 -5 0
-10 5 0
10 5 0
10 -5 0
-10 -5 100
-10 5 100
10 5 100
10 -5 100
12
1 2
2 3
3 4
4 1
5 6
6 7
7 8
8 5
5 1
6 2
7 3
8 4
Теперь мне остался последний штрих, надо связать три таких параллелепипеда, и сделать так,чтобы когда крутился первый, крутились бы второй и третий. Все бы хорошо, НО. Когда я кручу второй вместе с третим, то они улетают от первого. Вопрос как сделать так, чтобы оси для второго выходили из конца первого параллелепипеда?

Автор: volvo 2.07.2008 23:50

Цитата
Вопрос как сделать так, чтобы оси для второго выходили из конца первого параллелепипеда?
У тебя же есть координаты "конца" первого параллелепипеда (ну, скажем, середина той грани, к которой крепится второй параллелепипед может быть вычислена без проблем в любое время)? так вот высчитывай положение второго "кубика" относительно начала координат, так же, как делаешь с первым, а потом, только для того, чтобы отрисовать второй "кубик" делай пересчет координат его вершин (добавляй к каждой координате каждой вершины координату "конца" первого "кубика"). Повторяю: только отрисовывать с новыми координатами.

Фактически, достаточно в твою программу добавить процедуру сложения записи типа Object3D и структуры, хранящей 3 координаты X, Y, Z; и в ShowShape передавать не один параметр, а два: первый - это сам "кубик", а второй - это "концевая точка" предыдущего объекта (для первого "кубика" - нули по всем координатам), а уже внутри нее заводишь локальную переменную типа Object3D, в нее заносишь сумму Shape и той самой "концевой точки предыдущего объекта", и отрисовываешь именно ЭТУ структуру.

Попробуй сделать это сам, если не получится - обращайся smile.gif

Кстати, твою программу можно упростить, насколько я вижу.