Notice: If you are member of any public project or group, please make sure that your GitLab username is not the same as the LRZ identifier/Kennung (see https://gitlab.lrz.de/profile/account). Please change your username if necessary. For more information see the section "Public projects / Öffentliche Projekte" at https://doku.lrz.de/display/PUBLIC/GitLab . Thank you!

Commit 415d81b2 authored by BZoennchen's avatar BZoennchen

Merge branch 'dev/meshing' into 'master'

Dev/meshing

See merge request !73
parents 6c3ee934 5c863f00
Pipeline #129452 passed with stages
in 115 minutes and 30 seconds
......@@ -244,6 +244,7 @@ ProjectView.btnSnapshot.tooltip=Snapshot
ProjectView.btnPNGSnapshot.tooltip=PNG Snapshot
ProjectView.btnSVGSnapshot.tooltip=SVG Snapshot
ProjectView.btnTikZSnapshot.tooltip=TikZ Snapshot
ProjectView.btnPolySnapshot.tooltip=Poly Snapshot
PostVis.menuFile.title=File
PostVis.menuSettings.title=Setting
PostVis.menuRecentFiles.title=Recent Files
......
......@@ -240,6 +240,7 @@ ProjectView.btnSnapshot.tooltip=Snapshot
ProjectView.btnPNGSnapshot.tooltip=PNG-Snapshot
ProjectView.btnSVGSnapshot.tooltip=SVG-Snapshot
ProjectView.btnTikZSnapshot.tooltip=TikZ-Snapshot
ProjectView.btnPolySnapshot.tooltip=Poly-Snapshot
PostVis.menuFile.title=Datei
PostVis.menuSettings.title=Einstellungen
PostVis.menuRecentFiles.title=K\u00FCrzlich verwendete Dateien
......
package org.vadere.gui.components.control.simulation;
import org.vadere.gui.components.model.DefaultSimulationConfig;
import org.vadere.gui.components.model.SimulationModel;
import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.components.utils.Resources;
import org.vadere.gui.components.view.SimulationRenderer;
import org.vadere.gui.postvisualization.PostVisualisation;
import org.vadere.meshing.utils.io.poly.PSLGGenerator;
import org.vadere.state.scenario.Obstacle;
import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.logging.Logger;
import java.awt.event.ActionEvent;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.prefs.Preferences;
import java.util.stream.Collectors;
import javax.swing.*;
public class ActionGeneratePoly extends AbstractAction {
private static Logger logger = Logger.getLogger(ActionGeneratePNG.class);
private static Resources resources = Resources.getInstance("global");
private final SimulationModel<? extends DefaultSimulationConfig> model;
public ActionGeneratePoly(final String name, Icon icon, final SimulationRenderer renderer,
final SimulationModel<? extends DefaultSimulationConfig> model) {
super(name, icon);
this.model = model;
}
@Override
public void actionPerformed(final ActionEvent e) {
JFileChooser fileChooser = new JFileChooser(Preferences.userNodeForPackage(PostVisualisation.class).get("SettingsDialog.snapshotDirectory.path", "."));
Date todaysDate = new java.util.Date();
SimpleDateFormat formatter = new SimpleDateFormat(resources.getProperty("SettingsDialog.dataFormat"));
String formattedDate = formatter.format(todaysDate);
File outputFile = new File(Messages.getString("FileDialog.filenamePrefix") + formattedDate + ".poly");
fileChooser.setSelectedFile(outputFile);
int returnVal = fileChooser.showDialog(null, "Save");
if (returnVal == JFileChooser.APPROVE_OPTION) {
outputFile = fileChooser.getSelectedFile().toString().endsWith(".poly") ? fileChooser.getSelectedFile()
: new File(fileChooser.getSelectedFile().toString() + ".poly");
List<Obstacle> boundingObstacles = model.getTopography().getBoundaryObstacles();
Rectangle2D.Double boundWithBorder = model.getTopography().getBounds();
double boundWidth = model.getTopography().getBoundingBoxWidth();
VRectangle bound = new VRectangle(boundWithBorder.x + boundWidth, boundWithBorder.y + boundWidth, boundWithBorder.width - 2*boundWidth, boundWithBorder.height - 2*boundWidth);
List<Obstacle> obstacles = new ArrayList<>(model.getTopography().getObstacles());
obstacles.removeAll(model.getTopography().getBoundaryObstacles());
String polyString = PSLGGenerator.toPSLG(
new VPolygon(bound),
obstacles.stream()
.map(obs -> obs.getShape())
.map(shape -> new VPolygon(shape))
.collect(Collectors.toList()));
try {
outputFile.createNewFile();
Writer out = new OutputStreamWriter(new FileOutputStream(outputFile), "UTF-8");
out.write(polyString);
out.flush();
logger.info("generate new Poly.file: " + outputFile.getAbsolutePath());
} catch (IOException e1) {
logger.error(e1.getMessage());
e1.printStackTrace();
}
}
}
}
......@@ -6,11 +6,8 @@ import java.util.function.Function;
import org.vadere.meshing.mesh.gen.PMesh;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.simulator.models.potential.solver.calculators.mesh.PotentialPoint;
import org.vadere.state.scenario.Agent;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.geometry.shapes.VPoint;
import org.vadere.util.geometry.shapes.VRectangle;
public abstract class SimulationModel<T extends DefaultSimulationConfig> extends DefaultModel {
......@@ -42,8 +39,8 @@ public abstract class SimulationModel<T extends DefaultSimulationConfig> extends
return config;
}
public IMesh<? extends IPotentialPoint, ?, ?, ?> getDiscretization() {
return new PMesh<IPotentialPoint>((x,y) -> new PotentialPoint(x,y));
public IMesh<?, ?, ?> getDiscretization() {
return new PMesh();
}
/*public double getPotential(final int x, final int y) {
......
......@@ -8,7 +8,6 @@ import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.MeasurementArea;
import org.vadere.state.scenario.ScenarioElement;
import org.vadere.state.scenario.Stairs;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.Vector2D;
import org.vadere.util.geometry.shapes.VCircle;
import org.vadere.util.geometry.shapes.VLine;
......@@ -634,10 +633,10 @@ public abstract class DefaultRenderer {
protected void renderMesh(
@NotNull final Graphics2D g,
@NotNull final IMesh<? extends IPotentialPoint, ?, ?, ?> mesh,
@NotNull final IMesh<?, ?, ?> mesh,
@NotNull final VRectangle bound) {
MeshRenderer<? extends IPotentialPoint, ?, ?, ?> meshRenderer = new MeshRenderer<>(mesh);
meshRenderer.renderGraphics(g, bound);
MeshRenderer<?, ?, ?> meshRenderer = new MeshRenderer<>(mesh);
//meshRenderer.renderGraphics(g, bound);
}
protected void renderVoronoiDiagram(final Graphics2D g, final VoronoiDiagram voronoiDiagram) {
......
......@@ -13,7 +13,6 @@ import org.vadere.simulator.models.potential.fields.IPotentialField;
import org.vadere.simulator.models.potential.fields.IPotentialFieldTarget;
import org.vadere.state.scenario.Agent;
import org.vadere.state.scenario.Topography;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.VRectangle;
import java.util.function.Function;
......@@ -32,7 +31,7 @@ public class OnlineVisualization implements PassiveCallback {
public final IPotentialField potentialFieldTarget;
public final Agent selectedAgent;
public final IPotentialField potentialField;
public final Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations;
public final Function<Agent, IMesh<?, ?, ?>> discretizations;
public ObservationAreaSnapshotData(
final double simTimeInSec,
......@@ -40,7 +39,7 @@ public class OnlineVisualization implements PassiveCallback {
@Nullable final IPotentialField potentialFieldTarget,
@Nullable final IPotentialField potentialField,
@Nullable final Agent selectedAgent,
@Nullable final Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations) {
@Nullable final Function<Agent, IMesh<?, ?, ?>> discretizations) {
this.simTimeInSec = simTimeInSec;
this.scenario = scenario;
this.potentialFieldTarget = potentialFieldTarget;
......@@ -124,7 +123,7 @@ public class OnlineVisualization implements PassiveCallback {
synchronized (model.getDataSynchronizer()) {
/* Push new snapshot of the observation area to the draw thread. */
IPotentialField pft = (model.config.isShowTargetPotentialField() && potentialFieldTarget != null) ? potentialFieldTarget.getSolution() : null;
Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations = (model.config.isShowTargetPotentielFieldMesh() && potentialFieldTarget != null) ? potentialFieldTarget.getDiscretization() : null;
Function<Agent, IMesh<?, ?, ?>> discretizations = (model.config.isShowTargetPotentielFieldMesh() && potentialFieldTarget != null) ? potentialFieldTarget.getDiscretization() : null;
IPotentialField pedPotentialField = null;
Agent selectedAgent = null;
......
......@@ -14,9 +14,7 @@ import org.vadere.gui.onlinevisualization.OnlineVisualization;
import org.vadere.meshing.mesh.gen.PMesh;
import org.vadere.meshing.mesh.inter.IMesh;
import org.vadere.simulator.models.potential.fields.IPotentialField;
import org.vadere.simulator.models.potential.solver.calculators.mesh.PotentialPoint;
import org.vadere.state.scenario.*;
import org.vadere.util.data.cellgrid.IPotentialPoint;
import org.vadere.util.geometry.shapes.IPoint;
import org.vadere.util.voronoi.VoronoiDiagram;
......@@ -37,7 +35,7 @@ public class OnlineVisualizationModel extends SimulationModel<DefaultSimulationC
private IPotentialField potentialField = null;
private Function<Agent, IMesh<? extends IPotentialPoint, ?, ?, ?>> discretizations = null;
private Function<Agent, IMesh<?, ?, ?>> discretizations = null;
private Agent agent = null;
......@@ -209,12 +207,12 @@ public class OnlineVisualizationModel extends SimulationModel<DefaultSimulationC
}
@Override
public IMesh<? extends IPotentialPoint, ?, ?, ?> getDiscretization() {
public IMesh<?, ?, ?> getDiscretization() {
if(agent != null && discretizations != null && config.isShowTargetPotentielFieldMesh() && agent.equals(getSelectedElement())) {
return discretizations.apply(agent);
}
return new PMesh<IPotentialPoint>((x, y) -> new PotentialPoint(x, y));
return new PMesh();
}
@Override
......
......@@ -7,6 +7,7 @@ import org.vadere.gui.components.control.IViewportChangeListener;
import org.vadere.gui.components.control.JViewportChangeListener;
import org.vadere.gui.components.control.PanelResizeListener;
import org.vadere.gui.components.control.ViewportChangeListener;
import org.vadere.gui.components.control.simulation.ActionGeneratePoly;
import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.components.utils.Resources;
import org.vadere.gui.components.utils.SwingUtils;
......@@ -174,7 +175,6 @@ public class OnlineVisualisationWindow extends JPanel implements Observer {
renderer,
model);
ActionGenerateSVG generateSVG = new ActionGenerateSVG(
Messages.getString("ProjectView.btnSVGSnapshot.tooltip"),
resources.getIcon("camera_svg.png", iconWidth, iconHeight),
......@@ -187,6 +187,12 @@ public class OnlineVisualisationWindow extends JPanel implements Observer {
renderer,
model);
ActionGeneratePoly generatePoly = new ActionGeneratePoly(
Messages.getString("ProjectView.btnPolySnapshot.tooltip"),
resources.getIcon("camera_poly.png", iconWidth, iconHeight),
renderer,
model);
ActionShowPotentialField showPotentialField = new ActionShowPotentialField(
"showPotentialField",
resources.getIcon("potentialField.png", iconWidth, iconHeight),
......@@ -222,6 +228,7 @@ public class OnlineVisualisationWindow extends JPanel implements Observer {
imgOptions.add(generatePNG);
imgOptions.add(generateSVG);
imgOptions.add(generateTikz);
imgOptions.add(generatePoly);
ActionOnlineVisMenu imgDialog = new ActionOnlineVisMenu(
"camera_menu",
......
......@@ -7,7 +7,12 @@ import org.vadere.gui.components.control.IViewportChangeListener;
import org.vadere.gui.components.control.JViewportChangeListener;
import org.vadere.gui.components.control.PanelResizeListener;
import org.vadere.gui.components.control.ViewportChangeListener;
import org.vadere.gui.components.control.simulation.*;
import org.vadere.gui.components.control.simulation.ActionGeneratePNG;
import org.vadere.gui.components.control.simulation.ActionGeneratePoly;
import org.vadere.gui.components.control.simulation.ActionGenerateSVG;
import org.vadere.gui.components.control.simulation.ActionGenerateTikz;
import org.vadere.gui.components.control.simulation.ActionSwapSelectionMode;
import org.vadere.gui.components.control.simulation.ActionVisualization;
import org.vadere.gui.components.model.IDefaultModel;
import org.vadere.gui.components.utils.Messages;
import org.vadere.gui.components.utils.Resources;
......@@ -244,11 +249,16 @@ public class PostvisualizationWindow extends JPanel implements Observer, DropTar
renderer, model);
AbstractAction tikzImg = new ActionGenerateTikz(Messages.getString("ProjectView.btnTikZSnapshot.tooltip"), resources.getIcon("camera_tikz.png", iconWidth, iconHeight),
renderer, model);
AbstractAction polyImg = new ActionGeneratePoly(Messages.getString("ProjectView.btnPolySnapshot.tooltip"), resources.getIcon("camera_poly.png", iconWidth, iconHeight),
renderer, model);
// add new ImageGenerator Action ...
imgOptions.add(pngImg);
imgOptions.add(svgImg);
imgOptions.add(tikzImg);
imgOptions.add(polyImg);
// add Action to List ....
ActionVisualizationMenu imgDialog = new ActionVisualizationMenu(
......
......@@ -3,6 +3,7 @@ package org.vadere.gui.projectview;
import org.apache.commons.lang3.time.StopWatch;
import org.vadere.gui.components.utils.Recorder;
import org.vadere.meshing.mesh.gen.MeshRenderer;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.impl.AEikMesh;
import org.vadere.util.logging.StdOutErrLog;
import org.vadere.util.visualization.ColorHelper;
import org.vadere.util.geometry.GeometryUtils;
......@@ -15,9 +16,7 @@ import org.vadere.util.geometry.shapes.VPolygon;
import org.vadere.util.geometry.shapes.VRectangle;
import org.vadere.util.geometry.shapes.VShape;
import org.vadere.util.math.DistanceFunction;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.EikMeshPoint;
import org.vadere.meshing.mesh.gen.MeshPanel;
import org.vadere.meshing.mesh.triangulation.improver.eikmesh.impl.AEikMesh;
import java.awt.*;
import java.io.IOException;
......@@ -53,21 +52,21 @@ public class RecordTriangulationMovie {
bbound,
obstacleShapes);
Function<AFace<EikMeshPoint>, Color> colorFunction1 = f -> {
Function<AFace, Color> colorFunction1 = f -> {
float q = Math.max(0.0f, Math.min(1.0f, (float) meshImprover.faceToQuality(f)));
return new Color(q, q, q);
};
Function<AFace<EikMeshPoint>, Color> colorFunction2 = f -> {
Function<AFace, Color> colorFunction2 = f -> {
return ColorHelper.numberToHurColor((float)f.getId() / meshImprover.getMesh().getNumberOfFaces());
};
//ColorHelper.numberToHurColor((float)f.getId() / meshImprover.getMesh().getNumberOfFaces());
//new ColorHelper(meshImprover.getMesh().getNumberOfFaces()).numberToColor(f.getId());
MeshRenderer<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> meshRenderer = new MeshRenderer<>(
MeshRenderer<AVertex, AHalfEdge, AFace> meshRenderer = new MeshRenderer<>(
meshImprover.getMesh(), f -> false, colorFunction1);
MeshPanel<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> distmeshPanel = new MeshPanel<>(
MeshPanel<AVertex, AHalfEdge, AFace> distmeshPanel = new MeshPanel<>(
meshRenderer, bbound.getWidth()*1000, bbound.getHeight()*1000);
JFrame frame = distmeshPanel.display();
......@@ -119,7 +118,7 @@ public class RecordTriangulationMovie {
}
public static void addPictures(Recorder recorder,
MeshRenderer<EikMeshPoint, AVertex<EikMeshPoint>, AHalfEdge<EikMeshPoint>, AFace<EikMeshPoint>> renderer,
MeshRenderer<AVertex, AHalfEdge, AFace> renderer,
int frames,
int width,
int height) throws IOException {
......
......@@ -46,7 +46,7 @@ public class ActionRenameScenario extends AbstractAction {
ProjectWriter.renameScenario(scenario, model.getCurrentProjectPath(), newName);
model.saveScenarioToDisk(scenario);
// remove and insert the element such that the table is still sorted by name
// remove and insertVertex the element such that the table is still sorted by name
model.getScenarioTableModel().replace(scenario, new VadereScenarioTableModel.VadereDisplay(scenario, VadereState.INITIALIZED));
model.refreshScenarioNames();
/*
......
......@@ -434,11 +434,11 @@ public class TopographyWindow extends JPanel {
getActionMap().put("copy-element", copyElementAction);
TopographyAction insertCopiedElementAction =
new ActionInsertCopiedElement("insert copied element", panelModel, undoSupport);
new ActionInsertCopiedElement("insertVertex copied element", panelModel, undoSupport);
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
"insert-copied-element");
getActionMap().put("insert-copied-element", insertCopiedElementAction);
"insertVertex-copied-element");
getActionMap().put("insertVertex-copied-element", insertCopiedElementAction);
// delete element
TopographyAction deleteElement =
......
......@@ -43,5 +43,19 @@
<artifactId>utils</artifactId>
<version>${project.version}</version>
</dependency>
<!-- fast collections especially for primitive data tyes -->
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.2.3</version>
</dependency>
<!-- this is only to record some movies -->
<dependency>
<groupId>org.jcodec</groupId>
<artifactId>jcodec-javase</artifactId>
<version>0.1.9</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
# a.poly
#
# The capital letter A
#
# Declare 29 vertices, 2 dimensions, 1 attribute, no boundary markers.
#
29 2 1 0
#
# List the vertices.
#
1 0.200000 -0.776400 -0.57
2 0.220000 -0.773200 -0.55
3 0.245600 -0.756400 -0.51
4 0.277600 -0.702000 -0.53
5 0.488800 -0.207600 0.28
6 0.504800 -0.207600 0.30
7 0.740800 -0.739600 0
8 0.756000 -0.761200 -0.01
9 0.774400 -0.772400 0
10 0.800000 -0.776400 0.02
11 0.800000 -0.792400 0.01
12 0.579200 -0.792400 -0.21
13 0.579200 -0.776400 -0.2
14 0.621600 -0.771600 -0.15
15 0.633600 -0.762800 -0.13
16 0.639200 -0.744400 -0.1
17 0.620800 -0.684400 -0.06
18 0.587200 -0.604400 -0.01
19 0.360800 -0.604400 -0.24
20 0.319200 -0.706800 -0.39
21 0.312000 -0.739600 -0.43
22 0.318400 -0.761200 -0.44
23 0.334400 -0.771600 -0.44
24 0.371200 -0.776400 -0.41
25 0.371200 -0.792400 -0.42
26 0.374400 -0.570000 -0.2
27 0.574400 -0.570000 0
28 0.473600 -0.330800 0.14
29 0.200000 -0.792400 -0.59
#
# Declare the number of segments.
#
29 0
#
# List the segments.
#
1 29 1
2 1 2
3 2 3
4 3 4
5 4 5
6 5 6
7 6 7
8 7 8
9 8 9
10 9 10
11 10 11
12 11 12
13 12 13
14 13 14
15 14 15
16 15 16
17 16 17
18 17 18
19 18 19
20 19 20
21 20 21
22 21 22
23 22 23
24 23 24
25 24 25
26 25 29
27 26 27
28 27 28
29 28 26
#
# Declare the number of holes.
#
1
#
# Define the hole.
#
1 0.47 -0.5
\ No newline at end of file
# nVertices dimension nAttributes boundaryMarker
21 2 0 0
# vertexId x y
1 0.500000 0.500000
2 0.326351 11.349890
3 50.295924 42.506680
4 10.068317 15.240938
5 50.129121 5.936819
6 49.500000 49.500000
7 49.500000 0.500000
8 7.711478 10.030659
9 0.463889 45.907735
10 0.500000 49.500000
11 32.129121 5.936819
12 29.943119 0.478289
13 3.888684 20.251412
14 0.463889 42.907735
15 1.463889 42.907735
16 23.463889 45.907735
17 0.326351 -0.650110
18 15.459378 12.808810
19 20.931872 10.544835
20 29.943119 -1.521711
21 31.295924 42.506680
#
# nSegments boundaryMarker
21 0
# lineId vertexId1 vertexId2
1 7 6
2 6 10
3 10 1
4 1 7
5 3 21
6 21 19
7 19 11
8 11 5
9 5 3
10 20 12
11 12 8
12 8 2
13 2 17
14 17 20
15 13 4
16 4 18
17 18 16
18 16 9
19 9 14
20 14 15
21 15 13
#
# nHoles
3
# vertexId x y (of a vertex which lies inside the hole)
1 37.999061 23.296979
2 11.703993 3.490417
3 11.505979 32.412715
\ No newline at end of file
# nVertices dimension nAttributes boundaryMarker
82 2 0 0
# vertexId x y
1 20.800000 3.000000
2 22.300000 3.000000
3 22.300000 4.800000
4 27.500000 9.500000
5 19.000000 5.400000
6 21.500000 5.300000
7 20.000000 5.400000
8 20.800000 6.000000
9 11.300000 7.200000
10 16.000000 5.500000
11 27.500000 0.500000
12 20.800000 4.200000
13 20.800000 3.600000
14 10.000000 4.583333
15 22.400000 6.000000
16 15.000000 4.700000
17 0.500000 0.500000
18 14.000000 5.600000
19 24.000000 3.000000
20 25.500000 3.000000
21 9.000000 8.000000
22 8.000000 7.000000
23 10.000000 8.000000
24 15.000000 6.000000
25 8.000000 6.000000
26 16.000000 3.000000
27 17.000000 3.000000
28 13.000000 8.000000
29 18.000000 3.000000
30 19.500000 4.900000
31 19.000000 4.900000
32 21.500000 4.800000
33 8.000000 5.000000
34 10.000000 6.000000
35 14.000000 8.000000
36 20.000000 3.000000
37 23.000000 3.000000
38 12.000000 3.000000
39 16.000000 8.000000
40 24.000000 6.000000
41 17.000000 8.000000
42 25.500000 6.000000
43 13.000000 3.000000
44 14.000000 3.000000
45 11.900000 6.400000
46 23.000000 8.000000
47 8.000000 3.000000
48 24.000000 8.000000
49 10.721320 5.283356
50 9.000000 3.000000
51 18.000000 6.000000
52 10.000000 3.000000
53 20.000000 6.000000
54 24.700000 5.200000
55 0.500000 9.500000
56 11.000000 3.000000
57 4.000000 4.000000
58 6.000000 3.000000
59 21.600000 3.600000
60 5.000000 4.000000
61 7.000000 3.000000
62 3.000000 8.000000
63 6.000000 4.000000
64 19.000000 4.200000
65 19.500000 4.200000