Die Pipelines in CAD3D

CAD3D ist eines der wenigen 3D-CAD Programme, die es für den ATARI ST-Computer gibt. In dem Review in dieser Zeitung [3] wurde darauf verwiesen, daß der Autor Tom Hudson eine Communication Pipeline entworfen hat, die allen Programmierern Zugang zu den Routinen dieses Programms ermöglicht. Dieses ist nun das erste Beispiel, wie man sich die Routinen des CAD3D für eigene Zwecke zunutze macht. Die Originaldokumentation aller Routinen findet man auf der 3D-Developers Disk for CAD3D, Best. Nr. ST0244 der Firma Antic Publishing.

Die tägliche Neuerfindung des Rades

Nichts ist uneffektiver und frustrierender, als nach tage-, wochen- oder gar monatelanger Arbeit festzustellen, daß es für das Problem, das man gerade unter den Tasten hat, bereits eine Lösung (sprich: ein Programm) gibt. Eines der Probleme, die man getrost vergessen kann, ist die Darstellung von Körpern auf dem flachen Bildschirm des Computers; vorausgesetzt, man hat CAD3D und die nötige Zeit, das Objekt einzugeben. Hat man beide Hürden genommen, wird man durch eine gelungene 3D-Darstellung entschädigt, womöglich noch in Farbe und Stereo. Wer von CAD3D bisher nichts gehört hat, sollte seinen Stapel alter ST-Hefte nochmals durchwühlen und nach [3] suchen. Dort findet sich ein Bericht über dieses leistungsfähige 3D-Programm. Kommen wir nun zum Kern der Sache. Schon seit längerem spukt mir ein Artikel über den Hypercubus im Kopf herum, der in der Zeitschrift Spektrum der Wissenschaft [2] erschienen ist. Ein Hypercubus ist nichts anderes als ein vierdimensionaler Würfel. Und so, wie man einen dreidimensionalen Würfel auf ein Blatt Papier projizieren kann, kann man einen vierdimensionalen Würfel in den dreidimensionalen Raum (unsere Umwelt) projizieren. Das Ergebnis ist ein Körper, dessen Umrisse nicht immer denen eines Würfels ähneln. Ein erster Versuch, sich das Ergebnis vorzustellen, ist in [4] veröffentlicht. Hier allerdings ist der Körper als Kantenmodell dargestellt. Und das ist nicht zu vergleichen mit dem räumlichen Eindruck, den CAD3D ermöglicht. Und wenn noch eine Stereobrille für den rechten räumlichen Eindruck sorgt, dann steht einer experiementellen räumlichen Geometrie nur noch die eigene Phantasie im Weg.

Der Hypercubus

Abb. 1 zeigt einen Würfel, dessen Eckpunkte um den Ursprung eines kartesischen Koordinatensystems herum angeordnet sind. Jeder Punkt in einem solchen dreidimensionalen Koordinatensystem ist durch ein Zahlentripel eindeutig festgelegt. Diese drei Zahlen heißen die Koordinaten des Punktes. Nehmen wir der Einfachheit halber an, daß die Kantenlänge des Würfels 2 beträgt, dann lassen sich die Koordinaten der 8 Eckpunkte des Würfels leicht angeben:

	W0 (-1/-1/-1)
	W1 (+1/-1/-1)
	W2 (-1/+1/-1)
	W3 (+1/+1/-1)
	W4 (-1/-1/+1)
	W5 (+1/-1/+1)
	W6 (-1/+1/+1)
	W7 (+1/+1/+1)

Diese Eckpunkte sind (soweit sichtbar) in Abb.1 mit ihrem Index eingezeichnet. Einen vierdimensionalen Hypercubus erhalten wir, indem wir uns in die vierte Dimension aufschwingen und das gleiche Bildungsgesetz für neu hinzukommende Eckpunkte des Hypercubus anwenden:

	H0	(-1/-1/-1/-1)
	H1	(+1/-1/-1/-1)
	H2	(-1/+1/-1/-1)
	H3	(+1/+1/-1/-1)
	H4	(-1/-1/+1/-1)
	H5	(+1/-1/+1/-1)
	H6	(-1/+1/+1/-1)
	H7	(+1/+1/+1/-1)
	H8	(-1/-1/-1/+1)
	H9	(+1/-1/-1/+1)
	H10	(-1/+1/-1/+1)
	H11	(+1/+1/-1/+1)
	H12	(-1/-1/+1/+1)
	H13	(+1/-1/+1/+1)
	H14	(-1/+1/+1/+1)
	H15	(+1/+1/+1/+1)

