How to find coordinates (as Natural numbers) of two points that form a tangent line for a circle limited by the x axis? - geometry

Two points P and Q with coordinates (Px, Py) and (Qx, Qy) satisfy the following properties:
The coordinates Px, Py, Qx, and Qy are integers.
Px = −Qx.
The line PQ is tangent to a circle with center (0, 0) and radius r
0 < Px ≤ a for some integer limit a.
How do I find all such pairs of points P and Q?
For example, in the image below I have a circle with radius r=2 and the limit a = 6. The pair of points P = (6, 2) and Q = (−6, −7) are a solution, because:
The coordinates of P and Q are integers.
Px = −Qx.
The line PQ is tangent to the circle.
0 < Px ≤ 6.
But this is just one pair. I need to find all such pairs. There are a finite number of solutions.
So, is there a way to check if coordinates of points are tangent to the circle and are integers, then to list them all? I've looked at slope equations and shortest path from the center of the circle to the line equations, however, in the first case it requires coordinates to be known (which I could do by brute forcing every single digit, but I cannot see the pattern, because my guts tell me there should be some sort of equation I should apply), and in the second case I have to know the slope equation.
This is the algorithm I came up with but I don't think it is correct or good enough:
Find the slope equation y = mx + b for all 1 ≤ Px ≤ a and −a ≤ Qx ≤ −1.
For every y = mx + b check if it is tangent to the circle (how to do that???)
If true, return the pair

Line PQ has equation:
(x-Px)/(Qx-Px)=(y-Py)/(Qy-Py) or
(x-Px)*(Qy-Py)-(y-Py)*(Qx-Px)=0 or
x*(Qy-Py)+y*(Px-Qx)-Px*Qy+Px*Py+Py*Qx-Py*Px =
x*(Qy-Py)+y*2*Px-Px*(Qy+Py)=0
Distance from zero point to this line (circle radius) is
r=Px*(Qy+Py)/Sqrt((2*Px)^2+(Qy-Py)^2)
Note that radius and nominator are integers, so denominator must be integer too. It is possible when 2*Px and |Qy-Py| are members of some Pythagorean triple (for your example - 12^2+9^2 =15^2).So you can use "Generating a triple" method from the above link to significantly reduce the search and find all the possible point pairs (with radius checking)
Px = k * m * n (for m>=n, radius < k*m*n <= a)
|Qy-Py| = k * (m^2 - n^2)
With a=6 max value of n is 2, and your example corresponds to (k, m, n) set of (3, 2, 1)

Related

Tessellating hexagons over a rectangle

