Algorithm for drawing a polygon grid - algorithm

Is there an algorithm for drawing grids of n-sided polygons. Here is an example for hexagons:

It's my solution using grid package.
library(grid)
hexagon_layer <- function(x, y, r) {
axis.x <- c(x, x + 3 * r, x + 6 * r, x + 9 * r, x + 12 * r, x + 15 *
r, x + 18 * r, x + 1.5 * r, x + 4.5 * r, x + 7.5 * r, x + 10.5 *
r, x + 13.5 * r, x + 16.5 * r, x + 1.5 * r, x + 4.5 * r, x + 7.5 *
r, x + 10.5 * r, x + 13.5 * r, x + 16.5 * r)
axis.y <- c(rep(y, 7), rep(y + r * sqrt(3)/2, 6), rep(y - r * sqrt(3)/2,
6))
hexagon <- function(x, y, r) {
grid.path(x = c(x + 0.5 * r, x + r, x + 0.5 * r, x - 0.5 * r, x -
r, x - 0.5 * r), y = c(y + r * sqrt(3)/2, y, y - r * sqrt(3)/2,
y - r * sqrt(3)/2, y, y + r * sqrt(3)/2))
}
for (i in 1:length(axis.x)) {
hexagon(axis.x[i], axis.y[i], r = 0.05)
next
}
}
for (i in seq(1, 21, by = 2)) {
hexagon_layer(x = 0.05, y = i * 0.05 * sqrt(3)/2, r = 0.05)
next
}

Related

Deriving an unknown matrix in an equation

I'm working on reverse-engineering a software system doing some computer graphics math. I've wound up in a weird situation where the following math is coming up:
M * X * M^-1 * A = B
Where M is a 3x3 constant invertible matrix, M^-1 is the inverse of M, X is a 3x3 matrix I can control, A is a 3x1 column vector I can also control. B is measurable.
How can I find what M is? I'm pretty sure that I could find the answer by expanding out all matrix components algebraically into a few massive equations - but it sure feels like there should be a more straightforward mechanism.
This looks like the Eigendecomposition of a matrix.
where the matrix A is decomposed into a diagonal matrix Λ and a vector of eigenvectors Q.
In your case you have
C = (M X M-1)
If you can confirm that indeed X in your case is a diagonal matrix, then you know M to be the eigenvectors of C. You can get C from C = A-1 B
As far as finding the eigenvectors, even for 3×3 matrices, is a genuinely hard problem. Typically you do a Shur Decomposition and recover the eigevectors.
I did find an online resource for the 3×3 problem, which I ported into C# for an other project. Original source here.
/// <summary>
/// Calculates the three eigenvalues analytically.
/// </summary>
/// <remarks>
/// Code taken from:
/// https://www.mpi-hd.mpg.de/personalhomes/globes/3x3/index.html
/// </remarks>
/// <returns>A vector containing the three eigenvalues.</returns>
public Vector3 GetEigenValues()
{
// Determine coefficients of characteristic polynomial. We write
// | A D F |
// A = | D* B E |
// | F* E* C |
var de = data.m_12 * data.m_23;
var dd = data.m_12 * data.m_12;
var ee = data.m_23 * data.m_23;
var ff = data.m_13 * data.m_13;
var m = data.m_11 + data.m_22 + data.m_33;
var c1 = (data.m_11 * data.m_22 + data.m_11 * data.m_33 + data.m_22 * data.m_33) - (dd + ee + ff);
var c0 = data.m_33 * dd + data.m_11 * ee + data.m_22 * ff - data.m_11 * data.m_22 * data.m_33 - 2.0 * data.m_13 * de;
var p = m * m - 3.0 * c1;
var q = m * (p - (3.0 / 2.0) * c1) - (27.0 / 2.0) * c0;
var sqrt_p = (float) Math.Sqrt(Math.Abs(p));
var sqrt_z = (float) Math.Sqrt(Math.Abs(27.0 * (0.25 * c1 * c1 * (p - c1) + c0 * (q + 27.0 / 4.0 * c0))));
var phi = (1 / 3f) * (float) Math.Atan2(sqrt_z, q);
var c = sqrt_p * (float) Math.Cos(phi);
var s = sqrt_p * (float)( Math.Abs(Math.Sin(phi))/ Math.Sqrt(3));
var w = (1 / 3f) * (m - c);
// sort the eigenvalues
if (c >= s)
{
return new Vector3(
w - s,
w + s,
w + c);
}
else if (c >= -s)
{
return new Vector3(
w - s,
w + c,
w + s);
}
else
{
return new Vector3(
w + c,
w - s,
w + s);
}
}
public Matrix3 GetEigenVectors() => GetEigenVectors(GetEigenValues());
public Matrix3 GetEigenVectors(Vector3 eigenValues)
{
Vector3 ev1 = GetEigenVector(eigenValues.X).Unit();
Vector3 ev2 = GetEigenVector(eigenValues.Y).Unit();
Vector3 ev3 = GetEigenVector(eigenValues.Z).Unit();
return FromColumns(ev1, ev2, ev3);
}
Vector3 GetEigenVector(float w)
{
return new Vector3(
data.m_12 * (data.m_23 - data.m_33 + w) - data.m_13 * (data.m_22 - data.m_23 - w)
+ data.m_22 * (data.m_33 - w) - data.m_23 * data.m_23 - w * (data.m_33 - w),
-data.m_11 * (data.m_23 - data.m_33 + w) + data.m_12 * (data.m_13 - data.m_33 + w)
- data.m_13 * data.m_13 + data.m_13 * data.m_23 + w * (data.m_23 - data.m_33 + w),
data.m_11 * (data.m_22 - data.m_23 - w) - data.m_12 * data.m_12 + data.m_12 * (data.m_13 + data.m_23)
+ data.m_13 * (w - data.m_22) - w * (data.m_22 - data.m_23 - w));
}
For your case you would do M=C.GetEigenVectors();
A final note here is that you can scale M up or down by a factor, and it wont change the equation since you are multiplying with M and M-1 at the same time. So you just need to find just one of the infinite matrices M that would make this equation work.

