Skip to content

Commit

Permalink
New layout algorithms
Browse files Browse the repository at this point in the history
  • Loading branch information
ptaillandier committed Jun 30, 2021
1 parent cf587fa commit 74c0d56
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 4 deletions.
76 changes: 76 additions & 0 deletions msi.gama.core/src/msi/gaml/operators/Graphs.java
Expand Up @@ -23,6 +23,13 @@
import org.apache.commons.lang.ArrayUtils;
import org.jgrapht.alg.clique.BronKerboschCliqueFinder;
import org.jgrapht.alg.connectivity.ConnectivityInspector;
import org.jgrapht.alg.drawing.FRLayoutAlgorithm2D;
import org.jgrapht.alg.drawing.IndexedFRLayoutAlgorithm2D;
import org.jgrapht.alg.drawing.MedianGreedyTwoLayeredBipartiteLayout2D;
import org.jgrapht.alg.drawing.model.Box2D;
import org.jgrapht.alg.drawing.model.LayoutModel2D;
import org.jgrapht.alg.drawing.model.MapLayoutModel2D;
import org.jgrapht.alg.drawing.model.Point2D;
import org.jgrapht.alg.flow.EdmondsKarpMFImpl;
import org.jgrapht.alg.interfaces.MaximumFlowAlgorithm.MaximumFlow;
import org.jgrapht.generate.BarabasiAlbertGraphGenerator;
Expand All @@ -36,6 +43,7 @@
import org.jgrapht.util.SupplierUtil;
import org.locationtech.jts.geom.Coordinate;

import msi.gama.common.geometry.Envelope3D;
import msi.gama.common.geometry.GeometryUtils;
import msi.gama.common.interfaces.IKeyword;
import msi.gama.metamodel.agent.IAgent;
Expand Down Expand Up @@ -1859,6 +1867,74 @@ public static IGraph layoutForce(final IScope scope, final GamaGraph graph, fina
return graph;
}


@operator (
value = "layout_force_FR",
content_type = ITypeProvider.CONTENT_TYPE_AT_INDEX + 1,
index_type = ITypeProvider.KEY_TYPE_AT_INDEX + 1,

category = { IOperatorCategory.GRAPH },
concept = { IConcept.GRAPH })
@doc (
value = "layouts a GAMA graph using Fruchterman and Reingold Force-Directed Placement Algorithm (in a given spatial bound, normalization factor and max_iteration parameters). ",
masterDoc = true,
special_cases = "usage: layoutForce(graph, bounds, normalization_factor, max_iteration, equilibirum criterion). graph is the graph to which "
+ "applied the layout; bounds is the shape (geometry) in which the graph should be located; normalization_factor is the normalization factor for the optimal distance, typical value is 1.0; "
+ " max_iteration is the maximal number of iterations")
@no_test
public static IGraph layoutForceFR(final IScope scope, final GamaGraph graph, final IShape bounds,
final double normalization_factor, final int maxIteration) {
final FRLayoutAlgorithm2D sim = new FRLayoutAlgorithm2D(maxIteration,normalization_factor,scope.getSimulation().getRandomGenerator().getGenerator());
LayoutModel2D model = toModel(graph,bounds);
sim.layout(graph, model);
return update_loc(graph,model);
}

@operator (
value = "layout_force_FR_indexed",
content_type = ITypeProvider.CONTENT_TYPE_AT_INDEX + 1,
index_type = ITypeProvider.KEY_TYPE_AT_INDEX + 1,

category = { IOperatorCategory.GRAPH },
concept = { IConcept.GRAPH })
@doc (
value = "layouts a GAMA graph using Fruchterman and Reingold Force-Directed Placement Algorithm with The Barnes-Hut indexing technique(in a given spatial bound, theta, normalization factor and max_iteration parameters). ",
masterDoc = true,
special_cases = "usage: layoutForce(graph, bounds, normalization_factor, max_iteration, equilibirum criterion). graph is the graph to which "
+ "applied the layout; bounds is the shape (geometry) in which the graph should be located; theta value for approximation using the Barnes-Hut technique, typical value is 0.5; normalization_factor is the normalization factor for the optimal distance, typical value is 1.0; "
+ " max_iteration is the maximal number of iterations")
@no_test
public static IGraph indexedFRLayout(final IScope scope, final GamaGraph graph, final IShape bounds,
final double theta, final double normalizationFactor, final int maxIteration) {
final IndexedFRLayoutAlgorithm2D sim = new IndexedFRLayoutAlgorithm2D(maxIteration,theta, normalizationFactor,scope.getSimulation().getRandomGenerator().getGenerator());
LayoutModel2D model = toModel(graph,bounds);
sim.layout(graph, model);
return update_loc(graph,model);
}



