Modifying arrow length based on intersection with polygon

4 次查看(过去 30 天)

Background: I'm running a niche analysis for animal body part coordinates, attempting to estimate the visual field of an animal. For each frame of a video, I have extracted XY coordinates of a body part, which I have been using as an origin to draw polygons representing the visual fields of this animal (not shown here). For each row of coordinates, I am drawing multiple cone-like polygons, rotating them such that they are evenly spaced by 10°, extending outwards from the coordinate of this body part.
Difficulty with new analysis: I would like to create a separate analysis, where instead of extending polygons, I am instead extending arrows from the coordinate/origin, with their own rotations, as the animal moves about a separate polygon object. I would like the arrows/lines to be set at a fixed default length (let's say 10 'units'), except when they intersect the boundary/edges of the polygon. When an arrow would intersect, I would like to automatically adjust the length such that the tip of the intersecting arrow stops at the boundary. In Part 3 of my sample figure, you can see that when the arrows 'intersect' or contact the red polygon boundary, their length is capped at the edge of the boundary.
Main Question: Is is possible to set the length of the arrows in this dynamic way? Would it be recommended to write a statement that checks if an arrow intersects the polygon and instead change the endpoint position to the intersection coordinate?

采纳的回答

Mike Croucher
Mike Croucher 2024-9-18
编辑:Mike Croucher 2024-9-18
The polyxpoly function is what you need
polygon_x = [-20 20 20 -20 -20];
polygon_y = [-50 -50 50 50 -50];
origin = [-50, 0];
% Define arrow parameters
num_arrows = 5; % Number of arrows to be drawn
arrow_length_default = 50; % Default arrow length
angle_offset = 10; % Angle offset between arrows (degrees)
% Calculate arrow directions (evenly spaced by angle_offset)
angles = linspace(-30, 30, num_arrows); % Adjust angle range as necessary
% Convert angles to radians for trigonometry
angles_rad = deg2rad(angles);
figure;
hold on;
axis equal;
plot([polygon_x polygon_x(1)], [polygon_y polygon_y(1)], 'r'); % Plot polygon
% Function to calculate intersection of line with polygon
for i = 1:num_arrows
% Calculate default arrow endpoint assuming no intersection
arrow_end_x = origin(1) + arrow_length_default * cos(angles_rad(i));
arrow_end_y = origin(2) + arrow_length_default * sin(angles_rad(i));
% Check for intersection between the arrow and the polygon
[xi, yi] = polyxpoly([origin(1) arrow_end_x], [origin(2) arrow_end_y], polygon_x, polygon_y);
if ~isempty(xi)
% If intersection occurs, shorten the arrow to stop at the boundary
arrow_end_x = xi(1);
arrow_end_y = yi(1);
end
% Plot the arrow
quiver(origin(1), origin(2), arrow_end_x - origin(1), arrow_end_y - origin(2), 0, 'b', 'LineWidth', 2);
end
%plot the oirigin
plot(origin(1), origin(2), 'ro', 'MarkerSize', 15, 'MarkerFaceColor', 'r');
  2 个评论
Lochlan
Lochlan 2024-9-19
Thanks for the quick response, Mike.
I ran into the issue here that if the origin gets close enough to the polygon such that the arrows would intersect another boundary of the polygon, the tip gets placed there instead.
origin = [-30 10]
When I look at the intersections, the order is:
xi = [20; -20]
yi = [10; 10]
So, would it make sense for me to check if there are multiple intersections, and then set the endpoint as [xi(end) yi(end)]? I just want to make sure I'm thinking about this correctly
Mike Croucher
Mike Croucher 2024-9-19
If there are multiple intersections, choose the closest one. Something like
if ~isempty(xi)
% If multiple intersection points, choose the closest one to the origin
distances = sqrt((xi - origin(1)).^2 + (yi - origin(2)).^2);
[~, idx] = min(distances); % Find the index of the closest intersection
arrow_end_x = xi(idx);
arrow_end_y = yi(idx);
end

请先登录,再进行评论。

更多回答(1 个)

Matt J
Matt J 2024-9-18
编辑:Matt J 2024-9-18
An alternative to Mike's approach using linexlines2D() from the File Exchange,
is below:
polygon= polyshape([-20 20 20 -20 -20] , [-50 -50 50 50 -50]);
origin = [-50, 0];
% Define arrow parameters
num_arrows = 5; % Number of arrows to be drawn
arrow_length_default = 50; % Default arrow length
angle_offset = 10; % Angle offset between arrows (degrees)
% Calculate arrow directions (evenly spaced by angle_offset)
angles = linspace(-30, 30, num_arrows)'; % Adjust angle range as necessary
% Calculate intersection(s) of line with polygon and shorten arrows
ArrowStart = repmat(origin, num_arrows,1);
ArrowEnd= ArrowStart + arrow_length_default*[cosd(angles), sind(angles)];
for i = 1:num_arrows
I = linexlines2D(polygon,ArrowStart(i,:),ArrowEnd(i,:));
if ~isnan(I(:,1))
ArrowEnd(i,:)=I(:,1);
end
end
Directions=ArrowEnd-ArrowStart;
%Plot everything
hold on;
plot(polygon, 'FaceColor','none','EdgeColor','r'); axis equal;
plot(origin(1), origin(2), 'ro', 'MarkerSize', 15, 'MarkerFaceColor', 'r');
quiver(ArrowStart(:,1), ArrowStart(:,2),Directions(:,1), Directions(:,2),0, 'b', 'LineWidth', 2);
hold off
  3 个评论
Matt J
Matt J 2024-9-19
That's fine. Just accept whichever of them you ended up most closely adapting.
Mike Croucher
Mike Croucher 2024-9-19
Indeed, all is fair in love and accepting an aswer :)
I honestly didn't know about either of these functions until I investigated your problem so you've already done me a favour by asking the question :)

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Elementary Polygons 的更多信息

Community Treasure Hunt

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

Start Hunting!

Translated by