Seite 1 von 2

Vector-Class

Verfasst: 19.09.2005 20:24
von remi_meier
oder so...

# Also was ist das?
Ein Interface zum Rechnen mit Vektoren.
# Ist das schwer?
Nö. Beispiel am Code angehängt.
# Was ist ein Interface?
Lies die PB-Hilfe.
# Vorteile?
Objektorientierter Ansatz, nicht zu langsam, übersichtlich.
# Ne genauere Beschreibung wär schon gut...
Sry, so viel Zeit nehm ich mir nicht.
# Brauch ich nicht.
Mir egal.

Code: Alles auswählen

Structure cOVECTORVT
	; Functions
	fSetXYZ.l
	fSetV.l
	fGetX.l
	fGetY.l
	fGetZ.l
	fGetLength.l
	fGetLengthSqr.l
	fSetX.l
	fSetY.l
	fSetZ.l
	fAddV.l
	fAddXYZ.l
	fSubV.l
	fSubXYZ.l
	fGetDotPV.l
	fCrossPV.l
	fCpy2OV.l
	fMul.l
	fDiv.l
	fNormalize.l
	fGetDataPtr.l
	fGetDataFromMem.l
	fRotateAroundX.l
	fRotateAroundY.l
	fRotateAroundZ.l
	fRotateAroundV.l
EndStructure

Structure cOVECTOR
	VTable.l
	
	; Data
	x.f
	y.f
	z.f
EndStructure

Interface iOVECTOR
	SetXYZ(x.f, y.f, z.f)
	SetV(*v.cOVECTOR)
	GetX.f()
	GetY.f()
	GetZ.f()
	GetLength.f()
	GetLengthSqr.f()
	SetX(x.f)
	SetY(y.f)
	SetZ(z.f)
	AddV(*v.cOVECTOR)
	AddXYZ(x.f, y.f, z.f)
	SubV(*v.cOVECTOR)
	SubXYZ(x.f, y.f, z.f)
	GetDotPV.f(*v.cOVECTOR)
	CrossPV(*v.cOVECTOR)
	Cpy2OV.l()
	Mul(Factor.f)
	Div(Divisor.f)
	Normalize()
	GetDataPtr.l()
	GetDataFromMem(*mem)
	RotateAroundX(a.f)
	RotateAroundY(a.f)
	RotateAroundZ(a.f)
	RotateAroundV(*v.cOVECTOR, a.f)
EndInterface



Procedure vect_SetXYZ(*this.cOVECTOR, x.f, y.f, z.f)
	*this\x = x
	*this\y = y
	*this\z = z
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_SetV(*this.cOVECTOR, *v.cOVECTOR)
	If *v
		*this\x = *v\x
		*this\y = *v\y
		*this\z = *v\z
	EndIf
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure.f vect_GetX(*this.cOVECTOR)
	ProcedureReturn *this\x
EndProcedure

Procedure.f vect_GetY(*this.cOVECTOR)
	ProcedureReturn *this\y
EndProcedure

Procedure.f vect_GetZ(*this.cOVECTOR)
	ProcedureReturn *this\z
EndProcedure

Procedure.f vect_GetLength(*this.cOVECTOR)
	ProcedureReturn Sqr(*this\x * *this\x + *this\y * *this\y + *this\z * *this\z)
EndProcedure

Procedure.f vect_GetLengthSqr(*this.cOVECTOR)
	ProcedureReturn *this\x * *this\x + *this\y * *this\y + *this\z * *this\z
EndProcedure

