Skip to content

Conversation

@wade-cheng
Copy link
Contributor

@wade-cheng wade-cheng commented Nov 3, 2025

Closes #2532.

@wade-cheng
Copy link
Contributor Author

I should say while this is on my mind right now, performance should probably be looked at for this PR. We convert the entire vec of polygon points from one unit to another once every frame.

@wade-cheng wade-cheng changed the title Improve node graph and artboard selection parity Add lasso selection to node graph Nov 11, 2025
Copy link
Contributor

@0HyperCube 0HyperCube left a comment

Choose a reason for hiding this comment

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

Thanks for your work on this. It seems to work nicely.

It is good to hear you thinking about the performance. However current architectural decisions unfortunately means an excessive number of allocations are necessary.

Comment on lines 71 to 70
/// plus a flag indicating if it has been dragged since the mousedown began.
lasso_selection_curr: Option<(Vec<DVec2>, bool)>,
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: It is probably clearer to make a struct { lasoo_points: Vec<DVec2>, has_dragged: bool } rather than relying on the doc comment to name the fields. However I suppose the current implementation is consistent with the box selection.

I wonder if it is even necessary to store the has_dragged bool. Can't you just check if the number of points is ≥ 2?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Re: paragraph 2. Good point, pretty sure that's all the functionality that the dragged bool is used for in the box selection logic anyways.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm. Perhaps the has_dragged field helps make it explicit that we do something related to whether we have moved from the initial mousedown or not. But I agree with removing it.

Also, I took a look, and the only reason box selection can't do without the field either is because we want to update_node_graph_hints only after moving from the initial mousedown. That is, if the initial mousedown was to update the hints, we could remove the field. But for the analogous lasso logic, we just check if the length is at least two, again.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

implemented in 4f86201 below

let lasso_selection_viewport: Vec<DVec2> = lasso_selection_curr
.iter()
.map(|selection_point| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(*selection_point))
.collect();
Copy link
Contributor

Choose a reason for hiding this comment

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

There is no need to call .collect() since you use into_iter() later. You might have to move the frontend message to here though if the borrow checker is unhappy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The borrow checker indeed was. And yes, moving the frontend message there fixes it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

implemented in 49efe27 below

Comment on lines 1994 to 1999
// WARNING WARNING WARNING: this commented-out code is copy pasted from UpdateBoxSelection above and has not been edited for lasso
// The mouse button was released but we missed the pointer up event
// if ((e.buttons & 1) === 0) {
// completeBoxSelection();
// boxSelection = undefined;
// } else if ((e.buttons & 2) !== 0) {
// editor.handle.selectNodes(new BigUint64Array(previousSelection));
// boxSelection = undefined;
// }

Copy link
Contributor

Choose a reason for hiding this comment

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

What is this relating to? It looks like javascript.

Copy link
Contributor Author

@wade-cheng wade-cheng Nov 23, 2025

Choose a reason for hiding this comment

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

Oh neat, that is javascript for some reason. Yeah, the identical comment appears in UpdateBoxSelection, and got copied over when I copy-pasted the entire UpdateBoxSelection block. Didn't know if it was important so I left it.

To answer the question more explicitly, don't really know what this relates to, but your guess would be better than mine anyhow.

Copy link
Contributor

Choose a reason for hiding this comment

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

The box selection seems to be working fine for many months, so it is probably safe to delete this comment (in both places).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

implemented in 4f86201 below

Comment on lines 2010 to 2009
let node_graph_point = network_metadata
.persistent_metadata
.navigation_metadata
.node_graph_to_viewport
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Probably less verbose to let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

implemented in 0aa3860 below

if nodes != previous_selection {
responses.add(NodeGraphMessage::SelectedNodesSet {
nodes: nodes.into_iter().collect::<Vec<_>>(),
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It is probably easiest to just always send this message (rather than allocating the previous_selection HashMap each frame).

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 can't intuit which is better, but I'll take your word for it. When I or whoever makes the change, I assume they should also make the identical analogous change to the box selection code?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess it doesn't matter very much either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Leaving it for now, then.

Comment on lines +2039 to +2045
fn points_to_polygon(points: &[DVec2]) -> Vec<PathSeg> {
points
.windows(2)
.map(|w| PathSeg::Line(Line::new(dvec2_to_point(w[0]), dvec2_to_point(w[1]))))
.chain(std::iter::once(PathSeg::Line(Line::new(
dvec2_to_point(*points.last().unwrap()),
dvec2_to_point(*points.first().unwrap()),
))))
.collect()
}
points_to_polygon(lasso_selection_curr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than allocating, consider a simplye point in polygon algorithm https://wrfranklin.org/Research/Short_Notes/pnpoly.html.

Copy link
Contributor Author

@wade-cheng wade-cheng Nov 24, 2025

Choose a reason for hiding this comment

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

Hmm, I feel the disappeal of needing to allocate, but I'm not sure how point-in-polygon helps. I stole click_targets.node_click_target.intersect_path from... uh, probably the box selection code, and I didn't look further because I knew it worked. I'd need to think about it lots and dig deeper into the code, but first impression: aren't nodes not points? We rather need nodes (rounded rectangles) in polygon?

That is, without some digging, I currently don't know how to get the bounding boxes of all the nodes.

@wade-cheng wade-cheng force-pushed the node-selection-parity branch 2 times, most recently from 0203b77 to 7e4eb0f Compare November 24, 2025 20:16
@wade-cheng wade-cheng force-pushed the node-selection-parity branch from 7e4eb0f to 03aa7f9 Compare November 24, 2025 20:27
@wade-cheng
Copy link
Contributor Author

Made some initial tweaks, discussion above. Feel free to mark whatever resolved if you agree with changes.

I suppose the last holdup is the "point in polygon" note that I'd be stuck on.

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.

Add lasso selection mode to the node graph as well

2 participants