Best way to get the bounding rectangle of a set of 3D points on a plane in Matlab - matlab

I need to get the four edges of the bounding rectangle of a set of 3D points stored as a 3xN matrix (tt). N >=4. The points lies on a plane.
Code sample:
% Simulate some points
deltaXY = 20;
[xx,yy] = meshgrid(-100:deltaXY:100,-100:deltaXY:100);
XYZ = [xx(:)'; yy(:)'; zeros(1,numel(xx))];
% Add some imperfection to data removing the top rigth point
maxXids = find(XYZ(1,:) == max(XYZ(1,:)));
maxYids = find(XYZ(2,:) == max(XYZ(2,:)));
id = intersect(maxXids,maxYids);
XYZ = removerows(XYZ',id)';
% Lets rotate a bit
XYZ = roty(5)*rotx(7)*rotz(0)*XYZ;
% Plot points
figure;
grid on;
rotate3d on;
axis vis3d;
hold on;
plot3(XYZ(1,:),XYZ(2,:),XYZ(3,:),'.r');
% Find bounding rectangle
% ??? :(
%Currently I'm using this code:
tt = XYZ;
%Get the max and min indexes
minX = find(tt(1,:) == min(tt(1,:)));
minY = find(tt(2,:) == min(tt(2,:)));
maxX = find(tt(1,:) == max(tt(1,:)));
maxY = find(tt(2,:) == max(tt(2,:)));
%Intersect to find the common index
id1 = intersect(minX,minY);
id2 = intersect(maxX,minY);
id3 = intersect(maxX,maxY);
id4 = intersect(minX,maxY);
%Get the points
p1 = tt(:,id1(1));
p2 = tt(:,id2(1));
p3 = tt(:,id3(1));
p4 = tt(:,id4(1));
Sample points plot:
The problem is that intersect some times can be null, eg: if the points does not form a rectangle. Resulting this error:
Index exceeds matrix dimensions.

First solution : Use logical indexing to get rid of the find calls
p1=tt(:,tt(1,:)==min(tt(1,:))&tt(2,:)==min(tt(2,:)));
p2=tt(:,tt(1,:)==max(tt(1,:))&tt(2,:)==min(tt(2,:)));
p3=tt(:,tt(1,:)==max(tt(1,:))&tt(2,:)==max(tt(2,:)));
p4=tt(:,tt(1,:)==min(tt(1,:))&tt(2,:)==max(tt(2,:)));
Second solution : Use convhull to get the corners :
k=convhull(tt(1,:),tt(2,:));
Corners=[tt(:,k(1:end-1))];

Ok found a solution:
% Find bounding rectangle
tt = XYZ;
%Get the max and min indexes
minXids = find(tt(1,:) == min(tt(1,:)));
minYids = find(tt(2,:) == min(tt(2,:)));
maxXids = find(tt(1,:) == max(tt(1,:)));
maxYids = find(tt(2,:) == max(tt(2,:)));
%Intersect to find the common index
id1 = intersect(minXids,minYids);
id2 = intersect(maxXids,minYids);
id3 = intersect(maxXids,maxYids);
id4 = intersect(minXids,maxYids);
%Get the points
% Find affine plane on points
[np,~,pp] = affine_fit(tt');
% Converts to cart. eq.
% ax + yb + cz + d = 0
% Find d
a = np(1); b = np(2); c = np(3);
x = pp(1); y = pp(2); z = pp(3);
d = - (a*x + y*b + c*z);
% Get only one value
minX = min(tt(1,minXids)); maxX = max(tt(1,maxXids));
minY = min(tt(2,minYids)); maxY = max(tt(2,maxYids));
if numel(id1) == 0
x = minX; y = minY;
% Calculate z at xy.
z = - (d + a*x + y*b)/c;
p1 = [x y z]';
else
p1 = tt(:,id1(1));
end
if numel(id2) == 0
x = maxX; y = minY;
z = - (d + a*x + y*b)/c;
p2 = [x y z]';
else
p2 = tt(:,id1(1));
end
if numel(id3) == 0
x = maxX; y = maxY;
z = - (d + a*x + y*b)/c;
p3 = [x y z]';
else
p3 = tt(:,id1(1));
end
if numel(id4) == 0
x = minX; y = maxY;
z = - (d + a*x + y*b)/c;
p4 = [x y z]';
else
p4 = tt(:,id1(1));
end
ps = [p1 p2 p3 p4];
plot3(ps(1,:),ps(2,:),ps(3,:),'ob');

Related

Is there a possibility to have a quiver plot with vectors of same length?

I am using a quiver plot in MATLAB to simulate a velocity field. Now I would like the vectors produced by the quiver plot to be all the same length, so that they just indicate the vectors direction. The value of the velocity in each point should be illustrated by different colors then.
Is there a possibility to have quiver plotting vectors of same length?
That's my current code:
%defining parameters:
age = 900;
vis= 15;
turbulences = zeros(9,3);
a = 0.01;
spacing = 1000;
[x,y] = meshgrid(-100000:spacing:100000);%, 0:spacing:10000);
u = a;
v = 0;
n = 0;
for i = 1:4
turbulences(i,1) = -80000 + n;
turbulences(i,2) = 15000;
n = 15000 * i;
end
n = 0;
for i = 5:9
turbulences(i,1) = -15000 + n*5000;
turbulences(i,2) = 4000;
n = n+1;
end
for i = 1:4
turbulences(i,3) = -1000;
end
for i = 5:9
turbulences(i,3) = 800;
end
%compute velocities in x and y direction
for k = 1:9
xc = turbulences(k,1);
yc = turbulences(k,2);
r1 = ((x-xc).^2 + (y-yc).^2);
r2 = ((x-xc).^2 + (y+yc).^2);
u = u + turbulences(k,3)/2*pi * (((y-yc)./r1).*(1-exp(-(r1./(4*vis*age)))) - ((y+yc)./r2).*(1-exp(-(r2./(4*vis*age)))));
v = v - turbulences(k,3)/2*pi* (((x-xc)./r1).*(1-exp(-(r1./(4*vis*age)))) - ((x-xc)./r2).*(1-exp(-(r2./(4*vis*age)))));
end
quiver(x,y,u,v);
grid on;
Thank you for your help!
One way to do this would be to normalize each component of your vectors to +- 1 just to keep their direction.
un = u./abs(u); % normalized u
vn = v./abs(v); % normalized v
quiver(x, y, un, vn)

Calculate size of resulting array (matrix transformation)

So I have this code to rotate and skew an image. it works well for the rotation, and the image will fit exactly in the canvas. However if I apply skewing the image doesn't fit anymore. Can someone explain how to calculate the proper array dimension for the resulting image rotated and skewed by specific angles? In particular, I'm using this 2 lines for the rotated image (and it works although I don't fully understand them). How should I modify them such as even when skewed, the final image will fit? Thanks!
rows_new = ceil(rows_init_img * abs(cos(rads)) + cols_init_img * abs(sin(rads)));
cols_new = ceil(rows_init_img * abs(sin(rads)) + cols_init_img * abs(cos(rads)));
full code
clc;
clear;
%% init values
%loading initial image
init_img = imread('name2.png');
% define rows/cols dimension of original image pixel matrix
[rows_init_img, cols_init_img,z]= size(init_img);
% skew angle in radians
sk_angle = 50;
sk_rads = 2*pi*sk_angle/360;
% rotation angle in radians
angle = 20;
rads = 2*pi*angle/360;
%% calculate size of final_image
orig_corners = [ 1, 1; 1, rows_init_img; 1, cols_init_img; rows_init_img, cols_init_img];
new_corners = uint8(zeros(size(orig_corners)));
for i = 1:size(orig_corners, 1)
for j = 1:size(orig_corners, 2)
% translate
a = i - final_origin_x;
b = j - final_origin_y;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis (AFTER rotation)
x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
if (x >= 1 && y >= 1 && x <= size(orig_corners, 1) && y <= size(orig_corners, 2) )
new_corners(i, j) = init_img(x, y);
end
end
end
% calculating array dimesions such that rotated image gets fit in it exactly.
% rows_new = ceil(rows_init_img * abs(cos(rads)) + cols_init_img * abs(sin(rads)));
% cols_new = ceil(rows_init_img * abs(sin(rads)) + cols_init_img * abs(cos(rads)));
% define an array with calculated dimensions and fill the array with zeros ie.,black
% uint8 is important. without it will show noise WHY?
final_img = uint8(zeros([rows_new cols_new 3 ]));
%calculating center of original image
init_origin_x = ceil(rows_init_img/2);
init_origin_y = ceil(cols_init_img/2);
%calculating center of final image
final_origin_x = ceil( size(final_img, 1)/2 );
final_origin_y = ceil( size(final_img, 2)/2 );
%% main loop
% apply transformation to each pixel of the image
for i = 1:size(final_img ,1)
for j = 1:size(final_img, 2)
% translate
a = i - final_origin_x;
b = j - final_origin_y;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis
x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
% make sure values exists (are part of the initial image) and copy
% them in the final image matrix
if (x >= 1 && y >= 1 && x <= size(init_img, 1) && y <= size(init_img, 2) )
final_img(i, j, :) = init_img(x, y, :);
end
end
end
%% display images
% original image
% figure('name','Original Image','numbertitle','off');
% imshow(init_img);
% result image
figure('name','Manipulated Image','numbertitle','off');
imshow(final_img);
updated code
clc;
clear;
%% init values
%loading initial image
init_img = imread('name2.png');
% define rows/cols dimension of original image pixel matrix
[rows_init_img, cols_init_img, z]= size(init_img);
% skew angle in radians
sk_angle = 50;
sk_rads = 2*pi*sk_angle/360;
% rotation angle in radians
angle = 20;
rads = 2*pi*angle/360;
%calculating center of original image
init_origin_x = ceil(rows_init_img/2);
init_origin_y = ceil(cols_init_img/2);
%% calculate size of final_image
orig_corners = [ 1, 1; 1, rows_init_img; 1, cols_init_img; rows_init_img, cols_init_img];
new_corners = uint8(zeros(size(orig_corners)));
for i = 1:size(orig_corners, 1)
for j = 1:size(orig_corners, 2)
% translate
a = i - final_origin_x; %at this point I don't have this variable because I can't create it yet
b = j - final_origin_y;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis (AFTER rotation)
x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
if (x >= 1 && y >= 1 && x <= size(orig_corners, 1) && y <= size(orig_corners, 2) )
new_corners(i, j) = init_img(x, y);
end
end
end
% calculating array dimesions such that rotated image gets fit in it exactly.
rows_new = abs(max(new_corners(1, :)) - min(new_corners(1, :)));
cols_new = abs(max(new_corners(2, :)) - min(new_corners(2, :)));
% define an array with calculated dimensions and fill the array with zeros ie.,black
final_img = uint8(zeros([rows_new cols_new 3 ]));
%calculating center of final image
final_origin_x = ceil( size(final_img, 1)/2 );
final_origin_y = ceil( size(final_img, 2)/2 );
%% main loop
% apply transformation to each pixel of the image
for i = 1:size(final_img ,1)
for j = 1:size(final_img, 2)
% translate
a = i - final_origin_x;
b = j - final_origin_y;
% skew along x axis (BEFORE rotation)
a = a + sk_rads * b;
% rotate
x = a * cos(rads) - b * sin(rads);
y = a * sin(rads) + b * cos(rads);
% skew along x axis (AFTER rotation)
%x = x + sk_rads * y;
% translate
x = x + init_origin_x;
y = y + init_origin_y;
% round to turn values to positive integers
x = round(x);
y = round(y);
% make sure values exists (are part of the initial image) and copy
% them in the final image matrix
if (x >= 1 && y >= 1 && x <= size(init_img, 1) && y <= size(init_img, 2) )
final_img(i, j, :) = init_img(x, y, :);
end
end
end
%% display images
% original image
% figure('name','Original Image','numbertitle','off');
% imshow(init_img);
% result image
figure('name','Manipulated Image','numbertitle','off');
imshow(final_img);

Plot equally spaced markers along a spiral

I want to move a red star marker along the spiral trajectory with an equal distance of 5 units between the red star points on its circumference like in the below image.
vertspacing = 10;
horzspacing = 10;
thetamax = 10*pi;
% Calculation of (x,y) - underlying archimedean spiral.
b = vertspacing/2/pi;
theta = 0:0.01:thetamax;
x = b*theta.*cos(theta)+50;
y = b*theta.*sin(theta)+50;
% Calculation of equidistant (xi,yi) points on spiral.
smax = 0.5*b*thetamax.*thetamax;
s = 0:horzspacing:smax;
thetai = sqrt(2*s/b);
xi = b*thetai.*cos(thetai);
yi = b*thetai.*sin(thetai);
plot(x,y,'b-');
hold on
I want to get a figure that looks like the following:
This is my code for the circle trajectory:
% Initialization steps.
format long g;
format compact;
fontSize = 20;
r1 = 50;
r2 = 35;
r3= 20;
xc = 50;
yc = 50;
% Since arclength = radius * (angle in radians),
% (angle in radians) = arclength / radius = 5 / radius.
deltaAngle1 = 5 / r1;
deltaAngle2 = 5 / r2;
deltaAngle3 = 5 / r3;
theta1 = 0 : deltaAngle1 : (2 * pi);
theta2 = 0 : deltaAngle2 : (2 * pi);
theta3 = 0 : deltaAngle3 : (2 * pi);
x1 = r1*cos(theta1) + xc;
y1 = r1*sin(theta1) + yc;
x2 = r2*cos(theta2) + xc;
y2 = r2*sin(theta2) + yc;
x3 = r3*cos(theta3) + xc;
y3 = r3*sin(theta3) + yc;
plot(x1,y1,'color',[1 0.5 0])
hold on
plot(x2,y2,'color',[1 0.5 0])
hold on
plot(x3,y3,'color',[1 0.5 0])
hold on
% Connecting Line:
plot([70 100], [50 50],'color',[1 0.5 0])
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0, 0, 1, 1]);
drawnow;
axis square;
for i = 1 : length(theta1)
plot(x1(i),y1(i),'r*')
pause(0.1)
end
for i = 1 : length(theta2)
plot(x2(i),y2(i),'r*')
pause(0.1)
end
for i = 1 : length(theta3)
plot(x3(i),y3(i),'r*')
pause(0.1)
end
I can't think of a way to compute distance along a spiral, so I'm approximating it with circles, in hopes that it will still be useful.
My solution relies on the InterX function from FEX, to find the intersection of circles with the spiral. I am providing an animation so it is easier to understand.
The code (tested on R2017a):
function [x,y,xi,yi] = q44916610(doPlot)
%% Input handling:
if nargin < 1 || isempty(doPlot)
doPlot = false;
end
%% Initialization:
origin = [50,50];
vertspacing = 10;
thetamax = 5*(2*pi);
%% Calculation of (x,y) - underlying archimedean spiral.
b = vertspacing/(2*pi);
theta = 0:0.01:thetamax;
x = b*theta.*cos(theta) + origin(1);
y = b*theta.*sin(theta) + origin(2);
%% Calculation of equidistant (xi,yi) points on spiral.
DST = 5; cRes = 360;
numPts = ceil(vertspacing*thetamax); % Preallocation
[xi,yi] = deal(NaN(numPts,1));
if doPlot && isHG2() % Plots are only enabled if the MATLAB version is new enough.
figure(); plot(x,y,'b-'); hold on; axis equal; grid on; grid minor;
hAx = gca; hAx.XLim = [-5 105]; hAx.YLim = [-5 105];
hP = plot(xi,yi,'r*');
else
hP = struct('XData',xi,'YData',yi);
end
hP.XData(1) = origin(1); hP.YData(1) = origin(2);
for ind = 2:numPts
P = InterX([x;y], makeCircle([hP.XData(ind-1),hP.YData(ind-1)],DST/2,cRes));
[~,I] = max(abs(P(1,:)-origin(1)+1i*(P(2,:)-origin(2))));
if doPlot, pause(0.1); end
hP.XData(ind) = P(1,I); hP.YData(ind) = P(2,I);
if doPlot, pause(0.1); delete(hAx.Children(1)); end
end
xi = hP.XData(~isnan(hP.XData)); yi = hP.YData(~isnan(hP.YData));
%% Nested function(s):
function [XY] = makeCircle(cnt, R, nPts)
P = (cnt(1)+1i*cnt(2))+R*exp(linspace(0,1,nPts)*pi*2i);
if doPlot, plot(P,'Color',lines(1)); end
XY = [real(P); imag(P)];
end
end
%% Local function(s):
function tf = isHG2()
try
tf = ~verLessThan('MATLAB', '8.4');
catch
tf = false;
end
end
function P = InterX(L1,varargin)
% DOCUMENTATION REMOVED. For a full version go to:
% https://www.mathworks.com/matlabcentral/fileexchange/22441-curve-intersections
narginchk(1,2);
if nargin == 1
L2 = L1; hF = #lt; %...Avoid the inclusion of common points
else
L2 = varargin{1}; hF = #le;
end
%...Preliminary stuff
x1 = L1(1,:)'; x2 = L2(1,:);
y1 = L1(2,:)'; y2 = L2(2,:);
dx1 = diff(x1); dy1 = diff(y1);
dx2 = diff(x2); dy2 = diff(y2);
%...Determine 'signed distances'
S1 = dx1.*y1(1:end-1) - dy1.*x1(1:end-1);
S2 = dx2.*y2(1:end-1) - dy2.*x2(1:end-1);
C1 = feval(hF,D(bsxfun(#times,dx1,y2)-bsxfun(#times,dy1,x2),S1),0);
C2 = feval(hF,D((bsxfun(#times,y1,dx2)-bsxfun(#times,x1,dy2))',S2'),0)';
%...Obtain the segments where an intersection is expected
[i,j] = find(C1 & C2);
if isempty(i), P = zeros(2,0); return; end
%...Transpose and prepare for output
i=i'; dx2=dx2'; dy2=dy2'; S2 = S2';
L = dy2(j).*dx1(i) - dy1(i).*dx2(j);
i = i(L~=0); j=j(L~=0); L=L(L~=0); %...Avoid divisions by 0
%...Solve system of eqs to get the common points
P = unique([dx2(j).*S1(i) - dx1(i).*S2(j), ...
dy2(j).*S1(i) - dy1(i).*S2(j)]./[L L],'rows')';
function u = D(x,y)
u = bsxfun(#minus,x(:,1:end-1),y).*bsxfun(#minus,x(:,2:end),y);
end
end
Result:
Note that in the animation above, the diameter of the circle (and hence the distance between the red points) is 10 and not 5.

Estimate the amount of the area of the hemisphere’s surface which can be seen by the eye?

We suppose that there are one hemisphere and three triangles in a 3D space. The center point of the hemisphere’s bottom is denoted by C. The radius of the hemisphere’s bottom is represented by R. The normal vector to hemisphere’s bottom is denoted by n.
The first triangle is given by the three points V1, V2 and V3. The second triangle is given by the three points V4, V5 and V6. The third triangle is given by the three points V7, V8 and V9. The positions of the points V1, V2, …, V9 are arbitrary. Now, we further assume that an eye is located at the point E. Note that the triangles may block the line of sight from the eye to the hemisphere’s surface; hence some region of the hemisphere’s surface may not be seen by the eye.
Please develop a method to estimate the amount of the area of the hemisphere’s surface which can be seen by the eye?
Here is a code for the rectangle rather than hemisphere:
function r = month_1()
P1 = [0.918559, 0.750000, -0.918559];
P2 = [0.653394, 0.649519, 1.183724];
P3 = [-0.918559, -0.750000, 0.918559];
P4 = [-0.653394, -0.649519, -1.183724];
V1 = [0.989609, -1.125000, 0.071051];
V2 = [1.377838, -0.808013, -0.317178];
V3 = [1.265766, -0.850481, 0.571351];
V4 = [0.989609, -1.125000, 0.071051];
V5 = [1.265766, -0.850481, 0.571351];
V6 = [0.601381, -1.441987, 0.459279];
V7 = [0.989609, -1.125000, 0.071051];
V8 = [1.377838, -0.808013, -0.317178];
V9 = [0.713453, -1.399519, -0.429250];
E = [1.714054, -1.948557, 0.123064];
C = [0,1,0];
Radius = 2;
n = [0,1,0];
%hold on
patches.vertices(1,:)= P1;
patches.vertices(2,:)= P2;
patches.vertices(3,:)= P3;
patches.vertices(4,:)= P4;
patches.vertices(5,:)= V1;
patches.vertices(6,:)= V2;
patches.vertices(7,:)= V3;
patches.vertices(8,:)= V4;
patches.vertices(9,:)= V5;
patches.vertices(10,:)= V6;
patches.vertices(11,:)= V7;
patches.vertices(12,:)= V8;
patches.vertices(13,:)= V9;
patches.faces(1,:)= [5,6,7];
patches.faces(2,:)= [8,9,10];
patches.faces(3,:)= [11,12,13];
patches.faces(4,:)= [1,2,3];
patches.faces(5,:)= [1,3,4];
patches.facevertexcdata = 1;
patch(patches);
shading faceted; view (3);
% dispatch([1,1,1])
hold on
Num = 20;
Sum = 0;
%Srec = norm(cross(P1 - P4, P3 - P4));
for i = 1:Num
x1 = rand;
x2 = rand;
v1 = P1-P4;
v2 = P3-P4;
Samp = P4+v1*x1+v2*x2;
ABC = fun_f(E, Samp, V1,V2,V3)*fun_f(E,Samp, V4, V5, V6)*fun_f(E,Samp, V7,V8,V9);
Sum = Sum + ABC;
% if ABC ==1
% plot3(Samp(1), Samp(2), Samp(3),'r +'), hold on
% else
% plot3(Samp(1), Samp(2), Samp(3),'b +'), hold on
% end
%............................
[x, y, z]= sphere;
patches = surf2patch(x,y,z,z);
patches.vertices(:,3) = abs(patches.vertices(:,3));
patches.facevertexcdata = 1;
patch(patches)
shading faceted; view(3)
daspect([1 1 1])
%............................
end
%r = Sum/Num;
%view(31, 15)
%end
r = Sum/Num*norm(cross (P1-P4,P3-P4));
disp(sprintf('the integration is: %.5f',r));
disp(sprintf('the accurate result is: %.5f',norm(cross(P1-P4,P3-P4)/4)));
function res = fun_f(LineB, LineE, V1, V2, V3)
O = LineB;
Len = norm(LineE-LineB);
v = (LineE-LineB)/Len;
N = cross(V2-V1, V3-V1)/norm(cross(V2-V1, V3-V1));
if dot(N,v)~=0
tp = dot(N, V1-O)/ dot(N,v);
% if tp >=0 && tp <= (1:3);
P = LineB+tp*v(1:3);
A = V1 - P;
B = V2 - P;
Stri1 = norm(cross(A,B))/2;
A = V1 - P;
B = V3 - P;
Stri2 = norm(cross(A,B))/2;
A = V3 - P;
B = V2 - P;
Stri3 = norm(cross(A,B))/2;
A = V1 - V2;
B = V3 - V2;
Stotal = norm(cross(A,B))/2;
if (Stri1 + Stri2 + Stri3)> (Stotal + 1e-8)
res = 1;
else
res = 0;
end
else
res =1;
end
end
end
Take a small element of surface area centered on , dimensions . The area element is given by
The idea is to loop over these elements on the sphere; calculate the center point of the element at , and work out if the line segment between this point and the camera intersects a triangle. More here: https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm.
Now we need to find the points; trivially this means incrementing by over all of the hemisphere. But this would make the sampling resolution uneven - the factor would make the elements far larger near the apex of the hemisphere than at its edge.
Instead:
Set a fixed number N of rings to loop around, i.e. number of iterations of .
Set the minimum iteration area . The number of iterations of , M is gven by
Where is the total area of the ring at :
And of course from above the increments are given by
Loop over all the rings, being careful that gives the middle line of each ring (So start at ); same concern need not apply to due to the symmetry. For each ring loop over each , and do the line intersection test as mentioned above.
The above method reduces the amount of bias in the area sampling resolution at small .
An even better way would be Fibonacci lattices, but they are more complicated. See this paper: http://geonaut.eu/published/016_Fibonacci_Lattice.pdf
clc
%% Declaration of Initial Variables
C = [0.918559, 0.750000, -0.918559];
R = 10;
n = [1, 2, 1.5];
V1 = [0.989609, -1.125000, 0.071051];
V2 = [1.377838, -0.808013, -0.317178];
V3 = [1.265766, -0.850481, 0.571351];
V4 = [0.989609, -1.125000, 0.071051];
V5 = [1.265766, -0.850481, 0.571351];
V6 = [0.601381, -1.441987, 0.459279];
V7 = [0.989609, -1.125000, 0.071051];
V8 = [1.377838, -0.808013, -0.317178];
V9 = [0.713453, -1.399519, -0.429250];
E = [1.714054, -1.948557, 0.123064];
Num = 10000;
count1 = 0; count2 = 0; count3 = 0;
%% Calculating the triangles Normal and Area
N1 = cross((V2-V1),(V3-V1));
N2 = cross((V5-V4),(V6-V4));
N3 = cross((V8-V7),(V9-V7));
Area1 = norm(N1)/2;
Area2 = norm(N2)/2;
Area3 = norm(N3)/2;
%% Plotting the triangle
patch([V1(1),V2(1),V3(1),V1(1)],[V1(2),V2(2),V3(2),V1(2)],[V1(3),V2(3),V3(3),V1(3)], 'green');
hold on
patch([V4(1),V5(1),V6(1),V4(1)],[V4(2),V5(2),V6(2),V4(2)],[V4(3),V5(3),V6(3),V4(3)],'green');
hold on
patch([V7(1),V8(1),V9(1),V7(1)],[V7(2),V8(2),V9(2),V7(2)],[V7(3),V8(3),V9(3),V7(3)], 'green');
plot3(E(1),E(2),E(3),'ro')
hold on
%% The Loop Section
for i=1:Num
x1 = rand;
x2 = rand;
Px = R*sqrt(x1*(2-x1))*cos(2*pi*x2)+C(1);
Py = R*sqrt(x1*(2-x1))*sin(2*pi*x2)+C(2);
Pz = R*(1 - x1)+C(3);
z = [0,0,1];
if norm(cross(n,z)) ~= 0
v = cross(n,z)/norm(cross(n,z));
u = cross(v,n)/norm(cross(v,n));
w = n/norm(n);
else
u = (dot(n,z)/abs(dot(n,z))).*[1,0,0];
v = (dot(n,z)/abs(dot(n,z))).*[0,1,0];
w = (dot(n,z)/abs(dot(n,z))).*[0,0,1];
end
M = [u(1),u(2),u(3),0;v(1),v(2),v(3),0;w(1),w(2),w(3),0;0,0,0,1]*...
[1,0,0,-C(1);0,1,0,-C(2);0,0,1,-C(3);0,0,0,1];
L = [Px,Py,Pz,1]*M;
Points = [L(1),L(2),L(3)];
Len = norm(E - Points);
plot3(L(1),L(2),L(3),'b.'),hold on
dv = (E - Points)/norm(E - Points);
%% Triangle 1
tp1 = dot(N1,(V1-Points))/dot(N1,dv);
if tp1>=0 && tp1<=Len
R1 = Points + tp1*dv;
A1 = norm(cross((V1-R1),(V2-R1)))/2;
A2 = norm(cross((V1-R1),(V3-R1)))/2;
A3 = norm(cross((V2-R1),(V3-R1)))/2;
if (A1+A2+A3) <= Area1
count1 = count1 + 1;
plot3(L(1),L(2),L(3),'r*')
end
end
%% Triangle 2
tp2 = dot(N2,(V4-Points))/dot(N2,dv);
if tp2>=0 && tp2<=Len
R2 = Points + tp2*dv;
A4 = norm(cross((V4-R2),(V5-R2)))/2;
A5 = norm(cross((V4-R2),(V6-R2)))/2;
A6 = norm(cross((V5-R2),(V6-R2)))/2;
if (A4+A5+A6) <= Area2
count2 = count2 + 1;
plot3(L(1),L(2),L(3),'r*')
end
end
%% Triangle 3
tp3 = dot(N3,(V7-Points))/dot(N3,dv);
if tp3>=0 && tp3<=Len
R3 = Points + tp3*dv;
A7 = norm(cross((V7-R3),(V8-R3)))/2;
A8 = norm(cross((V7-R3),(V9-R3)))/2;
A9 = norm(cross((V8-R3),(V9-R3)))/2;
if (A7+A8+A9) <= Area3
count3 = count3 + 1;
plot3(L(1),L(2),L(3),'r*')
end
end
end
%% Final Solution
AreaofHemi = 2*pi*R^2;
Totalcount = count1 + count2 + count3;
Areaseen=((Num-Totalcount)/Num)*AreaofHemi;
disp(fprintf('AreaofHemi %f, AreaSeen %f ',AreaofHemi,Areaseen))

How can I plot a 3D-plane in Matlab?

I would like to plot a plane using a vector that I calculated from 3 points where:
pointA = [0,0,0];
pointB = [-10,-20,10];
pointC = [10,20,10];
plane1 = cross(pointA-pointB, pointA-pointC)
How do I plot 'plane1' in 3D?
Here's an easy way to plot the plane using fill3:
points=[pointA' pointB' pointC']; % using the data given in the question
fill3(points(1,:),points(2,:),points(3,:),'r')
grid on
alpha(0.3)
You have already calculated the normal vector. Now you should decide what are the limits of your plane in x and z and create a rectangular patch.
An explanation : Each plane can be characterized by its normal vector (A,B,C) and another coefficient D. The equation of the plane is AX+BY+CZ+D=0. Cross product between two differences between points, cross(P3-P1,P2-P1) allows finding (A,B,C). In order to find D, simply put any point into the equation mentioned above:
D = -Ax-By-Cz;
Once you have the equation of the plane, you can take 4 points that lie on this plane, and draw the patch between them.
normal = cross(pointA-pointB, pointA-pointC); %# Calculate plane normal
%# Transform points to x,y,z
x = [pointA(1) pointB(1) pointC(1)];
y = [pointA(2) pointB(2) pointC(2)];
z = [pointA(3) pointB(3) pointC(3)];
%Find all coefficients of plane equation
A = normal(1); B = normal(2); C = normal(3);
D = -dot(normal,pointA);
%Decide on a suitable showing range
xLim = [min(x) max(x)];
zLim = [min(z) max(z)];
[X,Z] = meshgrid(xLim,zLim);
Y = (A * X + C * Z + D)/ (-B);
reOrder = [1 2 4 3];
figure();patch(X(reOrder),Y(reOrder),Z(reOrder),'b');
grid on;
alpha(0.3);
Here's what I came up with:
function [x, y, z] = plane_surf(normal, dist, size)
normal = normal / norm(normal);
center = normal * dist;
tangents = null(normal') * size;
res(1,1,:) = center + tangents * [-1;-1];
res(1,2,:) = center + tangents * [-1;1];
res(2,2,:) = center + tangents * [1;1];
res(2,1,:) = center + tangents * [1;-1];
x = squeeze(res(:,:,1));
y = squeeze(res(:,:,2));
z = squeeze(res(:,:,3));
end
Which you would use as:
normal = cross(pointA-pointB, pointA-pointC);
dist = dot(normal, pointA)
[x, y, z] = plane_surf(normal, dist, 30);
surf(x, y, z);
Which plots a square of side length 60 on the plane in question
I want to add to the answer given by Andrey Rubshtein, his code works perfectly well except at B=0. Here is the edited version of his code
Below Code works when A is not 0
normal = cross(pointA-pointB, pointA-pointC);
x = [pointA(1) pointB(1) pointC(1)];
y = [pointA(2) pointB(2) pointC(2)];
z = [pointA(3) pointB(3) pointC(3)];
A = normal(1); B = normal(2); C = normal(3);
D = -dot(normal,pointA);
zLim = [min(z) max(z)];
yLim = [min(y) max(y)];
[Y,Z] = meshgrid(yLim,zLim);
X = (C * Z + B * Y + D)/ (-A);
reOrder = [1 2 4 3];
figure();patch(X(reOrder),Y(reOrder),Z(reOrder),'r');
grid on;
alpha(0.3);
Below Code works when C is not 0
normal = cross(pointA-pointB, pointA-pointC);
x = [pointA(1) pointB(1) pointC(1)];
y = [pointA(2) pointB(2) pointC(2)];
z = [pointA(3) pointB(3) pointC(3)];
A = normal(1); B = normal(2); C = normal(3);
D = -dot(normal,pointA);
xLim = [min(x) max(x)];
yLim = [min(y) max(y)];
[Y,X] = meshgrid(yLim,xLim);
Z = (A * X + B * Y + D)/ (-C);
reOrder = [1 2 4 3];
figure();patch(X(reOrder),Y(reOrder),Z(reOrder),'r');
grid on;
alpha(0.3);