Procedure vect_SetX(*this.cOVECTOR, x.f)
	*this\x = x
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_SetY(*this.cOVECTOR, y.f)
	*this\y = y
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_SetZ(*this.cOVECTOR, z.f)
	*this\z = z
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_AddV(*this.cOVECTOR, *v.cOVECTOR)
	If *v
		*this\x + *v\x
		*this\y + *v\y
		*this\z + *v\z
	EndIf
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_AddXYZ(*this.cOVECTOR, x.f, y.f, z.f)
	*this\x + x
	*this\y + y
	*this\z + z
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_SubV(*this.cOVECTOR, *v.cOVECTOR)
	If *v
		*this\x - *v\x
		*this\y - *v\y
		*this\z - *v\z
	EndIf
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_SubXYZ(*this.cOVECTOR, x.f, y.f, z.f)
	*this\x - x
	*this\y - y
	*this\z - z
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure.f vect_GetDotPV(*this.cOVECTOR, *v.cOVECTOR)
	If *v
		ProcedureReturn *this\x * *v\x + *this\y * *v\y + *this\z * *v\z
	EndIf
	
	ProcedureReturn 0
EndProcedure

Procedure vect_CrossPV(*this.cOVECTOR, *v.cOVECTOR)
	Protected vx.f, vy.f, tx.f, ty.f, tz.f
	
	If *v
		tx = *this\x
		ty = *this\y
		tz = *this\z
		*this\x = ty * *v\z - tz * *v\y
		*this\y = tz * *v\x - tx * *v\z
		*this\z = tx * *v\y - ty * *v\x
	EndIf
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Declare new_ovector()
Procedure vect_Cpy2OV(*this.cOVECTOR)
	Protected *v.iOVECTOR
	
	*v.iOVECTOR = new_ovector()
	*v\SetV(*this)
	
	ProcedureReturn *v
EndProcedure

Procedure vect_Mul(*this.cOVECTOR, Factor.f)
	*this\x * Factor
	*this\y * Factor
	*this\z * Factor
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_Div(*this.cOVECTOR, Divisor.f)
	Protected f.f
	
	f = 1.0 / Divisor
	*this\x * f
	*this\y * f
	*this\z * f
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_Normalize(*this.cOVECTOR)
	Protected Len.f
	
	Len = 1.0 / vect_GetLength(*this)
	*this\x * Len
	*this\y * Len
	*this\z * Len
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure.l vect_GetDataPtr(*this.cOVECTOR)
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_GetDataFromMem(*this.cOVECTOR, *mem)
	CopyMemory(*mem, *this + OffsetOf(cOVECTOR\x), 3 * 4)
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_RotateAroundX(*this.cOVECTOR, a.f)
	Protected x.f, y.f, z.f
	
	x = *this\x
	y = *this\y
	z = *this\z
	; M * *this
	*this\x = x
	*this\y = Cos(a) * y - Sin(a) * z
	*this\z = Sin(a) * y + Cos(a) * z
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_RotateAroundY(*this.cOVECTOR, a.f)
	Protected x.f, y.f, z.f
	
	x = *this\x
	y = *this\y
	z = *this\z
	; M * *this
	*this\x = Cos(a) * x + Sin(a) * z
	*this\y = y
	*this\z = -Sin(a) * x + Cos(a) * z
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_RotateAroundZ(*this.cOVECTOR, a.f)
	Protected x.f, y.f, z.f
	
	x = *this\x
	y = *this\y
	z = *this\z
	; M * *this
	*this\x = Cos(a) * x - Sin(a) * y
	*this\y = Sin(a) * x + Cos(a) * y
	*this\z = z
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure

Procedure vect_RotateAroundV(*this.cOVECTOR, *v.cOVECTOR, a.f) ; *v has to be normalized
	Protected x.f, y.f, z.f, cosa.f, sina.f, ecosa.f
	
	cosa = Cos(a)
	sina = Sin(a)
	ecosa = 1.0 - cosa
	
	x = *this\x
	y = *this\y
	z = *this\z
	; M * *this
	*this\x = x * (cosa + *v\x * *v\x * ecosa) + y * (*v\x * *v\y * ecosa - *v\z * sina) + z * (*v\x * *v\z * ecosa + *v\y * sina)
	*this\y = x * (*v\y * *v\x * ecosa + *v\z * sina) + y * (cosa + *v\y * *v\y * ecosa) + z * (*v\y * *v\z * ecosa - *v\x * sina)
	*this\z = x * (*v\z * *v\x * ecosa - *v\y * sina) + y * (*v\z * *v\y * ecosa + *v\x * sina) + z * (cosa + *v\z * *v\z * ecosa)
	
	
	ProcedureReturn *this + OffsetOf(cOVECTOR\x)
