Matrix Rotation 2D

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
silbersurfer
Beiträge: 175
Registriert: 06.07.2014 12:21

Matrix Rotation 2D

Beitrag von silbersurfer »

Hallo leute

Ich bin dabei für mein Grafik Proggy Rotation einzubinden
was Ich dann mit Matrizen realisieren wollte (anregung durch Stargates Drawing3D)

soweit so gut !

die Rotation klappt

Code: Alles auswählen

Procedure Rotation(*matrix.Matrix2D,winkel.f)
	*Matrix\A11	=Cos(winkel)	: *matrix\A12	=-Sin(winkel)
	*Matrix\A21	=Sin(winkel) 	: *matrix\A22	=Cos(winkel)
	ProcedureReturn *matrix
EndProcedure
die Spieglung nur in x richtung

Code: Alles auswählen

Procedure Spieglung(*matrix.Matrix2D,spx=1,spy=1)
	*Matrix\A11	=spx	: *matrix\A12	=0
	*Matrix\A21	=0	: *matrix\A22	=spy
	ProcedureReturn *matrix
EndProcedure
die Scalierung auch nur in x richtung und mit Rotation wird diese verzehrt

Code: Alles auswählen

Procedure scale(*matrix.Matrix2D,scalex.f=1,scaley.f=1)
	*Matrix\A11	=scalex	: *matrix\A12	=0
	*Matrix\A21	=0		: *matrix\A22	=scaley
	ProcedureReturn *matrix
EndProcedure
hier noch wie ich das ganze dann zusammen Rechnen lasse

Code: Alles auswählen

Procedure BerechnePoint(*matrix.Matrix2D,*point.vertex2D)
	Protected Buffer.vertex2D
	CopyMemory(*point, @Buffer, SizeOf(vertex2D))
	*point\X =Buffer\X**matrix\A11 + Buffer\Y**matrix\A12
	*point\y =Buffer\X**matrix\A21 + Buffer\Y**matrix\A22
	ProcedureReturn *point
EndProcedure

Procedure matrix_Multi(*Use.Matrix2D, *Source.Matrix2d)
	Protected Buffer.Matrix2D
	CopyMemory(*Use, @Buffer, SizeOf(Matrix2d)) 
	With *Use
		\A11 = Buffer\A11 * *Source\A11 + Buffer\A21* *Source\A12
		\A12 = Buffer\A12 * *Source\A11 + Buffer\A22* *Source\A12
		\A21 = Buffer\A11 * *Source\A21 + Buffer\A21* *Source\A22
		\A22 = Buffer\A12 * *Source\A22 + Buffer\A22* *Source\A22	
	EndWith
	ProcedureReturn *Use
EndProcedure
Zeichen lasse Ich dann so

Code: Alles auswählen

Procedure DrawImage2D(*this.Image2D,x,y)
	If (Not *this) : ProcedureReturn #False : EndIf
	Protected *pointer.Matrix2D,Scale.Matrix2D,Rotation.Matrix2D,Spieglung.Matrix2D
	Protected *p1.vertex2D,p1.vertex2D,punkte.i,w.i,h.i,z.i,e.i,width.i,height.i
	

	With *this
		\PosX=x : \PosY=y 
		e = Sqr(\width*\width +\height*\height) 
		width=\width/2+(e-\width)/2
		height=\height/2+(e-\height)/2
		*pointer=scale        (scale,\ScaleX,\ScaleY)
		*pointer=Spieglung		(Spieglung,\FlipX,\FlipY)
		*pointer=Rotation 		(Rotation,Radian(\Winkel))
		*pointer=matrix_Multi	(Scale,Rotation)
		*pointer=matrix_Multi	(Spieglung,*pointer)
		For h=y To y+e-1
			For w=x To x+e-1
				p1\x=w-x-width
				p1\y=h-y-height
				*p1=BerechnePoint(*pointer,p1)	
				*p1\x=*p1\x+\width/2
				*p1\y=*p1\y+\height/2
				If *p1\x>=0 And *p1\x<\width And *p1\y>=0 And *p1\y<\height
					Plot(w,h,\color(Int(*p1\x),Int(*p1\y)))
				EndIf	
			Next 
		Next 	
	EndWith
