How to stop plotting once line touches perimeter of predefined square? - matlab

I am trying to recreate a Voronoi diagram without actually using the Voronoi function plot. I have a predefined 1x1 square that acts as my "test" area. My code knows where the lines of the diagram intersect the perimeter, but the line doesn't stop there. It keeps going until it reaches a random point.
x1 = 6
y1 = x1
x = gallery('uniformdata',[1,x1],0)
y = gallery('uniformdata',[1,y1],1)
sizeofx = size(x,2)
sizeofy = size(y,2)
reshapedx = reshape(x,sizeofx,1)
reshapedy = reshape(y,sizeofy,1)
[vxx,vyy] = voronoi(x,y)
hold on
[v,c] = voronoin([x(:) y(:)]) %intersection point matrix
for i=1:numel(c)
v(c{i},:)
ans = ans( ~any( isnan( ans ) | isinf( ans ), 2 ),: )%deletes infs or nans from polygon points
plot(ans(:,1),ans(:,2),'b-','linewidth',2) %%this code plots the points
end
%for our test purposes , the voronoi diagram will only be in a 1x1 square.
v(v<0) = inf
v(v>1) = inf
v = v( ~any( isnan( v ) | isinf( v ), 2 ),: ) %deletes the inf or nan
DT = delaunayTriangulation(reshapedx,reshapedy)
[V,R] = voronoiDiagram(DT)
sizeofR = size(R,1)
rectangle('Position',[0,0,1,1])
axis equal
xlimit = [0 1];
ylimit = [0 1];
xbox = xlimit([1 1 2 2 1]);
ybox = ylimit([1 2 2 1 1]);
%finds intersection from diagram to square
for j=1:length(vxx(1,:))
line([vxx(1,j) vxx(2,j)],[vyy(1,j) vyy(2,j)]);
[xi, yi, ii] = ...
polyxpoly([vxx(1,j) vxx(2,j)], [vyy(1,j) vyy(2,j)], xbox, ybox);
if ~isempty(xi)
intersectx(j) = xi
intersecty(j) = yi
plot(xi,yi,'r*');
axis equal
end
end
I want the line to stop plotting once it reaches a perimeter point.

You can replace the coordinate of line's edge with the intersection point.
Assume line goes from (x1,y1) to (x2,y2).
Check if (x1,y1) is outside the boundaries of the rectangle.
I your case (x1,y1) is outside the boundaries if (x1<0) || (y1<0) || (x1>1) || (y1>1).
In case (x1,y1) is outside, replace (x1,y1) with intersection point (xi,yi).
Note: Replace it only if there is an intersection point.
I ignored the case of two intersection points, because this case never happens in your case (in that case, you need to replace both).
Here is the complete code with the modifications:
x1 = 6;
y1 = x1;
x = gallery('uniformdata',[1,x1],0);
y = gallery('uniformdata',[1,y1],1);
sizeofx = size(x,2);
sizeofy = size(y,2);
reshapedx = reshape(x,sizeofx,1);
reshapedy = reshape(y,sizeofy,1);
[vxx,vyy] = voronoi(x,y);
hold on
[v,c] = voronoin([x(:) y(:)]); %intersection point matrix
for i=1:numel(c)
v(c{i},:);
ans = ans( ~any( isnan( ans ) | isinf( ans ), 2 ),: );%deletes infs or nans from polygon points
plot(ans(:,1),ans(:,2),'b-','linewidth',2); %%this code plots the points
end
%for our test purposes , the voronoi diagram will only be in a 1x1 square.
v(v<0) = inf;
v(v>1) = inf;
v = v( ~any( isnan( v ) | isinf( v ), 2 ),: ); %deletes the inf or nan
DT = delaunayTriangulation(reshapedx,reshapedy);
[V,R] = voronoiDiagram(DT);
sizeofR = size(R,1);
rectangle('Position',[0,0,1,1]);
axis equal
xlimit = [0 1];
ylimit = [0 1];
xbox = xlimit([1 1 2 2 1]);
ybox = ylimit([1 2 2 1 1]);
%Vxx and Vyy are going to be a new set of line coordinates, replacing vxx and vyy.
Vxx = vxx;
Vyy = vyy;
%finds intersection from diagram to square
for j=1:length(vxx(1,:))
%line([vxx(1,j) vxx(2,j)],[vyy(1,j) vyy(2,j)]);
[xi, yi, ii] = ...
polyxpoly([vxx(1,j) vxx(2,j)], [vyy(1,j) vyy(2,j)], xbox, ybox);
if ~isempty(xi)
intersectx(j) = xi;
intersecty(j) = yi;
plot(xi,yi,'r*', 'MarkerSize', 10);
axis equal
%Replace line edges outsize the rectangle with the inersection point.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
x1 = vxx(1,j);
x2 = vxx(2,j);
y1 = vyy(1,j);
y2 = vyy(2,j);
is_outsize1 = (x1 < 0) || (y1 < 0) || (x1 > 1) || (y1 > 1);
is_outsize2 = (x2 < 0) || (y2 < 0) || (x2 > 1) || (y2 > 1);
%Assume rectangle's boundaries are (0,0) to (1,1)
if is_outsize1
%Replace the coordinate [vxx(1,j), vyy(1,j)] with [xi, yi].
Vxx(1,j) = xi;
Vyy(1,j) = yi;
end
if is_outsize2
%Replace the coordinate [vxx(2,j), vyy(2,j)] with [xi, yi].
Vxx(2,j) = xi;
Vyy(2,j) = yi;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
%Plot the line with the replaces coordinates
line([Vxx(1,j) Vxx(2,j)],[Vyy(1,j) Vyy(2,j)], 'color', 'g', 'LineWidth', 1, 'Marker', '+');
end
Result:
Original plot:

Related

How to prevent an object from being illuminated by camlight in Matlab?

[Hereafter are 4 snippets, one should only be interested in reading the two first ones. However by copy-pasting all of these, one should be able to launch what I see, although screenshots are provided at the end.]
Hi, by launching this main.m :
%To see if plotting a tick after setting camlight headlight will leads to
%its background becoming gray or not
%clear all
figure
arrow = arrow3D([0 0 0], [1 1 1], 'r', 0.8, 0.2, 1.5);
set(arrow, 'EdgeColor', 'interp', 'FaceColor', 'interp');
%camlight headlight %might be interesting to uncomment this line
pause(5)
surfaceHandle = rotateAxisTicks('lol','r',10,-0.3,0.5,0.5,1,1,1,0);
pause(5)
camlight headlight
%material(surfaceHandle,'default') %doesn't work
%surfaceHandle1.FaceLighting = 'none' %doesn't work
, which uses that function rotateAxisTicks.m
function surfaceHandle = rotateAxisTicks(str,color,fontsize,zmax,graduSpace,boxHeight,perc,labelNumber,axnumber,thetaInput)
%https://stackoverflow.com/questions/9843048/matlab-how-to-plot-a-text-in-3d
%zmax : give it a negative value to not overlap the axis
%graduSpace : space between each graduation, within the projected on [0,1] axis if axis = x||y, OR local (not yet projected on x,y) axis !!
%boxHeight : width of the boxes depend on how much the axis graduations are refined, so height shouldn't depend on graduSpace
%perc : if perc = 1 (100%), then the labels are all sticked together with no space inbetween
%labelNumber : the first tick to be displayed is actually associated to the second graduation (0 can't get several labels)
%axnumber : out of nbParams, 1 for x, 2 for y, then, from closest to x, to closest to y : 3 to nbParams.
%thetaInput : (angle around z, from x to the axis) has to be in degree
%% Seems like there is no way to get rid of the black contouring...
hFigure = figure(1000);
set(hFigure,'Color', 'w', ... % Create a figure window
'MenuBar', 'none', ...
'ToolBar', 'none');
hText = uicontrol('Parent', hFigure, ... % Create a text object
'Style', 'text', ...
'String', str, ...
'BackgroundColor', 'w', ...
'ForegroundColor', color, ...
'FontSize', fontsize, ...
'FontWeight', 'normal');
set([hText hFigure], 'Pos', get(hText, 'Extent')); %# Adjust the sizes of the
%# text and figure
imageData = getframe(hFigure); %# Save the figure as an image frame
delete(hFigure);
textImage = imageData.cdata; %# Get the RGB image of the text
%% MAKE THE X,Y,Z (text) REVERSE DEPENDING ON AZIMUT VALUE (launch a fig and see on the bottom in real time the azimut value)
% X or Y or Z(1,1) = _______
% * |
% | |
% |_______|
% X or Y or Z(1,2) = _______
% | *
% | |
% |_______|
% X or Y or Z(2,1) = _______
% | |
% | |
% x_______|
% X or Y or Z(2,2) = _______
% | |
% | |
% |_______x
if axnumber == 2 %axis = y
X = [0 0; 0 0];
Y = [0 perc*graduSpace; 0 perc*graduSpace] + labelNumber*graduSpace - perc*graduSpace/2;
%(graduSpace/2)/2 to center under the graduation, (1-perc)/2) to
%additionally shift a bit so that the perc% of graduSpace stay centered
%under the graduation
else %I assume axis = x, that I might later rotate if it's not actually x
X = [0 perc*graduSpace; 0 perc*graduSpace] + labelNumber*graduSpace - perc*graduSpace/2; %+labelNumber*((graduSpace/2)+((1-perc)/2)*graduSpace)
Y = [0 0; 0 0];
end
Z = [zmax zmax; zmax-boxHeight zmax-boxHeight];
surfaceHandle = surf(X, Y, Z, 'FaceColor', 'texturemap', 'CData', textImage);
if axnumber > 2
rotate(surfaceHandle, [0 0 1], thetaInput,[0 0 0]);
end
end
as well as that function arrow3D.m :
function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio, cylRad, radRatioCone)
% arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead
% pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem)
% deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos')
% colorCode - Color parameters as per the 'surf' command. For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow
% stemRatio - The ratio of the length of the stem in proportion to the arrowhead. For example, a call of:
% arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance
% of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18.
%
% Example:
% arrow3D([0,0,0], [4,3,7]); %---- arrow with default parameters
% axis equal;
%
% Author: Shawn Arseneau
% Created: September 14, 2006
% Updated: September 18, 2006
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<2 || nargin>6
error('Incorrect number of inputs to arrow3D');
end
if numel(pos)~=3 || numel(deltaValues)~=3
error('pos and/or deltaValues is incorrect dimensions (should be three)');
end
if nargin<3
colorCode = 'interp';
end
if nargin<4
stemRatio = 0.75;
end
X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector
Y = pos(2);
Z = pos(3);
[sphi, stheta, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3));
%******************************************* CYLINDER == STEM *********************************************
%cylinderRadius = 0.05*srho;
cylinderRadius = cylRad;
cylinderLength = srho*stemRatio;
[CX,CY,CZ] = cylinder(cylinderRadius);
CZ = CZ.*cylinderLength; %---- lengthen
%----- ROTATE CYLINDER
[row, col] = size(CX); %---- initial rotation to coincide with X-axis
newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]); %CX(:) actually reshape the 2xN matrices in a 2N vert vector, by vertically concatenating each column
CX = reshape(newEll(:,1), row, col);
CY = reshape(newEll(:,2), row, col);
CZ = reshape(newEll(:,3), row, col);
[row, col] = size(CX);
newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]);
stemX = reshape(newEll(:,1), row, col);
stemY = reshape(newEll(:,2), row, col);
stemZ = reshape(newEll(:,3), row, col);
%----- TRANSLATE CYLINDER
stemX = stemX + X;
stemY = stemY + Y;
stemZ = stemZ + Z;
%******************************************* CONE == ARROWHEAD *********************************************
coneLength = srho*(1-stemRatio);
coneRadius = cylinderRadius*radRatioCone;
incr = 100; %---- Steps of cone increments
coneincr = coneRadius/incr;
[coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0); %---------- CONE
coneZ = coneZ.*coneLength;
%----- ROTATE CONE
[row, col] = size(coneX);
newEll = rotatePoints([0 0 -1], [coneX(:), coneY(:), coneZ(:)]);
coneX = reshape(newEll(:,1), row, col);
coneY = reshape(newEll(:,2), row, col);
coneZ = reshape(newEll(:,3), row, col);
newEll = rotatePoints(deltaValues, [coneX(:), coneY(:), coneZ(:)]);
headX = reshape(newEll(:,1), row, col);
headY = reshape(newEll(:,2), row, col);
headZ = reshape(newEll(:,3), row, col);
%---- TRANSLATE CONE
V = [0, 0, srho*stemRatio]; %---- centerline for cylinder: the multiplier is to set the cone 'on the rim' of the cylinder
Vp = rotatePoints([0 0 -1], V);
Vp = rotatePoints(deltaValues, Vp);
headX = headX + Vp(1) + X;
headY = headY + Vp(2) + Y;
headZ = headZ + Vp(3) + Z;
%************************************************************************************************************
hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
hold on
hBottStem = fill3(stemX(1,:),stemY(1,:),stemZ(1,:), colorCode, 'EdgeColor', 'none');
hold on
hHead = surf(headX, headY, headZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
hold on
hBottCone = fill3(headX(1,:),headY(1,:),headZ(1,:), colorCode, 'EdgeColor', 'none');
if nargout==1
arrowHandle = [hStem, hBottStem, hHead, hBottCone];
end
which itself uses that function rotatePoints.m :
function rotatedData = rotatePoints(alignmentVector, originalData)
% rotatedData = rotatePoints(alignmentVector, originalData) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Rotate the 'originalData' in the form of Nx2 or Nx3 about the origin by aligning the x-axis with the alignment vector
%
% Rdata = rotatePoints([1,2,-1], [Xpts(:), Ypts(:), Zpts(:)]) - rotate the (X,Y,Z)pts in 3D with respect to the vector [1,2,-1]
%
% Rotating using spherical components can be done by first converting using [dX,dY,dZ] = cart2sph(theta, phi, rho); alignmentVector = [dX,dY,dZ];
%
% Example:
% %% Rotate the point [3,4,-7] with respect to the following:
% %%%% Original associated vector is always [1,0,0]
% %%%% Calculate the appropriate rotation requested with respect to the x-axis. For example, if only a rotation about the z-axis is
% %%%% sought, alignmentVector = [2,1,0] %% Note that the z-component is zero
% rotData = rotatePoints(alignmentVector, [3,4,-7]);
%
% Author: Shawn Arseneau
% Created: Feb.2, 2006
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
alignmentDim = numel(alignmentVector); %number of elements in a matrix
DOF = size(originalData,2); %---- DOF = Degrees of Freedom (i.e. 2 for two dimensional and 3 for three dimensional data)
if alignmentDim~=DOF
error('Alignment vector does not agree with originalData dimensions');
end
if DOF<2 || DOF>3
error('rotatePoints only does rotation in two or three dimensions');
end
if DOF==2 % 2D rotation...
[rad_theta, rho] = cart2pol(alignmentVector(1), alignmentVector(2));
deg_theta = -1 * rad_theta * (180/pi);
ctheta = cosd(deg_theta); stheta = sind(deg_theta);
Rmatrix = [ctheta, -1.*stheta;...
stheta, ctheta];
rotatedData = originalData*Rmatrix;
%assumption: rotate all the datas from the original base to the
%base where the original x becomes alignmentVector
else % 3D rotation...
[rad_theta, rad_phi, rho] = cart2sph(alignmentVector(1), alignmentVector(2), alignmentVector(3));
rad_theta = rad_theta * -1;
deg_theta = rad_theta * (180/pi);
deg_phi = rad_phi * (180/pi);
ctheta = cosd(deg_theta); stheta = sind(deg_theta); %MM : is it more accurate??
Rz = [ctheta, -1.*stheta, 0;...
stheta, ctheta, 0;...
0, 0, 1]; %% First rotate as per theta around the Z axis
rotatedData = originalData*Rz;
[rotX, rotY, rotZ] = sph2cart(-1* (rad_theta+(pi/2)), 0, 1); %% Second rotation corresponding to phi
%assuming alignmentVector is the x for the new base, then the
%hereabove argument corresponds to the y (z inversed)
%the hereabove output = newX(in base 0) vectorial product -z(in base0)
rotationAxis = [rotX, rotY, rotZ];
u = rotationAxis(:)/norm(rotationAxis); %% Code extract from rotate.m from MATLAB
cosPhi = cosd(deg_phi);
sinPhi = sind(deg_phi);
invCosPhi = 1 - cosPhi;
x = u(1);
y = u(2);
z = u(3);
Rmatrix = [cosPhi+x^2*invCosPhi x*y*invCosPhi-z*sinPhi x*z*invCosPhi+y*sinPhi; ...
x*y*invCosPhi+z*sinPhi cosPhi+y^2*invCosPhi y*z*invCosPhi-x*sinPhi; ...
x*z*invCosPhi-y*sinPhi y*z*invCosPhi+x*sinPhi cosPhi+z^2*invCosPhi]';
rotatedData = rotatedData*Rmatrix;
end
I end up getting:
while I would like to conserve both intermediate plots containing the interp arrow:
and the text on flashy white background:
So there are actually two questions:
1) Why calling my text tick disables the interp effect (varying color from blue to yellow) ?
2) How can I keep the camlight without enlightening my tick box? (i.e while keeping its background white)
Basically one should only need to look at the two first snippets, the later 2 ones are useless for my issue.
By thanking you a lot!
Place it in another axes
As I said in comment, you have 2 graphic objects in the same axes which have to interpret their CData in a completely different manner.
The first options I looked for was to modify one of the arrow3d or rotateAxisTicks so their graphic objects would be "compatible" (in the way the color data are interpolated on an axes), but it would be quite intensive and the aspect of the 3d text would have to be constantly monitored/adjusted for any other change in the figure.
So the easiest option is a classic MATLAB hack ... place your graphic objects in different containers (different axes), then superimpose them on a figure, and match some properties (limits, view, etc ...) so they appear to be only one.
Here it goes:
%% Draw your main arrow in the main figure
mainfig = figure ;
ax1 = axes ;
arrow = arrow3D([0 0 0], [1 1 1], 'r', 0.8, 0.2, 1.5);
set(arrow, 'EdgeColor', 'interp', 'FaceColor', 'interp');
camlight headlight
%% Draw your text in a temporary figure
tempfig = figure ;
ax2 = axes ;
surfaceHandle = rotateAxisTicks('lol','r',10,-0.3,0.5,0.5,1,1,1,0);
camlight headlight
%material(surfaceHandle,'default') %doesn't work
%surfaceHandle1.FaceLighting = 'none' %doesn't work
%% Prepare and set matching limits
xl = [ax1.XLim ; ax2.XLim] ;
xl = [min(xl(:,1)) , max(xl(:,2))] ;
yl = [ax1.YLim ; ax2.YLim] ;
yl = [min(yl(:,1)) , max(yl(:,2))] ;
zl = [ax1.ZLim ; ax2.ZLim] ;
zl = [min(zl(:,1)) , max(zl(:,2))] ;
hax = [ax1;ax2] ;
set(hax,'XLim',xl,'YLim',yl,'ZLim',zl)
% Adjust the view to be sure
ax2.View = ax1.View ;
%% Remove secondary axes background, then move it to main figure
ax2.Visible = 'off' ;
ax2.Parent = mainfig ;
delete(tempfig)
%% link the view between axes
hl = linkprop( hax , 'View' ) ;
% or link even more properties at once
% hl = linkprop( hax , 'View' , 'XLim','YLim','ZLim') ;
Which gives you:
note: Your 3d arrow is also made up of 2 different graphic objects (2x surf and 2x patch). The 2 patches are not rendered when you set the interp mode. You should modify the arrow3d function to either (a) changes the patch objects to surf so everything is the same type and compatible, or (b) remove them completely from the function (if they are not rendered they are only annoying ... triggering warnings everywhere).
edit
And here is the modified code for arrow3d.m. I changed it so the output is now only one surface object, easier to assign properties and no danger of mismatch between patch and surf. I also simplified it, removed a few bits that were not necessary, and reduced the total number of points necessary for the surface.
With this you get the bottom of the stem and the under-cone:
function arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio, cylRad )
% arrowHandle = arrow3D(pos, deltaValues, colorCode, stemRatio) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Used to plot a single 3D arrow with a cylindrical stem and cone arrowhead
% pos = [X,Y,Z] - spatial location of the starting point of the arrow (end of stem)
% deltaValues = [QX,QY,QZ] - delta parameters denoting the magnitude of the arrow along the x,y,z-axes (relative to 'pos')
% colorCode - Color parameters as per the 'surf' command. For example, 'r', 'red', [1 0 0] are all examples of a red-colored arrow
% stemRatio - The ratio of the length of the stem in proportion to the arrowhead. For example, a call of:
% arrow3D([0,0,0], [100,0,0] , 'r', 0.82) will produce a red arrow of magnitude 100, with the arrowstem spanning a distance
% of 82 (note 0.82 ratio of length 100) while the arrowhead (cone) spans 18.
%
% Example:
% arrow3D([0,0,0], [4,3,7]); %---- arrow with default parameters
% axis equal;
%
% Author: Shawn Arseneau
% Created: September 14, 2006
% Updated: September 18, 2006
%
% Updated: December 20, 2018
% Tlab - refactored to have only one surface object as ouput
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<2 || nargin>6
error('Incorrect number of inputs to arrow3D');
end
if numel(pos)~=3 || numel(deltaValues)~=3
error('pos and/or deltaValues is incorrect dimensions (should be three)');
end
if nargin<3
colorCode = 'interp';
end
if nargin<4
stemRatio = 0.75;
end
Ncol = 21 ; % default number of column for the "cylinder.m" function
X = pos(1); %---- with this notation, there is no need to transpose if the user has chosen a row vs col vector
Y = pos(2);
Z = pos(3);
[~, ~, srho] = cart2sph(deltaValues(1), deltaValues(2), deltaValues(3));
%******************************************* CYLINDER == STEM *********************************************
cylinderRadius = cylRad;
cylinderLength = srho*stemRatio;
[CX,CY,CZ] = cylinder(cylinderRadius,Ncol-1);
CZ = CZ.*cylinderLength; %---- lengthen
%******************************************* CONE == ARROWHEAD *********************************************
coneLength = srho*(1-stemRatio);
[coneX, coneY, coneZ] = cylinder([cylinderRadius*2 0],Ncol-1); %---------- CONE
coneZ = coneZ.*coneLength;
% Translate cone on top of the stem cylinder
coneZ = coneZ + cylinderLength ;
% now close the bottom and add the cone to the stem cylinder surface
bottom = zeros(1,Ncol) ;
CX = [ bottom ; CX ; coneX ] ;
CY = [ bottom ; CY ; coneY ] ;
CZ = [ bottom ; CZ ; coneZ ] ;
Nrow = size(CX,1);
%----- ROTATE
%---- initial rotation to coincide with X-axis
newEll = rotatePoints([0 0 -1], [CX(:), CY(:), CZ(:)]); %CX(:) actually reshape the 2xN matrices in a 2N vert vector, by vertically concatenating each column
CX = reshape(newEll(:,1), Nrow, Ncol);
CY = reshape(newEll(:,2), Nrow, Ncol);
CZ = reshape(newEll(:,3), Nrow, Ncol);
newEll = rotatePoints(deltaValues, [CX(:), CY(:), CZ(:)]);
stemX = reshape(newEll(:,1), Nrow, Ncol);
stemY = reshape(newEll(:,2), Nrow, Ncol);
stemZ = reshape(newEll(:,3), Nrow, Ncol);
%----- TRANSLATE
stemX = stemX + X;
stemY = stemY + Y;
stemZ = stemZ + Z;
%----- DISPLAY
hStem = surf(stemX, stemY, stemZ, 'FaceColor', colorCode, 'EdgeColor', 'none');
%----- DISPLAY
if nargout==1
arrowHandle = hStem ;
end

