Modifying arrow length based on intersection with polygon

조회 수: 4 (최근 30일)
Lochlan
Lochlan 2024년 9월 18일
댓글: Mike Croucher 2024년 9월 19일

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