Hi, who just loves conics today? Even better, solid angles!
Yeah, the Monte Carlo approach, while seemingly accurate to a degree, was seemingly too slow for my purposes. So I tried numerical integration instead. And this function is putting out nonsense that is either contributed to programmer error or numerical instability. I can't tell which.
function [p] = generateProbSeq(c, b, r, d, t)
%GENERATEPROBSEQ Generates probability sequence for initial CoF c,
% bloom b and max rate of fire r at range d for fire pattern t.
p = zeros(length(t),1);
alpha = c*pi/180;
dt = [diff(t);0];
dir = [0 0 -1]';
function [prob] = fastProb(d, alpha, dir)
%Computes the probability by calculating the solid angle of the part
%of the rectangle inside the cone.
% d is the distance from the xy plane, alpha is the apex angle and
% dir is the direction of the cone. The cone must be above the xy
% plane.
%Main integrand
fun = @(x,y) d./(x.^2 + y.^2 + d.^2).^(1.5);
if d < 0
%Apex below xy plane
prob = 0;
return;
elseif d == 0
%Point blank
phi = acos(dot([0 0 1],dir)/sqrt(sum(dir.^2)));%azimuth
if phi > pi/2 - alpha
%Part of the cone is still intersecting
prob = 1;
else
%No intersection.
prob = 0;
end
return;
end
len = 1.8;%m
wid = 0.88/1.8;%m
h = [0 0 d]';
z1 = dir/sqrt(sum(dir.^2));%Normalize
A = null(z1');
x1 = A(:,1);%Orthonormal to z
y1 = A(:,2);%Orthonormal to z
%Both orthonormal to each other
if alpha == 0 %Line must intersect with rectangle for hit
k_z = (-h'*[0 0 1]')/(z1'*[0 0 1]');
point = h + k_z*z1;
if k_z > 0 && abs(point(1,1)) <= len/2 && abs(point(2,1)) <= wid/2
%Is pointing towards it and intersects rectangle
prob = 1;
else
%Is not
prob = 0;
end
return;
end
%Solid angle of spherical cap
solidAngleCone = 2*pi*(1-cos(alpha/2));
%Solid angle of rectangle
solidAngleRect = dblquad(@(x,y) ...
isInCone(x,y,h, x1, y1, z1, alpha).*fun(x,y),...
-len/2, len/2, -wid/2, wid/2);
%Final probability
%Should be between 0 and 1
prob = solidAngleRect/solidAngleCone;
end
for i = 1:length(t);
[prob] = fastProb(d, alpha, dir);
p(i) = prob;
alpha = alpha + b*pi/180;
if (dt(i) > 60/r + 0.05)
alpha = c*pi/180;
end
end
end
function [yes] = isInCone(x, y, h, x1, y1, z1, alpha)
%x is a vector, y a scalar
[m, ~] = size(x);
if (m ~= 1)
xs = x';
else
xs = x;
end
A = zeros(3, length(xs));
A(1,:) = xs;
A(2,:) = y*ones(1,length(xs));
X = repmat(x1, 1, length(xs));
Y = repmat(y1, 1, length(xs));
Z = repmat(z1, 1, length(xs));
H = repmat(h, 1, length(xs));
x2 = dot(A-H,X);
y2 = dot(A-H,Y);
z2 = dot(A-H,Z);
yes = (x2.^2 + y2.^2 <= ...
((z2.^2).*tan(alpha/2)).^2) & (z2 >= 0);
if isequal(size(yes), size(x)) == 0
yes = yes';
end
end