Motion of a square

3 views (last 30 days)
Mattia
Mattia on 27 Sep 2024
Commented: Mattia on 30 Sep 2024
Good morning, I am asking for a review of the code that I am leaving as an attachment. The objective of the code should be to take as input the position of 4 points inside the square (integral with respect to the square, fixed in the face). Through an analysis of the variation of the 4 x and y coordinates you want to construct a code that simulates the motion of the square built around these points. What is to appear on the screen will be a black square with 4 fixed white points inside moving in a gray plane. The data with the positions are extracted from a text file that comes from a camera capture. Thank you in advance for your help.
  3 Comments
Mattia
Mattia on 27 Sep 2024
Here is the file, thank you so much
Umar
Umar on 27 Sep 2024
Hi @ Mattia,
Hope you are not in rush, give me some time to take a look into it.

Sign in to comment.

Accepted Answer

Voss
Voss on 27 Sep 2024
The code is OK, in the sense that it runs and presumably fulfills the requirements. However, there are some improvements that can be made:
1. Rather than using an importfile function that amounts to table2array(readtable(_,opts)), you can just use readmatrix. The result is the same for the example input file given.
2. Rather than creating 8 separate variables (x1, y1, x2, y2, ...), simply access the appropriate rows/columns of the variable XY when you need to.
3. Vectorize the calculations, e.g., rather than calculating the center of the square separately for each row of XY, calculate all the centers once before the loop, then use the appropriate one when needed inside the loop.
4. Pull things out of the loop that don't change within the loop, e.g., no need to set sideLength and vertices each time since they never change. In general, separate what's changing from what's not changing.
5. Rather than clearing the axes and creating new graphics objects on each iteration, you can create them once and modify their properties on each iteration. And if you avoid clearing the axes each iteration, you can avoid setting the axes title and other axes properties more than once.
A version of the code making those changes is given below. The behavior seems to be the same as the original (except faster).
%% Prova Motion faccia con punti interni
% IMPORT DATA
XY = readmatrix("Example_Write_TextFile1.txt");
fps = 40;
n = 1/fps;
% Inizializzazione della figura
figure;
axis equal;
grid on;
xlim([-1000 3000]);
ylim([-1000 2000]);
hold on;
title('Simulazione del moto di un quadrato con punti interni');
xlabel('X');
ylabel('Y');
ax = gca();
% Correggi sistema di riferimento Y
set(ax, 'YDir', 'reverse');
% Creazione del piano grigio scuro (una sola volta)
fill([-3000 3000 3000 -3000], [-3000 -3000 3000 3000], [0.4 0.4 0.4], 'EdgeColor', 'none');
sideLength = 2000; % Lunghezza ipotetica del lato del quadrato
vertices = sideLength/2*[-1, 1, 1, -1; -1, -1, 1, 1];
% Calcolo del centroide del quadrato basato sui punti interni
centerX = mean(XY(:,[1 3 5 7]),2);
centerY = mean(XY(:,[2 4 6 8]),2);
% Calcolo dell'orientamento del quadrato basato sui punti interni
dx = XY(:,5) - XY(:,1); % Differenza lungo x tra i punti
dy = XY(:,6) - XY(:,2); % Differenza lungo y tra i punti
angle = atan2(dy, dx); % Angolo di rotazione del quadrato
c = cos(angle);
s = sin(angle);
p = patch(ax, 'XData', [], 'YData', [], 'FaceColor', [0 0 0], 'EdgeColor', 'none');
l = line(ax, 'XData', [], 'YData', [], 'LineStyle', 'none', 'Color', 'w', 'Marker', 'o', ...
'MarkerSize', 4, 'MarkerFaceColor', 'w', 'MarkerEdgeColor', 'w'); % Pallini bianchi pieni
% Simulazione del moto del quadrato
for i = 1:size(XY,1) % numero di frame
% Determina i vertici del quadrato basati sui punti interni
% Calcolo della trasformazione (rotazione e traslazione)
rotatedVertices = [c(i), -s(i); s(i), c(i)] * vertices; % Ruota i vertici
% Trasla i vertici in modo che coincidano con il centro calcolato
X = rotatedVertices(1,:) + centerX(i);
Y = rotatedVertices(2,:) + centerY(i);
% Disegna il quadrato nero più intenso
set(p, 'XData', X, 'YData', Y);
% Disegna i punti interni
set(l, 'XData', XY(i,[1 3 5 7]), 'YData', XY(i,[2 4 6 8]));
% Aggiorna la visualizzazione
pause(n);
end