Halide internal error issue

Here's the code. I'm using Halide on VS2013, Win64 trunk of Aug 5, 2015. When I execute diag.compile_to_lowered_stmt("diag.html", {}, HTML) (with a 16MB stack), I get the following error message:
"Internal error at E:\Code\Halide\src\IR.cpp:160
Condition failed: a.type() == b.type()
LT of mismatched types"
I have confirmed that the error occurs because of the line:
diag(x, y, c) = select(m135(x, y) > m45(x, y), f45(x, y, c), select(m45(x, y) > m135(x, y), f135(x, y, c), f4x4(x, y, c)));
The only way I've been able to remove the error is to remove both selects (the function is unusable in that case, of course.) I've tried converting the condition to an Expr, and I've also checked the types of m45 and m135 (by assigning them to an Expr t1, and then looking at t1.type().) I note that changing the ">" to an "<" or even ">=" does NOT change the error message from "LT".
Any ideas?
Code is still the same as my previous post:
Image<uint8_t> orig_uint = Tools::load_image("../foo.ppm");
Var x, y, c;
Func orig("orig"), orig_lum("orig_lum"), m45("m45"), m135("m135"), f45("f45"), f135("f135"), f4x4_horiz("f4x4_horiz"), f4x4("f4x4"), diag("diag");
Func orig_clamped = BoundaryConditions::repeat_edge(orig_uint);
const float wta = 1.0f, wtb = 3.0f, wt0 = wta * wta, wt1 = wta * wtb, wt2 = wtb * wtb;
orig(x, y, c) = cast<float_t>(orig_clamped(x, y, c));
orig_lum(x, y) = 0.299f * orig(x, y, 0) + 0.587f * orig(x, y, 1) + 0.114f * orig(x, y, 2);
m45(x, y) = abs(orig_lum(x - 1, y - 1) - orig_lum(x, y)) + abs(orig_lum(x, y) - orig_lum(x + 1, y + 1)) + abs(orig_lum(x + 1, y + 1) - orig_lum(x + 2, y + 2));
m135(x, y) = abs(orig_lum(x + 2, y - 1) - orig_lum(x + 1, y)) + abs(orig_lum(x + 1, y) - orig_lum(x, y + 1)) + abs(orig_lum(x, y + 1) - orig_lum(x - 1, y + 2));
f45(x, y, c) = wta * (orig(x - 1, y - 1, c) + orig(x + 2, y + 2, c)) + wtb * (orig(x, y, c) + orig(x + 1, y + 1, c));
f135(x, y, c) = wta * (orig(x - 1, y + 2, c) + orig(x + 2, y - 1, c)) + wtb * (orig(x, y + 1, c) + orig(x + 1, y, c));
f4x4_horiz(x, y, c) = wta * (orig(x - 1, y, c) + orig(x + 2, y, c)) + wtb * (orig(x, y, c) + orig(x + 1, y, c));
f4x4(x, y, c) = wta * (f4x4_horiz(x, y - 1, c) + f4x4_horiz(x, y + 2, c)) + wtb * (f4x4_horiz(x, y, c) + f4x4_horiz(x, y + 1, c));
diag(x, y, c) = select(m135(x, y) > m45(x, y), f45(x, y, c), select(m45(x, y) > m135(x, y), f135(x, y, c), f4x4(x, y, c)));
// schedule
orig_lum.compute_root();
m45.compute_root().bound(x, 0, orig_uint.width()).bound(y, 0, orig_uint.height());
m135.compute_root().bound(x, 0, orig_uint.width()).bound(y, 0, orig_uint.height());
f45.compute_at(diag, x);
f135.compute_at(diag, x);
f4x4.compute_at(diag, x);
diag.compute_root();
// compile so we can take a look at the code
diag.compile_to_lowered_stmt("diag.html", {}, HTML); // stack oflo here
It's a bug in Halide. Fix pushed by Andrew Adams an hour ago (thanks!)

