How to do pattern /shape match / recognition on a board (20x20)? - c#
The board is int[][] and I would like to find this shape
1
1
1
with all 4 of it's symmetric (rotational) variants from the board and log the positions.
e.g.
...
...
... x x x x x x ...
... x x 1 1 x x ...
... x 1 x x x x ...
... x x x x x x ...
...
...
Is it better to use F# to deal with these kinds of problems?
Below is my c# code for checking patterns vertically only (the code to check horizontally is simillar)
List<Position> GetMatchVertical(int reelID)
{
List<Position> ret = new List<Position>();
var myReel = board[reelID];
var leftReel = reelID - 1 >= 0 ? board[reelID - 1] : null;
var rightReel = reelID + 1 < boardSize ? board[reelID + 1] : null;
int currentColor = myReel[0];
for (int reelPosition = 1; reelPosition < boardSize; reelPosition++)
{
int nextColor = myReel[reelPosition];
if (currentColor == nextColor)
{
if (leftReel!=null)
{
if (reelPosition + 1 < boardSize && leftReel[reelPosition + 1] == currentColor)
{
ret.Add(logPosition(...));
}
}
if (rightReel!=null)
{
if (reelPosition - 2 >= 0 && rightReel[reelPosition - 2] == currentColor)
{
ret.Add(logPosition(...));
}
}
}
else
{
currentColor = nextColor;
}
}
return ret;
}
This is definitely a great fit for functional programming and F#. There is a large number of possible approaches. I think the solution by pad is probably the most direct one and it is a really good starting point. If you need something more general, then the solution by Huusom is quite nice.
There is even more general approach, which is to build a domain specific language (DSL) for detecting patterns in an array. This is more advanced functional technique, but it works really nicely for your example. If you did that, then you could express quite complex patterns in a really concise way. Here is an example:
// Create a detector that tests if a location
// contains 1 and returns 'false' when out of range
let one = border false (equals 1)
// A shape detector for your pattern
let pattern =
around (0, 0) one <&> around (1, 0) one <&>
around (-1, 1) one
// Test pattern with any rotation: Combine
// 4 possible rotations with logical or.
let any =
pattern <|> rotate pattern <|>
rotate (rotate pattern) <|>
rotate (rotate (rotate pattern))
This sample uses various primitives to build a declarative specification of the pattern. The value any represents a function that you can run to test whether the pattern occurs at a given location. It handles all rotations of the pattern and it also does bounds checks. You'd also need to add mirrored patterns, but that would be quite easy extension.
Explaining the implementation would probably need a full blog post, but here is a commented source code that should be quite readable:
/// A type that represents a function that tests
/// whether an array contains some pattern at a
/// specified location. It gets the location to
/// test & the array as arguments and returns bool.
type ShapeDetector = SD of (int -> int -> int[,] -> bool)
/// A primitive that tests whether the value at the
/// current location contains a value 'v'
let equals v = SD (fun x y arr -> arr.[x,y] = v)
/// A combinator that takes 'ShapeDetector' and
/// creates a new one that returns 'def' when
/// accessing outside of the array bounds
let border def (SD f) = SD (fun x y arr ->
if x < 0 || y < 0 || x >= arr.GetLength(0) || y >= arr.GetLength(1)
then def else f x y arr)
/// A combinator that calls a given ShapeDetector
/// at a location specified by offset dx, dy
let around (dx, dy) (SD f) = SD (fun x y arr ->
f (x + dx) (y + dy) arr)
/// A combinator that takes a ShapeDetector and
/// builds a new one, which is rotated by 90 degrees
let rotate (SD f) = SD (fun x y arr ->
f -y x arr)
/// Creates a shape detector that succeeds only
/// when both of the arguments succeed.
let (<&>) (SD f1) (SD f2) = SD (fun x y arr ->
f1 x y arr && f2 x y arr)
/// Creates a shape detector that succeeds
/// when either of the arguments succeed.
let (<|>) (SD f1) (SD f2) = SD (fun x y arr ->
f1 x y arr || f2 x y arr)
Finally, here is an example that runs the pattern detector on a sample 2D array:
// Create a 2D array as a sample input
let inp =
array2D [ [ 0; 0; 1 ]
[ 0; 1; 0 ]
[ 0; 1; 0 ] ]
// Get the underlying function and run it
// for all possible indices in the array
let (SD f) = any
for x in 0 .. 2 do
for y in 0 .. 2 do
printfn "%A %A" (x, y) (f x y inp)
You can find horizontal shapes using pattern matching in F# like this (do similarly for vertical shapes):
/// Try to match with horizontal shapes
/// 1 x x and 1 1 x
/// x 1 1 x x 1
///
/// 1 1 x and x x 1
/// x x 1 1 1 x
/// could be found by reversing matched sub-arrays
let matchHorizontalShapes (board: _ [] []) =
let positions = ResizeArray()
for i in 0..board.Length - 2 do
for j in 0..board.[0].Length - 3 do
match [|board.[i].[j..j+2];
board.[i+1].[j..j+2]|] with
| [|[|1; 1; _|];
[|_; 1; 1|]|] -> positions.Add((i, j), (i+1, j+1), (i+1, j+2))
positions.Add((i, j), (i, j+1), (i+1, j+2))
| [|[|1; _; _|];
[|_; 1; 1|]|] -> positions.Add((i, j), (i+1, j+1), (i+1, j+2))
| [|[|1; 1; _|];
[|_; _; 1|]|] -> positions.Add((i, j), (i, j+1), (i+1, j+2))
| _ -> ()
positions.ToArray()
If you create a set of coordinat offsets based on the pattern then you can get the values and match the result to a known set of values.
let find_matches board pattern =
let xb = Array2D.length1 board
let yb = Array2D.length2 board
// safe lookup on board
let get_value= function
| (x, _) when (x < 0) || (x >= xb) -> None
| (_, y) when (y < 0) || (y >= yb) -> None
| (x, y) -> Some (Array2D.get board x y)
// do a patten match on board.
let has_pattern = function
| [Some 1; Some 1; Some 1] -> true
| _ -> false
// se if a given coordinate is a match
let is_match (x,y) =
pattern
|> List.map (fun (x',y') -> (x+x', y+y')) // expand the coordinat to a list of coordinates
|> List.map get_value // find the values coordinates
|> has_pattern // match to pattern
[for x in 0..(xb-1) do for y in 0..(yb-1) -> x, y]
|> List.filter is_match
This functions works with a pattern of [(0,0); (1, -1); (1, -2)] (your example from above).
Please note I use an Array2D (int[,]) instead of int[][] given in your example.
Related
C# Find Nearby Points on a XY Grid
Say I have an grid of 100by100. Now I have a location on 23,70. How can I find all XY points on this grid within a distance of 5?
Your question is a little vague, but there might be some simple methods to do it quickly depending on your requirements and definitions. Assuming that we're talking about a unit-square grid there are 3 primary ways to define the distance: Number of steps in the 8 directions: n, ne, e, se, s, sw, w, nw Number of steps in the 4 directions: n, e, s, w Linear distance between the cells (Pythagoras) The first is the simplest, being simply a square from [x - 5, y - 5] to [x + 5, y + 5]. Quick enough to calculate on the fly. Second option is a diamond shape which satisfies the following function: static bool InRange(Point C, Point P) => (Math.Abs(P.X - C.X) + Math.Abs(P.Y - C.Y)) <= 5; And finally, linear distance uses Pythagoras to find the distance between the cells and compares that to your threshold value. The final shape will depend on how you handle overlap. You could use the following test function: static bool InRange(Point C, Point P) => ((P.X - C.X) * (P.X - C.X)) + ((P.Y - C.Y) * (P.Y - C.Y)) <= 25; Note that in all cases the possible solution range falls in the square defined by the first solution, so you don't have to test every single cell on your grid. At most there are 24 tests (for a distance of 5) modified by the size of the grid. Here's a general solution building on the above, using LINQ because I like it: public static IEnumerable<Point> PointsInRange(this Point C, int range, int method) { // select filter function Func<int, int, bool> filter = (x, y) => true; if (method == 1) filter = (x, y) => (Math.Abs(x) + Math.Abs(y)) <= range; else if (method == 2) filter = (x, y) => (x * x + y * y) <= (range * range); // apply filter to all cells in potential range var validOffsets = from dx in Enumerable.Range(-range, range * 2 + 1) from dy in Enumerable.Range(-range, range * 2 + 1) where (dx != 0 || dy != 0) && filter(dx, dy) select new { dx, dy }; // offset from center and clip to grid var result = from o in validOffsets let x = C.x + o.dx let y = C.y + o.dy where x >= 0 && x < 100 && y >= 0 && y < 100 select new Point(x, y); return result; } There are a few speed-ups you can apply, as always. Of course if you only ever want to get the valid cells for a specific range (5 for instance) then you can reduce it further by specifying the valid offsets in an array instead of calculating them as above. You can cut the whole start of the method and replace it with a constant array with the shape you want. Or combine the two ideas and cache the answers so that you have the flexibility of arbitrary range and the speed of computing the valid offsets only once.
Returning list that satisfy conditions
I have two lists filled with (x, y) data points; one of the lists being the main list and the other being a list I want to compare against. So for example, in the main list I try to find "gaps" in the data; say I'm looking at two x data points x1 = 21 and x2 = 24. The difference between those two points is greater than deltaX = 1. So what I'd like to do, is look through the second list, and find all data points between x1 = 21 and x2 = 24 to "fill in the gap". I have something like this: double diffX = Math.Abs(datapoints1[i + 1].X - datapoints1[i].X); if (diffX > deltaX) { datapoints1.AddRange(LookBetween(datapoints1[i + 1].X, datapoints1[i].X); } . . . private IEnumerable<PointXY> LookBetween(double upperLimit, double lowerLimit) { return datapoints2.Where(x => x.X < upperLimit && x.X > lowerLimit); } LookBetween seems to return a boolean because nothing gets added to the main list. How can I get it to return a list of the x, y values that match the criteria based on the gap of x?
It seems like you're trying to do a pairwise iteration through neighbors in datapoints1. Using the function linked above, you might have something like: var pairs = datapoints1.Pairwise((d1, d2) => new { x1 = d1.X, x2 = d2.X, diffX = Math.Abs(d1.X - d2.X), }); var gaps = from pair in pairs where pair.diffX > deltaX from dp2 in datapoints2 where pair.x1 < dp2.X && dp2.X < pair.x2 select dp2; Or using your LookBetween function... var gaps = from pair in pairs where pair.diffX > deltaX from dp2 in LookBetween(pair.x2, pair.x1) select dp2;
Recursive Multiplication Method
I'm following along with this http://www.cs.berkeley.edu/~vazirani/algorithms/chap1.pdf (bottom of page 24). In the book the author describes Al Khwarizmi multiplication algorithm. Here is my implementation static int RecMultiply(int x, int y) { if (y == 0) return 0; int z = RecMultiply(x, y / 2); if (y % 2 == 0) return 2 * z; else return x + 2 * z; } I've stepped through the code a couple times and I'm just not grokking it. Why does the bottom else add x to 2 * z? It seems to me that z is used both as a running total and as the "right column" number in the algorithm in the book. Can someone break this code down and explain it please?
Since Multiplication is simple repetitive addition, if y is pair, you can divide it by two, and multiply x by two. (so, 2*2 = 2+2. 2*3 = 2+2+2, 2*4 = 2+2+2+2 ....) If y is odd, you can subtract 1, to get a y that is pair, and you need to add an x, (basically, 1*y). Here's a breakdown: RecMultiply(5,5) : +- z = RecMultiply(5,2) | return 5 + 2 * z (=20 +5 =25) | | +-- RecMultiply(5,2) : +- z = RecMultiply(5,1) | return 2 * z (=10) | +-- RecMultiply(5,1) : +- z = RecMultiply(5,0) | return 5 + 0 | +---RecMultiply(5,0) : return 0 RecMultiply(5,4) : +- z = RecMultiply(5,2) | return 2 * z (=) | +-- RecMultiply(5,2) : +- z = RecMultiply(5,1) | return 2 * z (=10) | +-- RecMultiply(5,1) : +- z = RecMultiply(5,0) | return 5 + 0 | +---RecMultiply(5,0) : return 0 So, basically, after the recursive bit (that takes care of all the pair multiplications), you might need to add another y, which in the first case above, is 5 for the first call). Note the special case of y=1, which means x*1 which obviously is 5 in our case. Same logic applies. You might want to look at it like this, if it helps: static int RecMultiply(int x, int y) { switch (y) { case 0: return 0; break; case 1: return x; break; default: return (y%2 ==0) ? RecMultiply(x, y/2) : x + RecMultiply(x, y/2); break; } } I think it denotes the +1 (or odd cases) in a more understandable manner.
It is quite simple. Z is calculated by multiplying x and half of y. If y was of even parity (if section) return 2*z = 2 * x * y/2 = x * y (which is original request) If y was of odd parity (else section) return 2*z + x. Why do we add x??? That is because y/2 will be the same for even and following odd number. So Z would be the same. But, with this if section we are detecting if it's odd or even and in case of odd we add x once more to the result.
Checking if points are diagonal
Hello I'm having a little trouble on this one aspect in my code that I'm working on. It deals with points and returns true or not if it's diagonal to other points in my arrayList of Points. Here my code so far: private List<Point> point; public void check() { for (int i = 0; i < point.Count; i++) { validSpot(i); } }
One note, your graph has your y upside down from the way an array stores it. You could treat your indexes as points on a graph. To find what falls on the diagonal use slope intercept form. y = m x + b. Since you only want diagonals, valid slopes are limited to 1 and -1. Then you just have to define the line that passes through the point of interest and test if the point in question satisfies one of the equations for m = -1 or m = 1. Since the slope is known you only need one point to define the line. public bool func(int[] knownPt,int xTest, int yTest) { //knownPt is int[]{x,y} // y = m*x + (yi - xi) return yTest== xTest + knownPt[1] - KnownPt[0] || yTest == -xTest +knownPt[1] + KnownPt[0]; } As a walk through here is m = -1 yi = -xi + b yi + xi = b since b = yi + xi y = -x + (yi + xi)
How to tell whether a point is to the right or left side of a line
I have a set of points. I want to separate them into 2 distinct sets. To do this, I choose two points (a and b) and draw an imaginary line between them. Now I want to have all points that are left from this line in one set and those that are right from this line in the other set. How can I tell for any given point z whether it is in the left or in the right set? I tried to calculate the angle between a-z-b – angles smaller than 180 are on the right hand side, greater than 180 on the left hand side – but because of the definition of ArcCos, the calculated angles are always smaller than 180°. Is there a formula to calculate angles greater than 180° (or any other formula to chose right or left side)?
Try this code which makes use of a cross product: public bool isLeft(Point a, Point b, Point c){ return ((b.X - a.X)*(c.Y - a.Y) - (b.Y - a.Y)*(c.X - a.X)) > 0; } Where a = line point 1; b = line point 2; c = point to check against. If the formula is equal to 0, the points are colinear. If the line is horizontal, then this returns true if the point is above the line.
Use the sign of the determinant of vectors (AB,AM), where M(X,Y) is the query point: position = sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax)) It is 0 on the line, and +1 on one side, -1 on the other side.
You look at the sign of the determinant of | x2-x1 x3-x1 | | y2-y1 y3-y1 | It will be positive for points on one side, and negative on the other (and zero for points on the line itself).
The vector (y1 - y2, x2 - x1) is perpendicular to the line, and always pointing right (or always pointing left, if you plane orientation is different from mine). You can then compute the dot product of that vector and (x3 - x1, y3 - y1) to determine if the point lies on the same side of the line as the perpendicular vector (dot product > 0) or not.
Using the equation of the line ab, get the x-coordinate on the line at the same y-coordinate as the point to be sorted. If point's x > line's x, the point is to the right of the line. If point's x < line's x, the point is to the left of the line. If point's x == line's x, the point is on the line.
I implemented this in java and ran a unit test (source below). None of the above solutions work. This code passes the unit test. If anyone finds a unit test that does not pass, please let me know. Code: NOTE: nearlyEqual(double,double) returns true if the two numbers are very close. /* * #return integer code for which side of the line ab c is on. 1 means * left turn, -1 means right turn. Returns * 0 if all three are on a line */ public static int findSide( double ax, double ay, double bx, double by, double cx, double cy) { if (nearlyEqual(bx-ax,0)) { // vertical line if (cx < bx) { return by > ay ? 1 : -1; } if (cx > bx) { return by > ay ? -1 : 1; } return 0; } if (nearlyEqual(by-ay,0)) { // horizontal line if (cy < by) { return bx > ax ? -1 : 1; } if (cy > by) { return bx > ax ? 1 : -1; } return 0; } double slope = (by - ay) / (bx - ax); double yIntercept = ay - ax * slope; double cSolution = (slope*cx) + yIntercept; if (slope != 0) { if (cy > cSolution) { return bx > ax ? 1 : -1; } if (cy < cSolution) { return bx > ax ? -1 : 1; } return 0; } return 0; } Here's the unit test: #Test public void testFindSide() { assertTrue("1", 1 == Utility.findSide(1, 0, 0, 0, -1, -1)); assertTrue("1.1", 1 == Utility.findSide(25, 0, 0, 0, -1, -14)); assertTrue("1.2", 1 == Utility.findSide(25, 20, 0, 20, -1, 6)); assertTrue("1.3", 1 == Utility.findSide(24, 20, -1, 20, -2, 6)); assertTrue("-1", -1 == Utility.findSide(1, 0, 0, 0, 1, 1)); assertTrue("-1.1", -1 == Utility.findSide(12, 0, 0, 0, 2, 1)); assertTrue("-1.2", -1 == Utility.findSide(-25, 0, 0, 0, -1, -14)); assertTrue("-1.3", -1 == Utility.findSide(1, 0.5, 0, 0, 1, 1)); assertTrue("2.1", -1 == Utility.findSide(0,5, 1,10, 10,20)); assertTrue("2.2", 1 == Utility.findSide(0,9.1, 1,10, 10,20)); assertTrue("2.3", -1 == Utility.findSide(0,5, 1,10, 20,10)); assertTrue("2.4", -1 == Utility.findSide(0,9.1, 1,10, 20,10)); assertTrue("vertical 1", 1 == Utility.findSide(1,1, 1,10, 0,0)); assertTrue("vertical 2", -1 == Utility.findSide(1,10, 1,1, 0,0)); assertTrue("vertical 3", -1 == Utility.findSide(1,1, 1,10, 5,0)); assertTrue("vertical 3", 1 == Utility.findSide(1,10, 1,1, 5,0)); assertTrue("horizontal 1", 1 == Utility.findSide(1,-1, 10,-1, 0,0)); assertTrue("horizontal 2", -1 == Utility.findSide(10,-1, 1,-1, 0,0)); assertTrue("horizontal 3", -1 == Utility.findSide(1,-1, 10,-1, 0,-9)); assertTrue("horizontal 4", 1 == Utility.findSide(10,-1, 1,-1, 0,-9)); assertTrue("positive slope 1", 1 == Utility.findSide(0,0, 10,10, 1,2)); assertTrue("positive slope 2", -1 == Utility.findSide(10,10, 0,0, 1,2)); assertTrue("positive slope 3", -1 == Utility.findSide(0,0, 10,10, 1,0)); assertTrue("positive slope 4", 1 == Utility.findSide(10,10, 0,0, 1,0)); assertTrue("negative slope 1", -1 == Utility.findSide(0,0, -10,10, 1,2)); assertTrue("negative slope 2", -1 == Utility.findSide(0,0, -10,10, 1,2)); assertTrue("negative slope 3", 1 == Utility.findSide(0,0, -10,10, -1,-2)); assertTrue("negative slope 4", -1 == Utility.findSide(-10,10, 0,0, -1,-2)); assertTrue("0", 0 == Utility.findSide(1, 0, 0, 0, -1, 0)); assertTrue("1", 0 == Utility.findSide(0,0, 0, 0, 0, 0)); assertTrue("2", 0 == Utility.findSide(0,0, 0,1, 0,2)); assertTrue("3", 0 == Utility.findSide(0,0, 2,0, 1,0)); assertTrue("4", 0 == Utility.findSide(1, -2, 0, 0, -1, 2)); }
First check if you have a vertical line: if (x2-x1) == 0 if x3 < x2 it's on the left if x3 > x2 it's on the right else it's on the line Then, calculate the slope: m = (y2-y1)/(x2-x1) Then, create an equation of the line using point slope form: y - y1 = m*(x-x1) + y1. For the sake of my explanation, simplify it to slope-intercept form (not necessary in your algorithm): y = mx+b. Now plug in (x3, y3) for x and y. Here is some pseudocode detailing what should happen: if m > 0 if y3 > m*x3 + b it's on the left else if y3 < m*x3 + b it's on the right else it's on the line else if m < 0 if y3 < m*x3 + b it's on the left if y3 > m*x3+b it's on the right else it's on the line else horizontal line; up to you what you do
I wanted to provide with a solution inspired by physics. Imagine a force applied along the line and you are measuring the torque of the force about the point. If the torque is positive (counterclockwise) then the point is to the "left" of the line, but if the torque is negative the point is the "right" of the line. So if the force vector equals the span of the two points defining the line fx = x_2 - x_1 fy = y_2 - y_1 you test for the side of a point (px,py) based on the sign of the following test var torque = fx*(py-y_1)-fy*(px-x_1) if torque>0 then "point on left side" else if torque <0 then "point on right side" else "point on line" end if
Assuming the points are (Ax,Ay) (Bx,By) and (Cx,Cy), you need to compute: (Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Ax) This will equal zero if the point C is on the line formed by points A and B, and will have a different sign depending on the side. Which side this is depends on the orientation of your (x,y) coordinates, but you can plug test values for A,B and C into this formula to determine whether negative values are to the left or to the right.
basically, I think that there is a solution which is much easier and straight forward, for any given polygon, lets say consist of four vertices(p1,p2,p3,p4), find the two extreme opposite vertices in the polygon, in another words, find the for example the most top left vertex (lets say p1) and the opposite vertex which is located at most bottom right (lets say ). Hence, given your testing point C(x,y), now you have to make double check between C and p1 and C and p4: if cx > p1x AND cy > p1y ==> means that C is lower and to right of p1 next if cx < p2x AND cy < p2y ==> means that C is upper and to left of p4 conclusion, C is inside the rectangle. Thanks :)
#AVB's answer in ruby det = Matrix[ [(x2 - x1), (x3 - x1)], [(y2 - y1), (y3 - y1)] ].determinant If det is positive its above, if negative its below. If 0, its on the line.
Here's a version, again using the cross product logic, written in Clojure. (defn is-left? [line point] (let [[[x1 y1] [x2 y2]] (sort line) [x-pt y-pt] point] (> (* (- x2 x1) (- y-pt y1)) (* (- y2 y1) (- x-pt x1))))) Example usage: (is-left? [[-3 -1] [3 1]] [0 10]) true Which is to say that the point (0, 10) is to the left of the line determined by (-3, -1) and (3, 1). NOTE: This implementation solves a problem that none of the others (so far) does! Order matters when giving the points that determine the line. I.e., it's a "directed line", in a certain sense. So with the above code, this invocation also produces the result of true: (is-left? [[3 1] [-3 -1]] [0 10]) true That's because of this snippet of code: (sort line) Finally, as with the other cross product based solutions, this solution returns a boolean, and does not give a third result for collinearity. But it will give a result that makes sense, e.g.: (is-left? [[1 1] [3 1]] [10 1]) false
Issues with the existing solution: While I found Eric Bainville's answer to be correct, I found it entirely inadequate to comprehend: How can two vectors have a determinant? I thought that applied to matrices? What is sign? How do I convert two vectors into a matrix? position = sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax)) What is Bx? What is Y? Isn't Y meant to be a Vector, rather than a scalar? Why is the solution correct - what is the reasoning behind it? Moreover, my use case involved complex curves rather than a simple line, hence it requires a little re-jigging: Reconstituted Answer Point a = new Point3d(ax, ay, az); // point on line Point b = new Point3d(bx, by, bz); // point on line If you want to see whether your points are above/below a curve, then you would need to get the first derivative of the particular curve you are interested in - also known as the tangent to the point on the curve. If you can do so, then you can highlight your points of interest. Of course, if your curve is a line, then you just need the point of interest without the tangent. The tangent IS the line. Vector3d lineVector = curve.GetFirstDerivative(a); // where "a" is a point on the curve. You may derive point b with a simple displacement calculation: Point3d b = new Point3d(a.X, a.Y, a.Z).TransformBy( Matrix3d.Displacement(curve.GetFirstDerivative(a)) ); Point m = new Point3d(mx, my, mz) // the point you are interested in. The Solution: return (b.X - a.X) * (m.Y - a.Y) - (b.Y - a.Y) * (m.X - a.X) < 0; // the answer Works for me! See the proof in the photo above. Green bricks satisfy the condition, but the bricks outside were filtered out! In my use case - I only want the bricks that are touching the circle. Theory behind the answer I will return to explain this. Someday. Somehow...
An alternative way of getting a feel of solutions provided by netters is to understand a little geometry implications. Let pqr=[P,Q,R] are points that forms a plane that is divided into 2 sides by line [P,R]. We are to find out if two points on pqr plane, A,B, are on the same side. Any point T on pqr plane can be represented with 2 vectors: v = P-Q and u = R-Q, as: T' = T-Q = i * v + j * u Now the geometry implications: i+j =1: T on pr line i+j <1: T on Sq i+j >1: T on Snq i+j =0: T = Q i+j <0: T on Sq and beyond Q. i+j: <0 0 <1 =1 >1 ---------Q------[PR]--------- <== this is PQR plane ^ pr line In general, i+j is a measure of how far T is away from Q or line [P,R], and the sign of i+j-1 implicates T's sideness. The other geometry significances of i and j (not related to this solution) are: i,j are the scalars for T in a new coordinate system where v,u are the new axes and Q is the new origin; i, j can be seen as pulling force for P,R, respectively. The larger i, the farther T is away from R (larger pull from P). The value of i,j can be obtained by solving the equations: i*vx + j*ux = T'x i*vy + j*uy = T'y i*vz + j*uz = T'z So we are given 2 points, A,B on the plane: A = a1 * v + a2 * u B = b1 * v + b2 * u If A,B are on the same side, this will be true: sign(a1+a2-1) = sign(b1+b2-1) Note that this applies also to the question: Are A,B in the same side of plane [P,Q,R], in which: T = i * P + j * Q + k * R and i+j+k=1 implies that T is on the plane [P,Q,R] and the sign of i+j+k-1 implies its sideness. From this we have: A = a1 * P + a2 * Q + a3 * R B = b1 * P + b2 * Q + b3 * R and A,B are on the same side of plane [P,Q,R] if sign(a1+a2+a3-1) = sign(b1+b2+b3-1)
equation of line is y-y1 = m(x-x1) here m is y2-y1 / x2-x1 now put m in equation and put condition on y < m(x-x1) + y1 then it is left side point eg. for i in rows: for j in cols: if j>m(i-a)+b: image[i][j]=0
A(x1,y1) B(x2,y2) a line segment with length L=sqrt( (y2-y1)^2 + (x2-x1)^2 ) and a point M(x,y) making a transformation of coordinates in order to be the point A the new start and B a point of the new X axis we have the new coordinates of the point M which are newX = ((x-x1)(x2-x1)+(y-y1)(y2-y1)) / L from (x-x1)*cos(t)+(y-y1)*sin(t) where cos(t)=(x2-x1)/L, sin(t)=(y2-y1)/L newY = ((y-y1)(x2-x1)-(x-x1)(y2-y1)) / L from (y-y1)*cos(t)-(x-x1)*sin(t) because "left" is the side of axis X where the Y is positive, if the newY (which is the distance of M from AB) is positive, then it is on the left side of AB (the new X axis) You may omit the division by L (allways positive), if you only want the sign