Testing if a line has a point within a triangle - geometry

How can I test whether a line has a point that lies within (not on the edge of) a triangle. (All in 2D).
Currently I'm thinking I'll do this:
Define the line, and each side of the triangle as Ax+By+C=0, and have an xrange.
Check if the line intersects any of the lines of the triangle.
If it does, check that this is NOT at the end of the line.
Is there a better way to do this?

substitute the 3 points into the line's equation. e.g. if the line is 4x − 3y + 2 = 0, and the triangle's vertices are (2, 1), (4, 3), (0, 5), we get the values 7, 9 and -13 respectively.
check if all values are of the same sign. If yes, the line does not intersect the triangle. In the above example, the line intersects the triangle.
http://www.imgftw.net/img/743059947.png

Related

Which GeoPandas function checks if at least one point of a geometry is within another?

I have a GeoSeries of linestrings, and a polygon. I aim to find those linestrings, which have at least one point within the polygon.
I know about geopandas.GeoSeries.within. I could decompose my linestrings to a list of points, and then check if each.within(polygon). If any point of a linestring are, I say the linestring has at least one point within the polygon.
Is there a way of determining if parts of a linestring is within a polygon without decomposing the linestring to points?
The functions I have looked at but do not work:
GeoSeries.touches(other, align=True)
Based on description, this is not what I need:
An object is said to touch other if it has at least one point in
common with other and its interior does not intersect with any part of
the other. Overlapping features therefore do not touch.
GeoSeries.overlaps(other, align=True)
Geometries overlaps if they have more than one but not all points in
common, have the same dimension, and the intersection of the interiors
of the geometries has the same dimension as the geometries themselves.
Does not work, and the reason I believe is that a line is 1 dimensional, a polygon is 2, so the have the same dimension condition is violated. I am unsure that this is the full reason, so here is a demonstration that this function does not work for the purpose described above:
import geopandas as gpd
from shapely.geometry import Polygon, LineString
Define a LineString and a Polygon:
l = LineString([(+0.25,0.5),(0.5,0.5),(1.5,0.5), (2.1, 0.5), (2,-1)])
l = gpd.GeoSeries([l])
p = Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)])
p = gpd.GeoSeries([p])
Plot them:
plt.plot([each[0] for each in list(l.iloc[0].coords)],
[each[1] for each in list(l.iloc[0].coords)])
plt.plot(p.iloc[0].exterior.xy[0],p.iloc[0].exterior.xy[1])
Both l.overlaps(p) and p.overlaps(l) return
0 False
dtype: bool
which is not what's expected.
geopandas.GeoSeries.intersects
Description:
An object is said to intersect other if its boundary and interior
intersects in any way with those of the other.
Some of the linestrings are entirely within my polygon. This function would return False and I would like to return True for those cases.

How to determine which side of a polar line a point lies?

If I have a 2D line given in polar coordinates (i.e. rho distance from the origin and theta angle from the x-axis) how can I determine which on which side of the line a point lies? Specifically, how would I take two points and determine if they are on the same side or opposite sides of this line?
Thanks!
Such line has equation:
-x*cos(theta)+y*sin(theta)-rho=0 [1]
Distance from point (x0, y0) to this line is
Dist = -x0*cos(theta)+y0*sin(theta)-rho [2]
Important thing: sign of Dist depends on which side of the line a point lies (positive when this point and coordinate origin lie on the different sides of line, and negative otherwise).
So it is enough to calc and compare the signs of the [2] expressions for two needed points
Could you take both of the supplied points and calculate their angles respective to theta?
Say for the sake of argument that your 2D line ends at (3,3);
2D Line:
Coord: (3,3)
Radius: 3 * √2
Theta: 0.79 radians
Point 1:
Coord: (3,4)
Radius: 5
Theta: Arcsin(4/5) = 0.92 radians
Point 2:
Coord: (3,1)
Radius: √10
Theta: Arcsin(2/√10) = 0.68 radians
Point 1's Theta is greater than that of the 2D Line; it is on one distinct side. Point 2's is less than that of the 2D line; it is on the other side.
Hope this helps! :)
I understand you have your line given by say rho with is the intersection of your line with the x-axis and theta with is the angle between your line and the x-axis.
An equation for your line then would read
f(x) = (x-rho)*tan(theta)
To determine if a point (x0,y0) is above that line check if
f(x0) = (x0-rho)*tan(theta) > y0
To check if it is under the line check
f(x0) = (x0-rho)*tan(theta) < y0
But note that this method breaks if theta= 90°, 270°. But in that case its easy you just have to check if x0 is larger or smaller then rho.