splitting trapezoid in given proportion

I need to split trapezoid in 2 part of given size with line, parallel basement. I need to get new h1 of new trapezoid.
For example I have trapezoid of area S and I want to split it in 2 trapezoids of areas S1 and S2.
S1 = aS; S2 = (1-a)S;
S1 = (a+z)*(h1)/2;
S2 = (b+z)*(1-h1)/2;
S1/S2 = KS;
To get new h1 I compare a and b, if a != b, I solve square equation and if a == b I work like with square. But sometimes I get mistakes because of rounding (for example when I solve this analytically I get a = b and program thinks a > b). How can I handle this? Or maybe there is another better way to split trapezoid?
Here is simplifyed code:
if (base > base_prev) {
b_t = base; // base of trapezoid
h = H; //height of trapezoid
a_t = base_prev; //another base of trapezoid
KS = S1 / S2;
a_x = (a_t - b_t) * (1 + KS) / h;
b_x = 2 * KS * b_t + 2 * b_t;
c_x = -(a_t * h + b_t * h);
h_tmp = (-b_x + sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
if (h_tmp > h || h_tmp < 0)
h_tmp = (-b_x - sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
} else if (base < base_prev) {
b_t = base_prev;
a_t = base;
KS = S1 / S2;
a_x = (a_t - b_t) * (1 + KS) / h;
b_x = 2 * KS * b_t + 2 * b_t;
c_x = -(a_t * h + b_t * h);
h_tmp = (-b_x + sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
if (h_tmp > h || h_tmp < 0)
h_tmp = (-b_x - sqrt(b_x * b_x - 4 * a_x * c_x)) / (2 * a_x);
}
else {
KS = S1 / S2;
h_tmp = h * KS;
}
If you're dealing with catastrophic cancellation, one approach, dating back to a classic article by Forsythe, is to use the alternative solution form x = 2c/(-b -+ sqrt(b^2 - 4ac)) for the quadratic equation ax^2 + bx + c = 0. One way to write the two roots, good for b < 0, is
x = (-b + sqrt(b^2 - 4ac))/(2a)
x = 2c/(-b + sqrt(b^2 - 4ac)),
and another, good for b >= 0, is
x = 2c/(-b - sqrt(b^2 - 4ac))
x = (-b - sqrt(b^2 - 4ac))/(2a).
Alternatively, you could use the bisection method to obtain a reasonably good guess and polish it with Newton's method.

Finding the intersection of two lines

I have two lines:
y = -1/3x + 4
y = 3x + 85
The intersection is at [24.3, 12.1].
I have a set of coordinates prepared:
points = [[1, 3], [4, 8], [25, 10], ... ]
#y = -1/3x + b
m_regr = -1/3
b_regr = 4
m_perp = 3 #(1 / m_regr * -1)
distances = []
points.each do |pair|
x1 = pair.first
y2 = pair.last
x2 = ((b_perp - b_regr / (m_regr - m_perp))
y2 = ((m_regr * b_perp) / (m_perp * b_regr))/(m_regr - m_perp)
distance = Math.hypot((y2 - y1), (x2 - x1))
distances << distance
end
Is there a gem or some better method for this?
NOTE: THE ABOVE METHOD DOES NOT WORK. See my answer for a solution that works.
What's wrong with using a little math?
If you have:
y = m1 x + b1
y = m2 x + b2
It's a simple system of linear equations.
If you solve them, your intersection is:
x = (b2 - b1)/(m1 - m2)
y = (m1 b2 - m2 b1)/(m1 - m2)
After much suffering and many different tries, I found a simple algebraic method here that not only works but is dramatically simplified.
distance = ((y - mx - b).abs / Math.sqrt(m**2 + 1))
where x and y are the coordinates for the known point.
For Future Googlers:
def solution k, l, m, n, p, q, r, s
intrsc_x1 = m - k
intrsc_y1 = n - l
intrsc_x2 = r - p
intrsc_y2 = s - q
v1 = (-intrsc_y1 * (k - p) + intrsc_x1 * (l - q)) / (-intrsc_x2 * intrsc_y1 + intrsc_x1 * intrsc_y2);
v2 = ( intrsc_x2 * (l - q) - intrsc_y2 * (k - p)) / (-intrsc_x2 * intrsc_y1 + intrsc_x1 * intrsc_y2);
(v1 >= 0 && v1 <= 1 && v2 >= 0 && v2 <= 1) ? true : false
end
The simplest and cleanest way I've found on the internet.

Unwanted evaluation on prolog

I was making a prolog knowledge base to implement geometry rules. When testing if a rectangle had a right angle, I found two answers.
?- rect_tri(triangle(line(point(0,0),point(0,1)),line(point(0,1),point(1,0)),line(point(1,0),point(0,0)))).
true ;
false.
Here is the kwnoledge base:
point(X,Y).
line(X,Y) :- X = point(A,B), Y = point(C,D), not(X = Y).
len(X,R) :- X = line(P,Q), P = point(A,B), Q = point(C,D), not(P = Q),
R is sqrt((A - C) * (A - C) + (B - D) * (B - D)).
triangle(X,Y,Z) :- X = point(A,B), Y = point(C,D), Z = point(E,F),
not(X = Y), not(X = Z), not(Y = Z),
L1 = line(X,Y), L2 = line(X,Z), L3 = line(Y,Z),
len(L1,G), len(L2,H), len(L3,I),
G + H > I, G + I > H, H + I > G.
triangle(X,Y,Z) :- X = line(A,B), Y = line(B,C), line(A,C),
len(X,G), len(Y,H), len(Z,I),
G + H > I, G + I > H, H + I > G.
rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
(G is sqrt(H * H + I * I);
H is sqrt(G * G + I * I);
I is sqrt(H * H + G * G)).
When tracing, I found that the answer true comes when prolog hits the line H is sqrt(G * G + I * I), and false when it evaluates the last line.
I don't want the last evaluation to occur, because I want it to exit when a true has been found.
Daniel comment probably shows the most sensible way to solve your problem. Some other option...
in modern compilers there is the if/then/else construct:
rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
( G is sqrt(H * H + I * I)
-> true
; H is sqrt(G * G + I * I)
-> true
; I is sqrt(H * H + G * G)
).
You could as well use cuts (old fashioned way, somewhat more readable here):
rect_tri(X) :- X = triangle(A,B,C), len(A,G), len(B,H), len(C,I),
( G is sqrt(H * H + I * I), !
; H is sqrt(G * G + I * I), !
; I is sqrt(H * H + G * G)
).

Resources