How to Mirror/Reflect a vector against another Vec

BlitzMax Forums/BlitzMax Programming/How to Mirror/Reflect a vector against another Vec

I just can't do this. Somehow I'm attacking the problem from the wrong angle..

I need to make a vector reflect in a surface, or in other words mirror it in the surface normal.

' M I R R O R
' This was a formula a found, but apperantly it doesn't work
Method Mirror( Surface:Vector2D )
'X = Surface.X* Surface.DOT( Self ) - X
'Y = Surface.Y* Surface.DOT( Self ) - Y
EndMethod

The example below requires Vector2D.bmx, which you can get here
'Projection And Reflection
Import "Vector2D.bmx"

Graphics 500,500,0

Global Line:Vector2D 		= CreateVector( 300, 00 )
Global LineStart:Vector2D 	= CreateVector( 10, 200  )

Global Vec:Vector2D		 	= CreateVector( 0, 0 )
Global VecStart:Vector2D 	= CreateVector( 200, 20 )

Global Project:Vector2D	 	= CreateVector( 0, 0 )
Global Start:Vector2D		= VecStart.Copy()


While Not KeyDown( Key_Escape )
	Start =  VecStart.Copy()
	Start.Add( Vec )
	
	SetColor 255,0,0'RED 
	DrawLine LineStart.X, LineStart.Y, LineStart.X + Line.X, LineStart.Y + Line.Y
	
	SetColor 0,255,0'BLUE
	Vec.Set( MouseX() - VecStart.X , MouseY() - VecStart.y  )
	Vec.Draw( VecStart )
	
	If KeyDown(Key_1)
		LineStart.Set( MouseX() ,MouseY() )
	End If
	
	If KeyDown(Key_2)
		Line.Set( MouseX() - LineStart.X, MouseY() - LineStart.Y   )
	End If
	
'	SetColor 0,0,255'GREEN
'	Project.ProjectionOf( Vec, Line )
'	Project.Draw( vecStart )
	
	Local SurfaceNormal:Vector2D = Line.CreateLeftNormal()
	SurfaceNormal.Normalize()
	

'	SetColor 255,255,0'YELLOW
'	Project.ProjectionOf( Vec, SurfaceNormal )
'	Project.Draw( vecStart )				
	
			
	' M I R R O R
	SetColor 0,255,255'TEAL
	Project = Vec.Copy()
	Project.Mirror( SurfaceNormal ) 
	Project.Draw( Start )		
		
Flip;Cls	
Wend


Linkage.

if this is what you wanted it to look like:


try this:
Method Mirror(normal:vector2d)
		Local dotprod#=-x*normal.x-y*normal.y
		x=x+2*normal.x*dotprod
		y=y+2*normal.y*dotprod
	End Method


EDIT: or the above :P

Diablo, THANKS!!

It all works now!

YES!

Check this out!
Requires: Vector2D.bmx (See my first post above)
Strict

Include "Vector2D.bmx"
Include "Circle2D.bmx"