Simple Trigonometry?

EDIT - Thanks for all the answers everyone. I think I accidentally led you slightly wrong as the square in the picture below should be a rectangle (I see most of you are referencing squares which seems like it would make my life a lot easier). Also, the x/y lines could go in any direction, so the red dot won't always be at the top y boundary. I was originally going for a y = mx + b solution, but then I got stuck trying to figure out how I know whether to plug in the x or the y (one of them has to be known, obviously).
I have a very simple question (I think) that I'm currently struggling with for some reason. I'm trying to have a type of minimap in my game which shows symbols around the perimeter of the view, pointing towards objectives off-screen.
Anyway, I'm trying to find the value of the red point (while the black borders and everything in green is known):
It seems like simple trigonometry, but for some reason I can't wrap my head around it. I just need to find the "new" x value from the green point to the red point, then I can utilize basic math to get the red point, but how I go about finding that new x is puzzling me.
Thanks in advance!
scale = max(abs(x), abs(y))
x = x / scale
y = y / scale
This is the simple case, for a square from (-1, -1) to (1, 1). If you want a different sized square, multiply the coordinates by sidelen / 2.
If you want a rectangle instead of a square, use the following formula. (This is another solution to the arbitrarily-sized square version)
scale = max(abs(x) / (width / 2), abs(y) / (height / 2))
x = x / scale
y = y / scale
Let's call the length of one side of the square l. The slope of the line is -y/x. That means, if you move along the line and rise a distance y toward the top of the square, then you'll move a distance x to the left. But since the green point is at the center of the square, you can rise only l/2. You can express this as a ratio:
-y -l/2
——— = ———
x d
Where d is the distance you'll move to the left. Solving for d, we have
d = xl/2y
So if the green dot is at (0, 0), the red dot is at (-l/2, xl/2y).
All you need is the angle and the width of the square w.
If the green dot is at (0,0), then the angle is a = atan(y/x), the y-coordinate of the dot is w/2, and therefore the x-coordinate of the dot is tan(1/a) * (w/2). Note that tan(1/a) == pi/2 - tan(a), or in other words the angle you really want to plug into tan is the one outside the box.
Edit: yes, this can be done without trig, too. All you need is to interpolate the x-coordinate of the dot on the line. So you know the y-coordinate is w/2, then the x-coordinate is (w/2) * x/y. But, be careful which quadrant of the square you're working with. That formula is only valid for -y<x<y, otherwise you want to reverse x and y.

How is CTTypesetterCreateLineWithOffset different from CTTypesetterCreateLine?

The docs say that calling CTTypesetterCreateLine is the same as calling CTTypesetterCreateLineWithOffset with offset set to 0.0, but the description of what offset means is rather lacking: "The line position offset."
I've tried providing different values to it and it doesn't seem to have any impact on the typographic bounds or image bounds of the resulting CTLineRef, nor does it seem to affect the result of drawing the line using CTLineDraw. Can anyone clue me in as to the purpose of this extra parameter?
The offset is a tab offset. It doesn't apply to the line as a whole, but to the first tab-stop.
From http://lists.apple.com/archives/Coretext-dev/2011/Feb/msg00021.html
You create a string containing a tab like "A[tab]B" with Tab position at 200.
When you create a line with offset Zero and draw it at (x, y), it will appear like this.
A B
(x,y) (x+200,y)
When you create a line with offset 50 and draw it at (x + 50, y) (← you need to adjust X coordinate yourself), it will appear like this,
A B
(x+50,y) (x+200,y)
Note that "B" remains at the same position even though the line starts at a different position. If you were passing offset 0 and draw it at (x + 50, y), it would have been like the following.
A B
(x+50,y) (x+250,y)

Find the corners of a deformed rectangle