EndProcedure
Ich hoffe das Ihr oder Stargate meinen Denkfehler mir aufzeigen könnt
Da diese mein erster ausflug in die Welt der Matrizen ist

Gruss Silbersurfer
Intel Quad Core 3,2 Ghz - GTX 1060 - BlitzBasic Plus 1.48 , PureBasic 5.70 LTS / Aktuelles Projekt PureCommander
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Matrix Rotation 2D

Beitrag von STARGÅTE »

Die Matrixmultiplikation ist nicht kommutativ!
Die Transformationsmatrizen "wirken" von rechts nach links.
In deinem Beispiel hast du Spieglung*Scale*Rotation, dass heißt, dein Bild wird erst nach der Rotation skaliert.
Die Skalierung findet aber im globalen Koordinatensystem statt und nicht im lokalen des Bilds.

Falls die Berechnugsprozeduren richtig sind, sollte es so funktionieren:

Code: Alles auswählen

scale(scale,\ScaleX,\ScaleY)
Spieglung(Spieglung,\FlipX,\FlipY)
Rotation(Rotation,Radian(\Winkel))
*pointer=matrix_Multi(Scale,Spieglung)
*pointer=matrix_Multi(Rotation,*pointer)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
silbersurfer
Beiträge: 175
Registriert: 06.07.2014 12:21

Re: Matrix Rotation 2D

Beitrag von silbersurfer »

Danke Stargate für deine schnelle antwort

wenn Ich deine reihenfolge einbaue bekomme Ich schon bei de Rotation verzehrungen
was wohl dann heist, das ich schon bei den berechung fehler haben muß.
wie stelle Ich das dann richtig an!

also

1. Spiegen
2. Scalieren
3. Rotieren
Intel Quad Core 3,2 Ghz - GTX 1060 - BlitzBasic Plus 1.48 , PureBasic 5.70 LTS / Aktuelles Projekt PureCommander
Benutzeravatar
silbersurfer
Beiträge: 175
Registriert: 06.07.2014 12:21

Re: Matrix Rotation 2D (gelöst)

Beitrag von silbersurfer »

So danke nochmal Stargate, habe jetzt alles nochmal durchgesehen und den Fehler gefunden !

hier hatte ich die Multipikation der Matrix verdreht :oops:

Code: Alles auswählen

Procedure BerechnePoint(*matrix.Matrix2D,*point.vertex2D)
   Protected Buffer.vertex2D
   CopyMemory(*point, @Buffer, SizeOf(vertex2D))
   *point\X =Buffer\X**matrix\A11 + Buffer\Y**matrix\A12
   *point\y =Buffer\X**matrix\A21 + Buffer\Y**matrix\A22
   ProcedureReturn *point
EndProcedure
richtig ist es so :mrgreen:

Code: Alles auswählen

Procedure BerechnePoint(*matrix.Matrix2D,*point.vertex2D)
	Protected Buffer.vertex2D
	CopyMemory(*point, @Buffer, SizeOf(vertex2D))
	*point\X =Buffer\X**matrix\A11 + Buffer\Y**matrix\A21
	*point\y =Buffer\X**matrix\A12 + Buffer\Y**matrix\A22
	ProcedureReturn *point
EndProcedure
jetzt läuft es wie gewünscht

natürlich mit dem code schnipsel von Stargete :allright:

gruss Silbersurfer
Intel Quad Core 3,2 Ghz - GTX 1060 - BlitzBasic Plus 1.48 , PureBasic 5.70 LTS / Aktuelles Projekt PureCommander
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Matrix Rotation 2D