I have an infinite grid of hexagons, defined by a cubic (x y z) coordinate system like so:
I also have a viewport -- a rectangular canvas where I will draw the hexagons.
My issue is this. Because the grid of hexagons is infinite in all directions, I can't feasibly draw all of them at once. Therefore, I need to draw all the hexagons that are in the viewport, and ONLY those hexagons.
This image summarizes what I want to do:
In this image, purple-colored hexagons are those I want to render, while white-colored hexagons are those I don't want to render. The black rectangle is hte viewport -- all the hexagons that intersect with it are to be drawn. How would I find which hexagons to render (IE their xyz coordinates)?
Some other info:
I have a function that can recall a hexagon tile and draw it centered at position(x,y) in the viewport, given its cubic xyz coordinates. Therefore, all I should need is the xyz coords of each rectangle to draw, and I can draw them. This might simplify the problem.
I have formulas to convert from cubic hexagon coordinates to x/y coordinates, and back. Given the above diagram, r/g/b being the axes for the cubic coords with the image above, x and y being the cartesian coordinates, and s being the length of a hexagon's edge...
y = 3/2 * s * b
b = 2/3 * y / s
x = sqrt(3) * s * ( b/2 + r)
x = - sqrt(3) * s * ( b/2 + g )
r = (sqrt(3)/3 * x - y/3 ) / s
g = -(sqrt(3)/3 * x + y/3 ) / s
r + b + g = 0
Let's X0, Y0 are coordinates of top left corner, RectWidth is rectangle width, HexWidth = s * Sqrt(3/2) is hexagon width.
Find center of the closest hexagon r0, g0, b0, HX0, HY0. (Rect corner lies in this hexagon, because hexagons are Voronoy diagram cells). Remember horizontal and vertical shift DX = X0 - HX0, DY = Y0 - HY0
Draw horizontal row of Ceil(RectWidth/HexWidth) hexagons, incrementing r coordinate, decrementing f, and keeping b the same, ROWINC=(1,-1,0).
Note that if DY > HexWidth/2, you need extra top row with initial coordinates shifted up (r0, g0-1, b0+1)
Shift starting point by L=(0, 1, -1) if the DX < 0, or by R=(1, 0, -1) otherwise. Draw another horizontal row with the same ROWINC
Shift row starting point by alternative way (L after R, R after L). Draw horizontal rows until bottom edge is reached.
Check whether extra row is needed in the bottom.
You can think of the rectangular box in terms of constraints on an axis.
In the diagram, the horizontal lines correspond to b and your constraints will be of the form somenumber ≤ b and b ≤ somenumber. For example the rectangle might be in the range 3 ≤ b ≤ 7.
The vertical lines are a little trickier, but they are a “diagonal” that corresponds to r-g. Your constraints will be of the form somenumber ≤ r-g and r-g ≤ somenumber. For example it might be the range -4 ≤ r-g ≤ 5.
Now you have two axes with constraints on them, and you can form a loop. The easiest thing will be to have the outer loop use b:
for (b = 3; b ≤ 7; b++) {
…
}
The inner loop is a little trickier, because that's the diagonal constraint. Since we know r+g+b=0, and we know the value of b from the outer loop, we can rewrite the two-variable constraint on r-g. Express r+g+b=0 as g=0-r-b. Now substitute into r-g and get r-(0-r-b). Simplify r-(0-r-b) to 2*r-b. Instead of -4 ≤ r-g we can say -4 ≤ 2*r-b or -4+b ≤ 2*r or (-4+b)/2 ≤ r. Similarly, we can rearrange r-g ≤ 5 to 2*r-b ≤ 5 to r ≤ (5+b)/2. This gives us our inner loop:
for (b = 3; b ≤ 7; b++) {
for (r = (-4+b)/2; r ≤ (5+b)/2; r++) {
g = 0-b-r;
…
}
}
The last bit is to generalize, replacing the constants 3,7,-4,5 with the actual bounds for your rectangle.

Find a coordinate along a path

My trigonometry needs a little help.
How would I go about calculating the point of the nearest possible intersection with a line along a rounded corner?
Take this image:
What I would like to know is, given that I know point a, and the dimensions of the rectangle, how would I find point b when the edges of the rectangle are curved?
So far, as you can see, I've only managed to calculate the nearest edge of the rectangle as if it had right-angled corners.
If it matters, I'm doing this in ActionScript 3. But example sudo-code will suffice.
Calculate the vector from the midpoint M of the corner to A:
v_x = a_x - m_x
v_y = a_y - m_y
then go radius of the corner r times towards A to get to the intersection point I
i_x = m_x + r*v_x
i_y = m_y + r*v_y
This obviously only works if the nearest intersection is on the rounded corner. Just calculate the other intersections with the edges, too, and then check which has the nearest distance to A.
You need to know the radius R of the circle that generates the round corner and the coordinates (Xr,Yr) of the point where the two sides of a non rounded rectangle cross each other.
Then the coordinates for the center of the circle that generates the round corner are (Xc, Yc) = (Xr-R, Yr-R)
From here, it's a matter of solving the equation of the cross point between the segment line defined by point A=(Xa, Ya) and point (Xc, Yc), whose parametric equation is:
x = Xa + p*(Xc-Xa)
y = Ya + p*(Yc-Ya)
and the circle whose equation is
(x-Xc)^2 + (y-Yc)^2 = R^2
Substitute values for x and y from the parametric euation of the line in the equation of the circle, and you will have an equation with only one unkown: p. Solve the equation, and if there are more than one solution, choose the one that is in the range [0,1]. Substitute the found value of p in the parametric equation of the line to get the point of intersection.
Graphically:
If you know the radius and center of the corner as R and C=(Xc, Yc), then the nearest point on the corner to the given point A=(Xa, Ya) is the intersection point of the corner and the line defined by the given point and the center. This point can be directly expressed as
X = Xc + R*(Xa-Xc)/|AC|
Y = Yc + R*(Ya-Yc)/|AC|
where |AC| = Sqrt((Xa-Xc)^2 + (Ya-Yc)^2)

find point where barycentric weights have a specific value

