1 package tim.prune.save;
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.FlowLayout;
6 import java.awt.GridLayout;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
10 import java.io.FileWriter;
11 import java.io.IOException;
12 import java.util.ArrayList;
13 import java.util.Iterator;
15 import javax.swing.BorderFactory;
16 import javax.swing.BoxLayout;
17 import javax.swing.ButtonGroup;
18 import javax.swing.JButton;
19 import javax.swing.JDialog;
20 import javax.swing.JFileChooser;
21 import javax.swing.JLabel;
22 import javax.swing.JOptionPane;
23 import javax.swing.JPanel;
24 import javax.swing.JRadioButton;
25 import javax.swing.JTextField;
26 import javax.swing.SwingConstants;
29 import tim.prune.I18nManager;
30 import tim.prune.UpdateMessageBroker;
31 import tim.prune.config.Config;
32 import tim.prune.data.NumberUtils;
33 import tim.prune.data.Track;
34 import tim.prune.function.Export3dFunction;
35 import tim.prune.gui.DialogCloser;
36 import tim.prune.load.GenericFileFilter;
37 import tim.prune.threedee.LineDialog;
38 import tim.prune.threedee.ThreeDModel;
41 * Class to export a 3d scene of the track to a specified Pov file
43 public class PovExporter extends Export3dFunction
45 private Track _track = null;
46 private JDialog _dialog = null;
47 private JFileChooser _fileChooser = null;
48 private String _cameraX = null, _cameraY = null, _cameraZ = null;
49 private JTextField _cameraXField = null, _cameraYField = null, _cameraZField = null;
50 private JTextField _fontName = null, _altitudeFactorField = null;
51 private JRadioButton _ballsAndSticksButton = null;
54 private static final double DEFAULT_CAMERA_DISTANCE = 30.0;
55 private static final String DEFAULT_FONT_FILE = "crystal.ttf";
60 * @param inApp App object
62 public PovExporter(App inApp)
65 _track = inApp.getTrackInfo().getTrack();
66 // Set default camera coordinates
67 _cameraX = "17"; _cameraY = "13"; _cameraZ = "-20";
70 /** Get the name key */
71 public String getNameKey() {
72 return "function.exportpov";
76 * Set the coordinates for the camera (can be any scale)
77 * @param inX X coordinate of camera
78 * @param inY Y coordinate of camera
79 * @param inZ Z coordinate of camera
81 public void setCameraCoordinates(double inX, double inY, double inZ)
83 // calculate distance from origin
84 double cameraDist = Math.sqrt(inX*inX + inY*inY + inZ*inZ);
87 _cameraX = NumberUtils.formatNumber(inX / cameraDist * DEFAULT_CAMERA_DISTANCE, 5);
88 _cameraY = NumberUtils.formatNumber(inY / cameraDist * DEFAULT_CAMERA_DISTANCE, 5);
89 // Careful! Need to convert from java3d (right-handed) to povray (left-handed) coordinate system!
90 _cameraZ = NumberUtils.formatNumber(-inZ / cameraDist * DEFAULT_CAMERA_DISTANCE, 5);
96 * Show the dialog to select options and export file
100 // Make dialog window to select angles, colours etc
103 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
104 _dialog.setLocationRelativeTo(_parentFrame);
105 _dialog.getContentPane().add(makeDialogComponents());
109 _cameraXField.setText(_cameraX);
110 _cameraYField.setText(_cameraY);
111 _cameraZField.setText(_cameraZ);
112 _altitudeFactorField.setText("" + _altFactor);
115 _dialog.setVisible(true);
120 * Make the dialog components to select the export options
121 * @return Component holding gui elements
123 private Component makeDialogComponents()
125 JPanel panel = new JPanel();
126 panel.setLayout(new BorderLayout());
127 JLabel introLabel = new JLabel(I18nManager.getText("dialog.exportpov.text"));
128 introLabel.setBorder(BorderFactory.createEmptyBorder(4, 4, 6, 4));
129 panel.add(introLabel, BorderLayout.NORTH);
130 // OK, Cancel buttons
131 JPanel buttonPanel = new JPanel();
132 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
133 JButton okButton = new JButton(I18nManager.getText("button.ok"));
134 okButton.addActionListener(new ActionListener() {
135 public void actionPerformed(ActionEvent e)
141 buttonPanel.add(okButton);
142 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
143 cancelButton.addActionListener(new ActionListener() {
144 public void actionPerformed(ActionEvent e)
149 buttonPanel.add(cancelButton);
150 panel.add(buttonPanel, BorderLayout.SOUTH);
153 JPanel centralPanel = new JPanel();
154 centralPanel.setLayout(new GridLayout(0, 2, 10, 4));
156 JLabel fontLabel = new JLabel(I18nManager.getText("dialog.exportpov.font"));
157 fontLabel.setHorizontalAlignment(SwingConstants.TRAILING);
158 centralPanel.add(fontLabel);
159 String defaultFont = Config.getConfigString(Config.KEY_POVRAY_FONT);
160 if (defaultFont == null || defaultFont.equals("")) {
161 defaultFont = DEFAULT_FONT_FILE;
163 _fontName = new JTextField(defaultFont, 12);
164 _fontName.setAlignmentX(Component.LEFT_ALIGNMENT);
165 _fontName.addKeyListener(new DialogCloser(_dialog));
166 centralPanel.add(_fontName);
167 //coordinates of camera
168 JLabel cameraXLabel = new JLabel(I18nManager.getText("dialog.exportpov.camerax"));
169 cameraXLabel.setHorizontalAlignment(SwingConstants.TRAILING);
170 centralPanel.add(cameraXLabel);
171 _cameraXField = new JTextField("" + _cameraX);
172 centralPanel.add(_cameraXField);
173 JLabel cameraYLabel = new JLabel(I18nManager.getText("dialog.exportpov.cameray"));
174 cameraYLabel.setHorizontalAlignment(SwingConstants.TRAILING);
175 centralPanel.add(cameraYLabel);
176 _cameraYField = new JTextField("" + _cameraY);
177 centralPanel.add(_cameraYField);
178 JLabel cameraZLabel = new JLabel(I18nManager.getText("dialog.exportpov.cameraz"));
179 cameraZLabel.setHorizontalAlignment(SwingConstants.TRAILING);
180 centralPanel.add(cameraZLabel);
181 _cameraZField = new JTextField("" + _cameraZ);
182 centralPanel.add(_cameraZField);
183 // Altitude exaggeration
184 JLabel altitudeCapLabel = new JLabel(I18nManager.getText("dialog.3d.altitudefactor"));
185 altitudeCapLabel.setHorizontalAlignment(SwingConstants.TRAILING);
186 centralPanel.add(altitudeCapLabel);
187 _altitudeFactorField = new JTextField("1.0");
188 centralPanel.add(_altitudeFactorField);
190 // Radio buttons for style - balls on sticks or tubes
191 JPanel stylePanel = new JPanel();
192 stylePanel.setLayout(new GridLayout(0, 2, 10, 4));
193 JLabel styleLabel = new JLabel(I18nManager.getText("dialog.exportpov.modelstyle"));
194 styleLabel.setHorizontalAlignment(SwingConstants.TRAILING);
195 stylePanel.add(styleLabel);
196 JPanel radioPanel = new JPanel();
197 radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.Y_AXIS));
198 _ballsAndSticksButton = new JRadioButton(I18nManager.getText("dialog.exportpov.ballsandsticks"));
199 _ballsAndSticksButton.setSelected(false);
200 radioPanel.add(_ballsAndSticksButton);
201 JRadioButton tubesButton = new JRadioButton(I18nManager.getText("dialog.exportpov.tubesandwalls"));
202 tubesButton.setSelected(true);
203 radioPanel.add(tubesButton);
204 ButtonGroup group = new ButtonGroup();
205 group.add(_ballsAndSticksButton); group.add(tubesButton);
206 stylePanel.add(radioPanel);
208 // add this grid to the holder panel
209 JPanel holderPanel = new JPanel();
210 holderPanel.setLayout(new BorderLayout(5, 5));
211 JPanel boxPanel = new JPanel();
212 boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
213 boxPanel.add(centralPanel);
214 boxPanel.add(stylePanel);
215 holderPanel.add(boxPanel, BorderLayout.CENTER);
218 JButton showLinesButton = new JButton(I18nManager.getText("button.showlines"));
219 showLinesButton.addActionListener(new ActionListener() {
220 public void actionPerformed(ActionEvent e)
222 // Need to scale model to find lines
223 ThreeDModel model = new ThreeDModel(_track);
225 double[] latLines = model.getLatitudeLines();
226 double[] lonLines = model.getLongitudeLines();
227 LineDialog dialog = new LineDialog(_parentFrame, latLines, lonLines);
231 JPanel flowPanel = new JPanel();
232 flowPanel.setLayout(new FlowLayout());
233 flowPanel.add(showLinesButton);
234 holderPanel.add(flowPanel, BorderLayout.EAST);
235 panel.add(holderPanel, BorderLayout.CENTER);
241 * Select the file and export data to it
243 private void doExport()
245 // Copy camera coordinates
246 _cameraX = checkCoordinate(_cameraXField.getText());
247 _cameraY = checkCoordinate(_cameraYField.getText());
248 _cameraZ = checkCoordinate(_cameraZField.getText());
250 // OK pressed, so choose output file
251 if (_fileChooser == null)
253 _fileChooser = new JFileChooser();
254 _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
255 _fileChooser.setFileFilter(new GenericFileFilter("filetype.pov", new String[] {"pov"}));
256 _fileChooser.setAcceptAllFileFilterUsed(false);
257 // start from directory in config which should be set
258 final String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
259 if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));}
262 // Allow choose again if an existing file is selected
263 boolean chooseAgain = false;
267 if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
269 // OK pressed and file chosen
270 File file = _fileChooser.getSelectedFile();
271 if (!file.getName().toLowerCase().endsWith(".pov"))
273 file = new File(file.getAbsolutePath() + ".pov");
275 // Check if file exists and if necessary prompt for overwrite
276 Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
277 if (!file.exists() || JOptionPane.showOptionDialog(_parentFrame,
278 I18nManager.getText("dialog.save.overwrite.text"),
279 I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
280 JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
281 == JOptionPane.YES_OPTION)
284 if (exportFile(file))
287 // Store directory in config for later
288 Config.setConfigString(Config.KEY_TRACK_DIR, file.getParentFile().getAbsolutePath());
292 // export failed so need to choose again
298 // overwrite cancelled so need to choose again
302 } while (chooseAgain);
307 * Export the track data to the specified file
308 * @param inFile File object to save to
309 * @return true if successful
311 private boolean exportFile(File inFile)
313 FileWriter writer = null;
314 // find out the line separator for this system
315 String lineSeparator = System.getProperty("line.separator");
318 // create and scale model
319 ThreeDModel model = new ThreeDModel(_track);
322 // try to use given altitude cap
323 double altFactor = Double.parseDouble(_altitudeFactorField.getText());
324 model.setAltitudeFactor(altFactor);
326 catch (NumberFormatException nfe) { // parse failed, reset
327 _altitudeFactorField.setText("1.0");
331 // Create file and write basics
332 writer = new FileWriter(inFile);
333 writeStartOfFile(writer, model.getModelSize(), lineSeparator);
335 // write out lat/long lines using model
336 writeLatLongLines(writer, model, lineSeparator);
339 if (_ballsAndSticksButton.isSelected()) {
340 writeDataPointsBallsAndSticks(writer, model, lineSeparator);
343 writeDataPointsTubesAndWalls(writer, model, lineSeparator);
347 UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
348 + " " + _track.getNumPoints() + " " + I18nManager.getText("confirm.save.ok2")
349 + " " + inFile.getAbsolutePath());
352 catch (IOException ioe)
354 JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.save.failed") + " : " + ioe.getMessage(),
355 I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
359 // close file ignoring exceptions
364 catch (Exception e) {}
371 * Write the start of the Pov file, including base plane and lights
372 * @param inWriter Writer to use for writing file
373 * @param inModelSize model size
374 * @param inLineSeparator line separator to use
375 * @throws IOException on file writing error
377 private void writeStartOfFile(FileWriter inWriter, double inModelSize, String inLineSeparator)
380 inWriter.write("// Pov file produced by GpsPrune - see http://activityworkshop.net/");
381 inWriter.write(inLineSeparator);
382 inWriter.write(inLineSeparator);
383 // Select font based on user input
384 String fontPath = _fontName.getText();
385 if (fontPath == null || fontPath.equals(""))
387 fontPath = DEFAULT_FONT_FILE;
390 Config.setConfigString(Config.KEY_POVRAY_FONT, fontPath);
393 String[] outputLines = {
394 "global_settings { ambient_light rgb <4, 4, 4> }", "",
395 "// Background and camera",
396 "background { color rgb <0, 0, 0> }",
399 " location <" + _cameraX + ", " + _cameraY + ", " + _cameraZ + ">",
400 " look_at <0, 0, 0>",
403 "// Global declares",
404 "#declare lat_line =",
406 " <-" + inModelSize + ", 0.1, 0>,",
407 " <" + inModelSize + ", 0.1, 0>,",
409 " pigment { color rgb <0.5 0.5 0.5> }",
411 "#declare lon_line =",
413 " <0, 0.1, -" + inModelSize + ">,",
414 " <0, 0.1, " + inModelSize + ">,",
416 " pigment { color rgb <0.5 0.5 0.5> }",
418 "#declare point_rod =",
424 " pigment { color rgb <0.5 0.5 0.5> }",
426 // MAYBE: Export rods to POV? How to store in data?
427 "#declare waypoint_sphere =",
431 " pigment {color rgb <0.1 0.1 1.0>}",
432 " finish { phong 1 }",
435 "#declare track_sphere0 =",
437 " <0, 0, 0>, 0.3", // size should depend on model size
439 " pigment {color rgb <0.2 1.0 0.2>}",
440 " finish { phong 1 }",
443 "#declare track_sphere1 =",
445 " <0, 0, 0>, 0.3", // size should depend on model size
447 " pigment {color rgb <0.6 1.0 0.2>}",
448 " finish { phong 1 }",
451 "#declare track_sphere2 =",
453 " <0, 0, 0>, 0.3", // size should depend on model size
455 " pigment {color rgb <1.0 1.0 0.1>}",
456 " finish { phong 1 }",
459 "#declare track_sphere3 =",
461 " <0, 0, 0>, 0.3", // size should depend on model size
463 " pigment {color rgb <1.0 1.0 1.0>}",
464 " finish { phong 1 }",
467 "#declare track_sphere4 =",
469 " <0, 0, 0>, 0.3", // size should depend on model size
471 " pigment {color rgb <0.1 1.0 1.0>}",
472 " finish { phong 1 }",
475 "#declare track_sphere_t =",
477 " <0, 0, 0>, 0.25", // size should depend on model size
479 " pigment {color rgb <0.6 1.0 0.2>}",
480 " finish { phong 1 }",
483 "#declare wall_colour = rgbt <0.5, 0.5, 0.5, 0.3>;", "",
486 " <-" + inModelSize + ", -0.15, -" + inModelSize + ">, // Near lower left corner",
487 " <" + inModelSize + ", 0.15, " + inModelSize + "> // Far upper right corner",
488 " pigment { color rgb <0.5 0.75 0.8> }",
491 "// Cardinal letters N,S,E,W",
493 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.n") + "\" 0.3, 0",
494 " pigment { color rgb <1 1 1> }",
495 " translate <0, 0.2, " + inModelSize + ">",
498 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.s") + "\" 0.3, 0",
499 " pigment { color rgb <1 1 1> }",
500 " translate <0, 0.2, -" + inModelSize + ">",
503 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.e") + "\" 0.3, 0",
504 " pigment { color rgb <1 1 1> }",
505 " translate <" + (inModelSize * 0.97) + ", 0.2, 0>",
508 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.w") + "\" 0.3, 0",
509 " pigment { color rgb <1 1 1> }",
510 " translate <-" + (inModelSize * 1.03) + ", 0.2, 0>",
512 // MAYBE: Light positions should relate to model size
514 "light_source { <-1, 9, -4> color rgb <0.5 0.5 0.5>}",
515 "light_source { <1, 6, -14> color rgb <0.6 0.6 0.6>}",
516 "light_source { <11, 12, 8> color rgb <0.3 0.3 0.3>}",
519 // write strings to file
520 int numLines = outputLines.length;
521 for (int i=0; i<numLines; i++)
523 inWriter.write(outputLines[i]);
524 inWriter.write(inLineSeparator);
530 * Write out all the lat and long lines to the file
531 * @param inWriter Writer to use for writing file
532 * @param inModel model object for getting lat/long lines
533 * @param inLineSeparator line separator to use
534 * @throws IOException on file writing error
536 private void writeLatLongLines(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
539 inWriter.write("// Latitude and longitude lines:");
540 inWriter.write(inLineSeparator);
541 int numlines = inModel.getLatitudeLines().length;
542 for (int i=0; i<numlines; i++)
544 // write cylinder to file
545 inWriter.write("object { lat_line translate <0, 0, " + inModel.getScaledLatitudeLine(i) + "> }");
546 inWriter.write(inLineSeparator);
548 numlines = inModel.getLongitudeLines().length;
549 for (int i=0; i<numlines; i++)
551 // write cylinder to file
552 inWriter.write("object { lon_line translate <" + inModel.getScaledLongitudeLine(i) + ", 0, 0> }");
553 inWriter.write(inLineSeparator);
555 inWriter.write(inLineSeparator);
560 * Write out all the data points to the file in the balls-and-sticks style
561 * @param inWriter Writer to use for writing file
562 * @param inModel model object for getting data points
563 * @param inLineSeparator line separator to use
564 * @throws IOException on file writing error
566 private void writeDataPointsBallsAndSticks(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
569 inWriter.write("// Data points:");
570 inWriter.write(inLineSeparator);
571 int numPoints = inModel.getNumPoints();
572 for (int i=0; i<numPoints; i++)
574 // ball (different according to type)
575 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_WAYPOINT)
578 inWriter.write("object { waypoint_sphere translate <" + inModel.getScaledHorizValue(i)
579 + "," + inModel.getScaledAltValue(i) + "," + inModel.getScaledVertValue(i) + "> }");
583 // normal track point ball
584 inWriter.write("object { track_sphere" + checkHeightCode(inModel.getPointHeightCode(i))
585 + " translate <" + inModel.getScaledHorizValue(i) + "," + inModel.getScaledAltValue(i)
586 + "," + inModel.getScaledVertValue(i) + "> }");
588 inWriter.write(inLineSeparator);
589 // vertical rod (if altitude positive)
590 if (inModel.getScaledAltValue(i) > 0.0)
592 inWriter.write("object { point_rod translate <" + inModel.getScaledHorizValue(i) + ",0,"
593 + inModel.getScaledVertValue(i) + "> scale <1," + inModel.getScaledAltValue(i) + ",1> }");
594 inWriter.write(inLineSeparator);
597 inWriter.write(inLineSeparator);
602 * Write out all the data points to the file in the tubes-and-walls style
603 * @param inWriter Writer to use for writing file
604 * @param inModel model object for getting data points
605 * @param inLineSeparator line separator to use
606 * @throws IOException on file writing error
608 private void writeDataPointsTubesAndWalls(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
611 inWriter.write("// Data points:");
612 inWriter.write(inLineSeparator);
613 int numPoints = inModel.getNumPoints();
614 int numTrackPoints = 0;
615 // Loop over all points and write out waypoints as balls
616 for (int i=0; i<numPoints; i++)
618 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_WAYPOINT)
621 inWriter.write("object { waypoint_sphere translate <" + inModel.getScaledHorizValue(i)
622 + "," + inModel.getScaledAltValue(i) + "," + inModel.getScaledVertValue(i) + "> }");
623 // vertical rod (if altitude positive)
624 if (inModel.getScaledAltValue(i) > 0.0)
626 inWriter.write(inLineSeparator);
627 inWriter.write("object { point_rod translate <" + inModel.getScaledHorizValue(i) + ",0,"
628 + inModel.getScaledVertValue(i) + "> scale <1," + inModel.getScaledAltValue(i) + ",1> }");
630 inWriter.write(inLineSeparator);
632 else {numTrackPoints++;}
634 inWriter.write(inLineSeparator);
636 // Loop over all the track segments
637 ArrayList<ModelSegment> segmentList = getSegmentList(inModel);
638 Iterator<ModelSegment> segmentIterator = segmentList.iterator();
639 while (segmentIterator.hasNext())
641 ModelSegment segment = segmentIterator.next();
642 int segLength = segment.getNumTrackPoints();
644 // if the track segment is long enough, do a cubic spline sphere sweep
647 // single point in segment - just draw sphere
648 int index = segment.getStartIndex();
649 inWriter.write("object { track_sphere_t"
650 + " translate <" + inModel.getScaledHorizValue(index) + "," + inModel.getScaledAltValue(index)
651 + "," + inModel.getScaledVertValue(index) + "> }");
652 // maybe draw some kind of polygon too or rod?
656 writeSphereSweep(inWriter, inModel, segment, inLineSeparator);
659 // Write wall underneath segment
662 writePolygonWall(inWriter, inModel, segment, inLineSeparator);
669 * Write out a single sphere sweep using either cubic spline or linear spline
670 * @param inWriter Writer to use for writing file
671 * @param inModel model object for getting data points
672 * @param inSegment model segment to draw
673 * @param inLineSeparator line separator to use
674 * @throws IOException on file writing error
676 private static void writeSphereSweep(FileWriter inWriter, ThreeDModel inModel, ModelSegment inSegment, String inLineSeparator)
680 inWriter.write("// Sphere sweep:");
681 inWriter.write(inLineSeparator);
682 String splineType = inSegment.getNumTrackPoints() < 5?"linear_spline":"cubic_spline";
683 inWriter.write("sphere_sweep { "); inWriter.write(splineType);
684 inWriter.write(" " + inSegment.getNumTrackPoints() + ",");
685 inWriter.write(inLineSeparator);
686 // Loop over all points in this segment and write out sphere sweep
687 for (int i=inSegment.getStartIndex(); i<=inSegment.getEndIndex(); i++)
689 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
691 inWriter.write(" <" + inModel.getScaledHorizValue(i) + "," + inModel.getScaledAltValue(i)
692 + "," + inModel.getScaledVertValue(i) + ">, 0.25");
693 inWriter.write(inLineSeparator);
696 inWriter.write(" tolerance 0.1");
697 inWriter.write(inLineSeparator);
698 inWriter.write(" texture { pigment {color rgb <0.6 1.0 0.2>} finish {phong 1} }");
699 inWriter.write(inLineSeparator);
700 inWriter.write(" no_shadow");
701 inWriter.write(inLineSeparator);
703 inWriter.write(inLineSeparator);
708 * Write out a single polygon-based wall for the tubes-and-walls style
709 * @param inWriter Writer to use for writing file
710 * @param inModel model object for getting data points
711 * @param inSegment model segment to draw
712 * @param inLineSeparator line separator to use
713 * @throws IOException on file writing error
715 private static void writePolygonWall(FileWriter inWriter, ThreeDModel inModel, ModelSegment inSegment, String inLineSeparator)
719 inWriter.write(inLineSeparator);
720 inWriter.write("// wall between sweep and floor:");
721 inWriter.write(inLineSeparator);
722 // Loop over all points in this segment again and write out polygons
724 for (int i=inSegment.getStartIndex(); i<=inSegment.getEndIndex(); i++)
726 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
730 double xDiff = inModel.getScaledHorizValue(i) - inModel.getScaledHorizValue(prevIndex);
731 double yDiff = inModel.getScaledVertValue(i) - inModel.getScaledVertValue(prevIndex);
732 double dist = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
735 inWriter.write("polygon {");
736 inWriter.write(" 5, <" + inModel.getScaledHorizValue(prevIndex) + ", 0.0, " + inModel.getScaledVertValue(prevIndex) + ">,");
737 inWriter.write(" <" + inModel.getScaledHorizValue(prevIndex) + ", " + inModel.getScaledAltValue(prevIndex) + ", "
738 + inModel.getScaledVertValue(prevIndex) + ">,");
739 inWriter.write(" <" + inModel.getScaledHorizValue(i) + ", " + inModel.getScaledAltValue(i) + ", "
740 + inModel.getScaledVertValue(i) + ">,");
741 inWriter.write(" <" + inModel.getScaledHorizValue(i) + ", 0.0, " + inModel.getScaledVertValue(i) + ">,");
742 inWriter.write(" <" + inModel.getScaledHorizValue(prevIndex) + ", 0.0, " + inModel.getScaledVertValue(prevIndex) + ">");
743 inWriter.write(" pigment { color wall_colour } no_shadow");
745 inWriter.write(inLineSeparator);
755 * @param inCode height code to check
756 * @return validated height code within range 0 to max
758 private static byte checkHeightCode(byte inCode)
760 final byte maxHeightCode = 4;
761 if (inCode < 0) return 0;
762 if (inCode > maxHeightCode) return maxHeightCode;
768 * Check the given coordinate
769 * @param inString String entered by user
770 * @return validated String value
772 private static String checkCoordinate(String inString)
777 value = Double.parseDouble(inString);
779 catch (Exception e) {} // ignore parse failures
784 * Go through the points making a list of the segment starts and the number of track points in each segment
785 * @param inModel model containing data
786 * @return list of ModelSegment objects
788 private static ArrayList<ModelSegment> getSegmentList(ThreeDModel inModel)
790 ArrayList<ModelSegment> segmentList = new ArrayList<ModelSegment>();
791 if (inModel != null && inModel.getNumPoints() > 0)
793 ModelSegment currSegment = null;
794 int numTrackPoints = 0;
795 for (int i=0; i<inModel.getNumPoints(); i++)
797 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
799 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_SEGMENT_START || currSegment == null)
802 if (currSegment != null)
804 currSegment.setEndIndex(i-1);
805 currSegment.setNumTrackPoints(numTrackPoints);
806 segmentList.add(currSegment);
809 currSegment = new ModelSegment(i);
814 // Add last segment to list
815 if (currSegment != null && numTrackPoints > 0)
817 currSegment.setEndIndex(inModel.getNumPoints()-1);
818 currSegment.setNumTrackPoints(numTrackPoints);
819 segmentList.add(currSegment);