Save/Load
* implemented saving/loading of graphical graph * fixed save/load graph * fixed and improved tests
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
package berack96.sim.util.graph;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import berack96.sim.util.graph.models.GraphSaveStructure;
|
||||
import berack96.sim.util.graph.visit.VisitInfo;
|
||||
import berack96.sim.util.graph.visit.VisitStrategy;
|
||||
|
||||
@@ -548,22 +550,65 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
*/
|
||||
Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Save the Graph passed as input to a file inserted as parameter.<br>
|
||||
* The resulting file is a Json string representing all the graph.<br>
|
||||
* If the directory for getting through the file do not exist,<br>
|
||||
* then it is created.
|
||||
*
|
||||
* @param graph the graph to save
|
||||
* @param file the name of the file
|
||||
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
|
||||
*/
|
||||
static void save(Graph<?, ?> graph, String file) throws IOException {
|
||||
save(graph, "", file);
|
||||
}
|
||||
|
||||
static <V, W extends Number> void save(Graph<V, W> graph, String other, String file) throws IOException {
|
||||
GraphSaveStructure<V, W> save = new GraphSaveStructure<>(graph, other);
|
||||
/**
|
||||
* Save the Graph passed as input to a file inserted as parameter.<br>
|
||||
* The resulting file is a Json string representing all the graph.<br>
|
||||
* If the directory for getting through the file do not exist,<br>
|
||||
* then it is created.<br>
|
||||
* The additional parameter is used if you want to save other as well as the graph.
|
||||
*
|
||||
* @param graph the graph to save
|
||||
* @param other other things to save
|
||||
* @param file the name of the file
|
||||
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
|
||||
*/
|
||||
static void save(Graph<?, ?> graph, String other, String file) throws IOException {
|
||||
GraphSaveStructure save = new GraphSaveStructure(graph, other);
|
||||
int slash = file.lastIndexOf("\\");
|
||||
if(slash == -1)
|
||||
slash = file.lastIndexOf("/");
|
||||
if(slash != -1) {
|
||||
String dir = file.substring(0, slash);
|
||||
File fDir = new File(dir);
|
||||
fDir.mkdirs();
|
||||
}
|
||||
|
||||
FileWriter writer = new FileWriter(file);
|
||||
|
||||
GSON.toJson(save, writer);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <V, W extends Number> String load(Graph<V, W> graph, String file, Class<V> classV, Class<W> classW) throws IOException {
|
||||
graph.removeAllVertex();
|
||||
|
||||
/**
|
||||
* Load an already saved graph in an instance of a graph.
|
||||
* Before loading the graph, it is emptied.
|
||||
*
|
||||
* @param <V> the parameter needed for the vertex
|
||||
* @param <W> the parameter needed for the weight
|
||||
* @param graph the graph to load with
|
||||
* @param file the file where the graph is saved
|
||||
* @param classV the class used for the Vertex
|
||||
* @param classW the class used for the Weight
|
||||
* @return the string saved in other, if any
|
||||
* @throws IOException for any possible reason, the most common: the file doesn't exist
|
||||
* @throws NullPointerException if the graph is null
|
||||
* @throws JsonSyntaxException if the file is malformed or corrupted
|
||||
*/
|
||||
static <V, W extends Number> String load(Graph<V, W> graph, String file, Class<V> classV, Class<W> classW) throws IOException, NullPointerException, JsonSyntaxException {
|
||||
FileReader reader = new FileReader(file);
|
||||
StringBuilder fileContent = new StringBuilder();
|
||||
int c;
|
||||
@@ -571,55 +616,23 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
while((c = reader.read()) != -1)
|
||||
fileContent.append((char)c);
|
||||
reader.close();
|
||||
GraphSaveStructure<V, W> save = GSON.fromJson(fileContent.toString(), GraphSaveStructure.class);
|
||||
GraphSaveStructure save = GSON.fromJson(fileContent.toString(), GraphSaveStructure.class);
|
||||
|
||||
graph.removeAllVertex();
|
||||
for(String str : save.vertices)
|
||||
graph.addVertex(GSON.fromJson(str, classV));
|
||||
|
||||
for(int i = 0; i<save.edges.src.size(); i++) {
|
||||
V s = GSON.fromJson(save.edges.src.get(i), classV);
|
||||
V d = GSON.fromJson(save.edges.dest.get(i), classV);
|
||||
W w = GSON.fromJson(save.edges.weight.get(i), classW);
|
||||
graph.addEdge(s, d, w);
|
||||
}
|
||||
for(int i = 0; i<save.edges.length; i++)
|
||||
graph.addEdge(
|
||||
GSON.fromJson(save.edges[i].src, classV),
|
||||
GSON.fromJson(save.edges[i].dest, classV),
|
||||
GSON.fromJson(save.edges[i].weight, classW));
|
||||
/*
|
||||
for(int i = 0; i<save.marks.length; i++)
|
||||
graph.mark(GSON.fromJson(save.marks[i].vert, classV), save.marks[i].mark);
|
||||
*/
|
||||
return save.other;
|
||||
}
|
||||
|
||||
class GraphSaveStructure<V, W extends Number> {
|
||||
public GraphSaveStructure() {}
|
||||
protected GraphSaveStructure(Graph<V, W> graph, String other) {
|
||||
vertices = new LinkedList<>();
|
||||
|
||||
for(V v: graph.vertices())
|
||||
vertices.add(GSON.toJson(v));
|
||||
edges = new EdgeSaveStructure<>(graph.edges());
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
public List<String> vertices;
|
||||
public EdgeSaveStructure<V, W> edges;
|
||||
public String other;
|
||||
}
|
||||
|
||||
class EdgeSaveStructure<V, W extends Number> {
|
||||
public EdgeSaveStructure() {}
|
||||
protected EdgeSaveStructure(Collection<Edge<V, W>> edges) {
|
||||
src = new LinkedList<>();
|
||||
dest = new LinkedList<>();
|
||||
weight = new LinkedList<>();
|
||||
|
||||
for(Edge<V, W> ed : edges) {
|
||||
src.add(GSON.toJson(ed.getSource()));
|
||||
dest.add(GSON.toJson(ed.getDestination()));
|
||||
weight.add(GSON.toJson(ed.getWeight()));
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> src;
|
||||
public List<String> dest;
|
||||
public List<String> weight;
|
||||
}
|
||||
|
||||
// TODO maybe -> STATIC saveOnFile(orString) INSTANCE loadFromFile(orString), but need JSON parser
|
||||
// TODO maybe, but i don't think so... STATIC DISTANCE V* -> V*
|
||||
}
|
||||
|
||||
20
src/berack96/sim/util/graph/models/EdgeSaveStructure.java
Normal file
20
src/berack96/sim/util/graph/models/EdgeSaveStructure.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package berack96.sim.util.graph.models;
|
||||
|
||||
/**
|
||||
* Support class used for saving a Graph in a file.
|
||||
*
|
||||
* @author Berack96
|
||||
*
|
||||
*/
|
||||
public class EdgeSaveStructure {
|
||||
public EdgeSaveStructure() {}
|
||||
protected EdgeSaveStructure(String s, String d, String w) {
|
||||
this.src = s;
|
||||
this.dest = d;
|
||||
this.weight = w;
|
||||
}
|
||||
|
||||
public String src;
|
||||
public String dest;
|
||||
public String weight;
|
||||
}
|
||||
41
src/berack96/sim/util/graph/models/GraphSaveStructure.java
Normal file
41
src/berack96/sim/util/graph/models/GraphSaveStructure.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package berack96.sim.util.graph.models;
|
||||
|
||||
import berack96.sim.util.graph.Edge;
|
||||
import berack96.sim.util.graph.Graph;
|
||||
|
||||
/**
|
||||
* Support class used for saving a Graph in a file.
|
||||
*
|
||||
* @author Berack96
|
||||
*
|
||||
*/
|
||||
public class GraphSaveStructure {
|
||||
public GraphSaveStructure() {}
|
||||
public GraphSaveStructure(Graph<?, ?> graph, String other) {
|
||||
this.vertices = new String[graph.numberOfVertices()];
|
||||
int i = 0;
|
||||
for(Object o: graph.vertices()) {
|
||||
this.vertices[i] = Graph.GSON.toJson(o);
|
||||
i++;
|
||||
}
|
||||
|
||||
this.edges = new EdgeSaveStructure[graph.numberOfEdges()];
|
||||
i = 0;
|
||||
for (Edge<?, ?> edge : graph.edges()) {
|
||||
this.edges[i] = new EdgeSaveStructure(
|
||||
Graph.GSON.toJson(edge.getSource()),
|
||||
Graph.GSON.toJson(edge.getDestination()),
|
||||
Graph.GSON.toJson(edge.getWeight())
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
public String[] vertices;
|
||||
public EdgeSaveStructure[] edges;
|
||||
//public MarkSaveStructure[] marks;
|
||||
public String other;
|
||||
}
|
||||
18
src/berack96/sim/util/graph/models/MarkSaveStructure.java
Normal file
18
src/berack96/sim/util/graph/models/MarkSaveStructure.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package berack96.sim.util.graph.models;
|
||||
|
||||
/**
|
||||
* Support class used for saving a Graph in a file.
|
||||
*
|
||||
* @author Berack96
|
||||
*
|
||||
*/
|
||||
public class MarkSaveStructure {
|
||||
public MarkSaveStructure() {}
|
||||
protected MarkSaveStructure(String v, Object m) {
|
||||
this.vert = v;
|
||||
this.mark = m;
|
||||
}
|
||||
|
||||
public String vert;
|
||||
public Object mark;
|
||||
}
|
||||
@@ -153,7 +153,6 @@ public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
graphPanel.save(fileText.getText());
|
||||
textResult.setText("");
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
textResult.setText(e1.getMessage());
|
||||
}
|
||||
});
|
||||
@@ -163,7 +162,6 @@ public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
graphPanel.load(fileText.getText());
|
||||
textResult.setText("");
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
textResult.setText(e1.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -31,6 +31,8 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final GraphicalView<VertexComponent<V>> vertexRender;
|
||||
private final GraphicalView<EdgeComponent<V, W>> edgeRender;
|
||||
private final Class<V> classV;
|
||||
private final Class<W> classW;
|
||||
|
||||
private final Container vertices = new Container();
|
||||
private final Container edges = new Container();
|
||||
@@ -40,9 +42,11 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
|
||||
private GraphListener old = null;
|
||||
|
||||
public GraphPanel(GraphicalView<VertexComponent<V>> vertexRender, GraphicalView<EdgeComponent<V, W>> edgeRender) {
|
||||
public GraphPanel(GraphicalView<VertexComponent<V>> vertexRender, GraphicalView<EdgeComponent<V, W>> edgeRender, Class<V> classV, Class<W> classW) {
|
||||
this.vertexRender = vertexRender;
|
||||
this.edgeRender = edgeRender;
|
||||
this.classV = classV;
|
||||
this.classW = classW;
|
||||
}
|
||||
|
||||
public Graph<V, W> getGraph() {
|
||||
@@ -166,17 +170,19 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
}
|
||||
|
||||
public void load(String fileName) throws IOException {
|
||||
String saveContent = Graph.load(graph, fileName);
|
||||
String saveContent = Graph.load(graph, fileName, classV, classW);
|
||||
GraphGraphicalSave save = Graph.GSON.fromJson(saveContent, GraphGraphicalSave.class);
|
||||
vertices.removeAll();
|
||||
edges.removeAll();
|
||||
|
||||
for(int i = 0; i<save.vertices.size(); i++) {
|
||||
V v = save.vertices.get(i);
|
||||
Point p = save.points.get(i);
|
||||
for(int i = 0; i<save.vertices.length; i++) {
|
||||
V v = Graph.GSON.fromJson(save.vertices[i], classV);
|
||||
Point p = save.points[i];
|
||||
addVertex(p, v);
|
||||
}
|
||||
save.vertices.forEach(v -> graph.getEdgesOut(v).forEach(e -> addEdge(e)));
|
||||
|
||||
for(String v : save.vertices)
|
||||
graph.getEdgesOut(Graph.GSON.fromJson(v, classV)).forEach(e -> addEdge(e));
|
||||
|
||||
repaint();
|
||||
}
|
||||
@@ -226,16 +232,34 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
class GraphGraphicalSave {
|
||||
public GraphGraphicalSave() {}
|
||||
protected GraphGraphicalSave(Container vertices) {
|
||||
this.vertices = new LinkedList<>();
|
||||
this.points = new LinkedList<>();
|
||||
List<String> v = new LinkedList<>();
|
||||
List<Point> p = new LinkedList<>();
|
||||
|
||||
for(Component vertex : vertices.getComponents()) {
|
||||
this.points.add(new Point(vertex.getX(), vertex.getY()));
|
||||
this.vertices.add(((VertexComponent<V>) vertex).vertex.getValue());
|
||||
Point temp = new Point(vertex.getX(), vertex.getY());
|
||||
temp.x += vertex.getWidth() / 2;
|
||||
temp.y += vertex.getHeight() / 2;
|
||||
|
||||
p.add(temp);
|
||||
v.add(Graph.GSON.toJson(((VertexComponent<V>) vertex).vertex.getValue()));
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
this.vertices = new String[v.size()];
|
||||
for(String s : v) {
|
||||
this.vertices[i] = s;
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
this.points = new Point[p.size()];
|
||||
for(Point pt : p) {
|
||||
this.points[i] = pt;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public List<V> vertices;
|
||||
public List<Point> points;
|
||||
public String[] vertices;
|
||||
public Point[] points;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class GraphWindow<V, W extends Number> extends JFrame {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static void main(String[] args) {
|
||||
GraphPanel<Integer, Integer> panel = new GraphPanel<>(new VertexView<>(), new EdgeView<>());
|
||||
GraphPanel<Integer, Integer> panel = new GraphPanel<>(new VertexView<>(), new EdgeView<>(), Integer.class, Integer.class);
|
||||
GraphWindow<Integer, Integer> win = new GraphWindow<>(panel, new VertexIntListener(panel), new EdgeIntListener<>(panel));
|
||||
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // full screen
|
||||
dim.setSize(dim.width / 2, dim.height / 2);
|
||||
|
||||
@@ -9,7 +9,8 @@ import java.awt.*;
|
||||
* @author Berack96
|
||||
*/
|
||||
public interface GraphicalView<O> {
|
||||
/**
|
||||
|
||||
/**
|
||||
* Box where the object is sensible at listeners (like Hitbox)
|
||||
*
|
||||
* @param obj the object to draw
|
||||
@@ -17,7 +18,7 @@ public interface GraphicalView<O> {
|
||||
* @return a rectangle where the object is sensible to the listeners
|
||||
*/
|
||||
Rectangle getBox(O obj, Point center);
|
||||
|
||||
|
||||
/**
|
||||
* The paint function, aka the part where you can draw things (like Mesh)
|
||||
*
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -24,6 +25,8 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import berack96.sim.util.graph.Edge;
|
||||
import berack96.sim.util.graph.Graph;
|
||||
import berack96.sim.util.graph.MapGraph;
|
||||
@@ -1332,6 +1335,8 @@ public class TestGraph {
|
||||
String fileName = "test/resources/test.json";
|
||||
Set<String> vertices = new HashSet<>();
|
||||
Set<Edge<String, Integer>> edges = new HashSet<>();
|
||||
Map<String, Set<Object>> marks = new HashMap<>();
|
||||
Set<Object> temp = new HashSet<>();
|
||||
|
||||
vertices.add("1");
|
||||
vertices.add("2");
|
||||
@@ -1351,30 +1356,63 @@ public class TestGraph {
|
||||
edges.add(new Edge<>("6", "2", 2));
|
||||
edges.add(new Edge<>("8", "7", 9));
|
||||
|
||||
temp.add(1);
|
||||
marks.put("2", new HashSet<>(temp));
|
||||
temp.add("blue");
|
||||
marks.put("1", new HashSet<>(temp));
|
||||
marks.put("7", new HashSet<>(temp));
|
||||
temp.remove(1);
|
||||
temp.add(4.0);
|
||||
marks.put("4", new HashSet<>(temp));
|
||||
marks.put("8", new HashSet<>(temp));
|
||||
temp.remove(4.0);
|
||||
temp.add("red");
|
||||
marks.put("5", new HashSet<>(temp));
|
||||
temp.remove("blue");
|
||||
marks.put("6", new HashSet<>(temp));
|
||||
temp.clear();
|
||||
|
||||
graph.addAllVertices(vertices);
|
||||
graph.addAllEdges(edges);
|
||||
|
||||
/* because GSON convert to double */
|
||||
/*
|
||||
Set<Edge<String, Double>> edgesD = new HashSet<>();
|
||||
edges.forEach((e) -> edgesD.add(new Edge<String, Double>(e.getSource(), e.getDestination(), e.getWeight().doubleValue())));
|
||||
*/
|
||||
Set<Edge<String, Integer>> edgesD = edges;
|
||||
marks.forEach((v, m) -> m.forEach(mk -> graph.mark(v, mk)));
|
||||
|
||||
try {
|
||||
Graph.save(graph, fileName);
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
shouldContain(graph.edges(), edgesD.toArray());
|
||||
shouldContain(graph.edges(), edges.toArray());
|
||||
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
|
||||
|
||||
graph.removeAllVertex();
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
shouldContain(graph.edges(), edgesD.toArray());
|
||||
shouldContain(graph.edges(), edges.toArray());
|
||||
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Graph.load(graph, "sadadafacensi", String.class, Integer.class);
|
||||
fail("Should have been thrown IOException");
|
||||
} catch (Exception ignore) {
|
||||
if (!(ignore instanceof IOException))
|
||||
fail("Should have been thrown IOException " + ignore.getMessage());
|
||||
}
|
||||
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
shouldContain(graph.edges(), edges.toArray());
|
||||
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
|
||||
|
||||
try {
|
||||
Graph.load(graph, fileName + ".fail", String.class, Integer.class);
|
||||
fail("Should have been thrown JsonSyntaxException");
|
||||
} catch (Exception ignore) {
|
||||
if (!(ignore instanceof JsonSyntaxException))
|
||||
fail("Should have been thrown JsonSyntaxException " + ignore.getMessage());
|
||||
}
|
||||
|
||||
graph = null;
|
||||
shouldThrow(new NullPointerException(), () -> { try {
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"vertices":["1","2","3","4","5","6","7","8"],"edges":[{"source":"1","destination":"2","weight":1},{"source":"1","destination":"3","weight":1},{"source":"5","destination":"4","weight":5},{"source":"6","destination":"2","weight":2},{"source":"5","destination":"3","weight":2},{"source":"8","destination":"7","weight":9},{"source":"4","destination":"6","weight":6},{"source":"2","destination":"5","weight":4}],"other":""}
|
||||
{"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","\"6\"","\"7\"","\"8\""],"edges":[{"src":"\"1\"","dest":"\"2\"","weight":"1"},{"src":"\"1\"","dest":"\"3\"","weight":"1"},{"src":"\"5\"","dest":"\"4\"","weight":"5"},{"src":"\"6\"","dest":"\"2\"","weight":"2"},{"src":"\"5\"","dest":"\"3\"","weight":"2"},{"src":"\"8\"","dest":"\"7\"","weight":"9"},{"src":"\"4\"","dest":"\"6\"","weight":"6"},{"src":"\"2\"","dest":"\"5\"","weight":"4"}],"other":""}
|
||||
1
test/resources/test.json.fail
Normal file
1
test/resources/test.json.fail
Normal file
@@ -0,0 +1 @@
|
||||
{"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","gfadad\"6\"","\"7\"","\"8\""],"edges":{"src":["\"1\"","\"1\"","\"5\"","\"6\"","\"5\"","\"8\"","\"4\"","\"2\""],"dest":["\"2\"","\"3\"","\"4\"","\"2\"","\"3\"","\"7\"","\"6ads\"","\"5\""],ad"wedight":["1","1","5","2","2","9","6","4"]},"other":""dsada}
|
||||
Reference in New Issue
Block a user