So leicht die Eckpunkte dieses Hypercubus auch anzugeben sind, man kann sich dieses Gebilde nicht mehr vorstellen (oder können Sie etwa...???).

Schattenspiele

Stellen Sie sich vor, Sie nehmen den Würfel aus Abb. 1 als Kantenmodell und stellen ihn in die Mittagssonne. Auf dem Boden sehen Sie dann einen Schatten. Der Mathematiker spricht von einer Projektion eines dreidimensionalen Körpers auf eine Ebene (zweidimensionale Fläche). Die Projektion eines Eckpunktes auf die xy-Ebene läßt sich mathematisch ganz einfach dadurch berechnen, daß man die z-Koordinate des entsprechenden Punktes 0 setzt. W=', der Schatten von W= auf die xy-Ebene, hätte demnach die Koordinaten W0'(-1/-1/0). Bei dieser Projektion fallen dann jeweils die Projektionen zweier Eckpunkte zusammen; in diesem Fall WO' und W4'. Durch dieses Verfahren gelingt es uns, einen dreidimensiona-

len Körper auf einer zweidimensionalen Fläche darzustellen. Die Punkte des dreidimensionalen Raumes hatten wir in einem Koordinatensystem angegeben, in dem drei Achsen wechselseitig aufeinander senkrecht stehen und in gleiche Einheiten eingeteilt sind (kartesisches Koordinatensystem). Analog dazu denkt man sich ein kartesisches Koordinatensystem für den vierdimensionalen Raum so, daß die vier Koordinatenachsen ebenfalls aufeinander senkrecht stehen; wobei die vierte Achse auf den drei Achsen, die den dreidimensionalen Raum aufspannen, senkrecht steht, in diesem also nicht als Achse sichtbar ist. Falls Sie sich das noch räumlich vorstellen können, gehören Sie zweifellos zu der bevorzugten Gattung Mensch, die einen Rubick Cube aus jeder Stellung mit einer einzigen Drehung in der vierten Dimension innerhalb von 0.02 msec in seine Ausgangslage drehen kann. Aber rechnen kann man in der vierten Dimension vorzüglich. Vor allem lassen sich die Eckpunkte des Hypercubus aus der vierten Dimension in den dreidimensionalen Raum projizieren. Aber dieser “Schatten” ist nicht flächig sondern räumlich (eben dreidimensional). Auch bei dieser Projektion entlang der vierten Koordinatenachse (Parallelprojektion) fallen jeweils zwei Punkte zusammen. z.B. H0'(-1/-1/-1/0) und H8'(-1/-1/-1/0). Die Projektion des Hypercubus in den dreidimensionalen Raum sieht also wie ein normaler Würfel aus. Interessant wird es erst, wenn man den Hypercubus in einer Ebene, die die vierte Koordinatenachse enthält dreht. Dann nämlich werden durch die Drehung die beiden Punkte H=' und H8' im dreidimensionalen Raum getrennt und fallen nicht mehr zusammen.

Mathematische Pirouetten

Um die Drehung eines Körpers zu erklären, bedarf es zunächst der Einführung eines neuen Begriffes: des Vektors. Dies ist ein gerichtetes Objekt (Pfeil) mit einer bestimmten Länge, einer bestimmten Richtung im Raum (Trägergerade) und einer Orientierung. Bindet man nun einen Vektor am Ursprung des Koordinatensystems fest, erhält man einen Ortsvektor, dessen Spitze auf einen Punkt im Raum zeigt (Abb.2). Der Ortsvektor zum Punkt HO hätte dann folgende Darstellung:

		-1
		-1
r0 =	-1
		-1

Im Gegensatz zur Koordinatenschreibweise eines Punktes, schreibt man den affinen (verwandten) Ortsvektor senkrecht (Spaltenschreibweise) um Verwechslungen zu vermeiden. Will man nun den Punkt um eine Koordinatenachse drehen, läßt sich das mit Hilfe der Vektorrechnung einfach als Multiplikation des Ortsvektors mit der Drehmatrix erledigen.

Die Wirbelmatratze (Drehmatrix)

