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.BoxLayout;
16 import javax.swing.ButtonGroup;
17 import javax.swing.JButton;
18 import javax.swing.JDialog;
19 import javax.swing.JFileChooser;
20 import javax.swing.JFrame;
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;
28 import tim.prune.Config;
29 import tim.prune.I18nManager;
30 import tim.prune.UpdateMessageBroker;
31 import tim.prune.data.Track;
32 import tim.prune.load.GenericFileFilter;
33 import tim.prune.threedee.LineDialog;
34 import tim.prune.threedee.ThreeDModel;
37 * Class to export track information
38 * into a specified Pov file
40 public class PovExporter
42 private JFrame _parentFrame = null;
43 private Track _track = null;
44 private JDialog _dialog = null;
45 private JFileChooser _fileChooser = null;
46 private String _cameraX = null, _cameraY = null, _cameraZ = null;
47 private JTextField _cameraXField = null, _cameraYField = null, _cameraZField = null;
48 private JTextField _fontName = null, _altitudeCapField = null;
49 private int _altitudeCap = ThreeDModel.MINIMUM_ALTITUDE_CAP;
50 private JRadioButton _ballsAndSticksButton = null;
53 private static final double DEFAULT_CAMERA_DISTANCE = 30.0;
54 private static final String DEFAULT_FONT_FILE = "crystal.ttf";
58 * Constructor giving frame and track
59 * @param inParentFrame parent frame
60 * @param inTrack track object to save
62 public PovExporter(JFrame inParentFrame, Track inTrack)
64 _parentFrame = inParentFrame;
66 // Set default camera coordinates
67 _cameraX = "17"; _cameraY = "13"; _cameraZ = "-20";
72 * Set the coordinates for the camera (can be any scale)
73 * @param inX X coordinate of camera
74 * @param inY Y coordinate of camera
75 * @param inZ Z coordinate of camera
77 public void setCameraCoordinates(double inX, double inY, double inZ)
79 // calculate distance from origin
80 double cameraDist = Math.sqrt(inX*inX + inY*inY + inZ*inZ);
83 _cameraX = "" + (inX / cameraDist * DEFAULT_CAMERA_DISTANCE);
84 _cameraY = "" + (inY / cameraDist * DEFAULT_CAMERA_DISTANCE);
85 // Careful! Need to convert from java3d (right-handed) to povray (left-handed) coordinate system!
86 _cameraZ = "" + (-inZ / cameraDist * DEFAULT_CAMERA_DISTANCE);
92 * @param inAltitudeCap altitude cap to use
94 public void setAltitudeCap(int inAltitudeCap)
96 _altitudeCap = inAltitudeCap;
97 if (_altitudeCap < ThreeDModel.MINIMUM_ALTITUDE_CAP)
99 _altitudeCap = ThreeDModel.MINIMUM_ALTITUDE_CAP;
105 * Show the dialog to select options and export file
107 public void showDialog()
109 // Make dialog window to select angles, colours etc
112 _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.exportpov.title"), true);
113 _dialog.setLocationRelativeTo(_parentFrame);
114 _dialog.getContentPane().add(makeDialogComponents());
118 _cameraXField.setText(_cameraX);
119 _cameraYField.setText(_cameraY);
120 _cameraZField.setText(_cameraZ);
121 // Set vertical scale
122 _altitudeCapField.setText("" + _altitudeCap);
130 * Make the dialog components to select the export options
131 * @return Component holding gui elements
133 private Component makeDialogComponents()
135 JPanel panel = new JPanel();
136 panel.setLayout(new BorderLayout());
137 panel.add(new JLabel(I18nManager.getText("dialog.exportpov.text")), BorderLayout.NORTH);
138 // OK, Cancel buttons
139 JPanel buttonPanel = new JPanel();
140 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
141 JButton okButton = new JButton(I18nManager.getText("button.ok"));
142 okButton.addActionListener(new ActionListener() {
143 public void actionPerformed(ActionEvent e)
149 buttonPanel.add(okButton);
150 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
151 cancelButton.addActionListener(new ActionListener() {
152 public void actionPerformed(ActionEvent e)
157 buttonPanel.add(cancelButton);
158 panel.add(buttonPanel, BorderLayout.SOUTH);
161 JPanel centralPanel = new JPanel();
162 centralPanel.setLayout(new GridLayout(0, 2, 10, 4));
164 JLabel fontLabel = new JLabel(I18nManager.getText("dialog.exportpov.font"));
165 fontLabel.setHorizontalAlignment(SwingConstants.TRAILING);
166 centralPanel.add(fontLabel);
167 String defaultFont = Config.getPovrayFont();
168 if (defaultFont == null || defaultFont.equals("")) {
169 defaultFont = DEFAULT_FONT_FILE;
171 _fontName = new JTextField(defaultFont, 12);
172 _fontName.setAlignmentX(Component.LEFT_ALIGNMENT);
173 centralPanel.add(_fontName);
174 //coordinates of camera
175 JLabel cameraXLabel = new JLabel(I18nManager.getText("dialog.exportpov.camerax"));
176 cameraXLabel.setHorizontalAlignment(SwingConstants.TRAILING);
177 centralPanel.add(cameraXLabel);
178 _cameraXField = new JTextField("" + _cameraX);
179 centralPanel.add(_cameraXField);
180 JLabel cameraYLabel = new JLabel(I18nManager.getText("dialog.exportpov.cameray"));
181 cameraYLabel.setHorizontalAlignment(SwingConstants.TRAILING);
182 centralPanel.add(cameraYLabel);
183 _cameraYField = new JTextField("" + _cameraY);
184 centralPanel.add(_cameraYField);
185 JLabel cameraZLabel = new JLabel(I18nManager.getText("dialog.exportpov.cameraz"));
186 cameraZLabel.setHorizontalAlignment(SwingConstants.TRAILING);
187 centralPanel.add(cameraZLabel);
188 _cameraZField = new JTextField("" + _cameraZ);
189 centralPanel.add(_cameraZField);
191 JLabel altitudeCapLabel = new JLabel(I18nManager.getText("dialog.3d.altitudecap"));
192 altitudeCapLabel.setHorizontalAlignment(SwingConstants.TRAILING);
193 centralPanel.add(altitudeCapLabel);
194 _altitudeCapField = new JTextField("" + _altitudeCap);
195 centralPanel.add(_altitudeCapField);
197 // Radio buttons for style - balls on sticks or tubes
198 JPanel stylePanel = new JPanel();
199 stylePanel.setLayout(new GridLayout(0, 2, 10, 4));
200 JLabel styleLabel = new JLabel(I18nManager.getText("dialog.exportpov.modelstyle"));
201 styleLabel.setHorizontalAlignment(SwingConstants.TRAILING);
202 stylePanel.add(styleLabel);
203 JPanel radioPanel = new JPanel();
204 radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.Y_AXIS));
205 _ballsAndSticksButton = new JRadioButton(I18nManager.getText("dialog.exportpov.ballsandsticks"));
206 _ballsAndSticksButton.setSelected(false);
207 radioPanel.add(_ballsAndSticksButton);
208 JRadioButton tubesButton = new JRadioButton(I18nManager.getText("dialog.exportpov.tubesandwalls"));
209 tubesButton.setSelected(true);
210 radioPanel.add(tubesButton);
211 ButtonGroup group = new ButtonGroup();
212 group.add(_ballsAndSticksButton); group.add(tubesButton);
213 stylePanel.add(radioPanel);
215 // add this grid to the holder panel
216 JPanel holderPanel = new JPanel();
217 holderPanel.setLayout(new BorderLayout(5, 5));
218 JPanel boxPanel = new JPanel();
219 boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
220 boxPanel.add(centralPanel);
221 boxPanel.add(stylePanel);
222 holderPanel.add(boxPanel, BorderLayout.CENTER);
225 JButton showLinesButton = new JButton(I18nManager.getText("button.showlines"));
226 showLinesButton.addActionListener(new ActionListener() {
227 public void actionPerformed(ActionEvent e)
229 // Need to scale model to find lines
230 ThreeDModel model = new ThreeDModel(_track);
232 double[] latLines = model.getLatitudeLines();
233 double[] lonLines = model.getLongitudeLines();
234 LineDialog dialog = new LineDialog(_parentFrame, latLines, lonLines);
238 JPanel flowPanel = new JPanel();
239 flowPanel.setLayout(new FlowLayout());
240 flowPanel.add(showLinesButton);
241 holderPanel.add(flowPanel, BorderLayout.EAST);
242 panel.add(holderPanel, BorderLayout.CENTER);
248 * Select the file and export data to it
250 private void doExport()
252 // Copy camera coordinates
253 _cameraX = checkCoordinate(_cameraXField.getText());
254 _cameraY = checkCoordinate(_cameraYField.getText());
255 _cameraZ = checkCoordinate(_cameraZField.getText());
257 // OK pressed, so choose output file
258 if (_fileChooser == null)
260 _fileChooser = new JFileChooser();
261 _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
262 _fileChooser.setFileFilter(new GenericFileFilter("filetype.pov", new String[] {"pov"}));
263 _fileChooser.setAcceptAllFileFilterUsed(false);
264 // start from directory in config which should be set
265 File configDir = Config.getWorkingDirectory();
266 if (configDir != null) {_fileChooser.setCurrentDirectory(configDir);}
269 // Allow choose again if an existing file is selected
270 boolean chooseAgain = false;
274 if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
276 // OK pressed and file chosen
277 File file = _fileChooser.getSelectedFile();
278 if (!file.getName().toLowerCase().endsWith(".pov"))
280 file = new File(file.getAbsolutePath() + ".pov");
282 // Check if file exists and if necessary prompt for overwrite
283 Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
284 if (!file.exists() || JOptionPane.showOptionDialog(_parentFrame,
285 I18nManager.getText("dialog.save.overwrite.text"),
286 I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
287 JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
288 == JOptionPane.YES_OPTION)
291 if (exportFile(file))
294 // Store directory in config for later
295 Config.setWorkingDirectory(file.getParentFile());
299 // export failed so need to choose again
305 // overwrite cancelled so need to choose again
309 } while (chooseAgain);
314 * Export the track data to the specified file
315 * @param inFile File object to save to
316 * @return true if successful
318 private boolean exportFile(File inFile)
320 FileWriter writer = null;
321 // find out the line separator for this system
322 String lineSeparator = System.getProperty("line.separator");
325 // create and scale model
326 ThreeDModel model = new ThreeDModel(_track);
329 // try to use given altitude cap
330 _altitudeCap = Integer.parseInt(_altitudeCapField.getText());
331 model.setAltitudeCap(_altitudeCap);
333 catch (NumberFormatException nfe) {}
336 // Create file and write basics
337 writer = new FileWriter(inFile);
338 writeStartOfFile(writer, model.getModelSize(), lineSeparator);
340 // write out lat/long lines using model
341 writeLatLongLines(writer, model, lineSeparator);
344 if (_ballsAndSticksButton.isSelected()) {
345 writeDataPointsBallsAndSticks(writer, model, lineSeparator);
348 writeDataPointsTubesAndWalls(writer, model, lineSeparator);
352 UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
353 + " " + _track.getNumPoints() + " " + I18nManager.getText("confirm.save.ok2")
354 + " " + inFile.getAbsolutePath());
357 catch (IOException ioe)
359 JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.save.failed") + ioe.getMessage(),
360 I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
364 // close file ignoring exceptions
369 catch (Exception e) {}
376 * Write the start of the Pov file, including base plane and lights
377 * @param inWriter Writer to use for writing file
378 * @param inModelSize model size
379 * @param inLineSeparator line separator to use
380 * @throws IOException on file writing error
382 private void writeStartOfFile(FileWriter inWriter, double inModelSize, String inLineSeparator)
385 inWriter.write("// Pov file produced by Prune - see http://activityworkshop.net/");
386 inWriter.write(inLineSeparator);
387 inWriter.write(inLineSeparator);
388 // Select font based on user input
389 String fontPath = _fontName.getText();
390 if (fontPath == null || fontPath.equals(""))
392 fontPath = DEFAULT_FONT_FILE;
395 String[] outputLines = {
396 "global_settings { ambient_light rgb <4, 4, 4> }", "",
397 "// Background and camera",
398 "background { color rgb <0, 0, 0> }",
401 " location <" + _cameraX + ", " + _cameraY + ", " + _cameraZ + ">",
402 " look_at <0, 0, 0>",
405 "// Global declares",
406 "#declare lat_line =",
408 " <-" + inModelSize + ", 0.1, 0>,",
409 " <" + inModelSize + ", 0.1, 0>,",
411 " pigment { color rgb <0.5 0.5 0.5> }",
413 "#declare lon_line =",
415 " <0, 0.1, -" + inModelSize + ">,",
416 " <0, 0.1, " + inModelSize + ">,",
418 " pigment { color rgb <0.5 0.5 0.5> }",
420 "#declare point_rod =",
426 " pigment { color rgb <0.5 0.5 0.5> }",
428 // TODO: Export rods to POV? How to store in data?
429 "#declare waypoint_sphere =",
433 " pigment {color rgb <0.1 0.1 1.0>}",
434 " finish { phong 1 }",
437 "#declare track_sphere0 =",
439 " <0, 0, 0>, 0.3", // size should depend on model size
441 " pigment {color rgb <0.2 1.0 0.2>}",
442 " finish { phong 1 }",
445 "#declare track_sphere1 =",
447 " <0, 0, 0>, 0.3", // size should depend on model size
449 " pigment {color rgb <0.6 1.0 0.2>}",
450 " finish { phong 1 }",
453 "#declare track_sphere2 =",
455 " <0, 0, 0>, 0.3", // size should depend on model size
457 " pigment {color rgb <1.0 1.0 0.1>}",
458 " finish { phong 1 }",
461 "#declare track_sphere3 =",
463 " <0, 0, 0>, 0.3", // size should depend on model size
465 " pigment {color rgb <1.0 1.0 1.0>}",
466 " finish { phong 1 }",
469 "#declare track_sphere4 =",
471 " <0, 0, 0>, 0.3", // size should depend on model size
473 " pigment {color rgb <0.1 1.0 1.0>}",
474 " finish { phong 1 }",
477 "#declare track_sphere_t =",
479 " <0, 0, 0>, 0.25", // size should depend on model size
481 " pigment {color rgb <0.6 1.0 0.2>}",
482 " finish { phong 1 }",
485 "#declare wall_colour = rgbt <0.5, 0.5, 0.5, 0.3>;", "",
488 " <-" + inModelSize + ", -0.15, -" + inModelSize + ">, // Near lower left corner",
489 " <" + inModelSize + ", 0.15, " + inModelSize + "> // Far upper right corner",
490 " pigment { color rgb <0.5 0.75 0.8> }",
493 "// Cardinal letters N,S,E,W",
495 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.n") + "\" 0.3, 0",
496 " pigment { color rgb <1 1 1> }",
497 " translate <0, 0.2, " + inModelSize + ">",
500 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.s") + "\" 0.3, 0",
501 " pigment { color rgb <1 1 1> }",
502 " translate <0, 0.2, -" + inModelSize + ">",
505 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.e") + "\" 0.3, 0",
506 " pigment { color rgb <1 1 1> }",
507 " translate <" + (inModelSize * 0.97) + ", 0.2, 0>",
510 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.w") + "\" 0.3, 0",
511 " pigment { color rgb <1 1 1> }",
512 " translate <-" + (inModelSize * 1.03) + ", 0.2, 0>",
514 // TODO: Light positions should relate to model size
516 "light_source { <-1, 9, -4> color rgb <0.5 0.5 0.5>}",
517 "light_source { <1, 6, -14> color rgb <0.6 0.6 0.6>}",
518 "light_source { <11, 12, 8> color rgb <0.3 0.3 0.3>}",
521 // write strings to file
522 int numLines = outputLines.length;
523 for (int i=0; i<numLines; i++)
525 inWriter.write(outputLines[i]);
526 inWriter.write(inLineSeparator);
532 * Write out all the lat and long lines to the file
533 * @param inWriter Writer to use for writing file
534 * @param inModel model object for getting lat/long lines
535 * @param inLineSeparator line separator to use
536 * @throws IOException on file writing error
538 private void writeLatLongLines(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
541 inWriter.write("// Latitude and longitude lines:");
542 inWriter.write(inLineSeparator);
543 int numlines = inModel.getLatitudeLines().length;
544 for (int i=0; i<numlines; i++)
546 // write cylinder to file
547 inWriter.write("object { lat_line translate <0, 0, " + inModel.getScaledLatitudeLine(i) + "> }");
548 inWriter.write(inLineSeparator);
550 numlines = inModel.getLongitudeLines().length;
551 for (int i=0; i<numlines; i++)
553 // write cylinder to file
554 inWriter.write("object { lon_line translate <" + inModel.getScaledLongitudeLine(i) + ", 0, 0> }");
555 inWriter.write(inLineSeparator);
557 inWriter.write(inLineSeparator);
562 * Write out all the data points to the file in the balls-and-sticks style
563 * @param inWriter Writer to use for writing file
564 * @param inModel model object for getting data points
565 * @param inLineSeparator line separator to use
566 * @throws IOException on file writing error
568 private void writeDataPointsBallsAndSticks(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
571 inWriter.write("// Data points:");
572 inWriter.write(inLineSeparator);
573 int numPoints = inModel.getNumPoints();
574 for (int i=0; i<numPoints; i++)
576 // ball (different according to type)
577 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_WAYPOINT)
580 inWriter.write("object { waypoint_sphere translate <" + inModel.getScaledHorizValue(i)
581 + "," + inModel.getScaledAltValue(i) + "," + inModel.getScaledVertValue(i) + "> }");
585 // normal track point ball
586 inWriter.write("object { track_sphere" + checkHeightCode(inModel.getPointHeightCode(i))
587 + " translate <" + inModel.getScaledHorizValue(i) + "," + inModel.getScaledAltValue(i)
588 + "," + inModel.getScaledVertValue(i) + "> }");
590 inWriter.write(inLineSeparator);
591 // vertical rod (if altitude positive)
592 if (inModel.getScaledAltValue(i) > 0.0)
594 inWriter.write("object { point_rod translate <" + inModel.getScaledHorizValue(i) + ",0,"
595 + inModel.getScaledVertValue(i) + "> scale <1," + inModel.getScaledAltValue(i) + ",1> }");
596 inWriter.write(inLineSeparator);
599 inWriter.write(inLineSeparator);
604 * Write out all the data points to the file in the tubes-and-walls style
605 * @param inWriter Writer to use for writing file
606 * @param inModel model object for getting data points
607 * @param inLineSeparator line separator to use
608 * @throws IOException on file writing error
610 private void writeDataPointsTubesAndWalls(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
613 inWriter.write("// Data points:");
614 inWriter.write(inLineSeparator);
615 int numPoints = inModel.getNumPoints();
616 int numTrackPoints = 0;
617 // Loop over all points and write out waypoints as balls
618 for (int i=0; i<numPoints; i++)
620 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_WAYPOINT)
623 inWriter.write("object { waypoint_sphere translate <" + inModel.getScaledHorizValue(i)
624 + "," + inModel.getScaledAltValue(i) + "," + inModel.getScaledVertValue(i) + "> }");
625 // vertical rod (if altitude positive)
626 if (inModel.getScaledAltValue(i) > 0.0)
628 inWriter.write(inLineSeparator);
629 inWriter.write("object { point_rod translate <" + inModel.getScaledHorizValue(i) + ",0,"
630 + inModel.getScaledVertValue(i) + "> scale <1," + inModel.getScaledAltValue(i) + ",1> }");
632 inWriter.write(inLineSeparator);
634 else {numTrackPoints++;}
636 inWriter.write(inLineSeparator);
638 // Loop over all the track segments
639 ArrayList segmentList = getSegmentList(inModel);
640 Iterator segmentIterator = segmentList.iterator();
641 while (segmentIterator.hasNext())
643 ModelSegment segment = (ModelSegment) segmentIterator.next();
644 int segLength = segment.getNumTrackPoints();
646 // if the track segment is long enough, do a cubic spline sphere sweep
649 // single point in segment - just draw sphere
650 int index = segment.getStartIndex();
651 inWriter.write("object { track_sphere_t"
652 + " translate <" + inModel.getScaledHorizValue(index) + "," + inModel.getScaledAltValue(index)
653 + "," + inModel.getScaledVertValue(index) + "> }");
654 // maybe draw some kind of polygon too or rod?
658 writeSphereSweep(inWriter, inModel, segment, inLineSeparator);
661 // Write wall underneath segment
664 writePolygonWall(inWriter, inModel, segment, inLineSeparator);
671 * Write out a single sphere sweep using either cubic spline or linear spline
672 * @param inWriter Writer to use for writing file
673 * @param inModel model object for getting data points
674 * @param inSegment model segment to draw
675 * @param inLineSeparator line separator to use
676 * @throws IOException on file writing error
678 private static void writeSphereSweep(FileWriter inWriter, ThreeDModel inModel, ModelSegment inSegment, String inLineSeparator)
682 inWriter.write("// Sphere sweep:");
683 inWriter.write(inLineSeparator);
684 String splineType = inSegment.getNumTrackPoints() < 5?"linear_spline":"cubic_spline";
685 inWriter.write("sphere_sweep { "); inWriter.write(splineType);
686 inWriter.write(" " + inSegment.getNumTrackPoints() + ",");
687 inWriter.write(inLineSeparator);
688 // Loop over all points in this segment and write out sphere sweep
689 for (int i=inSegment.getStartIndex(); i<=inSegment.getEndIndex(); i++)
691 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
693 inWriter.write(" <" + inModel.getScaledHorizValue(i) + "," + inModel.getScaledAltValue(i)
694 + "," + inModel.getScaledVertValue(i) + ">, 0.25");
695 inWriter.write(inLineSeparator);
698 inWriter.write(" tolerance 0.1");
699 inWriter.write(inLineSeparator);
700 inWriter.write(" texture { pigment {color rgb <0.6 1.0 0.2>} finish {phong 1} }");
701 inWriter.write(inLineSeparator);
702 inWriter.write(" no_shadow");
703 inWriter.write(inLineSeparator);
705 inWriter.write(inLineSeparator);
710 * Write out a single polygon-based wall for the tubes-and-walls style
711 * @param inWriter Writer to use for writing file
712 * @param inModel model object for getting data points
713 * @param inSegment model segment to draw
714 * @param inLineSeparator line separator to use
715 * @throws IOException on file writing error
717 private static void writePolygonWall(FileWriter inWriter, ThreeDModel inModel, ModelSegment inSegment, String inLineSeparator)
721 inWriter.write(inLineSeparator);
722 inWriter.write("// wall between sweep and floor:");
723 inWriter.write(inLineSeparator);
724 // Loop over all points in this segment again and write out polygons
726 for (int i=inSegment.getStartIndex(); i<=inSegment.getEndIndex(); i++)
728 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
732 double xDiff = inModel.getScaledHorizValue(i) - inModel.getScaledHorizValue(prevIndex);
733 double yDiff = inModel.getScaledVertValue(i) - inModel.getScaledVertValue(prevIndex);
734 double dist = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
737 inWriter.write("polygon {");
738 inWriter.write(" 5, <" + inModel.getScaledHorizValue(prevIndex) + ", 0.0, " + inModel.getScaledVertValue(prevIndex) + ">,");
739 inWriter.write(" <" + inModel.getScaledHorizValue(prevIndex) + ", " + inModel.getScaledAltValue(prevIndex) + ", "
740 + inModel.getScaledVertValue(prevIndex) + ">,");
741 inWriter.write(" <" + inModel.getScaledHorizValue(i) + ", " + inModel.getScaledAltValue(i) + ", "
742 + inModel.getScaledVertValue(i) + ">,");
743 inWriter.write(" <" + inModel.getScaledHorizValue(i) + ", 0.0, " + inModel.getScaledVertValue(i) + ">,");
744 inWriter.write(" <" + inModel.getScaledHorizValue(prevIndex) + ", 0.0, " + inModel.getScaledVertValue(prevIndex) + ">");
745 inWriter.write(" pigment { color wall_colour } no_shadow");
747 inWriter.write(inLineSeparator);
757 * @param inCode height code to check
758 * @return validated height code within range 0 to max
760 private static byte checkHeightCode(byte inCode)
762 final byte maxHeightCode = 4;
763 if (inCode < 0) return 0;
764 if (inCode > maxHeightCode) return maxHeightCode;
770 * Check the given coordinate
771 * @param inString String entered by user
772 * @return validated String value
774 private static String checkCoordinate(String inString)
779 value = Double.parseDouble(inString);
781 catch (Exception e) {} // ignore parse failures
786 * Go through the points making a list of the segment starts and the number of track points in each segment
787 * @param inModel model containing data
788 * @return list of ModelSegment objects
790 private static ArrayList getSegmentList(ThreeDModel inModel)
792 ArrayList segmentList = new ArrayList();
793 if (inModel != null && inModel.getNumPoints() > 0)
795 ModelSegment currSegment = null;
796 int numTrackPoints = 0;
797 for (int i=0; i<inModel.getNumPoints(); i++)
799 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
801 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_SEGMENT_START || currSegment == null)
804 if (currSegment != null)
806 currSegment.setEndIndex(i-1);
807 currSegment.setNumTrackPoints(numTrackPoints);
808 segmentList.add(currSegment);
811 currSegment = new ModelSegment(i);
816 // Add last segment to list
817 if (currSegment != null && numTrackPoints > 0)
819 currSegment.setEndIndex(inModel.getNumPoints()-1);
820 currSegment.setNumTrackPoints(numTrackPoints);
821 segmentList.add(currSegment);