1

I have the following point configuration:

import numpy as np 

T=np.array([9,9])
X1=np.array([8,16])
X2=np.array([16,3])
points=np.array([[4, 15],
                 [13,17],
                 [2, 5],
                 [16,8]])

This can be represented as:

enter image description here

Given T, X1, and X2, I want to find all points of the array points that are inside the yellow region. This yellow region is always in the "opposite side" of the points X1 and X2.

How can I achieve this in a simple and efficient way?

Edit1 (trying B Remmelzwaal solution)

T=np.array([9,9])
X1=np.array([10,2])
X2=np.array([2,15])
points=np.array([[2, 5]])

valid_points = list()

# calculating y = mx + b for line T, X1
slope1 = np.diff(list(zip(T, X1)))
m1 = np.divide(slope1[1], slope1[0])
b1 = T[1] - m1*T[0]

# calculating y = mx + b for line T, X2
slope2 = np.diff(list(zip(T, X2)))
m2 = np.divide(slope2[1], slope2[0])
b2 = T[1] - m2*T[0]

for point in points:
    # check if point is under both lines
    for m, b in (m1, b1), (m2, b2):
        if point[1] > m*point[0] + b:
            break
    else:
        # only append if both checks pass
        valid_points.append(point)
        
print(valid_points)

The configuration is the following: enter image description here and the code returns returns [2,5] and it should return []. This is not correct since the region of interest is now in the opposite region (see image)

  • 1
    Do you know how to do it for one point but don't know how to do it for all points in the array, or what exactly was the difficulty? – mkrieger1 Jun 01 '23 at 16:30
  • I don't know how to do this for one point, or several points. Adding the complexity of having several points was a factor that I thought should be considered, for efficiency matters. – Optical_flow_lover Jun 01 '23 at 16:44

2 Answers2

1

A pretty naive solution, but it should do the job:

T=np.array([9,9])
X1=np.array([8,16])
X2=np.array([16,3])
points=np.array([[4, 15],
                 [13,17],
                 [2, 5],
                 [16,8]])

valid_points = list()

# calculating y = mx + b for line T, X1
slope1 = np.diff(list(zip(T, X1)))
m1 = np.divide(slope1[1], slope1[0])
b1 = T[1] - m1*T[0]

# calculating y = mx + b for line T, X2
slope2 = np.diff(list(zip(T, X2)))
m2 = np.divide(slope2[1], slope2[0])
b2 = T[1] - m2*T[0]

for point in points:
    # check if point is under both lines
    for m, b in (m1, b1), (m2, b2):
        if point[1] > m*point[0] + b:
            break
    else:
        # only append if both checks pass
        valid_points.append(point)
        
print(valid_points)

This code does assume that xT != xX1 and xT != xX2, but you haven't mentioned that being an option.

B Remmelzwaal
  • 1,581
  • 2
  • 4
  • 11
  • I am having trouble with your answer for other configuration cases. For example, for `T=np.array([4132,616]) X1=np.array([4038,435]) X2=np.array([4208,805]) points=np.array([[330,2479]])` the code return `[]`, and it should be `[330,2479]` – Optical_flow_lover Jun 01 '23 at 18:30
  • I've tried plotting the data you've given and I don't see how the point would lie in the area you've described. – B Remmelzwaal Jun 01 '23 at 19:30
  • Here's a GeoGebra demonstration: https://www.geogebra.org/calculator/wmdgxv4x – B Remmelzwaal Jun 01 '23 at 19:36
  • You are right, sorry for my confusion. However I am still having problems. I am going to make an edit to my post to explain them. – Optical_flow_lover Jun 01 '23 at 23:31
1

The naive solution to this can be thought of as a series of stages

  • embed the values into equations in a Two-Point Form
  • for each line defined by the Equations
    • for each point in the collection to compare
      • at X, see if Y is below the line value
  • boolean AND on the results, such that only values below both lines match

However, this can be much faster with NumPy's powerful numeric methods, as you can directly use the values in collections without bothering to create the intermediate equations, but need to then pose it in a manner it expects and would make more sense to do for a great number of lines (hundreds, millions..)

very extended approach

import numpy as np 

T=np.array([9,9])
X1=np.array([8,16])
X2=np.array([16,3])
points=np.array([[4, 15],
                 [13,17],
                 [2, 5],
                 [16,8]])

equations = []
for point_pair in [(T, X1), (T, X2)]:
    # extract points
    (x1, y1), (x2, y2) = point_pair  # unpack
    # create equation as a function of X to get Y
    fn = lambda x, x1=x1, y1=y1, x2=x2, y2=y2: (y2-y1)/(x2-x1)*(x-x1)+y1
    equations.append(fn)

results = {}  # dict mapping lines to their point comparisons
for index, equation in enumerate(equations):
    key_name = "line_{}".format(index + 1)
    results_eq = []
    for point in points:
        point_x, point_y = point  # unpack
        line_y = equation(point_x)
        results_eq.append(point_y < line_y)  # single bool
    array = np.array(results_eq)             # list -> array of bools
    results[key_name] = array                # dict of arrays of bools

# & is used here to compare boolean arrays such that both are True
final_truthyness = results["line_1"] & results["line_2"]
print(final_truthyness)
>>> print(final_truthyness)
[False False  True False]

Alternatively, you can carefully order your points and take the Cross Product

NOTE that the point ordering matters here such that points below are really to the right of the line (vector), you can calculate this by comparing the X values of the points

>>> X1[0] < T[0], X2[0] < T[0]             # determine point ordering
(True, False)
>>> a = np.cross(points - X1, T - X1) > 0
>>> b = np.cross(points - T, X2 - T) > 0
>>> a,b ; a&b                              # individual arrays ; AND
(array([ True, False,  True, False]), array([False, False,  True, False]))
array([False, False,  True, False])

Finally, you might take some caution in a larger program to special case point pairs which are exactly the same point

ti7
  • 16,375
  • 6
  • 40
  • 68
  • Very useful, the trick with the cross products was really interesting and I ended up using them. Btw, what do you mean by faster NumPy's powerful numeric methods? Can u give me a hint about what are those methods, so I can look them up and try to implement them in my code? – Optical_flow_lover Jun 02 '23 at 11:49
  • ah, simply using methods of NumPy is generally _much_ faster than equivalent logic in native Python as the arrays are special objects which arrange the memory in blocks and then can work on them in ways that take advantage of that structure https://stackoverflow.com/questions/8385602/why-are-numpy-arrays-so-fast https://stackoverflow.com/a/42082685/4541045 – ti7 Jun 02 '23 at 14:31