Reflecting a 2d vector by a 2d normal?

BlitzMax Forums/BlitzMax Programming/Reflecting a 2d vector by a 2d normal?

Anyone got a bit of code/theory that reflects a 2d vector by a 2d normal(Also a vector)?
Or even better, a way to do sliding 2d collisions with blitz's own image collision or pure math?

The answer to this and a lot of useful related maths was just discussed a few days ago in http://www.blitzbasic.com/Community/posts.php?topic=52384

I'm probably missing it, but I can't see anything to do with sliding 2d collisions on there? can you cut and paste the bit in question please?

I was talking about the reflecting vectors thing, but good point...

To slide instead of bounce, get the reflected vector, and multiply it by the unit vector pointing along the line.



Thanks but I can't understand your writing warp :)

Any chance you can put it in the form of a simple bmax function?

type maths
    function reflectVector( vectx#,vecty#,normx#,normy#)
        relx = warpy code.
        rely = warpy code.
    end function
   global relx#,rely#
end type


I'll give you a billion dollers in return.

fair enough, my writing's rubbish.
type maths

method reflectVector(vectx#,vecty#,normx#,normy#)
	dotprod#=-vectx*normx-vecty*normy
	relx=vectx+2*normx*dotprod
	rely=vecty+2*normy*dotprod
end method

method slide(vectx#,vecty#,linex#,liney#,normx#,normy#)
       reflectVector(vectx,vecty,normx,normy)
       slidex=relx*linex
       slidey=rely*liney
end method

global relx#,rely#
global slidex#,slidey#

end type


That should work, though who knows these days? :)

thanks again but there's two undefined variables used in the first func, vx,vy. that a typo and just vectx,y?

R = I - 2N(N*I)

Where is
R = Reflected Ray
I = Incident Ray
N = Normal Vector

cu olli

yep, it was meant to be vectx/y...
What I've got is the same thing as Vertex, but done in a different order :P

cool, one more dumb question and we're done. In the slide function, there's..what is the slide function? :) And linex,liney, is the the depth of intersection or the velocity of the intersection?

the slide function gives you the velocity if you want it to slide along the line it's colliding with
linex,liney is a unit vector in the direction of the line

Don't forget Bounce and friction ;)
method CollisionResponse( Bounce#, Friction# )
rem

  Divide our veclocity vector in two parts. One parallell to our line
  - This is already solved and this vector is called slidex,slidey.
  Multiply these fields with Friction# which should be a value from
  0.0 to 1.0. In this example our friction is = 0.
  The other is the part of the velocity vector projected on the line's
  normal. This is the bounce. Multiply this vector with Bounce#, which
  is a value from 0.0 to 0.9. Where we in this case would want to set it
   = 0 for NO bounce at all - sliding. 

endrem

   bounceX:*Bounce
   bounceY:*Bounce
   slidex:*Friction
   slidey:*Friction
endmethod

  global relx#,rely#
  global slidex#,slidey#
  global bounceX#,bounceY#

end type
Need help getting the line's normal though. Is it as simple as:
LineNormX = LineX
LineNormY = -LineY
I get a strong feeling that is wrong..

Public 2D Physic Library
So now that everyone is working on vector maths and physics shoudn't we start some combined effort to make a public opensource community physics module for 2D?

yep, that's wrong.
You can get *a* vector (V1x,V1y) that's perpendicular to a line (linex,liney) by setting V1x = 1, V1y = -linex/liney, but it isn't a unit vector, so you need to divide V1x and V1y by Sqr(1+V1y*V1y). Then add a check for if liney is zero to avoid divide by zero errors, and you're probably set.

Of course, I don't use that method :P
I get:
an#=atan2(liney,linex)
nx#=cos(atan2+90)
ny#=sin(atan2+90)

But that's probably quite slow.

I am with you Wave! Let's make this mod.
I am Making the start...
Here what I have done this morning
Type HaLine2d 
Field x1# , y1# , x2# , y2# 

	Function create:HALine2d(_x1# = 0 , _y1 = 0 , _x2# = 10 , _y2# = 0) 
		Local FLine:HALine2d = New HALine2d 
		FLine.x1 = _x1 
		FLine.y1 = _y1 
		FLine.x2 = _X2 
		FLine.y2 = _y2 
		Return FLine 
	End Function 

	Function createParallel:HALine2d(Line1:HALine2d , _x , _y , _Length) 
		Local Line2:HALine2d = New HALine2d 
		Line2.x1 = _x 
		Line2.y1 = _y 
		Line2.x2 = Line2.x1 + ( Cos(Line1.getAngle() ) * _Length) 
		Line2.y2 = Line2.y1 - ( Sin(Line1.getAngle() ) * _Length) 
		Return Line2 
	End Function 

	Function createVertical:HALine2d(Line1:HALine2d , _x , _y , _Length) 
		Local Line2:HALine2d = New HALine2d 
		Line2.x1 = _x 
		Line2.y1 = _y 
		Line2.x2 = Line2.x1 + ( Cos(Line1.getAngle() + 90) * _Length) 
		Line2.y2 = Line2.y1 - ( Sin(Line1.getAngle() + 90) * _Length) 
		Return Line2 
	End Function 

	Method Draw() 
		DrawLine x1 , y1 , x2 , y2 
	End Method 

	Method GetLength:Float() 
		Return Sqr( (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) ) 
	End Method 

	Method getAngle:Float() 
		Return ATan2(y1 - y2 , x2 - x1) 
	End Method 

	Method extendLine(Ex:Float , dir:Byte = 1) 
		Local an:Float = self.getAngle() 
		If Dir = True 
			x2 = x2 + (Cos(an) * Ex) 
			y2 =   y2 - (Sin(an) * Ex) 
		End If 
		If Dir = False 
			x1 = x1 - (Cos(an) * Ex) 
			y1 =   y1 + (Sin(an) * Ex) 
		End If 
	End Method 

	Method reverse() 
		Local xr# = x1 
		Local yr# = y1 
		x1 = x2 
		y1 = y2 
		x2 = xr 
		y2 = yr 
	End Method 

	Method setLength(L:Float , dir:Byte = 1) 
		Local an:Float = self.getAngle() 
		If dir = True 
			x2 = x1 + (Cos(an) * L) 
			y2 = y1 - (Sin(an) * L) 
		End If 
		If dir = False 
			x1 = x2 - (Cos(an) * L) 
			y1 = y2 + (Sin(an) * L) 
		End If 
	End Method 

	Method setAngle(an:Float , tr:Byte = 1) 
		Local L:Float = self.getLength() 
		If tr = True 
			x2 = x1 + ( Cos(an) * L) 
			y2 = y1 - ( Sin(an) * L) 
		End If 
		If tr = False 
			x1 = x2 + ( Cos(an) * L) 
			y1 = y2 - ( Sin(an) * L) 
		End If 
	End Method 

	Method MoveTo(_x , _y , tr:Byte = 1) 
		Local an# = getAngle() 
		Local L# = getLength() 
		If tr = True 
			x1 = _x 
			y1 = _y 
			x2 = x1 + (Cos(an) * L) 
			y2 = y1 - (Sin(an) * L) 
		End If 
		If tr = False 
			x2 = _x 
			y2 = _y 
			x1 = x2 - (Cos(an) * L) 
			y1 = y2 + (Sin(an) * L) 
		End If 
	End Method 

	Method CollideLine(_Line:HALine2d) 
		Local L1d:Float 
		Local L2d:Float 
		Local L1x#,L1y#,L2x#,L2y# 

		L1x = x2-x1 
		L1y = y2-y1 
		L2x = _Line.x2-_Line.x1 
		L2y = _Line.y2-_Line.y1 

		L1d = ( _Line.y1 - y1 + (L2y/L2x)*( x1 - _Line.x1 )) / ( L1y - L2y*L1x/L2x ) 

		If L1d >=0 And L1d <=1 
			L2d  = ( x1 + L1x*L1d - _Line.x1 ) / L2x 
			If L2d >=0 And L2d <=1 
				Return True 
			EndIf 
		EndIf 
		Return False 

	End Method 

	Method GetCollideLinePoint(xi# Var , yi# Var , _Line:HALine2d) 

		Local L1d:Float 
		Local L2d:Float 
		Local L1x#,L1y#,L2x#,L2y# 

		L1x = x2-x1 
		L1y = y2-y1 
		L2x = _Line.x2-_Line.x1 
		L2y = _Line.y2-_Line.y1 

		L1d = ( _Line.y1 - y1 + (L2y/L2x)*( x1 - _Line.x1 )) / ( L1y - L2y*L1x/L2x ) 
	
		If L1d >=0 And L1d <=1 
			L2d  = ( x1 + L1x*L1d - _Line.x1 ) / L2x 
			If L2d >=0 And L2d <=1 
				xi = x1 + L1d*L1x 
				yi = y1 + L1d*L1y 
				Return True 
			EndIf 
		EndIf 
		Return False 

	End Method 


End Type 



Thanks Warpy!

Great Haramanai!

I'll start to put together our stuff into an example. And I guess we should start a new topic for this. I'll use my vector library so that we can base everything on vector operations.

I'll write a short project plan too.

I get the 2d normal by sampling a 20x20 region of the image with the centre being the first pixel that the motion vector collided with.

Method pointNormal(x#,y#,l)
		normx=0
		normy=0
		For Local cx# = -10 To 10
		Local nx# = cx/4.0
		For Local cy# = -10 To 10
			Local ny# = cy/4.0
			Local rx# = x+nx
			Local ry# = y+ny
			Local tx,ty
			tx = rx/twidth
			ty = ry/theight
			Local til:tile = Null
			If tx>-1 And ty>-1 And tx<width And ty<height
				til = map[tx,ty,l]
			End If
			If til<>Null
				Local ox#,oy#
				ox = rx-(tx*twidth)
				oy = ry-(ty*theight)
				normx=normx+nx*til.cmap[ox,oy]
				normy=normy+ny*til.cmap[ox,oy]
			End If
									
		Next
		Next
	'	normx=normx/16
	'	normy=normy/16
		Local mag# = Sqr(normx*normx+normy*normy)
		If mag<0.001 mag=0.001
		normx=normx/mag
		normy=normy/mag
		
		
	End Method


it works well.

It's a shame we can't find my old vertlet lib, we could use it as the basis for a 2d physic lib and do ragdoll etc.

holy crunk, that's entirely the wrong way to do it!

Define wrong when it works?

wrong because it's needlessly complicated and slow

Just needs a 2byte times image size array for each tile and checks can be reduced to a couple of look ups per frame. ultra fast and accurate.