grantshandy / fdg

A Force Directed Graph Drawing Library
https://grantshandy.github.io/fdg
MIT License
183 stars 16 forks source link

Self-referenced nodes making simulation to blow up #10

Open blitzarx1 opened 1 year ago

blitzarx1 commented 1 year ago

If I have self-referenced nodes in ForceGraph and update simulation all the coordinates are becoming NaN

blitzarx1 commented 1 year ago

I ll try to provide more details later

zicklag commented 1 year ago

I ran into, this too. All I did was add a node that was connected by an edge to itself, and all the node positions would turn to NaN after updating the simulation a couple times.

blitzarx1 commented 1 year ago

Yeah thanks for update. This is how I hacked around it in my project interactive demo. Basicaly you need to remove all self referenced nodes before the simulation update, and after update add them again.

    fn update_simulation(&mut self) {
        if self.simulation_stopped {
            return;
        }

        // the following manipulations is a hack to avoid having looped edges in the simulation
        // because they cause the simulation to blow up; this is the issue of the fdg_sim engine
        // we use for the simulation
        // * remove loop edges
        // * update simulation
        // * restore loop edges

        let looped_nodes = {
            // remove looped edges
            let graph = self.simulation.get_graph_mut();
            let mut looped_nodes = vec![];
            let mut looped_edges = vec![];
            graph.edge_indices().for_each(|idx| {
                let edge = graph.edge_endpoints(idx).unwrap();
                let looped = edge.0 == edge.1;
                if looped {
                    looped_nodes.push((edge.0, ()));
                    looped_edges.push(idx);
                }
            });

            for idx in looped_edges {
                graph.remove_edge(idx);
            }

            self.simulation.update(SIMULATION_DT);

            looped_nodes
        };

        // restore looped edges
        let graph = self.simulation.get_graph_mut();
        for (idx, _) in looped_nodes.iter() {
            graph.add_edge(*idx, *idx, ());
        }
    }

I ll live this issue open. Maybe we will get some comments from the contributors

grantshandy commented 1 year ago

Thanks for taking an interest in this library! It's been a while since I've worked on it and in that time I've really improved my Rust API design skills (and calculus), so this library definitely isn't as polished as I'd like to be. Forces are due for a re-write or atleast some API and documentation changes.

@zicklag: ...All I did was add a node that was connected by an edge to itself, and all the node positions would turn to NaN after updating the simulation a couple times.

Both the attractive and repellent forces are highly dependent on the distance between the two nodes, so if two nodes are linked together my guess is the attractive edge forces will probably evaluate to Infinity/NaN because of a zero-division. Then that new velocity creates a chain reaction where all the connected nodes fly off into NaN territory because they have huge velocities. This is a bug, and I am going to try to address it in my new versions.

blitzarx1 commented 2 months ago

Hi, again!

I am using current master of fdg here (https://github.com/blitzarx1/egui_graphs/tree/master/examples/demo) and I do not think this is an issue anymore.