Um die Drehung in einem vierdimensionalen Vektorraum auszuführen, braucht man eine 4x4-Matrix folgenden Aufbaus: Die Hauptdiagonale der Drehmatrix ist 1, außer an den Stellen, die den Index einer der Achsen der Drehebene tragen. Die Außendiagonalelemente sind alle Null, außer denjenigen, deren Index gleich einer Achsennummer der Drehebene ist. Die Werte der Diagonalelemente sind der Cosinus des Drehwinkels, die Werte der Außerdiagonalelemente sind der Sinus bzw. Sinus des Drehwinkels, je nach Anordnung. Nehmen wir z.B. an, es soll eine Drehung in der 1-2-Ebene um den Winkel a durchgeführt werden. Die Drehmatrix hätte dann die Form:

	1	0		0		0
	0	cosa	sina	0
	0	-sina	cosa	0
	0	0		0		1

Die Koordinatenachsen sind der Einfachheit halber von 0 bis 3 durchnumeriert. Das Ergebnis der Drehung, also den gedrehten Ortsvektor, erhält man durch Multiplikation des Ortsvektors mit der Drehmatrix:

Wer sich eingehender mit der Mathematik beschäftigen möchte, dem sei [1] empfohlen.

Zur Sache CADzchen

Kommen wir zum Kern der Sache. CAD-3D erlaubt wie gesagt die Benutzung seiner Routinen von fremder Seite über sogenannte Pipelines. Hierzu muß das Anwenderprogramm gleichzeitig mit dem CAD-3D im Speicher resident sein. Das ist am einfachsten zu erreichen, wenn das Anwenderprogramm als Accessory vorliegt. Um dem Hypercubus in den dreidimensionalen Teil seines vierdimensionalen Angesichts zu blicken, habe ich ein Accessory geschrieben, das die Koordinaten des Hypercubus berechnet, eine Drehung in einer der Ebenen der vierten Dimension ermöglicht und schließlich ein Objekt erzeugt, welches von CAD-3D verarbeitet werden kann und der Projektion des vierdimensionalen Hypercubus in den dreidimensionalen Objektraum von CAD-3D entspricht. Das so erzeugte Objekt wird an CAD-3D über die Communication-Pipeline übergeben und steht anschließend für weitere Manipulationen in CAD-3D zur Verfügung. Um den Anblick möglichst anschaulich zu gestalten, habe ich einen Trick angewendet. Schaut man sich die Punkte H0 bis H15 des Hypercubus genauer an, so erkennt man 8 Würfel mit jeweils einer gemeinsamen Komponente. Beispielsweise der Würfel bestehend aus H0 bis H7, bei denen die 4. Komponente +1 ist. Diesen Würfel nennt das Programm cubus0. Cubus1 ist dann der Teilwürfel, dessen Eckpunkte die 3. Komponente +1 besitzen etc. Cubusl und cubus7 bilden somit zwei Würfel in CAD-3D, die sich decken. Erst bei einer Drehung in einer Ebene außerhalb des dreidimensionalen Raumes entfällt diese Entartung. Wer einen Farbmonitor besitzt, mag die verschiedenen Teilwürfel nach der Erzeugung beliebig einfärben. Das erhöht bei der anschließenden Betrachtung die Übersichtlichkeit. Geradezu ergreifend wirkt natürlich eine Farbdarstellung mit der Stereobrille.

Die Communication Pipeline

In CAD-3D werden, wie in allen Programmen, die GEM intensiv nutzen, die einzelnen Subroutinen über das event handling verwaltet. Der Autor von CAD-3D ist allerdings hier sehr systematisch vorgegangen und hat jedem Unterprogramm eine Messagenummer mit eindeutig definierten Parametern gegeben, so daß auch von externen Programmen, die gleichzeitig im Speicher sind (Accessories), auf die CAD-3D Routinen zugegriffen werden kann. Die Nummern der einzelnen Routinen und die benötigten Parameter findet man in der Dokumentation zur CAD-3D Developers Disk, die bei ANTIC Software erhältlich ist und für Programmierer eine notwendige Anschaffung ist, wenn man eigene Applikationen für CAD-3D schreiben will. Kennt man die Message Nummern, dann sieht ein typischer Aufruf einer CAD-3D Funktion so aus:

  1. Schreibe eine Message mit den zugehörigen Parametern in den Message Puffer.
  2. Schicke diese Nachricht an CAD-3D.
  3. Warte bis CAD-3D eine Nachricht zurückschickt.
  4. Schaue in der Nachricht von CAD-3D nach, ob die gewünschte Operation erfolgreich verlaufen ist. Wenn nicht, beende das Accessory.

