#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

#### In this Discussion

edited January 2015 in General Posts: 11

I have a sample code like this

``````function draw()
translate(300,300)
rotate(30)
scale(2,1.5)

fill(255, 255, 255, 255)
rect(0,0,100,100)
end
``````

Which draws a tilted rectangle somewhere on the screen. I wonder how can I detect if a given point (e.g. touch) is inside the rectangle? Any thoughts are appreciated.

SOLUTION

Thanks to @Ignatz and @LoopSpace I ended up with pretty simple and elegant solution for 2D rects. Just few lines of code allow to convert a point from world coordinates to current matrix and vice verse. The full code is below.

``````mm = matrix()

function draw()
translate(300,300)
rotate(30)
scale(2,1.5)

fill(255, 255, 255, 255)
rect(0,0,100,100)

mm = modelMatrix()
end

function touched(touch)
if touch.state ~= BEGAN then return end

local localPoint = worldToLocal(touch)
local worldPoint = localToWorld(localPoint)

print(touch.x, touch.y) -- the original touch point
print(localPoint)       -- the point in rect coordinates
print(worldPoint)       -- this should be the same as the original touch

if localPoint.x >= 0 and localPoint.x <= 100 and
localPoint.y >= 0 and localPoint.y <= 100 then
print("HIT!")
end
end

function multiplyVec2ByMatrix(vec, mat)
vec = vec4(vec.x, vec.y, 0, 1)
-- Normaly the code below should look like "local resultVec = mat*vec"
-- but as soon as something is broken in Codea right now multiply them manualy
local resultVec = vec4(
mat[1]*vec[1] + mat[5]*vec[2] + mat[09]*vec[3] + mat[13]*vec[4],
mat[2]*vec[1] + mat[6]*vec[2] + mat[10]*vec[3] + mat[14]*vec[4],
mat[3]*vec[1] + mat[7]*vec[2] + mat[11]*vec[3] + mat[15]*vec[4],
mat[4]*vec[1] + mat[8]*vec[2] + mat[12]*vec[3] + mat[16]*vec[4]
)
return vec2(resultVec.x, resultVec.y)
end

function localToWorld(localPoint)
return multiplyVec2ByMatrix(localPoint, mm)
end

function worldToLocal(worldPoint)
if mm:determinant() == 0 then
return nil
else
local resultVec = multiplyVec2ByMatrix(worldPoint, mm:inverse())
return vec2(resultVec.x, resultVec.y)
end
end
``````
Tagged:

• Mod
Posts: 5,396
• Mod
Posts: 8,723

@Iavmax Are all of your rectangles going to be drawn with translate and rotate.

• Posts: 11

Many of them. Mostly sprites. Rectangle is just an example.
Trying to figure out how this locating from coolcodea works.
Meanwhile what is the difference between modelMatrix(), viewMatrix() and projectionMatrix()?

• Mod
edited January 2015 Posts: 8,723

@Iavmax If your going to be drawing sprites, then maybe you could use circles or overlapping circles or ellipses instead of rectangles. It's very easy to determine if a touch is within a circle or ellipse.

• edited January 2015 Posts: 11

@Ignatz This code works like a charm. Thank you! And I actually have no idea how exactly it works, so it's a real magic

• Mod
Posts: 5,396

That code is thanks to @LoopSpace.

I explain modelMatrix here.

https://coolcodea.wordpress.com/2014/11/26/184-what-is-modelmatrix/

Someone else had a go at explaining the other matrices

http://codea.io/talk/discussion/2909/clarity-on-identitymatrix-modelmatrix-viewmatrix-projectionmatrix

But wait until you try 3D before trying too hard to understand them.

• Posts: 509

This is where I usually link to my explanation of the matrices, but I'm told that it's a bit too mathematical for general use!

• Posts: 11

@LoopSpace Well, if you have it already explained somewhere, please link, I would try to read for self education even if it's too math.

BTW. I get how to convert a world point (touch) to my rect or sprite coordinates. But is it possible somehow to use this code for the opposite conversion? I mean if I have a point inside a rect how do I get a wold point?

• Mod
Posts: 5,396

@lavmax - in 2D, if you have a vec2 point p, then

``````p2 = modelMatrix() * p
``````

gives you the world point

• Posts: 509

@Ignatz except that mat4 * vec4 is broken in Codea right now:

``````    print(matrix()*vec4(1,0,0,0))
print(matrix()*vec4(0,1,0,0))
print(matrix()*vec4(0,0,1,0))
print(matrix()*vec4(0,0,0,1))
``````

@lavmax http://loopspace.mathforge.org/HowDidIDoThat/Codea/Matrices/ but don't say I didn't warn you.

• edited January 2015 Posts: 11

@Ignatz thank you, this really works. And mat4 * vec4 is really broken in Codea. But thanks to @LoopSpace I have function applymatrix4(v,m) which works

So if

``````worldPoint = localPoint * modelMatrix()
``````

then I can assume that getting local point should be as simple as

``````localPoint = worldPoint / modelMatrix()
``````

But how to divide vec4 / mat4? Or it's too naive and I can't really do like this?j

• Mod
Posts: 5,396

Nope, it doesn't work like that, you would need to invert modelMatrix

But you should be able to use the code I gave you above for a 3D plane, just make z=0.

• Posts: 11

@Ignatz and @LoopSpace - thank you guys for your help. I finally figured it out. The solution is in the original question above to make it easier to find if somebody will need it.

• Posts: 24

I'm sorry to make this old post up, but I had to say thank you because it helped me a lot

Thank you @lavmax , @Ignatz and @LoopSpace !