Skip to content

Draw Virtual Obstacles #3406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 57 commits into
base: master
Choose a base branch
from

Conversation

Mr-Anyone
Copy link
Contributor

@Mr-Anyone Mr-Anyone commented Nov 12, 2024

Description

Have the ability to draw virtual obstacles. I think this is terrible UI design but it works for now. The way you use this is that you shift click to add points of a polygon. By pressing q, the polygon is saved to the stack, so you can create a new polygon by shift clicking again. Pressing w would remove all the polygon.

I am not sure what the most user friendly way to draw these obstacles, so please give some feedback.

See below for a video of this

Testing Done

I am going to maybe write a sensor fusion test some time later?

Also, I am probably going to field test test to see if it can avoid virtual obstacles in real life.

Resolved Issues

resolves #3367

Added virtual obstacles for testing and visualization purposes.

Length Justification and Key Files to Review

N/A

See the entire video here:
Screencast from 2024-11-11 06:01:02 PM.webm

  • Function & Class comments: All function definitions (usually in the .h file) should have a javadoc style comment at the start of them. For examples, see the functions defined in thunderbots/software/geom. Similarly, all classes should have an associated Javadoc comment explaining the purpose of the class.
  • Remove all commented out code
  • Remove extra print statements: for example, those just used for testing
  • Resolve all TODO's: All TODO (or similar) statements should either be completed or associated with a github issue

@Mr-Anyone
Copy link
Contributor Author

Also, highly likely that the code is buggy.

Copy link

@Mr-Anyone
Copy link
Contributor Author

From the sound of things on Saturday, are we reverting nuking the entire toolbar idea?

So something like shift+alt+double click and shift+alt+single click would be the new control instead?

@williamckha
Copy link
Contributor

From the sound of things on Saturday, are we reverting nuking the entire toolbar idea?

So something like shift+alt+double click and shift+alt+single click would be the new control instead?

Yes, shift + alt + click is fine for now. We can explore improving the toolbar in the future

@Mr-Anyone
Copy link
Contributor Author

I have just reset all the toolbar related commits.

for polygon in self.rendering_polygons:
polygon.hide()
self.rendering_polygons.resize(0, lambda: {})
self.current_polygon.hide()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential memory leak -- need to set parent of polygon to None

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think think fixed it?

@williamckha williamckha dismissed sauravbanna’s stale review March 15, 2025 23:13

Comments addressed

williamckha
williamckha previously approved these changes Mar 15, 2025
Copy link
Contributor

This PR is stale because it has been open for 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale Inactive pull requests label Apr 23, 2025
Copy link
Contributor

This PR was closed because it has been stalled for 5 days with no activity.

@github-actions github-actions bot closed this Apr 28, 2025
@itsarune itsarune reopened this Apr 29, 2025
@itsarune itsarune removed the Stale Inactive pull requests label Apr 29, 2025
@GrayHoang GrayHoang self-requested a review May 5, 2025 18:50
Copy link
Contributor

@GrayHoang GrayHoang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small clarifications, maybe some comments would be nice to explain certain actions? but it seems like it works to me

obstacles = self.obstacles.copy()

# only send to full system when the points form a valid polygon
if len(self.points) >= 3:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sends the same list to the fullsystem if the list of obstacles can't be updated. Do we need to send the list of obstacles every time as a proto? Or can we eliminate some of that call and have it not update the list of obstacles?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to send the list of obstacles every time as a proto?

Yes, you need to in the current implementation.

Or can we eliminate some of that call and have it not update the list of obstacles?

We could totally do that. Correct me if I am wrong, but you're suggesting that instead of sending the entire array, we only send the entries that were recently updated by the widget, right?

The main issue with that approach is that it requires implementing a linked list-like ADT and adding more abstraction on top of the VirtualObstacle proto. For example, imagine adding virtual obstacles in this order: A, then B, then C. If you later remove C, handling that on the C++ side becomes a bit tricky. You can use std::erase_if, or something along the line, but personally, I find that approach a bit clunky.

Another complication is that the VirtualObstacle proto itself becomes more complex. You'd need to introduce a new Operation field—probably an enum with values like Create, Destroy, and Modify (which might be covered by Create again)—plus an id field to track objects. Then you have to handle all the edge cases: repeated Destroy operations, modifying a non-existent obstacle, conflicting Destroy and Modify actions, and so on.

In my opinion, the added complexity doesn’t bring much value, since you can likely get away with just sending a relatively small array (like self.obstacles plus self.points). Unless there's a strong reason to go with the other approach?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, thank you so much for reviewing this. This is been an open PR for around a semester.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I didn't quite mean that, although I see how that would have been implied.
Right now, from what I understand, this function will always send a proto of the obstacles to the full system. However, we may not actually need to send that proto, because the current list of obstacles may not be in a valid state (for example, the current shape has <3 points).

So then we don't need to send a proto here at all. What I'm saying is, we can move the protobuffer call inside the if statement, so that we don't call it when there is nothing to update within the list of obstacles.

Copy link
Contributor Author

@Mr-Anyone Mr-Anyone May 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in something like this:

diff --git a/src/software/thunderscope/gl/layers/gl_draw_polygon_obstacle.py b/src/software/thunderscope/gl/layers/gl_draw_polygon_obstacle.py
index da15075f9..28cdcec68 100644
--- a/src/software/thunderscope/gl/layers/gl_draw_polygon_obstacle.py
+++ b/src/software/thunderscope/gl/layers/gl_draw_polygon_obstacle.py
@@ -89,17 +89,17 @@ class GLDrawPolygonObstacleLayer(GLLayer):

     def __send_to_fullsystem(self) -> None:
         """Sending a list of virtual obstacles to full system"""
-        obstacles = self.obstacles.copy()

         # only send to full system when the points form a valid polygon
         if len(self.points) >= 3:
+            obstacles = self.obstacles.copy()
             polygon = Polygon(points=self.points.copy())
             obstacle = Obstacle(polygon=polygon)
             obstacles.append(obstacle)

-        self.friendly_io.send_proto(
-            VirtualObstacles, VirtualObstacles(obstacles=obstacles)
-        )
+            self.friendly_io.send_proto(
+                VirtualObstacles, VirtualObstacles(obstacles=obstacles)
+            )

     def __create_single_click_callback(
         self, event: MouseInSceneEvent

That would kind of make sense as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New layer to draw obstacles on the field widget
5 participants