Related
I have the following code to generate a PRM map that will be used for A* application. There exist 2 problems with the code
It keeps the blue lines representing the original PRM where lines can cross over obstacles. I don't want to keep the blue lines but I couldn't find the way to remove them.
The green lines are going over obstacles even though they shouldn't
The code is as follows
clc;
clear all;
close all;
seed = 123512;
rng(seed);
xaxis = 100;
yaxis = 100;
obstacles = false(xaxis,yaxis);
[X,Y] = meshgrid(1:xaxis,1:yaxis);
obstacles(50:75,50:75) = true;
obstacles(25:35,30:40) = true;
obstacles(25:35,60:80) = true;
figure;
imshow(~obstacles,"InitialMagnification",1000);
axis([0 xaxis 0 yaxis]);
axis xy;
axis on;
%PRM PARAMETERS
max_nodes_connect = 4;
max_connect_len = 40;
segments = 1;
max_nodes_grid = 30;
skipped = 0;
%PRM ALGO
nodes = 0; %Counter
map = zeros(size(obstacles)); %generate map
map(obstacles) = 1; %put the obstacles
Graph_connections = Inf(max_nodes_grid,max_nodes_connect + 1); %rows = # nodes cols = ID and neighbors
while (nodes < max_nodes_grid)
node_x = randi(xaxis);
node_y = randi(yaxis);
if(map(node_y,node_x)==1 || map(node_y,node_x)==2)
continue;
end
nodes = nodes + 1; %a valid node generated
map(node_y,node_x) = 2; %2 means there exists a node at that location
hold on
scatter(node_x,node_y,"red","filled")
%NODES TO CONNECT
nodes_to_connect = [];
distances = [];
for i= 1:numel(Graph_connections(:,1))
if(Graph_connections(i,1)==Inf)
break
end
[row,col] = ind2sub(size(map),Graph_connections(i,1));
%Check if within range
if(norm([node_y,node_x]-[row,col])>max_connect_len)
continue;
end
line_on_obstacle = check_obstacle(map,node_x,node_y,row,col);
%Check if obstacle thru line HAS TO BE WRITTEN
if(line_on_obstacle)
disp("Check Obstacle: " + line_on_obstacle);
skipped = skipped + 1;
continue;
end
nodes_to_connect = [nodes_to_connect, Graph_connections(i,1)];
distances = [distances; [Graph_connections(i,1),norm([node_y,node_x]-[row,col])]];
end
Graph_connections(nodes,1) = sub2ind(size(map),node_y,node_x);
if(size(distances)>0)
sorted_distances = sortrows(distances,2);
for i = 1:min(max_nodes_connect,size(sorted_distances,1))
Graph_connections(nodes,i+1) = sorted_distances(i,1);
[row,col] = ind2sub(size(map),sorted_distances(i,1));
if(line_on_obstacle==false)
disp("Line is not on obstacle")
hold on
plot([node_x,col],[node_y,row],"green","LineWidth",1.5);
continue;
else
disp("Line is on obstacle: " + [node_x,col] + " " + [node_y,row]);
break;
end
end
disp("==========================")
end
end
function on_line = check_obstacle(map,node_x,node_y,row,col)
on_line = 0;
my_line = line([node_x,col],[node_y,row]);
line_spacing = max(abs(my_line.XData(1) - my_line.XData(2))+1,abs(my_line.XData(1) - my_line.XData(2))+1);
x_coordinates_line = round(linspace(my_line.XData(1),my_line.XData(2),line_spacing));
y_coordinates_line = round(linspace(my_line.YData(1),my_line.YData(2),line_spacing));
for i = 1:line_spacing
if(map(x_coordinates_line(i),y_coordinates_line(i))==1)
disp("ON OBSTACLE: " + x_coordinates_line(i) + " " + y_coordinates_line(i));
on_line = true;
break;
end
end
end
The check_obstacle function is used to check if the points on the line are in the boundaries of obstacles. What am I missing here?
close all;clear all;clc
format short
nx=100;ny=100; % grid size
[X,Y]=meshgrid(1:nx,1:ny);
Nobst=3 % amount obstacles
Nnet=30 % amount net points
Dmax=100 % net segment max length
% OBSTACLES
% define obstacles.
% Following are as defined in question
P1=[50 50; 75 50; 75 75; 50 75; 50 50];
P2=[25 30; 25 40; 35 40; 35 30; 25 30];
P3=[25 60; 25 80; 35 80;35 60;25 60];
% obstacle points all in one array
Pobst=[P1(:);P2(:);P3(:)];
Pobst=reshape(Pobst,[size(P1,1),size(P1,2),Nobst]);
% plot obstacles
hp=[]
figure(1)
ax=gca
hp=patch(squeeze(Pobst(:,1,:)),squeeze(Pobst(:,2,:)),[.5 .5 .5])
axis([1 nx 1 ny]);grid on
hp.EdgeAlpha=0;
ax.DataAspectRatio=[1 1 1]
hold(ax,'on')
% obstacle segments list : [x1 y1 x2 y2 d(X1,Y1)]
Lobst1=[]
for k=2:1:size(P1,1)
Lobst1=[Lobst1; [P1(k-1,:) P1(k,:) ((P1(k-1,1)-P1(k,1))^2+(P1(k-1,2)-P1(k,2))^2)^.5]];
end
Lobst2=[]
for k=2:1:size(P2,1)
Lobst2=[Lobst2; [P2(k-1,:) P2(k,:) ((P2(k-1,1)-P2(k,1))^2+(P2(k-1,2)-P2(k,2))^2)^.5]];
end
Lobst3=[]
for k=2:1:size(P3,1)
Lobst3=[Lobst3; [P3(k-1,:) P3(k,:) ((P3(k-1,1)-P3(k,1))^2+(P3(k-1,2)-P3(k,2))^2)^.5]];
end
Lobst=[Lobst1;Lobst2;Lobst3]
%% NETWORK
% all grid points outside obstacles
[in1,on1]=inpolygon(X(:),Y(:),P1(:,1),P1(:,2));
[in2,on2]=inpolygon(X(:),Y(:),P2(:,1),P2(:,2));
[in3,on3]=inpolygon(X(:),Y(:),P3(:,1),P3(:,2));
Xout=X(~in1 & ~in2 & ~in3);Yout=Y(~in1 & ~in2 & ~in3);
% plot(ax,Xout,Yout,'og','LineStyle','none') % check
% choose Nnet points outside obstacles
nP2=randi([1 numel(Xout)],Nnet,1);
Pnet=[Xout(nP2) Yout(nP2)];
plot(ax,Pnet(:,1),Pnet(:,2),'or','LineStyle','none')
% net segments list [x1 y1 x2 y2 d(X2,Y2) 0/1] 6th column [0 1] 1: draw 0: do not draw
nLnet=nchoosek([1:size(Pnet,1)],2);
Lnet=[Pnet(nLnet(:,1),1) Pnet(nLnet(:,1),2) ... % segment 1st point
Pnet(nLnet(:,2),1) Pnet(nLnet(:,2),2) ... % segment 2nd point
((Pnet(nLnet(:,1),1)-Pnet(nLnet(:,1),2)).^2+(Pnet(nLnet(:,2),1)+Pnet(nLnet(:,2),2)).^2).^.5 ... % segment length
ones(size(nLnet,1),1)];
% check all net links are plotted
for k=1:1:size(Lnet,1)
plot(ax,[Lnet(k,1) Lnet(k,3)],[Lnet(k,2) Lnet(k,4)],'b');
hold(ax,'on')
end
% remove segments longer than Dmax
Lnet=sortrows(Lnet,5,'descend');
[~,n1]=max(Lnet(:,5)<=Dmax);
Lnet(1:n1-1,:)=[];
for k=1:1:size(Lnet,1)
plot(ax,[Lnet(k,1) Lnet(k,3)],[Lnet(k,2) Lnet(k,4)],'r');
hold(ax,'on')
end
%%
Redrawing and NOT removing net segments longer than Dmax
close all
hp=[]
figure(1)
ax=gca
hp=patch(squeeze(Pobst(:,1,:)),squeeze(Pobst(:,2,:)),[.5 .5 .5])
axis([1 nx 1 ny]);grid on
hp.EdgeAlpha=0;
ax.DataAspectRatio=[1 1 1]
hold(ax,'on')
plot(ax,Pnet(:,1),Pnet(:,2),'or','LineStyle','none')
Lnet=[Pnet(nLnet(:,1),1) Pnet(nLnet(:,1),2) ... % segment 1st point
Pnet(nLnet(:,2),1) Pnet(nLnet(:,2),2) ... % segment 2nd point
((Pnet(nLnet(:,1),1)-Pnet(nLnet(:,1),2)).^2+(Pnet(nLnet(:,2),1)+Pnet(nLnet(:,2),2)).^2).^.5 ... % segment length
ones(size(nLnet,1),1)];
% check what pair segments intersect
for k2=1:1:size(Lnet,1)
allclear=ones(1,size(Lobst,1));
% allclear=zeros(1,size(Lobst,1));
for k1=1:1:size(Lobst,1)
% segments are contained in lines : check lines intersect
x1o=Lobst(k1,1);y1o=Lobst(k1,2);x2o=Lobst(k1,3);y2o=Lobst(k1,4);
x1n=Lnet(k2,1);y1n=Lnet(k2,2);x2n=Lnet(k2,3);y2n=Lnet(k2,4);
x1=x1o;x2=x2o;y1=y1o;y2=y2o;
x3=x1n;x4=x2n;y3=y1n;y4=y2n;
% t1 : x parameter
t1=((x1-x3)*(y3-y4)-(y1-y3)*(x3-x4))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
xp=x1+t1*(x2-x1); % xp : crossing x coordinage
% u1 : y parameter
u1=-((x1-x2)*(y1-y3)-(y1-y2)*(x1-x3))/((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4));
yp=y1+t1*(y2-y1); % yp : crossing y coordinate
% checks
plot(ax,x1o,y1o,'c*');plot(ax,x2o,y2o,'c*');plot(ax,[x1o x2o],[y1o y2o],'c')
plot(ax,x1n,y1n,'m*');plot(ax,x2n,y2n,'m*'); % plot(ax2,[x1n x2n],[y1n y2n],'m')
m1o=(y2o-y1o)/(x2o-x1o); % slopes
m2n=(y2n-y1n)/(x2n-x1n) ;
if (t1>=0 && t1<=1 && u1>=0 && u1<=1) && ...
(xp>=0 || xp<=nx || yp>=0 || yp<=ny)
allclear(k1)=0; % then do not plot this segment
end
end
if sum(allclear)==size(Lobst,1) %k2-th net segment hits no obstacles
plot(ax,x1n,y1n,'m*');plot(ax,x2n,y2n,'m*');plot(ax,[x1n x2n],[y1n y2n],'m')
elseif sum(allclear)~=size(Lobst,1)
Lnet(k2,end)=0;
end
end
Comments
1.- Note I have added format short because with format long there is decimal accretion right at the bottom of a few intersection points, that believe it or not, cause some false results.
2.- I like Torsen's explanation to find line segment intersections available here.
3.- There are faster ways to implement the main loop, but I make it go through all net-segment vs obstacle-element in case you may need it this way, to for instance count hits.
4.- There's also room for improvement in the way Lobst is generated.
5.- These lines
x1=x1o;x2=x2o;y1=y1o;y2=y2o;
x3=x1n;x4=x2n;y3=y1n;y4=y2n;
it's just an easy way to plug in formulation to already written lines, reducing amount variables is also left for next version.
I want to create a relative axis in Matlab like the $\Delta I$-rulers in the following plot.
Before I start writing up a function that constructs it manually, I would like to know if there's way of creating an object with the NumericRuler-properties (like the default axes of a figure())
So I ended up using the link provided by Sardar Usama's comment as inspiration and wrote a function to create an axes-object relative to the values of a "parent"-axes:
function ax = create_value_axes(hAx, pos)
%% ax = create_value_axes(hAx, pos)
%
% Create axes at the value points of hAx.
%
% pos(1) = x-position
% pos(2) = y-position
% pos(3) = x-width
% pos(4) = y-width
%
% Get "parent" position and value limits
hAx_pos = hAx.Position;
hAx_xlm = hAx.XLim;
hAx_ylm = hAx.YLim;
% Get relative position increment pr value increment
x_step = hAx_pos(3) / (hAx_xlm(2) - hAx_xlm(1));
y_step = hAx_pos(4) / (hAx_ylm(2) - hAx_ylm(1));
% Set position
subaxes_abs_pos(1) = (pos(1)-hAx_xlm(1)) * x_step + hAx_pos(1);
subaxes_abs_pos(2) = (pos(2)-hAx_ylm(1)) * y_step + hAx_pos(2);
subaxes_abs_pos(3) = pos(3) * x_step;
subaxes_abs_pos(4) = pos(4) * y_step;
% Create axes
ax = axes('Position', subaxes_abs_pos);
% Remove background
ax.Color = 'none';
end
Sidenote: I found that I didn't need plotboxpos to get the correct positions of the "parent"-axes, using Matlab r2019b on macOS Mojave 10.14.6
Anyway, this is what I end up with:
Using the code:
% Just some random data
mockup_data_ild = [-10 -7 -4 0 4 7 10];
mockup_data_itd_45 = [-40 -20 -10 0 10 20 40];
mockup_data_itd_60 = [-30 -15 -5 0 5 15 30];
% Create figure
figure('Color', 'w')
x_axis_offset = [0 30];
hold on
% Plot 45 dB result
p1 = plot_markers(x_axis_offset(1) + mockup_data_ild, mockup_data_itd_45, ii);
% Plot 60 dB results
p2 = plot_markers(x_axis_offset(2) + mockup_data_ild, mockup_data_itd_60, ii);
p2.Color = p1.Color;
p2.HandleVisibility = 'off';
hold off
% Set axes properties
ax = gca;
ax.XAxis.TickValues = [x_axis_offset(1) x_axis_offset(2)];
ax.XAxis.TickLabels = {'45 dB' '60 dB'};
ax.XAxis.Limits = [x_axis_offset(1)-15 x_axis_offset(2)+15];
ax.XAxisLocation = 'top';
ax.YAxis.Limits = [-80 100];
ax.YAxis.Label.String = 'Interaural Time Difference, \Deltat, in samples';
ax.YGrid = 'on';
% Create 45 dB axis
ax2 = create_DeltaI_axis(ax, x_axis_offset(1));
% Create 60 dB axis
ax3 = create_DeltaI_axis(ax, x_axis_offset(2));
% Create legend
leg = legend(ax, {'P1'});
leg.Location = 'northwest';
%% Helpers
function ax = create_DeltaI_axis(hAx, x_pos)
y_pos = -70;
y_height = 170;
range = 20;
ax = create_value_axes(hAx, [x_pos-range/2 y_pos range y_height]);
ax.XAxis.TickValues = [0 .25 .5 .75 1];
ax.XAxis.TickLabels = {'-10'
'-5'
'0'
'5'
'10'};
ax.XAxis.Label.String = '\DeltaI';
ax.XGrid = 'on';
ax.XMinorGrid = 'on';
ax.YAxis.Visible = 'off';
end
function p = plot_markers(x, y, ii)
markers = {'square','^', 'v', 'o', 'd'};
p = plot(x, y);
p.LineWidth = 1.5;
p.LineStyle = 'none';
p.Marker = markers{ii};
end
I want to find Orientation, MajorAxisLengthand MinorAxisLength of contour which is plotted with below code.
clear
[x1 , x2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [1,3];
sigm = [2,0;0,2];
xx_size = length(mu);
tem_matrix = ones(size(x1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {x1,x2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(x1));
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
% regionprops(z_plat,'Centroid','Orientation','MajorAxisLength','MinorAxisLength');
In my opinion, I may have to use regionprops command but I don't know how to do this. I want to find direction of axis of contour and plot something like this
How can I do this task? Thanks very much for your help
Rather than trying to process the graphical output of contour, I would instead recommend using contourc to compute the ContourMatrix and then use the x/y points to estimate the major and minor axes lengths as well as the orientation (for this I used this file exchange submission)
That would look something like the following. Note that I have modified the inputs to contourc as the first two inputs should be the vector form and not the output of meshgrid.
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
% 0 0 0
major_length = [ellipsedata.long_axis];
% 4.7175 3.3380 2.1539
minor_length = [ellipsedata.short_axis];
% 4.7172 3.3378 2.1532
As you can see, the contours are actually basically circles and therefore the orientation is zero and the major and minor axis lengths are almost equal. The reason that they look like ellipses in your post is because your x and y axes are scaled differently. To fix this, you can call axis equal
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
axis equal
Thank you #Suever. It help me to do my idea.
I add some line to code:
clear
[X1 , X2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [-1,0];
a = [3,2;1,4];
a = a * a';
sigm = a;
xx_size = length(mu);
tem_matrix = ones(size(X1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {X1,X2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(X1));
figure;contour(X1, X2, z_plat,3, 'LineWidth', 2,'color','m');
hold on;
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
major_length = [ellipsedata.long_axis];
minor_length = [ellipsedata.short_axis];
tet = orientations(1);
x1 = mu(1);
y1 = mu(2);
a = sin(tet) * sqrt(major_length(1));
b = cos(tet) * sqrt(major_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);
tet = ( pi/2 + orientations(1) );
a = sin(tet) * sqrt(minor_length(1));
b = cos(tet) * sqrt(minor_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);
I tried to write an animation code in Matlab that repeats itself in every two seconds. The core animation scheme is as below:
Please take care the gif is repeating the core animation, originally there is only one cycle.
Here is the code:
% Figure settings
h= figure(2);
set(h, 'Position', [100 50 1200 750])
set(h,'Toolbar','None','Menubar','None')
set(h,'Name','Animation')
set(gcf,'doublebuffer','off');
set(gca, 'xlimmode','manual','ylimmode','manual','zlimmode','manual',...
'climmode','manual','alimmode','manual');
xlim([-200 1350])
ylim([-250 800])
set(gca,'xtick',[],'ytick', [], 'Position', [0 0 1 1]);
%Parameters
diameter = 60; %spot çapı
RamanX = 350; %ölçüm noktssı x konumu
nOfSpots = 4; %spot sayısı
spotCount = 0; %toplam spot sayısı
initPos = [50 150;50 300; 50 450; 50 600]; %konum 1
posII = [350 150;350 300; 350 450; 350 600]; %konum 2
Choice = rand(1,4)<.5; %Ölçüm sonunda verilen karar
deltaY2 = 100; % spotlar arası mesafe
x11 = zeros(nOfSpots,2);
x22 = zeros(nOfSpots,2);
x22a = zeros(nOfSpots,2);
x22b = zeros(nOfSpots,2);
for i=1:nOfSpots
x11(i,:) = [RamanX 150*(i-1)];
x22(i,:) = [800 50+deltaY2*(i-1)];
end
for i=1:nOfSpots/2
x22a(2*i-1,:) = [1280 -270+250*(i-1)];
x22a(2*i,:) = [1075 -270+250*(i-1)];
x22b(2*i-1,:) = [1280 220+250*(i-1)];
x22b(2*i,:) = [1075 220+250*(i-1)];
end
%Add 4 Circles to initial position
for i=1:nOfSpots
% Drag & Drop elipsler yerleştiriliyor
spot(i) = imellipse(gca, [initPos(i,1),initPos(i,2),diameter,diameter]);
spotCount = spotCount+1;
%elips özellikleri
setFixedAspectRatioMode(spot(spotCount), 'TRUE');
setResizable(spot(spotCount),0);
posSpot(spotCount,:) = getPosition(spot(i));
end
%Move Circles to posII
r = sqrt(sum(bsxfun(#minus,posII(:,1),initPos(:,1)).^2,2));
v = 30;
stepsize = ceil(r/v);
xstep = (posII(:,1)-initPos(:,1))/stepsize;
for i=1:stepsize
for j=1:nOfSpots
setPosition(spot(j), [initPos(j,1)+xstep(j)*i, initPos(j,2), diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
pause(0.15)
end
%Move Circles to posIII
velocity = 30;
r2a = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2a = max(ceil(r2a/velocity));
r2b = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2b = max(ceil(r2b/velocity));
% Eğer öllçüm seçimi 1 ise taşı
for i=1:nOfSpots
if(Choice(i))
xstep2(i) = (x22a(i,1)-x11(i,1))./stepsize2a;
ystep2(i) = (x22a(i,2)-x11(i,2))./stepsize2a;
else
xstep2(i) = (x22b(i,1)-x11(i,1))./stepsize2b;
ystep2(i) = (x22b(i,2)-x11(i,2))./stepsize2b;
end
end
stepsize2 = max([stepsize2a stepsize2b]);
% Eğer ölçüm seçimi 0 ise taşı
for i=1:stepsize2
for j=1:nOfSpots
if(Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
pause(0.15)
end
for i=1:stepsize2
for j=1:nOfSpots
if(~Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
pause(0.15)
end
if(spotCount > 0)
for i=1:4
delete(spot(i))
end
end
The code doing this is a script not a function, say "animation.m". Now I am trying repeat this code in every 2 seconds. I tried to use loops with tic - toc commands, but the loop does not go to other cycle before finishing "animation.m". I need to get it work in the background.
One of my friend suggested me to use trigger. But, honestly, I could not apply the trigger command for my code even when I functionalized it.
Any help?
Edit:
The graphical flow chart of the problem is below:
I created an example that shows how it could be done.
Modifying your code, to draw just "one animated step" was too much work.
I decided to used your code to create all frames from advance (for example purpose).
I guess you are going to realize, that implementing background animation in Matlab is more difficult than you thought (unless I missed some hidden Matlab feature).
Matlab has very limited threading support, so I used a periodic timer.
My code sample does the following:
Build animation - create a cell array of all animated images.
You should avoid it, because it takes to much time (and memory).
I used it instead of modifying your code to draw one animated image.
Setup a periodic timer object with 0.2 seconds period (0.2 as an example).
I added a loop that illustrates the foreground processing (calculating sin(x) as an example).
Notice: I added small pause in the "foreground processing" loop.
The timer invokes a callback function every 0.2 seconds.
In the callback function the next animated frame is shown.
The timer is used for simulating a background execution.
You should replace the imshow, with your "animation step" function, that draws the frame (instead of showing a frame created from advance).
Here is the code sample (with your modified code included):
function TimerAnimation()
%Build set of images for animation.
[h_figure, Frames] = BuildAnimation();
t = timer;
t.TimerFcn = #timerFcn_Callback; %Set timer callback function
t.ExecutionMode = 'fixedRate'; %Set mode to "singleShot" - execute TimerFcn only once.
t.StartDelay = 0.1; %Wait 0.1 second from start(t) to executing timerFcn_Callback.
t.Period = 0.2; %Set period to 0.2 seconds.
%Turn on figure visibility
set(h_figure, 'Visible', 'on');
frame_counter = 1;
start(t) %Start timer;
%Do some other job...
%The animation is executed in the background (kind of in the background).
for x = 1:20000
y = sin(x/10000); %Calculate somthing...
if (mod(x, 100) == 0)
disp(['sin(', num2str(x/10000), ') = ', num2str(y)]); %Display somthing...
end
if (~isvalid(h_figure))
%Break loop if user closed the animation figure.
break;
end
%Must insert pause to "tight loop", allowing animation to run.
pause(0.01);
end
stop(t) %Stop timer;
delete(t); %Delete timer object.
if (~isvalid(h_figure))
close(h_figure);
end
%Timer function is executed every period of 0.2 seconds.
function timerFcn_Callback(mTimer, ~)
%Increse animation frame counter.
%figure(h_figure); %Set fo h_figure to be active figure.
h_axes = get(h_figure, 'CurrentAxes'); %Get axes of h_figure
imshow(Frames{frame_counter}, 'Parent', h_axes); %Display frame number frame_counter.
drawnow; %Force refresh.
frame_counter = mod(frame_counter, length(Frames)) + 1; %Advance to next frame (cyclically).
end
end
function [h, Frames] = BuildAnimation()
%Build set of images for animation.
%h - return handle to figure
%Frames - return cell array of animation images.
counter = 1;
% Figure settings
%h = figure(2);
%Create invisible figure.
h = figure('Visible', 'off');
set(h, 'Position', [100 50 1200 750])
set(h,'Toolbar','None','Menubar','None')
set(h,'Name','Animation')
set(gcf,'doublebuffer','off');
set(gca, 'xlimmode','manual','ylimmode','manual','zlimmode','manual',...
'climmode','manual','alimmode','manual');
xlim([-200 1350])
ylim([-250 800])
set(gca,'xtick',[],'ytick', [], 'Position', [0 0 1 1]);
%Parameters
diameter = 60; %spot ?ap?
RamanX = 350; %?l??m noktss? x konumu
nOfSpots = 4; %spot say?s?
spotCount = 0; %toplam spot say?s?
initPos = [50 150;50 300; 50 450; 50 600]; %konum 1
posII = [350 150;350 300; 350 450; 350 600]; %konum 2
Choice = rand(1,4)<.5; %?l??m sonunda verilen karar
deltaY2 = 100; % spotlar aras? mesafe
x11 = zeros(nOfSpots,2);
x22 = zeros(nOfSpots,2);
x22a = zeros(nOfSpots,2);
x22b = zeros(nOfSpots,2);
for i=1:nOfSpots
x11(i,:) = [RamanX 150*(i-1)];
x22(i,:) = [800 50+deltaY2*(i-1)];
end
for i=1:nOfSpots/2
x22a(2*i-1,:) = [1280 -270+250*(i-1)];
x22a(2*i,:) = [1075 -270+250*(i-1)];
x22b(2*i-1,:) = [1280 220+250*(i-1)];
x22b(2*i,:) = [1075 220+250*(i-1)];
end
%Add 4 Circles to initial position
for i=1:nOfSpots
% Drag & Drop elipsler yerle?tiriliyor
spot(i) = imellipse(gca, [initPos(i,1),initPos(i,2),diameter,diameter]);
spotCount = spotCount+1;
%elips ?zellikleri
setFixedAspectRatioMode(spot(spotCount), 'TRUE');
setResizable(spot(spotCount),0);
posSpot(spotCount,:) = getPosition(spot(i));
end
%Move Circles to posII
r = sqrt(sum(bsxfun(#minus,posII(:,1),initPos(:,1)).^2,2));
v = 30;
stepsize = ceil(r/v);
xstep = (posII(:,1)-initPos(:,1))/stepsize;
for i=1:stepsize
for j=1:nOfSpots
setPosition(spot(j), [initPos(j,1)+xstep(j)*i, initPos(j,2), diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
%pause(0.15)
%Get frame, convert frame to image, and store image in Frames
Frames{counter} = frame2im(getframe(h));counter = counter + 1;
end
%Move Circles to posIII
velocity = 30;
r2a = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2a = max(ceil(r2a/velocity));
r2b = sqrt(sum(bsxfun(#minus,x22a,x11).^2,2));
stepsize2b = max(ceil(r2b/velocity));
% E?er ?ll??m se?imi 1 ise ta??
for i=1:nOfSpots
if(Choice(i))
xstep2(i) = (x22a(i,1)-x11(i,1))./stepsize2a;
ystep2(i) = (x22a(i,2)-x11(i,2))./stepsize2a;
else
xstep2(i) = (x22b(i,1)-x11(i,1))./stepsize2b;
ystep2(i) = (x22b(i,2)-x11(i,2))./stepsize2b;
end
end
stepsize2 = max([stepsize2a stepsize2b]);
% E?er ?l??m se?imi 0 ise ta??
for i=1:stepsize2
for j=1:nOfSpots
if(Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
% pause(0.15)
%Get frame, convert frame to image, and store image in Frames
Frames{counter} = frame2im(getframe(h));counter = counter + 1;
end
for i=1:stepsize2
for j=1:nOfSpots
if(~Choice(j))
setPosition(spot(j), [posII(j,1)+xstep2(j)*i, posII(j,2)+ystep2(j)*i, diameter, diameter] )
posSpot(spotCount,:) = getPosition(spot(j));
end
end
% pause(0.15)
%Get frame, convert frame to image, and store image in Frames
Frames{counter} = frame2im(getframe(h));counter = counter + 1;
end
if(spotCount > 0)
for i=1:4
delete(spot(i))
end
end
imshow(Frames{1})
end
Example for what I meant by "drawing just one animated step":
function TimerAnimation2()
%Initiazlie animation.
param = InitAnimation();
%Same code as in previous example.
t = timer;t.TimerFcn = #timerFcn_Callback;t.ExecutionMode = 'fixedRate';t.StartDelay = 0.1;t.Period = 0.2;start(t)
for x = 1:20000;if (~isvalid(param.h)), break;end;pause(0.01);end
stop(t);delete(t);if (isvalid(param.h)), close(param.h);end
%Timer function is executed every period of 0.2 seconds.
function timerFcn_Callback(mTimer, ~)
%Animation single step
param = StepAnimation(param);
end
end
function param = InitAnimation()
h = figure;
set(h, 'Position', [100 50 1200 750]);set(h,'Toolbar','None','Menubar','None');set(h,'Name','Animation');set(gcf,'doublebuffer','off');
set(gca, 'xlimmode','manual','ylimmode','manual','zlimmode','manual', 'climmode','manual','alimmode','manual');
xlim([-200 1350]);ylim([-250 800]);set(gca,'xtick',[],'ytick', [], 'Position', [0 0 1 1]);
%Initialize param struct (param struct keeps animation parameters).
param.h = h;
param.x = 10;
param.y = 10;
%Draw rectangle in position x, y
h_axes = get(param.h, 'CurrentAxes');
rectangle('Position', [param.x param.y 20 20], 'Parent', h_axes);
end
%Example fo single animation step
%Get exsiting animation param as input, and retuen updated param as output.
function param = StepAnimation(param)
h_axes = get(param.h, 'CurrentAxes');
%Update param (to be used in next StepAnimation).
param.x = param.x + 10;
param.y = param.y + 10;
if (param.x > 500), param.x = 10;end
if (param.y > 500), param.y = 10;end
%Draw rectangle in position x, y
rectangle('Position', [param.x param.y 20 20], 'Parent', h_axes)
drawnow; %Force refresh.
end
I'm trying to output Voronoi cells to a format which can be used for 3D printing.
MATLAB generates voronoi cells from lists of X and Y coordinates. My script generates such a list of points, but getting to a format I can export is seeming problematic.
My main hopes lie with stlwrite, http://www.mathworks.com/matlabcentral/fileexchange/20922-stlwrite-write-binary-or-ascii-stl-file
This function/script requires a surface to export.
function [lines, LineData, pOut] = makeSurfaceFromVorVerts(Lx, Ly, varargin)
p = inputParser;
addRequired(p,'Lx',...
#(x) (isequal(class(x),'double') && isequal(size(x,1),2)));
addRequired(p,'Ly',...
#(x) (isequal(class(x),'double') && isequal(size(x,1),2)));
defaultResolution = 100;
addOptional(p,'Resolution',defaultResolution,...
#(x) (isequal(class(x),'double') && isequal(size(x),[1 1])));
defaultBoundary = [0 110; 0 110];
addOptional(p,'Boundaries',defaultBoundary,...
#(x) (isequal(class(x),'double') && isequal(size(x),[2 2])));
parse(p,Lx,Ly,varargin{:});
pOut = p;
LX = p.Results.Lx;
LY = p.Results.Ly;
Bounds = p.Results.Boundaries;
% Strip high values
reducedXdat = [];
reducedYdat = [];
for i=1:size(LX,2)
if LX(1,i) > Bounds(1,1) && LX(1,i) < Bounds(1,2) && ... % X value of start of line
LX(2,i) > Bounds(2,1) && LX(2,i) < Bounds(2,2) && ... % Y value of start of line
LY(1,i) > Bounds(1,1) && LY(1,i) < Bounds(1,2) && ... % X value of end of line
LY(2,i) > Bounds(2,1) && LY(2,i) < Bounds(2,2), % Y value of end of line
reducedXdat = [reducedXdat, LX(:,i)];
reducedYdat = [reducedYdat, LY(:,i)];
end
end
% Initialise a grid of points
%sXnew = (Bounds(1,2) - Bounds(1,1)) * p.Results.Resolution;
%sYnew = (Bounds(2,2) - Bounds(2,1)) * p.Results.Resolution;
%Z = zeros(sXnew, sYnew,'uint8');
%for x=1:size(X,1)
% for y=1:size(Y,1)
% nX = floor(X(x)*p.Results.Resolution);
% nY = floor(Y(y)*p.Results.Resolution);
% Z(nX,nY) = 1;
% end
%end
%surface = Z;
%coords = [X,Y];
lines = line(reducedXdat,reducedYdat);
LineData = [reducedXdat; reducedYdat];
end
My processing script, above, takes the points generated by the command
[Lx, Ly] = voronoi(xValuesOfCellCentres, yValuesOfCellCentres);
along with an optional 'boundary' matrix (there's also a check for resolution, for the commented section) and then outputs lines.
I would like these lines to form the surface. I considered creating a mesh using a binary Z value (1 for points, 0 for everywhere else), but I don't know how I could also include the positions between points, ie those covered by the lines.
I expect that there is some relevant middle step I can take, to create a frame based on extrusion of the lines drawn (either by this script, which has cut away the extra lines to infinity, or by voronoi(X,Y), but I can't work it out.
Found a way to do this.
Changed the script, new script is pasted at the bottom.
Workflow goes:
Matlab (create line plot, then for i=1:size(lineHandles,1), set(lineHandles(i),'lineWidth',4),end). Change the line width as required.)
Save as .png file.
Gimp (crop file to a nice rectangle)
InkScape (open png file, click image, menu Path -> Trace Bitmap -> Color Quantization (2 colors) -> Drag the path aside (it shows path in the status bar at the bottom when you have this selected). Click image and delete. Place path (with nodes) back onto the page (there's an x/y coordinates setting in a toolbar at the top, set these both to 0.
Save as a .dxf file. To get these to input more nicely, use the extension provided at http://www.thingiverse.com/thing:14221. This should be installed by copying the .py and .inx files to /usr/share/inkscape/extensions (or similar)
Open in OpenSCAD using the command import("/path/to/filename.dxf");
This object can be extruded using the linear_extrude(height = x) where x is a height in mm (other lengths probably configurable)
Render using CGAL (F6 is the shortcut for this in OpenSCAD.)
Export to .stl file (menu Design > Export as STL...)
MATLAB script (edit as needed and take outputs as required, if you want the line handles you'll need to put in almost all of the output arguments (or reorder them):
%voronoiScriptHex generates voronoi cells in a hexagonal tesselation grid
% [X, Y, Fig, Axis, Lx, Ly, lH, lD] = voronoiScript(Bnd, Spc, D, ...)
%
% Output variables
% X is the x coordinate of the voronoi cell centres
% Y is the y coordinate of the voronoi cell centres
% Fig is the handle of the figure generated
% Axis is the handle of the axes used
% Lx gives the start and end x coordinates of the voronoi lines
% Ly gives the start and end y coordinates of the voronoi lines
% lH is the set of handles for the voronoi lines
% lD is constructed from [Lx; Ly], it is a [4 by Length] array
%
% Bnd specifies the boundaries for the region to be covered. It should be
% either one number, or a pair of numbers in a [1x2] vector, specifying
% [maxX, maxY]. 0 is taken as the minimum value.
%
% Spc specifies the average spacing. For a hex grid, it only accepts one
% value.
%
% D specifies the variation from a uniform grid. It is multiplied by a
% random number between -0.5 and 0.5 and added to the [x,y] coordinates
% of a point. If size(D) = [1x2], then the values are for [Dx, Dy].
%
% Optional arguments can be used to place some points exactly on the grid
% they would lie on with D[x/y] = 0. The first should be 'PartFixed' -
% this is a boolean and if true, some points are fixed to the grid.
%
% The second argument is 'FractionFixed'. This is an integer value
% (double class variables are accepted, but floor(arg) must be equal to
% (arg)). It specifies inversely how often points should be fixed, eg a
% value of 1 fixes every point, whilst a value of 5 fixes 1/5 of the
% points.
%
% PlotScatter is another boolean value, which sets if a scatter plot of
% the X,Y values corresponding to the cell centres should be included in
% the figure.
function [X, Y, Figure, Axis, Lx, Ly, lineHandles, lineData] = ...
voronoiScriptHex(Boundary, Spacing, Delta, varargin)
p = inputParser;
p.FunctionName = 'voronoiScript';
addRequired(p, 'Boundary', #checkTypes);
addRequired(p, 'Spacing', #isnumeric);
addRequired(p, 'Delta', #checkTypes);
defaultPart = false;
addOptional(p, 'PartFixed', defaultPart, #islogical);
defaultFraction = 2;
addOptional(p, 'FractionFixed', defaultFraction, #isAnInt);
defaultScatter = false;
addOptional(p, 'PlotScatter', defaultScatter, #islogical);
parse(p, Boundary, Spacing, Delta, varargin{:});
% Get values for boundaries and delta
% (Can be vectors or scalars)
if isequal(size(p.Results.Boundary),[1,2])
% Boundary is a vector [maxX, maxY]
BoundaryY = p.Results.Boundary(1,2);
else
BoundaryY = p.Results.Boundary(1,1);
end
if isequal(size(p.Results.Delta),[1,2])
% Delta is a vector [dX, dY]
DeltaY = p.Results.Delta(1,2);
else
DeltaY = p.Results.Delta(1,1);
end
Spacing = p.Results.Spacing;
BoundaryX = p.Results.Boundary(1,1);
DeltaX = p.Results.Delta(1,1);
D1 = [2*Spacing*cosd(30), Spacing];
numP = [ceil(BoundaryX/D1(1,1)) ceil(BoundaryY/D1(1,2))];
D2 = D1 ./ 2;
% Create the values
counter = 1;
xList(numP(1,1)*numP(1,2)) = 0;
yList(numP(1,1)*numP(1,2)) = 0;
for x=1:numP(1,1)
for y = 1:numP(1,2)
xList(counter) = (getPointValue(x, D1(1,1), DeltaX)-D2(1,1));
xList(counter+1) = getPointValue(x, D1(1,1), DeltaX);
yList(counter) = (getPointValue(y, D1(1,2), DeltaY)-D2(1,2));
yList(counter+1) = getPointValue(y, D1(1,2), DeltaY);
counter = counter + 2;
end
end
% Set some of the points to be without random change
if (p.Results.PartFixed),
for counter=1:p.Results.FractionFixed:size(xList,2),
[x, y] = getXYfromC(counter, numP(1,2));
xList(counter) = x*Spacing;
yList(counter) = y*Spacing;
end
end
X = xList;
Y = yList;
% Set manual ticks for the figure axes
ticksX = zeros(1,numP(1,1)+1);
for i=1:numP(1,1)+1,
ticksX(i) = i*D1(1,1);
end
ticksY = zeros(1,numP(1,2)+1);
for i=1:numP(1,2)+1,
ticksY(i) = i*D1(1,2);
end
BoundCoeff = 1.08;
Bounds = [0 BoundCoeff*BoundaryX; 0 BoundCoeff*BoundaryY];
% Give the figure a handle that is returned, and set axes values
Figure = figure;
Axis = axes;
axis equal;
minor = 'off';
gridtoggle = 'off';
set(Axis,'XTickMode','manual','YTickMode','manual', ...
'XGrid',gridtoggle,'YGrid',gridtoggle, ...
'XMinorGrid',minor,'YMinorGrid',minor, ...
'XTick',ticksX,'YTick',ticksY, ...
'XMinorTick',minor,'YMinorTick',minor, ...
'XLim',[0 Bounds(1,2)],'YLim',[0 Bounds(2,2)]);
%set(Axis,'XLim',[0 Bounds(1,2)],'YLim',[0 Bounds(2,2)]);
% Create the voronoi cells, returning the line points
[Lx, Ly] = voronoi(X,Y);
% Strip high values
counter = 1;
reducedXdat = zeros(2,size(Lx,2));
reducedYdat = zeros(2,size(Lx,2));
for i=1:size(Lx,2)
if Lx(1,i) > Bounds(1,1) && Lx(1,i) < Bounds(1,2) && ... % X value of start of line
Lx(2,i) > Bounds(2,1) && Lx(2,i) < Bounds(2,2) && ... % Y value of start of line
Ly(1,i) > Bounds(1,1) && Ly(1,i) < Bounds(1,2) && ... % X value of end of line
Ly(2,i) > Bounds(2,1) && Ly(2,i) < Bounds(2,2), % Y value of end of line
reducedXdat(:,counter) = Lx(:,i);
reducedYdat(:,counter) = Ly(:,i);
counter = counter + 1;
end
end
Lx = reducedXdat(:,1:counter-1);
Ly = reducedYdat(:,1:counter-1);
% Plot the voronoi lines
lineHandles = line(Lx, Ly);
% Set colours to black
if (1)
for i=1:size(lineHandles,1)
set(lineHandles(i),...
'LineWidth',3, ...
'LineSmoothing','on', ...
'Color',[0 0 0]);
end
end
lineData = [Lx; Ly];
if (p.Results.PlotScatter)
hold on;
scatter(X,Y);
end
end
function bool = checkTypes(arg)
bool = (isequal(class(arg),'double') && ...
(isequal(size(arg),[1,1]) || isequal(size(arg),[1,2])));
end
function bool = isAnInt(arg)
bool = (isequal(floor(arg),arg) && ...
isequal(size(arg),[1,1]) && ...
isnumeric(arg));
end
function val = getPointValue(intV, spacing, delta)
val = (((rand(1)-0.5)*delta)+(intV*spacing));
end
function [x,y] = getXYfromC(counter, sizeY)
x = floor(counter/sizeY)+1;
y = counter - ((x-1)*sizeY);
end
SCAD script file to place the voronoi cells within a pair of cylinders for 3D printing a grid. Edit as needed with path, or changes to shapes etc:
$fn = 360;
inkFile = "/path/to/my/file";
scl = 1.05; // Scale variable
transVec = [-100, -98, 0]; // Move the imported image pattern so that it's centred.
union(){
makeRing([0,0,3],inR=96, outR=99, height=6);
makeRing([0,0,1.5], inR=99, outR=102, height=3);
intersection() {
#linear_extrude(height = 6.05, convexity=40, center=false) // Removing the # will get rid of the overlay, which helps see where the grid is.
scale([scl, scl, 1])
translate(transVec)
import(inkFile);
makeCylinder([0,0,3], 96, 6, $fn=360);
}
}
module makeCylinder(centre, radius, height) {
translate(centre){
cylinder(h = height, r = radius, center=true);
}
}
module makeRing(centre,inR, outR, height) {
difference() {
makeCylinder(centre, outR, height);
makeCylinder(centre, inR, height+0.1);
}
}