-
Notifications
You must be signed in to change notification settings - Fork 377
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
Allow d3.forceManyBody().distanceMax() and .distanceMin() to accept functions? (feature request) #186
Comments
Interesting. It's easy enough to plug in two arrays to store the values (as we do with strengths) in manyBody.js, and use them when evaluating the force; I'm happy to help you create the relevant force function (or patched version of d3-force) if you want to give it a try. However, I'm not sure it would work in the particular use case you've described. Since the fence nodes are fixed, they are never, at the end of the iteration, subject to movement, so it doesn't matter what this force has computed for them. In fact, the only impact of fixed nodes in the calculation is to inform a "density field" (*), computed in a first stage. In the second (and final) stage, we evaluate for each "receiving" node the impact of the field. DistanceMax is used in this final stage, so it seems that only the distanceMax pertaining to free nodes would be used in a meaningful way. What we might do in the case you're describing is to layer two forceManyBody. One would include only the free nodes, and would be parametrized with a long distanceMax; the other would include all nodes with a short distanceMax. Note that there are other ways of fencing nodes inside a polygon: for one example see forceWalls, and the whole discussion at #163. (*) In the Barnes–Hut algorithm, nodes interact with a "presence field", materialized in D3 as a quadtree that registers, for each quad, how much matter is contained in that quad. In other words, nodes don't interact with individual nodes, but with quads. |
Ahh, thanks for the information. Perhaps I was misinterpreting the docs about
(emphasis mine) - I interpreted that as the force belonging to the node itself, and therefore other nodes would only feel it if they were close by. E.g., even though the fixed node doesn't move, free nodes would only feel its force if they were within I will check out the forceWalls discussion as an alternative. Thanks! |
Hi, I came across this issue because I wanted to pass a function to here the relevant code snippet: function apply(quad, x1, _, x2) {
if (!quad.value) return true;
var x = quad.x - node.x,
y = quad.y - node.y,
w = x2 - x1,
l = x * x + y * y;
// Apply the Barnes-Hut approximation if possible.
// Limit forces for very close nodes; randomize direction if coincident.
if (w * w / theta2 < l) {
if (l < distanceMax2s[quad.data.index]) {
if (x === 0) x = jiggle(random), l += x * x;
if (y === 0) y = jiggle(random), l += y * y;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
node.vx += x * quad.value * alpha / l;
node.vy += y * quad.value * alpha / l;
}
return true;
} what can I do if there is no data of the quad ? edit: here is the commit of what I tried neesh-studio@7bad558 |
quad.data is only present for leaf nodes, not for those which have 4 subquads. Test |
thanks for your explanation! - if (l < distanceMax2) {
+ if (l < distanceMax2s[quad.data.index]) { Should I simply ignore distanceMax2 altogether if the node is not a leaf node? |
Oh so in that case, you'd need to dig into the quad to see if any point contained has a distanceMax2 that says it must be counted…? Then it seems it would totally defeat the purpose of the quadtree, which is to eliminate points without looking at them. See my point about density field (*) in the first comment. I'm going to close this issue, since it's more a topic for (fun) experimentations, than an issue with the current code. Feel free to continue the discussion here, or to open a thread in https://github.com/d3/d3/discussions instead. |
d3.forceManyBody().strength()
can accept a function as its parameter, allowing differentiation of strength based on some other node property. Why not implement the same for.distanceMax()
and.distanceMin()
?One use case is setting up a ring fence of fixed nodes in an irregular polygon to contain a bunch of nodes that are free to move in the simulation. You'd want the ring fence nodes to have strong repulsive strength but only at a local distance, while the free nodes could interact with each other over longer distances.
The text was updated successfully, but these errors were encountered: