algorithm - hit detection of rectangle inside rotated rectangle - javascript

I am working on an image editor project, where you can rotate and crop an image.
The problem I'm currently facing is once I've rotated the image, I'd like to be able to drag the crop box anywhere inside the boundaries of the rotated image. So far I've been looking at the Liang-Barsky and Cohen-Sutherland line-clipping algorithms, and Separating Axis Theorem, but I'm struggling to see how I can implement these for my use case.
Can anyone point me in the right direction? Am I barking up the wrong tree?

Use the comment by Alain. To check insideness of the corners, it suffices to counter-rotate the image to make its edges axis-aligned. Then you have an easy point-in-axis-aligned-box problem.
(I don't mean that you really have to rotate the image, just the geometry.)

If the movement that the user tries to make is [dx,dy] then consider the line segments from the corners of the selection to those points translated by [dx,dy] (the yellow lines in the example below). These lines may intersect with the rotated image boundaries (green lines) at certain points (the red dots). If there are no intersections, then the movement is legal. If there are one or more intersections, these will tell you up to which point the movement was legal; the intersection point which is closest to its original position (checking either horizontal or vertical distance is enough to establish this) determines the maximum movement (the bottom right corner in the example). You can then limit the translation to this point.
Depending on which quadrant the direction of the movement is in (towards top right in the example) you can skip checking one of the corners (the bottom left corner in the example); the other corners will always bump into the boundaries first.
You can also skip checking two of the boundaries (bottom and left in the example), by comparing the direction of the movement with the rotation angle of the image.
So you need to check for intersections of 3 line segments with 2 line segments. For line segment intersection code, see e.g. this question.
If the user is dragging only one side, and extending the rectangle instead of moving it, then you only have to check the two corners that are moving.

Related

Move and resize inner rectangle shapes as parent rectangle resizes

I have a scenario where a rectangle is drawn inside another rectangle.
Now the user is dragging, for example purposes, let's take the RIGHT border of the larger rectangle. I want to at the same time resize the inner rectangle as well, but it turns out it is not as trivial task as I thought so. In the image bellow is the expected result but if you look closely not only the rectangle expanded but it also moved for a certain distance to the right!
Now I tried and tried to find a formula how much to move the inner shape before expanding it to the right but continuously failed... Just scaling the inner rectangle is not a good solution because if there is another rectangle inside next to it, the first one will go over the second one if they do not move for a certain distance like bellow:
The question is valid only for one-sided drag and expand, not for all sides scale by keeping aspect ratio... Any input is appreciated.
You can scale both the coordinates and lengths, e.g. if you scale the width of the outer rectangle by 2, you can multiply the lengths and x-coordinates of the two inner rectangles by 2.

Mapbox - Ignoring icon padding when calling queryRenderedFeatures

I'm using Mapbox's queryRenderedFeatures() to handle hovering and clicking.
The issue is that some symbol layers have a fair amount of padding to reduce the density of symbols, and this padding is taken in consideration for the symbol's hitboxes. As a result, a naive implementation will think that the mouse is hovering or has clicked a symbol while it is not the case visually.
Here's an example of the kind of hitbox present in the style (the red ones are from a hidden symbol):
With no filtering on queryRenderedFeatures() results, the mouse will be considered as hovering the point as soon as it enters the hitbox.
I tried filtering out padded features manually by computing the point-to-cursor distance in pixels. It works ok for round or square symbols that are centered on their point, but gives incorrect results for rectangular symbols or those that have a translated position.
I also tried to find a way to get the symbol's position and size in pixels so that I can recheck the collision without padding but couldn't find any method for that.
Is there any way to use queryRenderedFeatures() or an equivalent while ignoring icon padding? Or any alternative to produce the expected result.
I also tried to find a way to get the symbol's position and size in pixels so that I can recheck the collision without padding but couldn't find any method for that.
You can get the anchor position for a symbol, in pixels, by:
Using querySourceFeatures() or queryRenderedFeatures() to obtain the feature.
Using map.project() to convert the feature's lngLat into pixel coordinates.
If your symbol is not placed at the anchor, you will have to perform the same calculation manually.
I don't think you can do much better than this method overall:
Detect a hit within the padded bounding box, find the feature's geometry
Get the pixel coordinates of the feature's anchor
Offset those coordinates using what you know about the symbol's offset etc.
Calculate the distance from there to the mouse cursor.

How to hover areas with XY coordinates shift in MapboxGL JS?

I use hover tooltips in my map. When an area is hovered, I show a tooltip with a small XY shift to the top left corner so that the pointer of the tooltip is not covered by the mouse cursor.
When I move mouse cursor to another area, near its border, like show in the image, the area is highlighted which is under the cursor, not under the square pointer as should be.
What are options to fix this issue? In the ideal way, I would like hover effect to be applied not to the mouse cursor coordinates, but to the coordinates of some other point that is known and changes while mouse is moving.
I once had a similar problem that I tried to solve with a different approach. I wanted to calculate the centroid of the polygon and always place the marker (in your case square pointer) on the calculated position once the user hovers over the polygon.
Main problem I had was that my polygons were concave and had holes in them (you will have the same problem if you are working with country borders) so I found a good algorithm (library) that I used to do this called Polylabel.
You can read more on this topic and how the guys from MapBox used it to solve their label positioning problems on this link.
Although this is not the answer to your question I found that this solution is fast and usable but only if the relation between the zoom level and polygon surface makes sense.
If I wanted to do something like you are suggesting I would first have a default point offset and if that offset goes outside the polygon I would find the nearest point in the polygon coordinates and attach it to that point.
To do these calculations you can use turf.js library. It has the function to return boolean value if the second geometry is completely contained by the first geometry and others that can help you to find the nearest point on the polygon border. I hope this helps!

Canvas - Sticking png images together without taking into account transparent pixels

I have big horizontal strip image in photoshop which is made of lots of smaller elements. The background is transparent and the strip goes from smaller elements (left) to bigger elements (right). My goal is to make this strip interactive to mouse events.
Each element is some kind of polygonal image which is trimmed left and right and then exported as a png. It is then imported into a canvas.
The problem is that I can put them side by side but since they are not rectangles I need a way to calculate the offset made up by the transparent pixels on each side of each element to make them stick together correctly... I am using KineticJs to get a precise hitarea for each element... So maybe there is a way to do it automatically with kineticjs,or there is some kind of operation I could do using each image data?
My problem illustrated:
Any ideas?
Also I am doing this simply because I would prefer precise mouseOver bounding box on each item (rather than a simple rectangle) and would rather avoid the solution to calculate each offset manually... But maybe that's not worth it?!
Ok, so you have yourself a custom shape you want to use, here is a tutorial for that: http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-shape-tutorial/ , the simplest thing you can do, and even that seems fairly long, is to calculate the bounding lines for that shape. (Two somewhat vertical lines, and two somewhat horizontal lines). Then you test if the right vertical line of shape one crosses with the left vertical line of shape two, if they do, then set the coordinates of the images to be the same coordinate.
http://www.mathopenref.com/coordintersection.html
line1 = ax + b ..... line2 = cx+d //see possible tests
if(...intersection test...){ // or just test if some coordinate is left of some other coordinate
shape2.setX(shape1.getX()+shape1.getWidth()); //account for image width, so they don't overlap
shape2.setY(shape1.getY()) // no need to account for height
}
UPDATE: This is a very rough solution to the workings of the problem. The next step would be to do more fine tuning dependent on each image.
http://jsfiddle.net/9jkr7/15/
If you want precise areas, use an image map. With some clever finagling and a blank image gif you should be able to have the background you want whenever you hover over any particular area of the image map (might require javascript).
The other option I can think of would be to use SVG itself or one of the many libraries in existance to build interactive vector graphics into your page.
You could also write a function that calculates the left most, top most, right most, and bottom most pixel by looking at all of the pixels in the image data. Here's a tutorial on that:
http://www.html5canvastutorials.com/advanced/html5-canvas-get-image-data-tutorial/

Determine coordinates of rotated rectangle

I'm creating an utility application that should detect and report the coordinates of the corners of a transparent rectangle (alpha=0) within an image.
So far, I've set up a system with Javascript + Canvas that displays the image and starts a floodfill-like operation when I click inside the transparent rectangle in the image. It correctly determines the bounding box of the floodfill operation and as such can provide me the correct coordinates.
Here's my implementation so-far: http://www.scriptorama.nl/image/ (works in recent Firefox / Safari ).
However, the bounding box approach breaks down then the transparent rectangle is rotated (CW or CCW) as the resulting bounding box no longer properly represents the proper width and height. I've tried to come up with a few alternatives to detect to corners, but have not been able to think up a proper solution.
So, does anyone have any suggestions on how I might approach this so I can properly detect the coordinates of 4 corners of the rotated rectangle?
I think you can do this with a simple extension to your existing solution: walk along each of the 4 edges of the bounding box, looking for transparent pixels:
In the non-rotated case, all the pixels along each edge of the box will be transparent.
In the rotated case, there must be one corner touching each edge of the box. This will be at the transparent pixel furthest away from the middle of the edge (there may be more than one due to aliasing, e.g. if the rectangle is only very slightly rotated).

Categories

Resources