I am trying to make a program that automatically corrects the perspective of a rectangle. I have managed to get the silhouette of the rectangle, and have the code to correct the perspective, but I can't find the corners. The biggest problem is that, because it has been deformed, I can't use the following "code":
c1 = min(x), min(y)
c2 = max(x), min(y)
c3 = min(x), max(y)
c4 = max(x), max(y)
This wouldn't work with this situation (X represents a corner):
X0000000000X
.00000000000
..X000000000
.....0000000
........0000
...........X
Does anyone know how to do this?
Farthest point from the center will give you one corner.
Farthest point from the first corner will give you another corner, which may be either adjacent or opposite to the first.
Farthest point from the line between those two corners (a bit more math intensitive) will give you a third corner. I'd use distance from center as a tie breaker.
For finding the 4th corner, it'll be the point outside the triangle formed by the first 3 corners you found, farthest from the nearest line between those corners.
This is a very time consuming way to do it, and I've never tried it, but it ought to work.
You could try to use a scanline algorithm - For every line of the polygon (so y = min(y)..max(y)), get l = min(x) and r = max(x). Calculate the left/right slope (deltax) and compare it with the slope the line before. If it changed (use some tolerance here), you are at a corner of the rectangle (or close to it). That won't work for all cases, as the slope can't be that exact because of low resolution, but for large rectangles and slopes not too similar, this should work.
At least, it works well for your example:
X0000000000X l = 0, r = 11
.00000000000 l = 1, r = 11, deltaxl = 1, deltaxr = 0
..X000000000 l = 2, r = 11, deltaxl = 1, deltaxr = 0
.....0000000 l = 5, r = 11, deltaxl = 3, deltaxr = 0
........0000 l = 8, r = 11, deltaxl = 3, deltaxr = 0
...........X l = 11, r = 11, deltaxl = 3, deltaxr = 0
You start with the top of the rectangle where you get two different values for l and r, so you already have two of the corners. On the left side, for the first three lines you'll get deltax = 1, but after it, you'll get deltax = 3, so there is a corner at (3, 3). On the right side, nothing changes, deltax = 0, so you only get the point at the end.
Note that you're "collecting" corners here, so if you don't have 4 corners at the end, the slopes were too similar (or you have a picture of a triangle) and you can switch to a different (more exact) algorithm or just give an error. The same if you have more than 4 corners or some other strange things like holes in the rectangle. It seems some kind of image detection is involved, so these cases can occur, right?
There are cases in which a simple deltax = (x - lastx) won't work good, see this example for the left side of a rectangle:
xxxxxx
xxxxx deltax = 1 dy/dx = 1/1 = 1
xxxxx deltax = 0 dy/dx = 2/1 = 2
xxxx deltax = 1 dy/dx = 3/2 = 1.5
xxxx deltax = 0 dy/dx = 4/2 = 2
xxx deltax = 1 dy/dx = 5/3 = 1.66
Sometimes deltax is 0, sometimes is 1. It's better to use the slope of the line from the actual point to the top left/right point (deltay / deltax). Using it, you'll still have to stick with a tolerance, but your values will get more exact with each new line.
You could use a hough transform to find the 4 most prominent lines in the masked image. These lines will be the sides of the quadrangle.
The lines will intersect in up to 6 points, which are the 4 corners and the 2 perspective vanishing points.
These are easy to distinguish: pick any point inside the quadrangle, and check if the line from this point to each of the 6 intersection points intersects any of the lines. If not, then that intersection point is a corner.
This has the advantage that it works well even for noisy or partially obstructed images, or if your segmentation is not exact.
en.wikipedia.org/wiki/Hough_transform
Example CImg Code
I would be very interested in your results. I have been thinking about writing something like this myself, to correct photos of paper sheets taken at an angle. I am currently struggling to think of a way to correct the perspective if the 4 points are known
p.s.
Also check out
Zhengyou Zhang , Li-Wei He, "Whiteboard scanning and image enhancement"
http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf
for a more advanced solution for quadrangle detection
I have asked a related question, which tries to solve the perspective transform:
proportions of a perspective-deformed rectangle
This looks like a convex hull problem.
http://en.wikipedia.org/wiki/Convex_hull
Your problem is simpler but the same solution should work.

Resources