More Answers (1)

Umar
Umar on 27 Sep 2024

Hi @Mattia ,

It seems that @Voss provided better suggestions. However, upon analyzing your code and going through your txt file data points, I finally decided to modify the code to execute it and expected the plot as you mentioned in your comments. Please see attached.

Now, please see my comments below regarding a detailed review of your code.

Data Importation

Your code begins by importing data from a specified text file using a custom function, importfile which reads the coordinates for four points, which are expected to be structured in eight columns (four for x-coordinates and four for y-coordinates).

Considerations

  • Make sure that the file path is correct and accessible.
  • Validate the format of the text file to confirm that it matches the expected structure (i.e., tab-delimited values).

Setting Up the Simulation Environment

figure;
axis equal;
grid on;
xlim([-1000 3000]);
ylim([-1000 2000]);
hold on;
fill([-3000 3000 3000 -3000], [-3000 -3000 3000 3000], [0.4 0.4 0.4], 
'EdgeColor', 'none');

This section of your code initializes a figure with specific axis limits and creates a gray background.

Considerations

  • Adjust axis limits based on actual data ranges to ensure all points are visible.
  • The fixed size of the gray area might need to be dynamic if your input data varies significantly.

Simulation Loop

The loop iterates through each frame of data, calculating the centroid and orientation of the square based on the four input points.

for i = 1:length(x1)
  centerX = (x1(i) + x2(i) + x3(i) + x4(i)) / 4;
  centerY = (y1(i) + y2(i) + y3(i) + y4(i)) / 4;
    dx = x3(i) - x1(i);
    dy = y3(i) - y1(i);
    angle = atan2(dy, dx);

Key Operations

Centroid Calculation: This correctly averages the coordinates of the four points. Orientation Calculation: Using atan2 provides an accurate angle for rotation.

Square Construction

The vertices of the square are defined and rotated according to the calculated angle:

R = [cos(angle), -sin(angle); sin(angle), cos(angle)];
vertices = [-sideLength/2, -sideLength/2; sideLength/2, -sideLength/2;     
sideLength/2, sideLength/2; -sideLength/2, sideLength/2]';
rotatedVertices = R * vertices;

Considerations

  • The sideLength is hard-coded; consider making it dynamic based on your application needs or parameters from your dataset.

Visualization Update

Each iteration updates the visualization by filling in the square and plotting the internal points:

fill(X, Y, [0 0 0], 'EdgeColor', 'none');
plot([x1(i), x2(i), x3(i), x4(i)], [y1(i), y2(i), y3(i), y4(i)], 'wo', ...
   'MarkerSize', 4, 'MarkerFaceColor', 'w', 'MarkerEdgeColor', 'w');

Suggestions

  • Consider using drawnow instead of pause for more responsive updates.
  • Make sure that cla effectively clears only what is necessary to avoid flickering.

Now, if you consider working with large datasets or high frame rates, then I will suggest optimizing rendering performance by reducing graphical overhead or utilizing efficient plotting functions. Make sure to implement checks to handle cases where data may be missing or improperly formatted and add UI elements such as sliders or buttons for real-time adjustments during simulation.

Hope this helps. If you have any further questions or need clarification on specific sections, feel free to ask!

  2 Comments
Umar
Umar on 28 Sep 2024
Hi @Mattia,
Please let us know if all your questions have been answered. We are still here to assist you.
Mattia
Mattia on 30 Sep 2024
thank you very, your answer was very helpulful

Sign in to comment.

Categories

Find more on Graphics Performance in Help Center and File Exchange

Products

Community Treasure Hunt

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

Start Hunting!