I have triangle: a, b, c. Each vertex has a value: va, vb, vc. In my software the user drags point p around inside and outside of this triangle. I use barycentric coordinates to determine the value vp at p based on va, vb, and vc. So far, so good.
Now I want to limit p so that vp is within range min and max. If a user chooses p where vp is < min or > max, how can I find the point closest to p where vp is equal to min or max, respectively?
Edit: Here is an example where I test each point. Light gray is within min/max. How can I find the equations of the lines that make up the min/max boundary?
a = 200, 180
b = 300, 220
c = 300, 300
va = 1
vb = 1.4
vc = 3.2
min = 0.5
max = 3.5
Edit: FWIW, so far first I get the barycentric coordinates v,w for p using the triangle vertices a, b, c (standard stuff I think, but looks like this). Then to get vp:
u = 1 - w - v
vp = va * u + vb * w + vc * v
That is all fine. My trouble is that I need the line equations for min/max so I can choose a new position for p when vp is out of range. The new position for p is the point closest to p on the min or max line.
Note that p is an XY coordinate and vp is a value for that coordinate determined by the triangle and the values at each vertex. min and max are also values. The two line equations I need will give me XY coordinates for which the values determined by the triangle are min or max.
It doesn't matter if barycentric coordinates are used in the solution.
The trick is to use the ratio of value to cartesian distance to extend each triangle edge until it hits min or max. Easier to see with a pic:
The cyan lines show how the triangle edges are extended, the green Xs are points on the min or max lines. With just 2 of these points we know the slope if the line. The yellow lines show connecting the Xs aligns with the light gray.
The math works like this, first get the value distance between vb and vc:
valueDistBtoC = vc - vb
Then get the cartesian distance from b to c:
cartesianDistBtoC = b.distance(c)
Then get the value distance from b to max:
valueDistBtoMax = max - vb
Now we can cross multiply to get the cartesian distance from b to max:
cartesianDistBtoMax = (valueDistBtoMax * cartesianDistBtoC) / valueDistBtoC
Do the same for min and also for a,b and c,a. The 6 points are enough to restrict the position of p.
Consider your triangle to actually be a 3D triangle, with points (ax,ay,va), (bx,by,vb), and (cx,cy,vc). These three points define a plane, containing all the possible p,vp triplets obtainable through barycentric interpolation.
Now think of your constraints as two other planes, at z>=max and z<=min. Each of these planes intersects your triangle's plane along an infinite line; the infinite beam between them, projected back down onto the xy plane, represents the area of points which satisfy the constraints. Once you have the lines (projected down), you can just find which (if either) is violated by a particular point, and move it onto that constraint (along a vector which is perpendicular to the constraint).
Now I'm not sure about your hexagon, though. That's not the shape I would expect.
Mathematically speaking the problem is simply a change of coordinates. The more difficult part is finding a good notation for the quantities involved.
You have two systems of coordinates: (x,y) are the cartesian coordinates of your display and (v,w) are the baricentric coordinates with respect to the vectors (c-a),(b-a) which determine another (non orthogonal) system.
What you need is to find the equation of the two lines in the (x,y) system, then it will be easy to project the point p on these lines.
To achieve this you could explicitly find the matrix to pass from (x,y) coordinates to (v,w) coordinates and back. The function you are using toBaryCoords makes this computation to find the coordinates (v,w) from (x,y) and we can reuse that function.
We want to find the coefficients of the transformation from world coordinates (x,y) to barycentric coordinates (v,w). It must be in the form
v = O_v + x_v * x + y_v * y
w = O_w + x_w * x + y_w * y
i.e.
(v,w) = (O_v,O_w) + (x_v,y_y) * (x,y)
and you can determine (O_v,O_w) by computing toBaryCoord(0,0), then find (x_v,x_w) by computing the coordinates of (1,0) and find (y_v,y_w)=toBaryCoord(1,0) - (O_v,O_w) and then find (y_v,y_w) by computing (y_v,y_w) = toBaryCoord(0,1)-(O_v,O_w).
This computation requires calling toBaryCoord three times, but actually the coefficients are computed inside that routine every time, so you could modify it to compute at once all six values.
The value of your function vp can be computed as follows. I will use f instead of v because we are using v for a baricenter coordinate. Hence in the following I mean f(x,y) = vp, fa = va, fb = vb, fc = vc.
You have:
f(v,w) = fa + (fb-fa)*v + (fc-fa)*w
i.e.
f(x,y) = fa + (fb-fa) (O_v + x_v * x + y_v * y) + (fc-fa) (O_w + x_w * x + y_w * y)
where (x,y) are the coordinates of your point p. You can check the validity of this equation by inserting the coordinates of the three vertices a, b, c and verify that you obtain the three values fa, fb and fc. Remember that the barycenter coordinates of a are (0,0) hence O_v + x_v * a_x + y_v * a_y = 0 and so on... (a_x and a_y are the x,y coordinates of the point a).
If you let
q = fa + (fb_fa)*O_v + (fc-fa)*O_w
fx = (fb-fa)*x_v + (fc-fa) * x_w
fy = (fb-fa)*y_v + (fc-fa) * y_w
you get
f(x,y) = q + fx*x + fy * y
Notice that q, fx and fy can be computed once from a,b,c,fa,fb,fc and you can reuse them if you only change the coordinates (x,y) of the point p.
Now if f(x,y)>max, you can easily project (x,y) on the line where max is achieved. The coordinates of the projection are:
(x',y') = (x,y) - [(x,y) * (fx,fy) - max + q]/[(fx,fy) * (fx,fy)] (fx,fy)
Now. You would like to have the code. Well here is some pseudo-code:
toBarycoord(Vector2(0,0),a,b,c,O);
toBarycoord(Vector2(1,0),a,b,c,X);
toBarycoord(Vector2(0,1),a,b,c,Y);
X.sub(O); // X = X - O
Y.sub(O); // Y = Y - O
V = Vector2(fb-fa,fc-fa);
q = fa + V.dot(O); // q = fa + V*O
N = Vector2(V.dot(X),V.dot(Y)); // N = (V*X,V*Y)
// p is the point to be considered
f = q + N.dot(p); // f = q + N*p
if (f > max) {
Vector2 tmp;
tmp.set(N);
tmp.multiply((N.dot(p) - max + q)/(N.dot(N))); // scalar multiplication
p.sub(tmp);
}
if (f < min) {
Vector2 tmp;
tmp.set(N);
tmp.multiply((N.dot(p) - min + q)/(N.dot(N))); // scalar multiplication
p.sum(tmp);
}
We think of the problem as follows: The three points are interpreted as a triangle floating in 3D space with the value being the Z-axis and the cartesian coordinates mapped to the X- and Y- axes respectively.
Then the question is to find the gradient of the plane that is defined by the three points. The lines where the plane intersects with the z = min and z = max planes are the lines you want to restrict your points to.
If you have found a point p where v(p) > max or v(p) < min we need to go in the direction of the steepest slope (the gradient) until v(p + k * g) = max or min respectively. g is the direction of the gradient and k is the factor we need to find. The coordinates you are looking for (in the cartesian coordinates) are the corresponding components of p + k * g.
In order to determine g we calculate the orthonormal vector that is perpendicular to the plane that is determined by the three points using the cross product:
// input: px, py, pz,
// output: p2x, p2y
// local variables
var v1x, v1y, v1z, v2x, v2y, v2z, nx, ny, nz, tp, k,
// two vectors pointing from b to a and c respectively
v1x = ax - bx;
v1y = ay - by;
v1z = az - bz;
v2x = cx - bx;
v2y = cy - by;
v2z = cz - bz;
// the cross poduct
nx = v2y * v1z - v2z * v1y;
ny = v2z * v1x - v2x * v1z;
nz = v2x * v1y - v2y * v1x;
// using the right triangle altitude theorem
// we can calculate the vector that is perpendicular to n
// in our triangle we are looking for q where p is nz, and h is sqrt(nx*nx+ny*ny)
// the theorem says p*q = h^2 so p = h^2 / q - we use tp to disambiguate with the point p - we need to negate the value as it points into the opposite Z direction
tp = -(nx*nx + ny*ny) / nz;
// now our vector g = (nx, ny, tp) points into the direction of the steepest slope
// and thus is perpendicular to the bounding lines
// given a point p (px, py, pz) we can now calculate the nearest point p2 (p2x, p2y, p2z) where min <= v(p2z) <= max
if (pz > max){
// find k
k = (max - pz) / tp;
p2x = px + k * nx;
p2y = py + k * ny;
// proof: p2z = v = pz + k * tp = pz + ((max - pz) / tp) * tp = pz + max - pz = max
} else if (pz < min){
// find k
k = (min - pz) / tp;
p2x = px + k * nx;
p2y = py + k * ny;
} else {
// already fits
p2x = px;
p2y = py;
}
Note that obviously if the triangle is vertically oriented (in 2D it's not a triangle anymore actually), nz becomes zero and tp cannot be calculated. That's because there are no more two lines where the value is min or max respectively. For this case you will have to choose another value on the remaining line or point.

How to determine whether a point (X,Y) is contained within an arc section of a circle (i.e. a Pie slice)?

Imagine a circle. Imagine a pie. Imagine trying to return a bool that determines whether the provided parameters of X, Y are contained within one of those pie pieces.
What I know about the arc:
I have the CenterX, CenterY, Radius, StartingAngle, EndingAngle, StartingPoint (point on circumference), EndingPoint (point on circumference).
Given a coordinate of X,Y, I'd like to determine if this coordinate is contained anywhere within the pie slide.
Check:
The angle from the centerX,centerY through X,Y should be between start&endangle.
The distance from centerX,centerY to X,Y should be less then the Radius
And you'll have your answer.
I know this question is old but none of the answers consider the placement of the arc on the circle.
This algorithm considers that all angles are between 0 and 360, and the arcs are drawn in positive mathematical direction (counter-clockwise)
First you can transform to polar coordinates: radius (R) and angle (A). Note: use Atan2 function if available. wiki
R = sqrt ((X - CenterX)^2 + (Y - CenterY)^2)
A = atan2 (Y - CenterY, X - CenterX)
Now if R < Radius the point is inside the circle.
To check if the angle is between StartingAngle (S) and EndingAngle (E) you need to consider two possibilities:
1) if S < E then if S < A < E the point lies inside the slice
2) if S > E then there are 2 possible scenarios
if A > S
then the point lies inside the slice
if A < E
then the point lies inside the slice
In all other cases the point lies outside the slice.
Convert X,Y to polar coordinates using this:
Angle = arctan(y/x);
Radius = sqrt(x * x + y * y);
Then Angle must be between StartingAngle and EndingAngle, and Radius between 0 and your Radius.
You have to convert atan2() to into 0-360 before making comparisons with starting and ending angles.
(A > 0 ? A : (2PI + A)) * 360 / (2PI)

