Skip to content

Commit d0a1e1b

Browse files
committed
✨ Added GraphWriter
Fixes #17
1 parent 0d642aa commit d0a1e1b

File tree

3 files changed

+251
-2
lines changed

3 files changed

+251
-2
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package komposten.tcs.backend;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.util.Map.Entry;
6+
7+
import javax.xml.XMLConstants;
8+
import javax.xml.parsers.DocumentBuilderFactory;
9+
import javax.xml.parsers.ParserConfigurationException;
10+
import javax.xml.transform.OutputKeys;
11+
import javax.xml.transform.Transformer;
12+
import javax.xml.transform.TransformerConfigurationException;
13+
import javax.xml.transform.TransformerException;
14+
import javax.xml.transform.TransformerFactory;
15+
import javax.xml.transform.dom.DOMSource;
16+
import javax.xml.transform.stream.StreamResult;
17+
18+
import org.w3c.dom.Document;
19+
import org.w3c.dom.Element;
20+
21+
import com.badlogic.gdx.graphics.Color;
22+
import com.badlogic.gdx.math.Vector3;
23+
24+
import komposten.tcs.backend.Style.Colour;
25+
import komposten.tcs.backend.Style.Setting;
26+
import komposten.tcs.backend.data.GraphData;
27+
import komposten.tcs.backend.data.Point;
28+
import komposten.tcs.backend.data.PointGroup;
29+
import komposten.tcs.backend.data.Volume;
30+
import komposten.tcs.util.TCSUtils;
31+
import komposten.utilities.tools.MathOps;
32+
33+
34+
public class GraphWriter
35+
{
36+
/**
37+
* Writes the specified {@link GraphData} to the specified file.
38+
* @param graph The <code>GraphData</code> to save.
39+
* @param style The graph's style.
40+
* @param file The destination file.
41+
* @throws IOException If the XML model could not be created or saved to the destination file.
42+
*/
43+
public void write(GraphData graph, Style style, File file) throws IOException
44+
{
45+
try
46+
{
47+
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
48+
docBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
49+
Document doc = docBuilderFactory.newDocumentBuilder().newDocument();
50+
51+
Element dataElement = doc.createElement("data");
52+
doc.appendChild(dataElement);
53+
54+
addStyleElement(style, doc, dataElement);
55+
addPointElements(graph, style, doc, dataElement);
56+
addVolumeElements(graph, doc, dataElement);
57+
58+
saveToFile(doc, file);
59+
}
60+
catch (ParserConfigurationException e)
61+
{
62+
throw new IOException("Could not configure the XML parser!", e);
63+
}
64+
}
65+
66+
67+
private void addStyleElement(Style style, Document doc, Element parent)
68+
{
69+
if (!style.getChangedColours().isEmpty() || !style.getChangedSettings().isEmpty())
70+
{
71+
Element styleElement = doc.createElement("style");
72+
parent.appendChild(styleElement);
73+
74+
for (Entry<Colour, Color> entry : style.getChangedColours().entrySet())
75+
{
76+
Element colourElement = doc.createElement("colour");
77+
colourElement.setAttribute("id", entry.getKey().name().toLowerCase());
78+
colourElement.setTextContent("#" + entry.getValue().toString());
79+
styleElement.appendChild(colourElement);
80+
}
81+
82+
for (Entry<Setting, Number> entry : style.getChangedSettings().entrySet())
83+
{
84+
Element settingElement = doc.createElement("setting");
85+
settingElement.setAttribute("id", entry.getKey().name().toLowerCase());
86+
settingElement.setTextContent(entry.getValue().toString());
87+
styleElement.appendChild(settingElement);
88+
}
89+
}
90+
}
91+
92+
93+
private void addPointElements(GraphData graph, Style style, Document doc,
94+
Element parent)
95+
{
96+
for (PointGroup group : graph.getDataGroups())
97+
{
98+
Element groupElement = doc.createElement("group");
99+
groupElement.setAttribute("name", group.getName());
100+
groupElement.setAttribute("shape", group.getShape().toString());
101+
102+
if (!MathOps.equals(group.getSize(), style.get(Setting.POINT_SIZE).floatValue(), 0.00001f))
103+
groupElement.setAttribute("size", Float.toString(group.getSize()));
104+
105+
for (Point point : group.getPoints())
106+
{
107+
Element pointElement = doc.createElement("point");
108+
pointElement.setAttribute("name", point.getName());
109+
pointElement.setAttribute("colour", "#" + point.getColour().toString());
110+
pointElement.setAttribute("position", vectorToString(point.getMetrics()));
111+
groupElement.appendChild(pointElement);
112+
}
113+
114+
parent.appendChild(groupElement);
115+
}
116+
}
117+
118+
119+
private void addVolumeElements(GraphData graph, Document doc, Element parent)
120+
{
121+
for (Volume volume : graph.getDataVolumes())
122+
{
123+
Element volumeElement = doc.createElement("volume");
124+
volumeElement.setAttribute("colour", "#" + volume.getColour().toString());
125+
volumeElement.setTextContent(volumeToString(volume));
126+
127+
parent.appendChild(volumeElement);
128+
}
129+
}
130+
131+
132+
private String vectorToString(Vector3 vector)
133+
{
134+
return String.format("%f,%f,%f", vector.x, vector.y, vector.z);
135+
}
136+
137+
138+
private String volumeToString(Volume volume)
139+
{
140+
StringBuilder builder = new StringBuilder();
141+
142+
double[] coords = volume.getCoordinates();
143+
for (int i = 0; i < coords.length; i += 3)
144+
{
145+
Vector3 metrics = TCSUtils.getMetricsForCoordinates(
146+
(float) coords[i], (float) coords[i + 1],
147+
(float) coords[i + 2]);
148+
builder.append(metrics.x).append(',')
149+
.append(metrics.y).append(',')
150+
.append(metrics.z).append('\n');
151+
}
152+
153+
return builder.toString();
154+
}
155+
156+
157+
private void saveToFile(Document doc, File file) throws IOException
158+
{
159+
try
160+
{
161+
TransformerFactory transformerFactory = TransformerFactory.newInstance();
162+
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
163+
Transformer transformer = transformerFactory.newTransformer();
164+
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
165+
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
166+
DOMSource source = new DOMSource(doc);
167+
StreamResult result = new StreamResult(file);
168+
169+
transformer.transform(source, result);
170+
}
171+
catch (TransformerConfigurationException e)
172+
{
173+
throw new IOException("Could not create the XML transformer!", e);
174+
}
175+
catch (TransformerException e)
176+
{
177+
throw new IOException("Could not save the XML to " + file.getName() + "!", e);
178+
}
179+
}
180+
}