'''''''''' seting Lines
Global Vector:Vector2D[10]
Vector[0] = Vector2d.create(4.0000000000000000 , 1.0000000000000000)
Vector[1] = Vector2d.create(204.00000000000000 , 369.00000000000000)

Vector[2] = Vector2d.create(197.00000000000000 , 238.00000000000000)
Vector[3] = Vector2d.create(634.00000000000000 , 0.0000000000000000)

Vector[4] = Vector2d.create(122.00000000000000 , 448.00000000000000)
Vector[5] = Vector2d.create(499.00000000000000 , 448.00000000000000)

Vector[6] = Vector2d.create(499.00000000000000 , 448.00000000000000)
Vector[7] = Vector2d.create(499.00000000000000 , 225.00000000000000)

Vector[8] = Vector2d.create(122.00000000000000 , 448.00000000000000)
Vector[9] = Vector2d.create(122.00000000000000 , 221.00000000000000)


'''''''''''''''''' Ball stuff and gravity
Global Grav:Vector2d = Vector2d.create(0, 0.000098)

Global Ball:Circle2d = Circle2d.create(400 , 20 , 10)

Global BallVelocity:Vector2d = Vector2d.create(0,0)

'''''''''''''''''''''''''''''''''''''''''Graphics and main Loop
Graphics 640 , 480, 0, 60
While Not KeyHit(KEY_ESCAPE)
	Cls
	
	'''''''''' Drawing
	SetScale 1.0 , 1.0
	DrawText MouseX() + "   " + MouseY() , 10 , 10
	For Local i = 0 To Vector.Length - 1 Step 2
		SetColor 0 , 255 , 0
		DrawLine Vector[i].x  , Vector[i].y , Vector[i+1].x , Vector[i+1].y
		SetColor 200 , 150 , 100
		DrawText i , Vector[i].x , Vector[i].y
		DrawText i + 1 , Vector[i + 1].x , Vector[i + 1].y
	Next
	SetColor 0 , 0 , 255
	Ball.Draw()
	
	'''''' Forces
	BallVelocity.add( Grav )

	
	CheckCollision()
	SetColor 255,255,255
	'BallVelocity.DrawModify( Ball.Position, 1000, 0 )
			
	'''''' Update Positions and store data for the old ones
	Local PreBall:Vector2D = Ball.position.copy()
	Ball.position.add(BallVelocity)	


	''''''' Positionning Lines
		''''''''''''''''''Line[0]
	If KeyDown(Key_0)
		Vector[0].x = MouseX()
		Vector[0].y = MouseY()

	End If
	
	If KeyDown(Key_1)
		Vector[1].x = MouseX()
		Vector[1].y = MouseY()

	End If
	
		''''''''''''''''''Line[1]
	If KeyDown(Key_2)
		Vector[2].x = MouseX()
		Vector[2].y = MouseY()
	End If
	
	If KeyDown(Key_3)
		Vector[3].x = MouseX()
		Vector[3].y = MouseY()
	End If
	
		''''''''''''''''''Line[1]
	If KeyDown(Key_4)
		Vector[4].x = MouseX()
		Vector[4].y = MouseY()

	End If
	
	If KeyDown(Key_5)
		Vector[5].x = MouseX()
		Vector[5].y = MouseY()

	End If
		''''''''''''''''''Line[3]
	If KeyDown(Key_6)
		Vector[6].x = MouseX()
		Vector[6].y = MouseY()
	End If
	
	If KeyDown(Key_7)
		Vector[7].x = MouseX()
		Vector[7].y = MouseY()
	End If
	
		''''''''''''''''''Line[4]
	If KeyDown(Key_8)
		Vector[8].x = MouseX()
		Vector[8].y = MouseY()
	End If
	
	If KeyDown(Key_9)
		Vector[9].x = MouseX()
		Vector[9].y = MouseY()
	End If
	
	''''''''''''''''''''''' Psitionning Ball
	If MouseDown(1)
		Ball.Position.set( MouseX() , MouseY() )
		BallVelocity.set(0,0)
	End If
		
	Flip 1
Wend

	'''''''''''' To copy paste this to the setting Line section on the top and have the costom MAP
Print ""
Print "copy paste the below"
Print "''''''''''''''''''''''''''''''''''''''''''''"
Print 	 "Local Vector:Vector2d[10]"
For Local i:Byte = 0 To Vector.Length - 1
	Local printout$ = ""
	Printout:+ "Vector[" + i +"] = Vector2d.create(" + Vector[i].x + " , " + Vector[i].y + ")"
	Print printout
	'	Vector[0] = Vector2d.create(100 , 300)
	'	Vector[1] = Vector2d.create(300 , 300)
