// point: { x: ..., y: ... } // rectangle: { a: { x: ..., y: ... }, b: { x: ..., y: ... }, c: { x: ..., y: ... } } // assuming the line from A to B and the line from B to C are perpendicular function isPointInRectangle(point, rectangle) { var abx = rectangle.b.x - rectangle.a.x, aby = rectangle.b.y - rectangle.a.y, bcx = rectangle.c.x - rectangle.b.x, bcy = rectangle.c.y - rectangle.b.y; // The value of each of these calculations comes out positive or negative depending // on the *side* of the line the point is on if ((point.x - rectangle.a.x) * abx + (point.y - rectangle.a.y) * aby < 0) return false; if ((point.x - rectangle.b.x) * abx + (point.y - rectangle.b.y) * aby < 0) return false; if ((point.x - rectangle.a.x) * bcx + (point.y - rectangle.a.y) * bcy < 0) return false; if ((point.x - rectangle.c.x) * bcx + (point.y - rectangle.c.y) * bcy < 0) return false; return true; } function getRotatedRectangleCoords(token) { var left = token.get('left'), top = token.get('top'), halfWidth = token.get('width') / 2, halfHeight = token.get('height') / 2, x1 = left - halfWidth, // tok.left and tok.top are the center point of the token, but we want the corners y1 = top - halfHeight, x2 = left + halfWidth, y2 = top - halfHeight, x3 = left + halfWidth, y3 = top + halfHeight, x4 = left - halfWidth, y4 = top + halfHeight, ox1 = x1 - left, // essentially, move the token so it's located at (0, 0) to get the points we'll rotate oy1 = y1 - top, ox2 = x1 - left, oy2 = y2 - top, ox3 = x3 - left, oy3 = y3 - top, ox4 = x4 - left, oy4 = y4 - top, theta = token.get('rotation'), result = { a: {}, b: {}, c: {}, d: {} }; // rotate the corner coordinates around (0, 0) and then add the token's center back to it result.a.x = ox1 * Math.cos(theta) - oy1 * Math.sin(theta) + left;
result.a.y = ox1 * Math.sin(theta) + oy1 * Math.cos(theta) + top; result.b.x = ox2 * Math.cos(theta) - oy2 * Math.sin(theta) + left;
result.b.y = ox2 * Math.sin(theta) + oy2 * Math.cos(theta) + top; result.c.x = ox3 * Math.cos(theta) - oy3 * Math.sin(theta) + left;
result.c.y = ox3 * Math.sin(theta) + oy3 * Math.cos(theta) + top; result.d.x = ox4 * Math.cos(theta) - oy4 * Math.sin(theta) + left; result.d.y = ox4 * Math.sin(theta) + oy4 * Math.cos(theta) + top; // isPointInRectangle doesn't care about point d, but we need it if we want to check all corners of potential target return result; } // Example use: var tok = getMyTargetToken(), tokCorners = getRotatedRectangleCoords(tok), blast = getMyBlastToken(), blastRect = getRotatedRectangleCoords(blast); // Check if center of token is inside rectangle isPointInRectangle({ x: tok.get('left'), y: tok.get('top') }, blastRect); // Check if token is *entirely* inside rectangle var isInside = true; _.each(tokCorners, function(pt) { isInside = isInside && isPointInRectangle(pt, blastRect); }); Disclaimer: above code is untested. I don't recall whether Roll20 stores token rotation as radians or degrees, so getRotatedRectangleCoords may need to convert the value of theta. (Math.cos and Math.sin expect radians.)