EndProcedure




Procedure.l new_ovector()
	Protected *v.cOVECTOR
	Static *VTable.cOVECTORVT
	
	If *VTable = 0
		*VTable = AllocateMemory(SizeOf(cOVECTORVT))
		*VTable\fSetXYZ				= @vect_SetXYZ()
		*VTable\fSetV					= @vect_SetV()
		*VTable\fGetX					= @vect_GetX()
		*VTable\fGetY					= @vect_GetY()
		*VTable\fGetZ					= @vect_GetZ()
		*VTable\fGetLength		= @vect_GetLength()
		*VTable\fGetLengthSqr	= @vect_GetLengthSqr()
		*VTable\fSetX					= @vect_SetX()
		*VTable\fSetY					= @vect_SetY()
		*VTable\fSetZ					= @vect_SetZ()
		*VTable\fAddV					= @vect_AddV()
		*VTable\fAddXYZ				= @vect_AddXYZ()
		*VTable\fSubV					= @vect_SubV()
		*VTable\fSubXYZ				= @vect_SubXYZ()
		*VTable\fGetDotPV			= @vect_GetDotPV()
		*VTable\fCrossPV			= @vect_CrossPV()
		*VTable\fCpy2OV				= @vect_Cpy2OV()
		*VTable\fMul					= @vect_Mul()
		*VTable\fDiv					= @vect_Div()
		*VTable\fNormalize		= @vect_Normalize()
		*VTable\fGetDataPtr		= @vect_GetDataPtr()
		*VTable\fGetDataFromMem = @vect_GetDataFromMem()
		*VTable\fRotateAroundX	= @vect_RotateAroundX()
		*VTable\fRotateAroundY	= @vect_RotateAroundY()
		*VTable\fRotateAroundZ	= @vect_RotateAroundZ()
		*VTable\fRotateAroundV	= @vect_RotateAroundV()
	EndIf
	
	*v = AllocateMemory(SizeOf(cOVECTOR))
	*v\VTABLE = *VTable
		
	ProcedureReturn *v
EndProcedure



; DefType.iOVECTOR a, b
; 
; a = new_ovector()
; b = new_ovector()
; 
; a\SetXYZ(1, 2, 0)
; b\SetXYZ(2, 3, 0)
; a\SubV(b)
; 
; Debug a\GetX()
; Debug a\GetY()
; Debug a\GetZ()
; 
; a\Normalize()
; Debug a\GetX()
; Debug a\GetY()
; Debug a\GetZ()
; 
; Debug a\GetLength()
; Debug a\GetLengthSqr()

; NewList vec.iOVECTOR()
; AddElement(vec())
; vec() = new_ovector()
; vec()\SetXYZ(1, 2, 0)
; 
; AddElement(vec())
; vec() = new_ovector()
; vec()\SetXYZ(3, 21, 0)
; 
; Debug vec()\GetX()




; DefType.iOVECTOR a, b
; 
; a = new_ovector()
; b = new_ovector()
; 
; a\SetXYZ(0, 10, 0)
; b\SetXYZ(1, 0, 0) ; X-Achse ^^
; b\Normalize() ; wäre nicht nötig hier
; 
; Debug a\GetX()
; Debug a\GetY()
; Debug a\GetZ()
; 
; Debug "RotateX"
; a\RotateAroundX(3.1415926 / 2.0)
; Debug a\GetX()
; Debug a\GetY()
; Debug a\GetZ()
; 
; Debug "RotateY"
; a\RotateAroundY(3.1415926 / 2.0)
; Debug a\GetX()
; Debug a\GetY()
; Debug a\GetZ()
; 
; Debug "RotateZ"
; a\RotateAroundZ(3.1415926 / 2.0)
; Debug a\GetX()
; Debug a\GetY()
; Debug a\GetZ()
; 
; Debug "RotateV = RotateX"
; a\RotateAroundV(b, 3.1415926 / 2.0)
; Debug a\GetX()
; Debug a\GetY()
; Debug a\GetZ()
Entstand so nebenbei...