Next
End


	Function CheckCollision()
	
		For Local i = 0 To Vector.Length - 1 Step 2
			' 
			' 1. Detect collision
			' Makes sure that with our current velocity and shape ( this time we are a circle )
			' we do not pass through any lines
			' This function does not check that, but this works if our velocity is not larger than or cirles radius
			' The check for collision rutine need improvement!
			' 
			'Local OverlapDist! = MinDistPointLine(Ball.position.x , Ball.position.y , Vector[i].x , Vector[i].y , Vector[i +1].x , Vector[i +1].y)
			
			Local VectorToLine:Vector2D  = VectorToLine(Ball.position.x , Ball.position.y , Vector[i].x , Vector[i].y , Vector[i +1].x , Vector[i +1].y)
			If VectorToLine.Length() < Ball.Radius
				SetColor 255 , 0 , 0 'Just for fun
				SetScale 1.0 , 1.0
				DrawText "\__ COLLIDE" , Ball.position.x , Ball.position.y ' Just for fun
	
				' 2. Project out of collision
				
				'Move backwards along the velocity vector until we are out of collision.
				''''''''''''''''''''''''Local DistIntoWall = Ball.Radius - OverlapDist
				'Make velocity unit vector
				'''''''Local ProjectVector:Vector2D = CreateUnitVector( BallVelocity )
				'''''''ProjectVector.Reverse()
				Ball.Position.subtract( VectorToLine ) 'We are now right where we are supposed to be. (right before the wall)
				VectorToLine.Normalize()
				VectorToLine.Multiply( Ball.Radius - VectorToLine.Length() )
				Ball.Position.add( VectorToLine )
					
																
					' 3. Get the line's surface normal
					Local Surface:Vector2D = Vector2D.CreateFrom( Vector[i] , Vector[i +1] )	
					Local SurfaceNormal:Vector2D  = Surface.CreateRightNormal()				
						
					'BallVelocity = BallVelocity.Reflect( SurfaceNormal )						
																					
					' 4. Apply response on velocity ( reflect )
					
					ApplyResponse( BallVelocity, SurfaceNormal, 0.00, 0.2 )'  0,0 would be Perfect Slide
					
					'Now before we move we should check that this new Velocity does not collide in something else.
					Ball.Position.add( BallVelocity )' It is safe to move ( Not really!)
					' Right now we only check against the remaining lines - which could be none or all
					' 

			End If
		Next
		
	EndFunction



	Function DistanceCircleLine( Circle:Circle2D, LineStart:Vector2D, LineEnd:Vector2D )
		'In progress
	EndFunction
	
	
	'-----------------------------------------------------------------
	''''Collision Handling
	'Calculated the distance from a point to a line
	Function MinDistPointLine!(px!,py!,x1!,y1!,x2!,y2!)  ''This function found in Blitz's forum Code Archive

		If x1 = x2 And y1 = y2 Then Return PointToPointDist(px,py,x1,y1)
	
		Local sx! = x2-x1
		Local sy! = y2-y1
	
		Local q! = ((px-x1) * (x2-x1) + (py - y1) * (y2-y1)) / (sx*sx + sy*sy)
	
		If q < 0.0 Then q = 0.0
		If q > 1.0 Then q = 1.0
	
		Return PointToPointDist(px,py,(1-q)*x1+q*x2,(1-q)*y1 + q*y2)
	End Function
	
	'-----------------------------------------------------------------
	Function pointToPointDist!(x1! , y1! , x2! , y2!)
		Return Sqr( (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) )
	End Function
	
	Function VectorToLine:Vector2D(px!,py!,x1!,y1!,x2!,y2!)

		If x1 = x2 And y1 = y2 Then Return Vector2D.Create( x1-px, y1-py )
	
		Local sx! = x2-x1
		Local sy! = y2-y1
		
		If sx = 0 And sy = 0 Then Return
	
		Local q! = ((px-x1) * (x2-x1) + (py - y1) * (y2-y1)) / (sx*sx + sy*sy)
	
		If q < 0.0 Then q = 0.0
		If q > 1.0 Then q = 1.0
		
		Local Xx! = (1-q)*x1 + q*x2
		Local Xy! = (1-q)*y1 + q*y2
		
		Return Vector2D.Create(Xx - Px, Xy - Py )
		
	End Function

Rem
		Friction! from 0 to 1 ; 1 = Total Friction (get stuck), 0 = No Friction
		Elasticy! from 0 to 1 ; 1 = Perfect Bounce, 0 = No Bounce

		USE: 
		If CollideSurface( SurfaceNormal,....)
			ApplyResponse( Tank.Velocity, SurfaceNormal, 0, 0.5 )
		Endif
EndRem
Function ApplyResponse( Velocity:Vector2D Var, SurfaceNormal:Vector2D, Friction!, Elasticity! )
	SurfaceNormal.Normalize()

	Velocity.Mirror( SurfaceNormal ) 
	
	If Elasticity < 0 Then Elasticity = 0'Slide
	If Elasticity > 1 Then Elasticity = 1'Perfect Bounce
	
	Local Bounce:Vector2D = CreateVector(0,0)	
	Bounce.ProjectionOf( Velocity, SurfaceNormal )	
	Bounce.Multiply( Elasticity ) ' Apply Elasticy, to the perpendicular part of velocity
	
	If Friction < 0 Then Friction = 0
	If Friction > 1 Then Friction = 1
	Friction = 1 - Friction''  Case 1, now: 0, Case 0, now: 1
	
	Local Slide:Vector2D  = CreateVector()
	SurfaceNormal.MakeLeftNormal()'Convert the normal to the surface!
	Slide.ProjectionOf( Velocity, SurfaceNormal )' Project to surface
	Slide.Multiply( Friction ) ' Apply Friction, to the parallel part of velocity
	
	Velocity.Set(0,0)
	Velocity.Add( Slide )
	Velocity.Add( Bounce )

'FOR DEBUGGING ONLY		
'	SetColor 0,0,255'GREEN
'	Slide.Draw  ( Ball.Position )	
'	SetColor 255,255,0'YELLOW		
'	Bounce.Draw ( Ball.Position )	
	
EndFunction