Beitrag von STARGÅTE »

auch wenn es in deinem Code jetzt läuft, so war die Prozedur vorher richtig.

Wenn deine Matrix definiert ist als:
( A11 , A12 )
( A21 , A22 )
und du dann einen Vektor multiplizierst:
( A11 , A12 ) . ( X )
( A21 , A22 )   ( Y )
ergibt es:
( X*A11 + Y*A12 )
( X*A21 + Y*A22 )

Was allerdings verdreht ist und wo auch ein Fehler drin ist, ist deine Multiplikation der Matrizen:
Wenn du Use*Source rechnen willst, muss es lauten:

Code: Alles auswählen

      \A11 = Buffer\A11 * *Source\A11 + Buffer\A12* *Source\A21
      \A12 = Buffer\A11 * *Source\A12 + Buffer\A12* *Source\A22
      \A21 = Buffer\A21 * *Source\A11 + Buffer\A22* *Source\A21
      \A22 = Buffer\A21 * *Source\A12 + Buffer\A22* *Source\A22
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
silbersurfer
Beiträge: 175
Registriert: 06.07.2014 12:21

Re: Matrix Rotation 2D

Beitrag von silbersurfer »

Wenn du Use*Source rechnen willst, muss es lauten:
Die hatte Ich auch verändert Stargate

Code: Alles auswählen

Procedure matrix_Multi(*Use.Matrix2D, *Source.Matrix2D)
	Protected Buffer.Matrix2D
	CopyMemory(*Use, @Buffer, SizeOf(Matrix2d)) 
	With *Use
		\A11 = Buffer\A11 * *Source\A11 + Buffer\A12* *Source\A12
		\A12 = Buffer\A11 * *Source\A21 + Buffer\A12* *Source\A22
		\A21 = Buffer\A21 * *Source\A11 + Buffer\A22* *Source\A12
		\A22 = Buffer\A21 * *Source\A21 + Buffer\A22* *Source\A22	
	EndWith
	ProcedureReturn *Use
EndProcedure
darum auch die Änderung der Punktberechnung

jetzt wollte Ich die Punkberechung aus der Procedure Herausholen und direkt
in DrawImage einfügen da bekomme ich dann immer eine Mav (absturz)
vieleicht kannst du mir da nochmal helfen

meine Idee war folgende

Code: Alles auswählen

Procedure DrawImage2D(*this.Image2D,x,y)
	If (Not *this) : ProcedureReturn #False : EndIf
	Protected *pointer.Matrix2D,Scale.Matrix2D,Rotation.Matrix2D,Spieglung.Matrix2D
	Protected *p1.vertex2D,p1.vertex2D,punkte.i,w.i,h.i,z.i,e.i,width.i,height.i

	With *this
		\PosX=x : \PosY=y 
		e = Sqr(\width*\width +\height*\height) 
		width=\width/2+(e-\width)/2
		height=\height/2+(e-\height)/2
		
    scale(scale,\ScaleX,\ScaleY)
    Spieglung(Spieglung,\FlipX,\FlipY)
    Rotation(Rotation,Radian(\Winkel))
    *pointer=matrix_Multi(scale,Spieglung)
    *pointer=matrix_Multi(Rotation,*pointer)      

		For h=y To y+e-1
			For w=x To x+e-1
				p1\x=w-x-width
				p1\y=h-y-height
				;statt dem Sprung in die Procedure hier
				*p1=BerechnePoint(*pointer,p1)
				;die Direckte berechnung Hier nur leider geht das so nicht (Abstruz)
          *p1\X =p1\X**pointer\A11 + p1\Y**Pointer\A21
          *p1\y =p1\X**pointer\A12 + p1\Y**Pointer\A22				
				
				*p1\x=*p1\x+\width/2
				*p1\y=*p1\y+\height/2	
				If *p1\x>=0 And *p1\x<\width And *p1\y>=0 And *p1\y<\height
					Plot(w,h,\color(Int(*p1\x),Int(*p1\y)))
				EndIf	
			Next 
		Next 	
	EndWith