Wenns Ergänzungen gibt, kann sie jeder selbst schreiben und hier posten,
oder mir sagen, dann werd ich sie einbauen.

greetz
Remi

[EDIT] VTable nur noch 1x erstellt.
[EDIT2] Paar Funktionen hinzugefügt

Verfasst: 19.09.2005 20:40
von NicTheQuick
Hey Remi!

Super Idee, das so zu machen.
Ich frag mich gerade, warum ich das in meiner Raytracing-Engine nicht auch so gelöst habe.

///Edit: Ah, ich weiß warum: Es verbraucht bei zu vielen Vektoren einfach zu viel Speicherplatz. /:->

Verfasst: 19.09.2005 21:09
von remi_meier
:D
Ok, ich baus ev. um, dass die VTable nur einmal gebraucht wird (ist so
irgendwie schon unsinnig^^)

Verfasst: 20.09.2005 11:45
von Sylvia
>>remi_meier: oder so...

Was ist denn das für eine Art, einen Thread zu beginnen ?
Um was geht es hier eigentlich ? :? :roll:

Verfasst: 20.09.2005 18:31
von remi_meier
Sylvia hat geschrieben:>>remi_meier: oder so...
Was ist denn das für eine Art, einen Thread zu beginnen ?
Ne eigene <)

> Um was geht es hier eigentlich ?
Recht haste :roll: , hab mal einen kleinen Kommentar oben hinzugefügt.

@Nic:
VTable wir jetzt nur noch einmal erstellt -> SizeOf(cOVECTOR) = 16b

Verfasst: 21.09.2005 07:42
von DarkDragon
Es ist wirklich schade, dass man Operatoren noch nicht damit bestimmen kann. :lol:

Dann könnte man folgendes machen:

Code: Alles auswählen

Vector3.CVector3F = Vector1.CVector3F+Vector2.CVector3F

Verfasst: 22.09.2005 11:56
von Hellhound66
Remi, wenn Du für jeden VT nutzt, dann ists aber auch essig mit ner Vererbung, oder? Ich mein, bei Vektoren stört das relativ wenig, aber bei "höheren" Objekten, ich denke da an meine Objekte, du erinnerst Dich, ist das ziemlich dämlich. Da nutz ich lieber dein "altes" Format. Mir erschließt sich nicht so der Sinn hier hinter. Ich meine das für Vektoren zu tun. Da wird wenig vererbt und der Unterschied zwischen V\Set(1,2,3) und Set(v,1,2,3) ist ja nicht allzu groß.

[edit] Liebe Mods. Bitte schreibt es doch in meinen Post rein, wenn ihr was ändert. Dann erschreck ich mich nicht so.[/edit]
Edit NicTheQuick: "Sorry, habs bei dem ganzen Durcheinander vergessen. Aber das nächste mal ganz bestimmt. :) "

Verfasst: 22.09.2005 17:34
von remi_meier
Ein Konzept von OOP ist die Kapselung von Daten und Funktionen, was
ich hiermit tue! Es muss dir nicht gefallen :wink:
Wenn ich die VT jedem Vektor gegeben hätte (war ja am Anfang so), dann
wäre der Speicherverbrauch pro Vektor bei ca. 90bytes gewesen, was
natürlich zu viel ist. Nun hab ich die VT für jeden Vektor gleich.

Für Vererbung sind Interfaces wohl allgemein nicht geeignet, da wenn
einfach mit 'extends' eine Struktur mit VT geerbt wird, weiss man nicht,
wo nun die Funktionen stehen.
Bsp:

Code: Alles auswählen

Structure cOVECTOR
	VTable.l
	
  f1.l
  f2.l
	; Data
	x.f
	y.f
	z.f
EndStructure