static IGraph update_loc(IGraph graph, LayoutModel2D model) {
for (Object s : graph.vertexSet()) {
if (s instanceof IShape) {
Point2D pt = model.get(s);
((IShape) s).setLocation(new GamaPoint(pt.getX(), pt.getY()));
}
}
return graph;
}

static LayoutModel2D toModel(final GamaGraph graph, final IShape bounds) {
Envelope3D env = bounds.getEnvelope();
LayoutModel2D model = new MapLayoutModel2D<>(new Box2D(env.getMinY(), env.getMinY(), env.getWidth(), env.getHeight()));
for (Object s : graph.vertexSet()) {
if (s instanceof IShape) {
model.put(s, new Point2D(((IShape)s).getLocation().getX(), ((IShape)s).getLocation().getY()));
}
}
return model;
}

@operator (
value = "layout_force",
content_type = ITypeProvider.CONTENT_TYPE_AT_INDEX + 1,
Expand Down
2 changes: 2 additions & 0 deletions msi.gama.ext/META-INF/MANIFEST.MF
Expand Up @@ -444,6 +444,8 @@ Export-Package: com.conversantmedia.util.collection,
org.jgrapht.alg.connectivity,
org.jgrapht.alg.cycle,
org.jgrapht.alg.decomposition,
org.jgrapht.alg.drawing,
org.jgrapht.alg.drawing.model,
org.jgrapht.alg.flow,
org.jgrapht.alg.flow.mincost,
org.jgrapht.alg.interfaces,
Expand Down
@@ -1,7 +1,7 @@
/**
* Name: Graph from DGS File and Layout Changed
* Author: Patrick Taillandier
* Description: Model which shows how to load a graph from a DGS File, and change its layout.
* Description: Model which shows how to load a graph from a graphml File, and change its layout.
* Tags: graph, load_file, dgs
*/

Expand All @@ -12,17 +12,18 @@ global {
string barabasi_file <- "../includes/simple.graphml";
geometry shape <- rectangle(500,500);
string layout_type;
int layout_time <- 1000 min: 0 max: 10000 parameter: "Max number of iterations" category: "Force";
int layout_time <- 1000 min: 0 max: 10000 parameter: "Max number of iterations" ;
float coeff_force <- 0.8 min: 0.1 max: 1.0 parameter: "Force coefficient" category: "Force";
float cooling_coefficient <- 0.1 min: 0.01 max: 0.5 parameter: "Decreasing coefficient of the temperature" category: "Force";
float coeff_nb_places <- 1.2 min: 0.0 max: 2.0 parameter: "Coefficient for the number of places to locate the vertices" category: "Grid";
float normalizationFactor <- 0.5 min: 0.1 max: 2.0 parameter: "Coefficient for the number of places to locate the vertices" category: "Force_FR";
float theta <- 0.5 min: 0.1 max: 2.0 parameter: "Coefficient for the number of places to locate the vertices" category: "Force_FR_indexed";


//The operator load_graph_from_file generates the graph from the file, and chose the vertices as agents of node_agent
//species, and edges as edge_agent agents
init {
the_graph <- graphml_file("../includes/simple.graphml", node_agent, edge_agent).contents;
write the_graph.edges;
}

//In case the layout type is forcedirected or random, the reflex will change at each step the layout of the graph
Expand All @@ -31,6 +32,12 @@ global {
match "Force" {
the_graph <- layout_force(the_graph, world.shape,coeff_force , cooling_coefficient, layout_time);
}
match "Force FR" {
the_graph <- layout_force_FR(the_graph, world.shape,normalizationFactor,layout_time);
}
match "Force FR Indexed" {
the_graph <- layout_force_FR_indexed(the_graph, world.shape,theta,normalizationFactor,layout_time);
}
match "Circular" {
the_graph <- layout_circle(the_graph, world.shape, false);
}
Expand All @@ -54,7 +61,7 @@ species node_agent {
}

experiment loadgraph type: gui {
parameter "Layout type" var: layout_type among:["Force", "Circular", "Grid"] init:"Circular";
parameter "Layout type" var: layout_type among:["Force FR","Force FR Indexed" , "Force", "Circular", "Grid"] init:"Force FR";
output {
display map type: opengl{
species edge_agent ;
Expand Down

0 comments on commit 74c0d56

Please sign in to comment.