Es gibt bereits ein Motion Control Accessory in der PD von ANTIC Software, das diese Pipeline ausnutzt. Bessere Versionen sollen folgen. Der Hypercubus jedenfalls nutzt diese Pipeline aus, um die Projektionen der Würfel cubusO bis cu-bus7 in das CAD-3D-Programm einzuspeisen. Dazu werden zunächst die Objekte cubusO - cubus7 gelöscht, falls sie bereits vorhanden sind. Dann werden die Würfelkoordinaten an die CAD-3D Objektstruktur übergeben und die Funktion zur Übernahme der Struktur aufgerufen. Wenn dieser Aufruf erfolgreich verläuft, verabschiedet sich das Accessory, und auf dem Bildschirm des CAD-3D Programms stehen die 8 Teilwürfel des Hypercubus für weitere Manipulationen zur Verfügung.

Abb.4: Cubes 0, 3, 4, 7 des Hypercubus im R3. Alle Drehwinkel 45°

Fazit

Abb.4 zeigt die Teilwürfel cubus0, cubus3, cubus4 und cubus7 des Hypercubus in Farbe, wenn er in den Ebenen 0-3, 1-3, 2-3 jeweils um 45 ° gedreht wurde. Listing 1 zeigt das C-Listing des Accessories. Es wurde mit dem Megamax C-Compiler entwickelt. Bitte haben Sie Verständnis dafür, daß wir die RSC-Datei nicht mitabdrucken, da dies den Rahmen deutlich sprengen würde. Wer diese trotzdem gerne zur Verfügung haben möchte, kann sie auf unserer Monatsdiskette November / Dezember '88 bestellen.

Dr. Karl Sarnow

GRUNDLAGEN

Literatur:

[1] Dewdney, A.K. Hyperkubus. Sonderheft Spektrum der Wissenschaft. Computer Kurzweil. p.25ff.
[2] Kowalsky, H.J. Lineare Algebra. Göschens Lehrbücherei, Band 27.
[3] Sarnow, K. CAD-3D - die dritte Dimension. ST Computer 11/87.
[4] Sarnow, K. Der Hypercubus. c t 2/87. p.124.

#include <stdio.h>
#include <gembind.h>
#include <gemdefs.h>
#include <obdefs.h>
#include <osbind.h>
#include <math.h>
#include <vt52.h>
#include "hypercub.h" /*Entfällt bei Einbindung von Listing 2 oder 3*/

#define TRUE (1)
#define FALSE (0)

extern int gl_apid;
int menu_id,cad_id,forever;

int contrl[12], 
	intin[128], 
	intout[128], 
	ptsin[128], 
	ptsout[128];

int work_in[12], 
	work_out[57];

int pxyarray[10]

int handle ;

OBJECT *regler_tree; /* Das Formular in Abb.3 */

int mouse ;	/* mouse ein = 1, aus = 0 */
int gl_dummy ;	/* globaler dummy */

int msgbuff[16]; 
int whand;

int xfull,yfull,wfull,hfull; /* Fensterkoord. */ 
int x_reg1,y_reg1,w_reg1,h_reg1; /* Koordinaten des Formulars */

char *text[3]; /* Zeiger a.Strings i.TEDINFO */ 
double	winkel,zentr,kubus[16][4], 
		dreh[4][4],ecke[16][4];

int cube[8]={-1,-1,-1,-1,-1,-1,-1,-1};
/* ID's der Würfel */

int vertx[8][8],verty[8][8],vertz[8][8];
/* 8 Punkte der 8 Würfel */

int verta[12]= /*Die Punkte eines Würfels*/
{5,5,7,7,6,6,4,4,5,5, 3, 1}; /*bilden Dreiecksflächen. Im Feld verta sind */ 
/*alle Punkte A der 12 Dreiecke enthalten */ 
int vertb[12]= /*i.Feld vertb alle Punkte B der 12 */
{1,3,3,2,2, 0,0,1,7, 6, 1, 0};	/* Dreiecksflächen und in vertc alle Punkte C *

int vertc[12]={3,7,2,6,0,4,1,5,6,4, 2, 2 };

int color[12]={0x060f,0x030f,0x060f,0x030f,0x060f,0x030f,0x060f, 
		0x030f,0x060f,0x030f,0x050f, 0x060f};
/* Das niedere Byte enthält die Farbinformation (15)*/
/* Das obere Byte enthält die Information, welche Kante sichtbar ist*/

