Get axes position from a 3D coordinate

15 views (last 30 days)
Gregory Vernon
Gregory Vernon on 6 Jun 2023
Edited: akshatsood on 18 Oct 2023
I'm creating quality animations of vectors for an educational video I'm making. I don't like that the existing quiver and quiver3 implementations don't create arrowheads that are solid, so would like to use annotation( 'arrow', ...) instead. In 2D, then, I can make animations that look like this:
I'd like to now do this for 3D vectors, where I can preferably also rotate the view. Since annotations only accept x & y, and have a 1x4 Position property, I think I should be able to compute the [n0 n1 width height] Position at each render frame from the [x, y, z] coordinates and then update the annotations. I've looked around the Add-ons manager and while there are quite a few "3D Arrow" add-ons, it seems like they either don't (easily) support updating coordinates of the arrow, don't draw a solid arrow, or the arrowhead doesn't stay "normal" to the camera. Any thoughts?
Here's a code framework, based on quiver3, that I'd like to get working as I've described:
clear
close all
fig = figure;
% Initialize "arrow" plotting
vec3d = [ 0.34; 0.72; 0.50 ];
q3d = quiver3( 0, 0, 0, 0, 0, 0, "off", LineWidth=2, MaxHeadSize=0.5 );
% Axis setup
ax = gca;
ax.Units = "normalized";
axis equal
axis vis3d
ax.XLim = [-1 1];
ax.YLim = [-1 1];
ax.ZLim = [-1 1];
ax.Box = "on";
ax.BoxStyle = "full";
view( 50, 20 )
drawnow
% Update vector draw length
rotation_angle = 360;
num_frames = 60;
for frame = 1 : num_frames
q3d.UData = vec3d(1) * frame / num_frames;
q3d.VData = vec3d(2) * frame / num_frames;
q3d.WData = vec3d(3) * frame / num_frames;
drawnow
end
% Rotate view
num_frames = 60;
for frame = 1 : num_frames
ax.View(1) = ax.View(1) + rotation_angle / num_frames;
drawnow
end

Answers (1)

akshatsood
akshatsood on 1 Sep 2023
Edited: akshatsood on 18 Oct 2023
Hi Gregory,
I understand that you wish to create quality animations for an educational video and prefer not to leverage quiver3 implementations. I carefully investigated your requirements and boiled down to a possible workaround which utilises arrow function. To be clear, I have used arrow function to plot the line in 3D space along with the arrowhead. Also, while updating the vector draw length, I have set the visibility of the arrow handle arr to off so that it does not get carried forward with the next iteration. Here is the code snippet for your reference
clear; close all;
origin = [0 0 0];
vec3d = [0.34 0.72 0.50];
% axis setup
ax = gca;
ax.Units = "normalized";
axis equal
axis vis3d
ax.XLim = [-1 1];
ax.YLim = [-1 1];
ax.ZLim = [-1 1];
ax.Box = "on";
ax.BoxStyle = "full";
view(50,20);
rotation_angle = 360;
num_frames = 60;
for frame = 1 : num_frames
newCoord = vec3d*(frame/num_frames); % store next set of coordinates
arr = arrow(origin,newCoord);
drawnow
arr.Visible = 'off';
end
arr.Visible = 'on'; % set Visible to on after updating the line
% Rotate view
for frame = 1 : num_frames
ax.View(1) = ax.View(1) + rotation_angle / num_frames;
drawnow
end
I hope this helps.

Categories

Find more on Graphics Performance in Help Center and File Exchange

Products


Release

R2023a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!