Define a function for a circle caps the end of a line segment

I need a function that returns points on a circle in three dimensions.
The circle should "cap" a line segment defined by points A and B and it's radius. each cap is perpendicular to the line segment. and centered at one of the endpoints.
Here is a shitty diagram
Let N be the unit vector in the direction from A to B, i.e., N = (B-A) / length(A-B). The first step is to find two more vectors X and Y such that {N, X, Y} form a basis. That means you want two more vectors so that all pairs of {N, X, Y} are perpendicular to each other and also so that they are all unit vectors. Another way to think about this is that you want to create a new coordinate system whose x-axis lines up with the line segment. You need to find vectors pointing in the direction of the y-axis and z-axis.
Note that there are infinitely many choices for X and Y. You just need to somehow find two that work.
One way to do this is to first find vectors {N, W, V} where N is from above and W and V are two of (1,0,0), (0,1,0), and (0,0,1). Pick the two vectors for W and V that correspond to the smallest coordinates of N. So if N = (.31, .95, 0) then you pick (1,0,0) and (0,0,1) for W and V. (Math geek note: This way of picking W and V ensures that {N,W,V} spans R^3). Then you apply the Gram-Schmidt process to {N, W, V} to get vectors {N, X, Y} as above. Note that you need the vector N to be the first vector so that it doesn't get changed by the process.
So now you have two vectors that are perpendicular to the line segment and perpendicular to each other. This means the points on the circle around A are X * cos t + Y * sin t + A where 0 <= t < 2 * pi. This is exactly like the usual description of a circle in two dimensions; it is just written in the new coordinate system described above.
As David Norman noted the crux is to find two orthogonal unit vectors X,Y that are orthogonal to N. However I think a simpler way to compute these is by finding the householder reflection Q that maps N to a multiple of (1,0,0) and then to take as X the image of (0,1,0) under Q and Y as the image of (0,0,1) under Q. While this might sound complicated it comes down to:
s = (N[0] > 0.0) ? 1.0 : -1.0
t = N[0] + s; f = -1.0/(s*t);
X[0] = f*N[1]*t; X[1] = 1 + f*N[1]*N[1]; X[2] = f*N[1]*N[2];
Y[0] = f*N[2]*t; Y[1] = f*N[1]*N[2]; Y[2] = 1 + f*N[2]*N[2];

Resources