It looks like you're new here. If you want to get involved, click one of these buttons!
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
Comments
https://coolcodea.wordpress.com/2015/01/13/192-locating-the-3d-position-of-a-2d-point-with-math/
@Iavmax Are all of your rectangles going to be drawn with translate and rotate.
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()?
@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.
@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
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.
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!
@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?
@lavmax - in 2D, if you have a vec2 point p, then
gives you the world point
@Ignatz except that mat4 * vec4 is broken in Codea right now:
@lavmax http://loopspace.mathforge.org/HowDidIDoThat/Codea/Matrices/ but don't say I didn't warn you.
@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
then I can assume that getting local point should be as simple as
But how to divide vec4 / mat4? Or it's too naive and I can't really do like this?j
PS. It's all about 2D
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.
@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.
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 !