Create random unit vector inside a defined conical region

I'm looking for a simple way for creating a random unit vector constrained by a conical region. The origin is always the [0,0,0].
My solution up to now:
function v = GetRandomVectorInsideCone(coneDir,coneAngleDegree)
coneDir = normc(coneDir);
ang = coneAngleDegree + 1;
while ang > coneAngleDegree
v = [randn(1); randn(1); randn(1)];
v = v + coneDir;
v = normc(v);
ang = atan2(norm(cross(v,coneDir)), dot(v,coneDir))*180/pi;
end
My code loops until the random generated unit vector is inside the defined cone. Is there a better way to do that?
Resultant image from test code bellow
Resultant frequency distribution using Ahmed Fasih code (in comments).
I wonder how to get a rectangular or normal distribution.
c = [1;1;1]; angs = arrayfun(#(i) subspace(c, GetRandomVectorInsideCone(c, 30)), 1:1e5) * 180/pi; figure(); hist(angs, 50);
Testing code:
clearvars; clc; close all;
coneDir = [randn(1); randn(1); randn(1)];
coneDir = [0 0 1]';
coneDir = normc(coneDir);
coneAngle = 45;
N = 1000;
vAngles = zeros(N,1);
vs = zeros(3,N);
for i=1:N
vs(:,i) = GetRandomVectorInsideCone(coneDir,coneAngle);
vAngles(i) = subspace(vs(:,i),coneDir)*180/pi;
end
maxAngle = max(vAngles);
minAngle = min(vAngles);
meanAngle = mean(vAngles);
AngleStd = std(vAngles);
fprintf('v angle\n');
fprintf('Direction: [%.3f %.3f %.3f]^T. Angle: %.2fº\n',coneDir,coneAngle);
fprintf('Min: %.2fº. Max: %.2fº\n',minAngle,maxAngle);
fprintf('Mean: %.2fº\n',meanAngle);
fprintf('Standard Dev: %.2fº\n',AngleStd);
%% Plot
figure;
grid on;
rotate3d on;
axis equal;
axis vis3d;
axis tight;
hold on;
xlabel('X'); ylabel('Y'); zlabel('Z');
% Plot all vectors
p1 = [0 0 0]';
for i=1:N
p2 = vs(:,i);
plot3ex(p1,p2);
end
% Trying to plot the limiting cone, but no success here :(
% k = [0 1];
% [X,Y,Z] = cylinder([0 1 0]');
% testsubject = surf(X,Y,Z);
% set(testsubject,'FaceAlpha',0.5)
% N = 50;
% r = linspace(0, 1, N);
% [X,Y,Z] = cylinder(r, N);
%
% h = surf(X, Y, Z);
%
% rotate(h, [1 1 0], 90);
plot3ex.m:
function p = plot3ex(varargin)
% Plots a line from each p1 to each p2.
% Inputs:
% p1 3xN
% p2 3xN
% args plot3 configuration string
% NOTE: p1 and p2 number of points can range from 1 to N
% but if the number of points are different, one must be 1!
% PVB 2016
p1 = varargin{1};
p2 = varargin{2};
extraArgs = varargin(3:end);
N1 = size(p1,2);
N2 = size(p2,2);
N = N1;
if N1 == 1 && N2 > 1
N = N2;
elseif N1 > 1 && N2 == 1
N = N1
elseif N1 ~= N2
error('if size(p1,2) ~= size(p1,2): size(p1,2) and/or size(p1,2) must be 1 !');
end
for i=1:N
i1 = i;
i2 = i;
if i > N1
i1 = N1;
end
if i > N2
i2 = N2;
end
x = [p1(1,i1) p2(1,i2)];
y = [p1(2,i1) p2(2,i2)];
z = [p1(3,i1) p2(3,i2)];
p = plot3(x,y,z,extraArgs{:});
end
Here’s the solution. It’s based on the wonderful answer at https://math.stackexchange.com/a/205589/81266. I found this answer by googling “random points on spherical cap”, after I learned on Mathworld that a spherical cap is this cut of a 3-sphere with a plane.
Here’s the function:
function r = randSphericalCap(coneAngleDegree, coneDir, N, RNG)
if ~exist('coneDir', 'var') || isempty(coneDir)
coneDir = [0;0;1];
end
if ~exist('N', 'var') || isempty(N)
N = 1;
end
if ~exist('RNG', 'var') || isempty(RNG)
RNG = RandStream.getGlobalStream();
end
coneAngle = coneAngleDegree * pi/180;
% Generate points on the spherical cap around the north pole [1].
% [1] See https://math.stackexchange.com/a/205589/81266
z = RNG.rand(1, N) * (1 - cos(coneAngle)) + cos(coneAngle);
phi = RNG.rand(1, N) * 2 * pi;
x = sqrt(1-z.^2).*cos(phi);
y = sqrt(1-z.^2).*sin(phi);
% If the spherical cap is centered around the north pole, we're done.
if all(coneDir(:) == [0;0;1])
r = [x; y; z];
return;
end
% Find the rotation axis `u` and rotation angle `rot` [1]
u = normc(cross([0;0;1], normc(coneDir)));
rot = acos(dot(normc(coneDir), [0;0;1]));
% Convert rotation axis and angle to 3x3 rotation matrix [2]
% [2] See https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
crossMatrix = #(x,y,z) [0 -z y; z 0 -x; -y x 0];
R = cos(rot) * eye(3) + sin(rot) * crossMatrix(u(1), u(2), u(3)) + (1-cos(rot))*(u * u');
% Rotate [x; y; z] from north pole to `coneDir`.
r = R * [x; y; z];
end
function y = normc(x)
y = bsxfun(#rdivide, x, sqrt(sum(x.^2)));
end
This code just implements joriki’s answer on math.stackexchange, filling in all the details that joriki omitted.
Here’s a script that shows how to use it.
clearvars
coneDir = [1;1;1];
coneAngleDegree = 30;
N = 1e4;
sol = randSphericalCap(coneAngleDegree, coneDir, N);
figure;plot3(sol(1,:), sol(2,:), sol(3,:), 'b.', 0,0,0,'rx');
grid
xlabel('x'); ylabel('y'); zlabel('z')
legend('random points','origin','location','best')
title('Final random points on spherical cap')
Here is a 3D plot of 10'000 points from the 30° spherical cap centered around the [1; 1; 1] vector:
Here’s 120° spherical cap:
Now, if you look at the histogram of the angles between these random points at the coneDir = [1;1;1], you will see that the distribution is skewed. Here’s the distribution:
Code to generate this:
normc = #(x) bsxfun(#rdivide, x, sqrt(sum(x.^2)));
mysubspace = #(a,b) real(acos(sum(bsxfun(#times, normc(a), normc(b)))));
angs = arrayfun(#(i) mysubspace(coneDir, sol(:,i)), 1:N) * 180/pi;
nBins = 16;
[n, edges] = histcounts(angs, nBins);
centers = diff(edges(1:2))*[0:(length(n)-1)] + mean(edges(1:2));
figure('color','white');
bar(centers, n);
xlabel('Angle (degrees)')
ylabel('Frequency')
title(sprintf('Histogram of angles between coneDir and random points: %d deg', coneAngleDegree))
Well, this makes sense! If you generate points from the 120° spherical cap around coneDir, of course the 1° cap is going to have very few of those samples, whereas the strip between the 10° and 11° caps will have far more points. So what we want to do is normalize the number of points at a given angle by the surface area of the spherical cap at that angle.
Here’s a function that gives us the surface area of the spherical cap with radius R and angle in radians theta (equation 16 on Mathworld’s spherical cap article):
rThetaToH = #(R, theta) R * (1 - cos(theta));
rThetaToS = #(R, theta) 2 * pi * R * rThetaToH(R, theta);
Then, we can normalize the histogram count for each bin (n above) by the difference in surface area of the spherical caps at the bin’s edges:
figure('color','white');
bar(centers, n ./ diff(rThetaToS(1, edges * pi/180)))
The figure:
This tells us “the number of random vectors divided by the surface area of the spherical segment between histogram bin edges”. This is uniform!
(N.B. If you do this normalized histogram for the vectors generated by your original code, using rejection sampling, the same holds: the normalized histogram is uniform. It’s just that rejection sampling is expensive compared to this.)
(N.B. 2: note that the naive way of picking random points on a sphere—by first generating azimuth/elevation angles and then converting these spherical coordinates to Cartesian coordinates—is no good because it bunches points near the poles: Mathworld, example, example 2. One way to pick points on the entire sphere is sampling from the 3D normal distribution: that way you won’t get bunching near poles. So I believe that your original technique is perfectly appropriate, giving you nice, evenly-distributed points on the sphere without any bunching. This algorithm described above also does the “right thing” and should avoid bunching. Carefully evaluate any proposed algorithms to ensure that the bunching-near-poles problem is avoided.)
it is better to use spherical coordinates and convert it to cartesian coordinates:
coneDirtheta = rand(1) * 2 * pi;
coneDirphi = rand(1) * pi;
coneAngle = 45;
N = 1000;
%perfom transformation preventing concentration of points around the pole
rpolar = acos(cos(coneAngle/2*pi/180) + (1-cos(coneAngle/2*pi/180)) * rand(N, 1));
thetapolar = rand(N,1) * 2 * pi;
x0 = rpolar .* cos(thetapolar);
y0 = rpolar .* sin(thetapolar);
theta = coneDirtheta + x0;
phi = coneDirphi + y0;
r = rand(N, 1);
x = r .* cos(theta) .* sin(phi);
y = r .* sin(theta) .* sin(phi);
z = r .* cos(phi);
scatter3(x,y,z)
if all points should be of length 1 set r = ones(N,1);
Edit:
since intersection of cone with sphere forms a circle first we create random points inside a circle with raduis of (45 / 2) in polar coordinates and as #Ahmed Fasih commented to prevent concentration of points near the pole we should first transform this random points, then convert polar to cartesian 2D coordinates to form x0 and y0
we can use x0 and y0 as phi & theta angle of spherical coordinates and add coneDirtheta & coneDirphi as offsets to these coordinates.
then convert spherical to cartesian 3D coordinates

Graphically represent density of iterations

Kind all,
I am working in MATLAB and I'm using Monte Carlo techniques to fit a model. Basically, if we assume that my model is a simple function such as
y=m*x^2+c
And that both my parameters m and c vary between 0.5 and 10, I may randomly draw from such a parameter space and obtain each time a new y. If I plot all my realizations of y I obtain something similar to the following figure:
Is there a way to represent the DENSITY of the realizations? I mean, is there a way (instead of plotting all the realizations) to obtain some kind of contour plot that lies between the minimum of my iterations and the maximum for which its color represents the amount of realizations that fall within a certain interval?
Thanks all!
This isn't very pretty, but you could vary the parameters and play with the scatter/plotting, to make it a bit more visually appealing.
Also I assumed a gaussian distribution instead of your random one (totally random coloring will give you a uniform density). Also this code could be optimized for speed.
n = 1000;
l = 100;
x = linspace(1, 10, l);
y = repmat(x.^2, n, 1);
c = repmat(normrnd(1, 1, n, 1), 1, l);
m = repmat(normrnd(1, 1, n, 1), 1, l);
y = y.*m + c;
p = plot(y', '.');
figure; hold on;
for i = 1:l
[N,edges,bin] = histcounts(y(:, i));
density = N./sum(N);
c = zeros(n, 3);
for j = 1:n
c(j, :) = [1-density(bin(j))/max(density), 1-density(bin(j))/max(density), 1-density(bin(j))/max(density)];
end
scatter(ones(n, 1)*x(i),y(:, i),[],c,'filled');
end
Gives
This creates a histogram of y values for every position in x, then calculates the probability density for each y-value and colors in the points. Here, the y-values for every position x are normalized individually, to color the points according to the overall density of the plot you need to renormalize.
You can calculate y for discrete points of x, while setting random values for c and m. Then using hist function you can find a "not-normalized density" of function values for a given x. You can then normalize it to get a real density of the values, so that the overall area under the distribution curve sums up to 1.
In order to visualize it, you construct a mesh grid [X, Y] along the values of x and y and put the density values as Z. Now you can either plot the surf or its contour plot.
Here is the code:
clear;
n = 1000000; %number of simulation steps
%parameter ranges
m_min = 0.5; m_max = 10;
c_min = 0.5; c_max = 10;
%x points
x_min = 1; x_max = 4; x_count = 100;
x = linspace(x_min, x_max, x_count);
x2 = x.^2;
y_min = 0; y_max = m_max*x_max*x_max + c_max; y_step = 1;
m = rand(n, 1)*(m_max - m_min) + m_min;
c = rand(n, 1)*(c_max - c_min) + c_min;
c = repmat(c, 1, x_count);
y = m*x2 + c;
x_step = (x_max- x_min)/(x_count-1);
[X, Y] = meshgrid(x_min:x_step:x_max, y_min-y_step:y_step:y_max+y_step);
Z = zeros(size(X));
bins = y_min:y_step:y_max;
for i=1:x_count
[n_hist,y_hist] = hist(y(:, i), bins);
%add zeros on both sides to close the profile
n_hist = [0 n_hist 0];
y_hist = [y_min-y_step y_hist y_max+y_step];
%normalization
S = trapz(y_hist,n_hist); %area under the bow
n_hist = n_hist/S; %scaling of the bow
Z(:, i) = n_hist';
end
surf(X, Y, Z, 'EdgeColor','none');
colormap jet;
xlim([x_min x_max]);
ylim([y_min y_max]);
xlabel('X');
ylabel('Y');
figure
contour(X,Y,Z, 20);
colormap jet;
colorbar;
grid on;
title('Density as function of X');
xlabel('X');
ylabel('Y');
Another interesting view is a plot of each section depending on the x value:
Here is the code for this plot:
clear;
n = 1000000; %number of simulation steps
%parameter ranges
m_min = 0.5; m_max = 10;
c_min = 0.5; c_max = 10;
%x points
x_min = 1; x_max = 4; x_count = 12;
x = linspace(x_min, x_max, x_count);
x2 = x.^2;
m = rand(n, 1)*(m_max - m_min) + m_min;
c = rand(n, 1)*(c_max - c_min) + c_min;
c = repmat(c, 1, x_count);
y = m*x2 + c;
%colors for the plot
colors = ...
[ 0 0 1; 0 1 0; 1 0 0; 0 1 1; 1 0 1; 0 0.75 0.75; 0 0.5 0; 0.75 0.75 0; ...
1 0.50 0.25; 0.75 0 0.75; 0.7 0.7 0.7; 0.8 0.7 0.6; 0.6 0.5 0.4; 1 1 0; 0 0 0 ];
%container for legend entries
legend_list = cell(1, x_count);
for i=1:x_count
bin_number = 30; %number of histogramm bins
[n_hist,y_hist] = hist(y(:, i), bin_number);
n_hist(1) = 0; n_hist(end) = 0; %set first and last values to zero
%normalization
S = trapz(y_hist,n_hist); %area under the bow
n_hist = n_hist/S; %scaling of the bow
plot(y_hist,n_hist, 'Color', colors(i, :), 'LineWidth', 2);
hold on;
legend_list{i} = sprintf('Plot of x = %2.2f', x(i));
end
xlabel('y');
ylabel('pdf(y)');
legend(legend_list);
title('Density depending on x');
grid on;
hold off;

In matlab, how to use k means to make 30 clusters with circle around each cluster and mark the center?

In matlab, if I have a code which draws a circle and generates 100 random points inside it. I want to use k means to cluster these 100 points into 30 clusters with a circle around each cluster to differentiate between the clusters and i want to mark the center if each cluster.this is the code of the circle and the 100 random points inside it . Any help please ?
%// Set parameters
R =250; %// radius
C = [0 0]; %// center [x y]
N = 100; %// number of points inside circle
%// generate circle boundary
t = linspace(0, 2*pi,100);
x = R*cos(t) + C(1);
y = R*sin(t) + C(2);
%// generate random points inside it
th = 2*pi*rand(N,1);
r = R*randnlimit(0, 1, 0.5, 1, [N 1]);
xR = r.*cos(th) + C(1);
yR = r.*sin(th) + C(2);
%// Plot everything
figure(1), clf, hold on
% subplot(1,N0,1);
plot(x,y,'b');
hold on
text(0,0,'C')
plot(xR,yR,'p')
axis equal
zR=cell(N,1);
for i=1:N
zR{i,1}= [xR(i) yR(i)];
end
m=cell2mat(zR);
function clusterCircle()
%// Set parameters
R = 250; %// radius
C = [0 0]; %// center [x y]
N = 100; %// number of points inside circle
k = 30; %// number of clusters
%// generate circle boundary
t = linspace(0, 2*pi, 100);
x = R*cos(t) + C(1);
y = R*sin(t) + C(2);
%// generate random points inside it
th = 2*pi*rand(N,1);
r = R*randnlimit(0, 1, 0.5, 1, [N 1]);
xR = r.*cos(th) + C(1);
yR = r.*sin(th) + C(2);
%// some simple k-means:
% initial centroids:
% -> use different method, if k > N
% -> can be done more reasonable (e.g. run k-Means for different
% seeds, select seeds equidistant, etc.)
xC = xR(1:k)';
yC = yR(1:k)';
% run:
clusters = zeros(N,1);
clusters_old = ones(N,1);
while sum((clusters - clusters_old).^2) > 0
clusters_old = clusters;
[~,clusters] = min((bsxfun(#minus,xR,xC)).^2 + ...
(bsxfun(#minus,yR,yC)).^2 , [] , 2);
for kIdx = 1:k
xC(kIdx) = mean(xR(clusters==kIdx));
yC(kIdx) = mean(yR(clusters==kIdx));
end
end
%// Plot everything
figure(1);
clf;
hold on;
% -> plot circle and center
text(C(1),C(2),'C');
plot(x,y,'k');
% -> plot clusters
co = hsv(k);
for kIdx = 1:k
% plot cluster points
plot(xR(clusters==kIdx),yR(clusters==kIdx),'p','Color',co(kIdx,:));
% plot cluster circle
maxR = sqrt(max((xR(clusters==kIdx)-xC(kIdx)).^2 + ...
(yR(clusters==kIdx)-yC(kIdx)).^2));
x = maxR*cos(t) + xC(kIdx);
y = maxR*sin(t) + yC(kIdx);
plot(x,y,'Color',co(kIdx,:));
% plot cluster center
text(xC(kIdx),yC(kIdx),num2str(kIdx));
end
axis equal
end
%// creates random numbers, not optimized!
function rn = randnlimit(a,b,mu,sigma,sz)
rn = zeros(sz);
for idx = 1:prod(sz)
searchOn = true;
while searchOn
rn_loc = randn(1) * sigma + mu;
if rn_loc >= a && rn_loc <= b
searchOn = false;
end
end
rn(idx) = rn_loc;
end
end

MATLAB Rotate and move 2d object in the same time

I made star using this code:
t = 0:4/5*pi:4*pi;
x = sin(t);
y = cos(t);
star = plot(x, y);
axis([-1 11 -1 11])
Now I need to rotate and move this star at the same time. I tried this:
for i=1:0.1:10;
zAxis = [0 0 1];
center = [0 0 0];
rotate(star, zAxis, 5, center);
x = x+0.1;
y = y+0.1;
set(star, 'x', x, 'y', y);
pause(0.1);
end
But this code only moves star and doesn't rotate it. If I delete "set" command then it rotates. How can I combine those two actions?
This can do the job..
t = 0:4/5*pi:4*pi;
x = sin(t);
y = cos(t) ;
y = y-mean(y);
x = x-mean(x); % # barycentric coordinates
% # rotation and translation
trasl = #(dx,dy) [dy; dx]; % # this vector will be rigidly added to each point of the system
rot = #(theta) [cos(theta) -sin(theta); sin(theta) cos(theta)]; % # this will provide rotation of angle theta
for i = 1:50
% # application of the roto-translation
% # a diagonal translation of x = i*.1 , y = i*.1 is added to the star
% # once a rotation of angle i*pi/50 is performed
x_t = bsxfun(#plus,rot(i*pi/50)*([x;y]), trasl(i*.1,i*.1) );
star = plot(x_t(1,:), x_t(2,:));
axis([-1 11 -1 11])
pause(.1)
end
In principle, homogeneous coordinates (in this case in the 2D projective space) allow one to do the same job in a neater way; in fact, they would allow one to use just one linear operator (3x3 matrix).
Homogeneous coordinates version:
Op = #(theta,dx,dy) [ rot(theta) , trasl(dx,dy) ; 0 0 1];
for i = 1:50
x_t = Op(i*pi/50,i*.1,i*.1)*[x;y;ones(size(x))];
star = plot(x_t(1,:), x_t(2,:));
axis([-1 11 -1 11])
pause(.1)
end
You can just use a rotation matrix to compute the correct transformation on the vectors [x; y]:
theta = 5 * (pi / 180); % 5 deg in radians
Arot = [cos(theta) -sin(theta); sin(theta) cos(theta)];
xyRot = Arot * [x; y]; % rotates the points by theta
xyTrans = xyRot + 0.1; % translates all points by 0.1
set(star, 'x', xyTrans(1, :), 'y', xyTrans(2, :));