int pfad[64]=
	{0,1,2,3,4,5,6,7,0,1,2,3,8,9, 10,11,0,1,4, 5,8,9, 12, 
	13,0,2,4,6,8,10,12,14, 1,3, 5,7,9, 11,13,15,2,3, 6,7,10, 
	11,14,15,4, 5, 6, 7,12,13,14,15, 8, 9,10,11,12,13,14,15}; 
/* Welche Eckpunkte gehören zu welchen Teilwürfeln? */

int mgin[8];/* Event Message Puffer f.CAD-3D Messages*/

/* Object load/unload structure */

struct obj_str
{
	char os_name[9];
	int os_points;
	int os_faces;
	int *os_x;
	int *os_y;
	int *os_z;
	int *os_a;
	int *os_b;
	int *os_c;
	int *os_color;
};

struct obj_str obstrc[8J;

/* Buffer address structure */ 

char noCAD[]="[1][CAD-3D is not present!][ OK ]";

/***********************************************/

open_vwork()
{
	int i,dummy; 

	appl_init();
	handle=graf_handle(&gl_dummy,&gl_dummy, &gl_dummy,&gl_dummy);
	 menu_id=menu_register(gl_apid," Hypercubus"); /*Hypercubus in die Accessory-Leiste */
} /*einklinken*/

close_vwork()	/* Ausstieg, wenn Fehler */
{
	appl_exit();
	exit();
}

show_mouse() /* Weg mit der Maus */
{ if (!mouse)
	{ graf_mouse(257,&gl_dummy); 
	mouse = TRUE;
	}
}

hide_mouse() /* Und wieder her damit */
{ if (mouse)
	{ graf_mouse(256,&gl_dummy);
	mouse = FALSE;
	}
}

rotation(temp) /* Drehung d.Hypercubus durch */ 
register double (*temp)[16][4]; /* Multiplikation der Ortsvektoren */
{				/* mit	der Drehmatrix */
	register int j,k,l;

	for (j=0;j<16;j++) 
		for (k=0;k<4;k++)
		{
			(*temp)[j][k]=0; 
			for (1=0;l<4;l++)
				(*temp)[j][k]+=kubus[j][l]
				*dreh[k][l];
		}
}

multi ()
{ int dummy,i1,i2,achse1,achse2 ;

	wind_get(0,WF_WORKXYWH,&xfull,&yfull,&wfull, &hfull);
	/* Hol die Fensterkoordinaten */ 
	whand=wind_create(0,xfull,yfull,wfull,hfull);
	/* Öffne Fenster */
	wind_open(whand,xfull,yfull,wfull,hfull); 
	do_regler();	/* Formular	abarbeiten	*/
	for (i1=0;i1<16;i1++)
		for (i2=0;i2<4;i2++) kubus[i1][i2] =
		((il & (1 << i2))==0) ? -1.0 : 1.0;
		/* Erzeuge Koordinaten */ 
	for (dummy=0;dummy<3;dummy++)
		{
			switch(dummy)
			{
				case 0: 
					achse1=0; 
					achse2=3; 
					break;

				case 1: 
					achse1=1; 
					achse2=3; 
					break;

				case 2:
					achse1=2; 
					achse2=3; 
					break;
			
			} /* Fallunterscheidung d.3 Drehebenen */ 
			for (i1=0;i1<4;i1++) 
			for (i2=0;i2<4;i2++)
				{
					if (i1==i2) dreh[i1][i2]=1;
					/* Initialisierung d.Drehmatrix */ 
					else dreh[i1][i2]=0;
				}
				winkel=atol(text[dummy]);/* Winkel aus TEDINFO Struktur lesen */
				dreh[achse1][achse1]=dreh[achse2] [achse2]=cos(winkel*dcpi/180);
				/* Diagonalelemente setzen */
				dreh[achse1][achse2]=sin(winkel*dcpi/180):

				/* Außerdiagonalelemente setzen */ 
				dreh[achse2][achse1]=-[achse1][achse2];
				rotation(&ecke); /*Drehung ausführen*/ 
				for (i1=0;i1<16;i1++)/*Ergebnis umspeichern */
				for (i2=0;i2<4;i2++)
					kubus[i1][i2]=ecke[i1][i2];
		}
		do_acc(); /* Übergabe an CAD-3D */
} /* multi */

schieben(nr,vater,kind) /* Manage d.Bedienung des Schiebers */
int nr,vater,kind;
{
	int mx,my,button,state,position; 
	long zwischen;
	evnt_button(1,1,1,&mx,&my,&button,&state); 
	position=graf_slidebox(regler_tree,vater, kind,0);
	/* Finde Reglerposition 0-1000 beim Loslassen */ 
	zwischen=((long)(regler_tree[vater].ob_width)-(long) (regler_tree[kind].ob_width))*((long)(position))/1000L;
	/* Berechnung der neuen Reglerposition */ 
	regler_tree[kind].ob_x=(int)zwischen;
	/* Abspeichern der neuen Reglerposition */ 
	zwischen=((360L*(long)(position))/1000L)-180L; 
	/* Umrechnung d.Schieberposition in Gradzahl*/ 
	sprintf(text[nr],"%1d",zwischen);
	/* Absp.d.Gradzahl als String in TEDINFO */
}

minus10(nr,vater,kind) /* Winkel um 10 Grad verringern */
int nr,vater,kind;
{
	long zwischen;

	zwischen=atol(text[nr])-10L; 
	if(zwischen<-180) zwischen=-180L; 
	sprintf(text[nr],"%1d",zwischen); zwischen=((long)(regler_tree[vater].ob_width) 
			-(long)(regler_tree[kind].ob_width))
			*(zwischen+180)/360L; 
	regler_tree[kind].ob_x=(int)zwischen;
}

minus1(nr,vater,kind)/* Winkel um 1° verringern*/ 
int nr,vater,kind;
{
	long zwischen;
	zwischen=atol(text[nr])-1L; 
	if(zwischen<-180) zwischen=-180L; 
	sprintf (text[nr],"%1d", zwischen) ; 
	zwischen=((long)(regler_tree[vater].ob_width) 			
			-(long)(regler_tree[kind].ob_width))
			*(zwischen+180)/360L; 
	regler_tree[kind].ob_x=(int)zwischen;
}

plus10(nr,vater,kind) /* Winkel um 10° erhöhen */ 
int nr,vater,kind;
{
	long zwischen;

	zwischen=atol(text[nr])+10L; 
	if(zwischen>180) zwischen=180L; 
	sprintf (text[nr], "%1d", zwischen); 
	zwischen=((long)(regler_tree[vater].ob_width)
			-(long)(regler_tree[kind].ob_width))
			*(zwischen+180)/360L; 
	regler_tree[kind].ob_x=(int)zwischen;
}

plus1(nr,vater,kind) /* Winkel um 1° erhöhen */ 
int nr,vater,kind;
{
	long zwischen;

	zwischen=atol(text[nr])+1L; 
	if(zwischen>180) zwischen=180L; 
	sprintf(text[nr],"%1d",zwischen); 
	zwischen=((long)(regler_tree[vater].ob_width) 
			-(long)(regler_tree[kind].ob_width))
			*(zwischen+180)/360L; 
	regler_tree[kind].ob_x=(int)zwischen;
}

do_regler() /* Manage das Formular */
{
	int keycode; 
	long zwischen;

	form_dial(FMD_START,320,200,0,0,x_reg1,y_reg1,w_reg1,h_reg1); /* Zeige das Formular */ 
	form_dial(FMD_GROW,320,200,0,0,x_reg1,y_reg1,w_reg1,h_reg1); /* für die Wahl der Winkel */
	objc_draw(regler_tree,0,80,x_reg1,y_reg1,w_reg1,h_reg1);
	objc_change(regler_tree,REGLEX,0,x_reg1,y_reg1, w_reg1,h_reg1,NORMAL,1); 
	do
		{
			keycode=form_do(regler_tree, 0);
			switch(keycode)
			{
				case MIN103:
					minus10(0,VATER3,SCHIEBE3);
					objc_draw(regler_tree, BOX3,MAX_DEPTH,x_reg1,y_reg1,w_reg1,h_reg1);
					break;

				case MIN105:
					minus10(1,VATER5,SCHIEBE5);
					objc_draw(regler_tree,BOX5,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);
					break; 

				case MIN106:
					minus10(2,VATER6,SCHIEBE6); objc_draw(regler_tree,BOX6,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);
					break; 

				case MIN13:
					minus1(0,VATER3,SCHIEBE3); 
					objc_draw(regler_tree,BOX3,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);
					break; 

				case MIN15:
					minus1(1,VATER5,SCHIEBE5); 				objc_draw(regler_tree,BOX5,MAX_DEPTH,x_reg1,y_reg1,w_reg1,h_reg1);
					break; 

				case MIN16:
					minus1(2,VATER6,SCHIEBE6); 
					objc_draw(regler_tree,BOX6,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);

				case PLUS103:
					plus10(0,VATER3,SCHIEBE3); 
					objc_draw(regler_tree,BOX3,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);
					break;

				case PLUS105:
					plus10(1,VATER5,SCHIEBE5); 
					objc_draw(regler_tree,BOX5,MAX_DEPTH,x_reg1,y_reg1, w_reg1, h_reg1);
					break;

				case PLUS106:
					plus10(2,VATER6,SCHIEBE6); 
					objc_draw(regler_tree,BOX6,MAX_DEPTH,x_reg1,y_reg1, w_reg1, h_reg1);
					break;

				case PLUS13:
					plus1(0,VATER3,SCHIEBE3); 	
					objc_draw(regler_tree,BOX3,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);
					break;

				case PLUS15:
					plus1(1,VATER5,SCHIEBE5); 
					objc_draw(regler_tree,BOX5,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);
					break;

				case PLUS16:
					plus1(2,VATER6,SCHIEBE6) ; 
					objc_draw(regieretree,BOX6,MAX_DEPTH,x_reg1,y_reg1 w_reg1,h_reg1);
					break;

				case SCHIEBE3:
					schieben(0,VATER3,SCHIEBE3); 
					objc_draw(regler_tree,BOX3,MAX_DEPTH,x_reg1,y_reg1, w_reg1,h_reg1);

				case SCHIEBE5:
					schieben(1,VATER5,SCHIEBE5); 
					objc_draw(regler_tree,BOX5,MAX_DEPTH,x_reg1, y_reg1,w_reg1,h_reg1);
					break;

				case SCHIEBE6:
					schieben(2,VATER6,SCHIEBE6); 
					objc_draw(regler_tree,BOX6,MAX_DEPTH,x_reg1, y_reg1 w_reg1,h_reg1);
					break;
			}
		}
		while (keycode!=REGLEX);
		form_dial(FMD_SHRINK,320,200,0,0,x_reg1, y_reg1,w_reg1,h_reg1); 
		form_dial (FMD__FINISH, 320,200,0, 0, x_reg1, y_reg1,w_reg1, h_reg1);
}

main()
{
	int i,event;

	open_vwork(); 
	if (Getrez()==2)
	{
		if (!rsrc_load("hypercub.rsc"))
		{
			form_alert(1,"[3][Ich kann HYPERCUB.RSC nicht finden !][Abbruch]"); 
			close_vwork();
		}
	}
	else
	{
		if (!rsrc_load("hypercol.rsc"))
		{
			form_alert(1,"[3][Ich kann HYPERCOL.RSC nicht finden !][Abbruch]"); 
			close_vwork();
		}
	}
	if (!rsrc_gaddr(R_TREE,REGLER,&regler_tree))
	{
		form_alert(1,"[3][Resource File nicht ok !] [Abbruch]"); 
		close_vwork();
	}
	form_center(regieretree,&x_reg1,&y_reg1, &w_reg1,&h_reg1); 
	text[0]=(((TEDINFO *)
			(regler_tree[GRAD3].ob_spec)) 
			->te_ptext);/* Zeiger auf Formulartexte */
	text[1]=(((TEDINFO *)
			(regler_tree[GRAD5].ob_spec)) 
			->te_ptext); /* initialisieren */ 
	text[2]=(((TEDINFO *)
			(regler_tree[GRAD6].ob_spec)) 
			->te_ptext); 
	for (i=0;i<3;i++) sprintf(text[i],"%d",0);
	/* Winkel auf 0 Grad setzen */
	while(forever==0) /* Warten auf ... */
	{
		evnt_mesag(msgbuff);
		if(msgbuff[0]==40 && msgbuff[4]==menu_id)
		/* HYPERCUBUS wurde aufgerufen */
		{
			cad_id=appl_find("CAD3D2  ");
			/* Ist CAD-3D vorhanden? */
			if(cad_id<0)
				form_alert(1,noCAD); /* Nein, Abbruch */
			else
			{	/* Frage CAD-3d Nach RAM-STATUS */
				toCAD(0x3d00,0,0,0,0,0); /* Falls nach 2000 Einheiten keine Reaktion */ 
				/* liegt ein Fehler vor */ 
				is_there:
				event=evnt_multi(0x0030,-1,-1, -1,
								0,0,0,0,0,
								0,0,0,0,0, 
								mgin,2000,0, 
								&gl_dummy,&gl_dummy, &gl_dummy,&gl_dummy, &gl_dummy,&gl_dummy); 
				if(event & 0x0020)
					form_alert(1,noCAD); 
				else 
				{
					if(mgin[0]==0x3d80)	/* CAD-3D meldet Erfolg */ 
					multi(); /*Stelle Winkel ein und Berechne Koord. */
					else
						goto is_there;
				}
			}
		}
	}
}

/* Found CAD-3D 2.0, let's rock-n-roll! */

do_acc()
{
		register int ix,iy; 
		int loeschen[40];

	for (ix=0;ix<40;ix++) loeschen[ix]=0; 
	for (ix=0;ix<8;ix++) /* Übergebe die berechneten Koordinaten in der */
	{	/* CAD-3D Object Struktur */
		sprintf(obstrc[ix].os_name,"cube%1d",ix);
		obstrc[ix].os_points=8;
		obstrc[ix].os_faces=12;
		obstrc[ix].os_x=vertx[ix];
		obstrc[ix].os_y=verty[ix];
		obstrc[ix].os_z=vertz[ix];
		obstrc[ix].os_a=verta;
		obstrc[ix].os_b=vertb;
		obstrc[ix].os_c=vertc;
		obstrc[ix].os_color=color;
		if (cube[ix]>=0) loeschen[ix]=TRUE;
	}
	if (loeschen[0]) /*Loesche cubus0 - cubus7 falls schon vorhanden*/
	{
		comm_it(mgin,0x3d07,loeschen,0,0,0);
		/* Löschbefehl an CAD-3D */ 
		if (mgin[3]<0)
		{
			disp_err("error erasing object"); 
			goto acc_exit;
		}
	}
	for (ix=0;ix<8;ix++)
	{
		for (iy=0;iy<8;iy++) /*Eingabe d.Punktkoordinaten */
		{	/* in die Objektstruktur */
			vertx[ix][iy]=1000 *kubus[pfad[iy+ix*8]][0]; 
			verty[ix][iy]=1000 *kubus[pfad[iy+ix*8]][1]; 
			vertz[ix][iy]=1000 *kubus[pfad[iy+ix*8]][2];
		}
		comm_it(mgin,0x3d05,&obstrc[ix],0,0,0);
		/* Befehl zur Übernahme des Objektes */ 
		if (mgin[3]<0) /* aus dem RAM */
		{
			disp_err("error loading object"); 
			goto acc_exit;
		}

		cube[ix]=mgin[3]; /* Speichern des Objekt ID */ 
		comm_it(mgin,0x3d58,cube[ix],1,0,0);
		/* Zeige das Objekt */ 
		if (mgin[3]<0)
		{
			disp_err("error selecting object"); 
			goto acc_exit;
		}
	}
	/* Accessory is done, close/delete window and return to main routine */
	
	hide_mouse();

	acc_exit:
	vind_close(whand); 
	wind_delete(whand);
}

comm_it(rbuf,command,v1,v2,v3,v4,v5)
/* Sende den Befehl an CAD-3D */ 
int rbuf[],command,v1,v2,v3,v4,v5;
/* und warte auf Antwort */
{
	toCAD(command,vl,v2,v3,v4,v5);

	do
	{
		evnt_mesag(rbuf);
	}
	while(rbuf[0]!=(command | 0x0080));
}

/***************************************/
/* Send Standard message to CAD-3D 2.0 */
/***************************************/

toCAD(command,v1,v2,v3,v4,v5) 
int command, v1, v2,v3,v4,v5;
{
	msgbuff[0]=command: 
	msgbuff[1]=gl_apid; 
	msgbuff[2]=0; 
	msgbuff[3]=v1; 
	msgbuff[4]=v2; 
	msgbuff[5]=v3; 
	msgbuff[6]=v4;
	msgbuff[7]=v5:
	appl_write(cad_id,16,msgbuff);
}

/********************************************/
/* Display an error message in an alert box */
/********************************************/

disp_err(string) 
char string[];
{
	char errstr[80];

	strcpy(errstr,"[1]["); 
	strcat(errstr,string); 
	strcat(errstr,"\[ OK ]");

	graf_mouse(0,&gl_dummy);

	form_alert(1,errstr);
}

Listing 1: Das C - Listing des Accessories



Aus: ST-Computer 12 / 1988, Seite 114

Links

Copyright-Bestimmungen: siehe Über diese Seite