core/src/komposten/tcs/backend/Style.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@
1919
package komposten.tcs.backend;
2020

2121
import java.util.EnumMap;
22+
import java.util.EnumSet;
2223
import java.util.Map;
24+
import java.util.Set;
2325

2426
import org.w3c.dom.Node;
2527
import org.w3c.dom.NodeList;
2628

2729
import com.badlogic.gdx.graphics.Color;
30+
import com.badlogic.gdx.math.MathUtils;
2831

2932
import komposten.tcs.util.TCSUtils;
3033
import komposten.utilities.tools.MathOps;
@@ -60,6 +63,9 @@ public enum Setting
6063

6164
private Map<Colour, Color> colours;
6265
private Map<Setting, Number> settings;
66+
67+
private Set<Colour> isDefaultColour;
68+
private Set<Setting> isDefaultSetting;
6369

6470
public Style()
6571
{
@@ -71,6 +77,8 @@ public Style()
7177
{
7278
colours = new EnumMap<>(Colour.class);
7379
settings = new EnumMap<>(Setting.class);
80+
isDefaultColour = EnumSet.noneOf(Colour.class);
81+
isDefaultSetting = EnumSet.noneOf(Setting.class);
7482

7583
loadDefaults();
7684
if (styleNode != null)
@@ -137,7 +145,15 @@ private void loadColour(String id, String value)
137145
Colour colour = Colour.valueOf(id);
138146

139147
if (colour != null)
140-
colours.put(colour, TCSUtils.getColourFromHex(value));
148+
{
149+
Color colourObj = TCSUtils.getColourFromHex(value);
150+
151+
if (!colourObj.equals(colours.get(colour)))
152+
{
153+
colours.put(colour, colourObj);
154+
isDefaultColour.add(colour);
155+
}
156+
}
141157
}
142158

143159

@@ -170,7 +186,11 @@ private void loadSetting(String id, String value)
170186
return;
171187
}
172188

173-
settings.put(setting, number);
189+
if (!MathUtils.isEqual(number.floatValue(), settings.get(setting).floatValue()))
190+
{
191+
settings.put(setting, number);
192+
isDefaultSetting.add(setting);
193+
}
174194
}
175195

176196

@@ -218,4 +238,26 @@ public Number get(Setting key)
218238
{
219239
return settings.get(key);
220240
}
241+
242+
243+
public Map<Colour, Color> getChangedColours()
244+
{
245+
Map<Colour, Color> result = new EnumMap<>(Colour.class);
246+
247+
for (Colour colour : isDefaultColour)
248+
result.put(colour, colours.get(colour));
249+
250+
return result;
251+
}
252+
253+
254+
public Map<Setting, Number> getChangedSettings()
255+
{
256+
Map<Setting, Number> result = new EnumMap<>(Setting.class);
257+
258+
for (Setting setting : isDefaultSetting)
259+
result.put(setting, settings.get(setting));
260+
261+
return result;
262+
}
221263
}

core/src/komposten/tcs/util/TCSUtils.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
2727
import com.badlogic.gdx.math.Vector3;
2828

29+
import komposten.utilities.tools.MathOps;
30+
2931

3032
public class TCSUtils
3133
{
@@ -54,6 +56,31 @@ public static Vector3 getCoordinatesForMetrics(float theta, float phi, float mag
5456
coords.setLength(magnitude);
5557
return coords;
5658
}
59+
60+
61+
/**
62+
* Calculates the colour metrics (theta, phi and r) for a given set of
63+
* Cartesian coordinates.
64+
*
65+
* @return A vector containing theta, phi and r (absolute magnitude) as x, y,
66+
* and z, respectively.
67+
*/
68+
public static Vector3 getMetricsForCoordinates(Vector3 coordinates)
69+
{
70+
float r = coordinates.len();
71+
float theta = -MathOps.angle(0, 0, coordinates.x, coordinates.z);
72+
73+
coordinates.rotateRad(Vector3.Y, -theta);
74+
float phi = MathOps.angle(0, 0, coordinates.x, coordinates.y);
75+
76+
return new Vector3(theta, phi, r);
77+
}
78+
79+
80+
public static Vector3 getMetricsForCoordinates(float x, float y, float z)
81+
{
82+
return getMetricsForCoordinates(new Vector3(x, y, z));
83+
}
5784

5885

5986
public static Color getColourFromHex(String hexColour)

0 commit comments

Comments
 (0)