EndProcedure
´das verstehe ich nicht ganz :freak:
Intel Quad Core 3,2 Ghz - GTX 1060 - BlitzBasic Plus 1.48 , PureBasic 5.70 LTS / Aktuelles Projekt PureCommander
Benutzeravatar
silbersurfer
Beiträge: 175
Registriert: 06.07.2014 12:21

Re: Matrix Rotation 2D

Beitrag von silbersurfer »

jetzt wollte Ich die Punkberechung aus der Procedure Herausholen
hat sich erledigt funzt jetzt :D

jetzt nochmal einer andere Frage

1. warum wirkt sich mein Scale Faktor negativ aus ???
zb. faktor 2 Sollte es doch vergrößern und nicht verkleinern
2. wie könnte ich die vegrößerung richtig realisieren da Ich ja die farbwerte nur verändere

hier dazu ein lauffähiger code

Code: Alles auswählen

EnableExplicit

UsePNGImageDecoder()
UseJPEGImageDecoder()
;erstelle ein Image
Meinimage = CreateImage(#PB_Any,128,128,32,0)
Define a
;zeichen Kreise 
If StartDrawing(ImageOutput(meinimage))
 For a=0 To 40
   Circle(Random(128,0),Random(128,0),Random(10,0),RGB(Random(255),Random(255),Random(255)))
 Next   
  StopDrawing()
EndIf 
InitSprite()

Structure Icolor
	x.i : y.i
EndStructure

Structure vertex2D
	x.f : y.f
EndStructure

Structure Matrix2D
	A11.f : A21.f
	A12.f : A22.f
EndStructure

Structure Image2D
	ID.i : PosX.i : PosY.i
	ScaleX.f :ScaleY.f
	Winkel.f : FlipX.i :FlipY.i	
	width.i : height.i
	Array color.i(0,0)
EndStructure




Procedure NewImage2D()
	Protected *this.Image2D	=	AllocateMemory(SizeOf(Image2D))
	InitializeStructure(*this, Image2D)
	With *this
		\Id=*this
		\FlipX=1 	: \FlipY=1
		\PosX=0 	: \PosY=0
		\ScaleX=1 : \ScaleY=1
		\Winkel=0
	EndWith
	ProcedureReturn *this
EndProcedure

Procedure ImageToBank(image.i,*this.Image2d)
	Protected w.i,h.i,z.i,t.i
	With *this
		\width	=ImageWidth		(Image)
		\height	=ImageHeight	(Image)
		If StartDrawing(ImageOutput(Image.i))
			Dim \color(\width,\height)
			For h=0 To \height-1
				For w=0 To \width-1							
				  \color(w,h)=Point(w,h)
				Next
			Next 	
			StopDrawing()
		EndIf 
	EndWith	
EndProcedure

Procedure Rotation(*matrix.Matrix2D,winkel.f)
	*Matrix\A11	=Cos(winkel)	: *matrix\A12	=-Sin(winkel)
	*Matrix\A21	=Sin(winkel) 	: *matrix\A22	=Cos(winkel)
	ProcedureReturn *matrix
EndProcedure

Procedure scale(*matrix.Matrix2D,scalex.f=1,scaley.f=1)
	*Matrix\A11	=scalex	: *matrix\A12	=0
	*Matrix\A21	=0		: *matrix\A22	=scaley
	ProcedureReturn *matrix
EndProcedure

Procedure Spieglung(*matrix.Matrix2D,spx=1,spy=1)

	*Matrix\A11	=spx	: *matrix\A12	=0
	*matrix\A21 =0    : *matrix\A22	=spy
	ProcedureReturn *matrix
EndProcedure

Procedure matrix_Multi(*Use.Matrix2D, *Source.Matrix2D)
	Protected Buffer.Matrix2D
	CopyMemory(*Use, @Buffer, SizeOf(Matrix2d)) 
	With *Use
      \A11 = Buffer\A11 * *Source\A11 + Buffer\A12* *Source\A21
      \A12 = Buffer\A11 * *Source\A12 + Buffer\A12* *Source\A22
      \A21 = Buffer\A21 * *Source\A11 + Buffer\A22* *Source\A21
      \A22 = Buffer\A21 * *Source\A12 + Buffer\A22* *Source\A22	  
; 		\A11 = Buffer\A11 * *Source\A11 + Buffer\A12* *Source\A12
; 		\A12 = Buffer\A11 * *Source\A21 + Buffer\A12* *Source\A22
; 		\A21 = Buffer\A21 * *Source\A11 + Buffer\A22* *Source\A12
; 		\A22 = Buffer\A21 * *Source\A21 + Buffer\A22* *Source\A22	
	EndWith
	ProcedureReturn *Use
EndProcedure

Procedure DrawImage2D(*this.Image2D,x,y,winkel.f=0)
	If (Not *this) : ProcedureReturn #False : EndIf
	Protected *pointer.Matrix2D,Scale.Matrix2D,Rotation.Matrix2D,Spieglung.Matrix2D
	Protected *p1.vertex2D,p1.vertex2D,punkte.i,w.i,h.i,z.i,e.i,width.i,height.i
   Protected Buffer.vertex2D,y1.i,x1.i
   With *this
     
    e = Sqr(\width*\width+\height*\height) 
	  width=\width/2+(e-\width)/2
    height=\height/2+(e-\height)/2 
    \PosX=x : \PosY=y :\Winkel=winkel
    y1=y+e-1 : x1=x+e-1		  
   
    
    Spieglung(Spieglung,\FlipX,\FlipY)
    scale(scale,\ScaleX,\ScaleY)
    Rotation(Rotation,Radian(\Winkel))
    *pointer=matrix_Multi(Spieglung,scale)
    *pointer=matrix_Multi(Rotation,*pointer)      

    For h=y To y1
      For w=x To x1     
 				p1\x=w-\PosX-width
 				p1\y=h-\PosY-height
 	      CopyMemory(p1, @Buffer, SizeOf(vertex2D))					
				*p1=Buffer
      	*p1\X =p1\X**pointer\A11 + p1\Y**pointer\A21
  	    *p1\y =p1\X**pointer\A12 + p1\Y**pointer\A22				
				*p1\x=*p1\x+\width/2
				*p1\y=*p1\y+\height/2	
				If *p1\x>=0 And *p1\x<\width And *p1\y>=0 And *p1\y<\height			  
				  If w>=0 And w<1599 And h>=0 And h<999
				    Plot(w,h,\color(Int(*p1\x),Int(*p1\y)))
				  EndIf   
				EndIf			
			Next 
		Next 	
		
	EndWith
EndProcedure

Procedure ScaleImage(*this.Image2D,ScaleX.f,ScaleY.f)
	*this\ScaleX=ScaleX
	*this\ScaleY=ScaleY
EndProcedure

Procedure FlipImage(*this.Image2D,FlipX.f,FlipY.f)
	*this\FlipX=FlipX
	*this\FlipY=FlipY
EndProcedure


Enumeration
	#My_Window
	#My_Sprite
EndEnumeration	

Define Event,Quit,ob,x,y,MausX,MausY,t.f
;erzeuge ein 2D Image
Define testimage=NewImage2D()
; Speicher die Bilddaten in eine bank
ImageToBank(meinimage,testimage)

If OpenWindow(#My_Window, 0, 0, 800, 600, "Test Window Event ", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	If OpenWindowedScreen(WindowID(#My_Window),0,0,800, 600,#True,0,0,#PB_Screen_NoSynchronization)
	
	EndIf	
EndIf

Repeat
	Event=WindowEvent()	
	mausx=WindowMouseX(#My_Window)
	mausy=WindowMouseY(#My_Window)		
	Select  event
		Case #PB_Event_CloseWindow
			Quit=#True
		Case #PB_Event_Gadget	
		Select EventGadget()
			
		EndSelect
	EndSelect	
  
	FlipBuffers() 
	ClearScreen(RGB(20, 50, 20))
	If StartDrawing(ScreenOutput())
	  DrawImage(ImageID(MeinImage),0,0)	
	  t=t+0.5
	  ScaleImage(testimage,1,1)
	  DrawImage2D(testimage,400,150,t)
	  ScaleImage(testimage,0.2,0.2)
	  DrawImage2D(testimage,40,150,-t)
	  ScaleImage(testimage,2,2)
	  DrawImage2D(testimage,200,350,-(t/2))
		StopDrawing()	
	EndIf 	
	
Until Quit=#True
Ich hoffe das ihr mir hier etwas weiterhelfen könnt

gruss Silbersurfer
Intel Quad Core 3,2 Ghz - GTX 1060 - BlitzBasic Plus 1.48 , PureBasic 5.70 LTS / Aktuelles Projekt PureCommander
Benutzeravatar
man-in-black
Beiträge: 362
Registriert: 21.08.2006 17:39

Re: Matrix Rotation 2D

Beitrag von man-in-black »

Hi,
warum wirkt sich mein Scale Faktor negativ aus ???

Code: Alles auswählen

Plot(w,h,\color(Int(*p1\x),Int(*p1\y)))
Nimmst du z.B. den Faktor "2", wird jeder zweite Pixel des Quellbildes genommen
und in deinem Zielbild direkt neben den vorherigen Pixel gesetzt. Damit "verlierst" du
jede zweite Zeile/Spalte und lässt das Zielbild schrumpfen.

edit

Wenn du richtig skalieren willst, musst du die Dimensionen des Zielbildes anpassen (Breite*Faktor,...)
und dann für jeden Pixel im Zielbild eine relative Position im Quellbild finden. Das Unangenehme
ist dabei, dass du im Quellbild gebrochene Pixelpositionen bekommst. Soll heißen, dass du über irgendwelche kreativen
Mischungsregeln deine Farbe ermitteln musst.

Beispiel Zielbild*2:

Code: Alles auswählen


zBreite = qBreite*2

For zx = 0 to zBreite
  ...
  qx = zx/zBreite*qBreite    ;qx ist gebrochen
  zcolor = (qcolor(round(qx),...)+qcolor(round(qx)+1,...))/2     ;ganz primitive Mischung; solls nur verdeutlichen (rgb beachten ...)

  plot(zx,... zcolor)
next
edit2:
Bei der Ermittlung von "qx" kommen natürlich wieder deine Matrizen zum Einsatz. Ich wollte nur nen Denkanstoß geben.


MFG
MIB
(hab alles, kann alles, weiß alles!!^^)

Bild
Benutzeravatar
silbersurfer
Beiträge: 175
Registriert: 06.07.2014 12:21

Re: Matrix Rotation 2D

Beitrag von silbersurfer »

hi man-in-black
Nimmst du z.B. den Faktor "2", wird jeder zweite Pixel des Quellbildes genommen
ok das habe Ich jetzt verstanden

das mit der farbmischung erscheint mir doch etwas kompliziert
Ich könnte ja auch das Orginalbild erst vergrößern und dann neu einlesen

z.B

Code: Alles auswählen

ResizeImage(dummyimage2,ImageWidth(dummyimage2)*multi,ImageHeight(dummyimage2)*multi)
Define testimage=NewImage2D()
ImageToBank(dummyimage2,testimage)
oder ist das zu viel des guten????
Intel Quad Core 3,2 Ghz - GTX 1060 - BlitzBasic Plus 1.48 , PureBasic 5.70 LTS / Aktuelles Projekt PureCommander
Antworten