Structure cOVECTOR2 extends cOVECTOR
	
  f3.l
	; Data
  u.f
  v.f
EndStructure
Nun wird ev. cOVECTOR am Anfang eingefügt, wobei zwischen der Funktion
f3 und f2 noch Daten stehen. Somit ist Vererbung so gut wie unmöglich
einfach zu realisieren, da dann die VT für das Interface nicht mehr bei-
einander liegt...
Es geht schon, aber ziemlich mühsam. Wenn man z. B. extra Strukturen
für die VTs anlegt (so wie hier), die können dann gegenseitig vererbt werden.
Das Grundobjekt sieht dann so aus:

Code: Alles auswählen

Structure cBase
  *VTable
  ; Data
  u.f
  v.f
EndStructure
Hier muss natürlich die VTable extern vererbt werden, aber dafür sollte
es gehen...

:| Aus diesem Post kommt sicher niemand draus, hab immer wieder was
geändert und neu überlegt... Widersprüche gibts sicher auch noch :?
Ev. bringts ja doch was^^. Aber interessantes Thema!


greetz
Remi <)

BIGEDIT: Da steht wie ichs gemeint habe:
http://forums.purebasic.com/german/viewtopic.php?t=4885

Verfasst: 22.09.2005 18:32
von Hellhound66
Das ist eben der Grund, warum ich bei mir die Interfaces weglasse und callfunctionfast nutze. Wie Du ja schon kennst:

Code: Alles auswählen

Structure _OBJECT
  *Show
  *HandleEvent
EndStructure

Structure _WINDOW Extends _OBJECT
  *Move
  
  X.l
  Y.l
EndStructure

;************* Object Procedures ******************
Procedure _obj_Show(*SELF._OBJECT)
  Debug "Object Show"
EndProcedure

Procedure _obj_HandleEvent(*SELF._OBJECT,Handle.l)
  debug "Object HandleEvent"
EndProcedure

;************* Window Procedures ***************
Procedure _win_Show(*SELF._WINDOW)
  Debug "Window Show"
EndProcedure

Procedure _win_Move(*SELF._WINDOW,_x.l,_y.l)
  *SELF\X = _x
  *SELF\Y = _y
EndProcedure

;**************** Main *****************************
Procedure.l O_CreateObject(SIZE.l)
  *SELF._OBJECT = AllocateMemory(SIZE)
  *SELF\SHOW = @_obj_Show()
  *SELF\HandleEvent = @_obj_HandleEvent()
  ProcedureReturn *SELF
EndProcedure 

Procedure.l O_CreateWindow(SIZE.l)
  *SELF._WINDOW = O_CreateObject(SIZE)
  *SELF\SHOW =@_win_Show()
  *SELF\Move = @_win_Move()
  ProcedureReturn *SELF
EndProcedure

*OBJECT._OBJECT = O_CreateObject(SizeOf(_OBJECT))
*WINDOW._WINDOW = O_CreateWindow(SizeOf(_WINDOW))

CallFunctionFast(*OBJECT\SHOW,*OBJECT)
CallFunctionFast(*WINDOW\SHOW,*WINDOW)

CallFunctionFast(*OBJECT\HandleEvent,*OBJECT,0)
CallFunctionFast(*WINDOW\HandleEvent,*WINDOW,0)

So kann man sehr schön Funktionen überladen. Das einzige, was hier noch fehlt, ist, dass die alten überschriebenen Funktionen in einer Tabelle gespeichert werden, um ein "Inherited Function()" Aufruf zu ermöglichen. Aber das brauche ich eigentlich nicht.

Verfasst: 22.09.2005 18:37
von remi_meier
Geht mit Interfaces glaub auch (wüsste nicht, was hier nicht gehen sollte).
Siehe mein BIGEDIT oben. Du musst dich einfach an strikte Regeln halten
und kannst die Funktionen nicht immer so einfach beim Namen nennen,
sondern musst dir auch bewusst sein, so sie im Speicher sind (für VTable).

Ziehs dir mal rein, sollte alles gehen.

greetz
Remi