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.JLabel;
21 import javax.swing.JOptionPane;
22 import javax.swing.JPanel;
23 import javax.swing.JRadioButton;
24 import javax.swing.JTextField;
25 import javax.swing.SwingConstants;
28 import tim.prune.Config;
29 import tim.prune.GenericFunction;
30 import tim.prune.I18nManager;
31 import tim.prune.UpdateMessageBroker;
32 import tim.prune.data.Track;
33 import tim.prune.load.GenericFileFilter;
34 import tim.prune.threedee.LineDialog;
35 import tim.prune.threedee.ThreeDModel;
38 * Class to export track information
39 * into a specified Pov file
41 public class PovExporter extends GenericFunction
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 inApp App object
61 public PovExporter(App inApp)
64 _track = inApp.getTrackInfo().getTrack();
65 // Set default camera coordinates
66 _cameraX = "17"; _cameraY = "13"; _cameraZ = "-20";
69 /** Get the name key */
70 public String getNameKey() {
71 return "function.exportpov";
75 * Set the coordinates for the camera (can be any scale)
76 * @param inX X coordinate of camera
77 * @param inY Y coordinate of camera
78 * @param inZ Z coordinate of camera
80 public void setCameraCoordinates(double inX, double inY, double inZ)
82 // calculate distance from origin
83 double cameraDist = Math.sqrt(inX*inX + inY*inY + inZ*inZ);
86 _cameraX = "" + (inX / cameraDist * DEFAULT_CAMERA_DISTANCE);
87 _cameraY = "" + (inY / cameraDist * DEFAULT_CAMERA_DISTANCE);
88 // Careful! Need to convert from java3d (right-handed) to povray (left-handed) coordinate system!
89 _cameraZ = "" + (-inZ / cameraDist * DEFAULT_CAMERA_DISTANCE);
95 * @param inAltitudeCap altitude cap to use
97 public void setAltitudeCap(int inAltitudeCap)
99 _altitudeCap = inAltitudeCap;
100 if (_altitudeCap < ThreeDModel.MINIMUM_ALTITUDE_CAP)
102 _altitudeCap = ThreeDModel.MINIMUM_ALTITUDE_CAP;
108 * Show the dialog to select options and export file
112 // Make dialog window to select angles, colours etc
115 _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
116 _dialog.setLocationRelativeTo(_parentFrame);
117 _dialog.getContentPane().add(makeDialogComponents());
121 _cameraXField.setText(_cameraX);
122 _cameraYField.setText(_cameraY);
123 _cameraZField.setText(_cameraZ);
124 // Set vertical scale
125 _altitudeCapField.setText("" + _altitudeCap);
128 _dialog.setVisible(true);
133 * Make the dialog components to select the export options
134 * @return Component holding gui elements
136 private Component makeDialogComponents()
138 JPanel panel = new JPanel();
139 panel.setLayout(new BorderLayout());
140 panel.add(new JLabel(I18nManager.getText("dialog.exportpov.text")), BorderLayout.NORTH);
141 // OK, Cancel buttons
142 JPanel buttonPanel = new JPanel();
143 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
144 JButton okButton = new JButton(I18nManager.getText("button.ok"));
145 okButton.addActionListener(new ActionListener() {
146 public void actionPerformed(ActionEvent e)
152 buttonPanel.add(okButton);
153 JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
154 cancelButton.addActionListener(new ActionListener() {
155 public void actionPerformed(ActionEvent e)
160 buttonPanel.add(cancelButton);
161 panel.add(buttonPanel, BorderLayout.SOUTH);
164 JPanel centralPanel = new JPanel();
165 centralPanel.setLayout(new GridLayout(0, 2, 10, 4));
167 JLabel fontLabel = new JLabel(I18nManager.getText("dialog.exportpov.font"));
168 fontLabel.setHorizontalAlignment(SwingConstants.TRAILING);
169 centralPanel.add(fontLabel);
170 String defaultFont = Config.getPovrayFont();
171 if (defaultFont == null || defaultFont.equals("")) {
172 defaultFont = DEFAULT_FONT_FILE;
174 _fontName = new JTextField(defaultFont, 12);
175 _fontName.setAlignmentX(Component.LEFT_ALIGNMENT);
176 centralPanel.add(_fontName);
177 //coordinates of camera
178 JLabel cameraXLabel = new JLabel(I18nManager.getText("dialog.exportpov.camerax"));
179 cameraXLabel.setHorizontalAlignment(SwingConstants.TRAILING);
180 centralPanel.add(cameraXLabel);
181 _cameraXField = new JTextField("" + _cameraX);
182 centralPanel.add(_cameraXField);
183 JLabel cameraYLabel = new JLabel(I18nManager.getText("dialog.exportpov.cameray"));
184 cameraYLabel.setHorizontalAlignment(SwingConstants.TRAILING);
185 centralPanel.add(cameraYLabel);
186 _cameraYField = new JTextField("" + _cameraY);
187 centralPanel.add(_cameraYField);
188 JLabel cameraZLabel = new JLabel(I18nManager.getText("dialog.exportpov.cameraz"));
189 cameraZLabel.setHorizontalAlignment(SwingConstants.TRAILING);
190 centralPanel.add(cameraZLabel);
191 _cameraZField = new JTextField("" + _cameraZ);
192 centralPanel.add(_cameraZField);
194 JLabel altitudeCapLabel = new JLabel(I18nManager.getText("dialog.3d.altitudecap"));
195 altitudeCapLabel.setHorizontalAlignment(SwingConstants.TRAILING);
196 centralPanel.add(altitudeCapLabel);
197 _altitudeCapField = new JTextField("" + _altitudeCap);
198 centralPanel.add(_altitudeCapField);
200 // Radio buttons for style - balls on sticks or tubes
201 JPanel stylePanel = new JPanel();
202 stylePanel.setLayout(new GridLayout(0, 2, 10, 4));
203 JLabel styleLabel = new JLabel(I18nManager.getText("dialog.exportpov.modelstyle"));
204 styleLabel.setHorizontalAlignment(SwingConstants.TRAILING);
205 stylePanel.add(styleLabel);
206 JPanel radioPanel = new JPanel();
207 radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.Y_AXIS));
208 _ballsAndSticksButton = new JRadioButton(I18nManager.getText("dialog.exportpov.ballsandsticks"));
209 _ballsAndSticksButton.setSelected(false);
210 radioPanel.add(_ballsAndSticksButton);
211 JRadioButton tubesButton = new JRadioButton(I18nManager.getText("dialog.exportpov.tubesandwalls"));
212 tubesButton.setSelected(true);
213 radioPanel.add(tubesButton);
214 ButtonGroup group = new ButtonGroup();
215 group.add(_ballsAndSticksButton); group.add(tubesButton);
216 stylePanel.add(radioPanel);
218 // add this grid to the holder panel
219 JPanel holderPanel = new JPanel();
220 holderPanel.setLayout(new BorderLayout(5, 5));
221 JPanel boxPanel = new JPanel();
222 boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.Y_AXIS));
223 boxPanel.add(centralPanel);
224 boxPanel.add(stylePanel);
225 holderPanel.add(boxPanel, BorderLayout.CENTER);
228 JButton showLinesButton = new JButton(I18nManager.getText("button.showlines"));
229 showLinesButton.addActionListener(new ActionListener() {
230 public void actionPerformed(ActionEvent e)
232 // Need to scale model to find lines
233 ThreeDModel model = new ThreeDModel(_track);
235 double[] latLines = model.getLatitudeLines();
236 double[] lonLines = model.getLongitudeLines();
237 LineDialog dialog = new LineDialog(_parentFrame, latLines, lonLines);
241 JPanel flowPanel = new JPanel();
242 flowPanel.setLayout(new FlowLayout());
243 flowPanel.add(showLinesButton);
244 holderPanel.add(flowPanel, BorderLayout.EAST);
245 panel.add(holderPanel, BorderLayout.CENTER);
251 * Select the file and export data to it
253 private void doExport()
255 // Copy camera coordinates
256 _cameraX = checkCoordinate(_cameraXField.getText());
257 _cameraY = checkCoordinate(_cameraYField.getText());
258 _cameraZ = checkCoordinate(_cameraZField.getText());
260 // OK pressed, so choose output file
261 if (_fileChooser == null)
263 _fileChooser = new JFileChooser();
264 _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
265 _fileChooser.setFileFilter(new GenericFileFilter("filetype.pov", new String[] {"pov"}));
266 _fileChooser.setAcceptAllFileFilterUsed(false);
267 // start from directory in config which should be set
268 File configDir = Config.getWorkingDirectory();
269 if (configDir != null) {_fileChooser.setCurrentDirectory(configDir);}
272 // Allow choose again if an existing file is selected
273 boolean chooseAgain = false;
277 if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
279 // OK pressed and file chosen
280 File file = _fileChooser.getSelectedFile();
281 if (!file.getName().toLowerCase().endsWith(".pov"))
283 file = new File(file.getAbsolutePath() + ".pov");
285 // Check if file exists and if necessary prompt for overwrite
286 Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
287 if (!file.exists() || JOptionPane.showOptionDialog(_parentFrame,
288 I18nManager.getText("dialog.save.overwrite.text"),
289 I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
290 JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
291 == JOptionPane.YES_OPTION)
294 if (exportFile(file))
297 // Store directory in config for later
298 Config.setWorkingDirectory(file.getParentFile());
302 // export failed so need to choose again
308 // overwrite cancelled so need to choose again
312 } while (chooseAgain);
317 * Export the track data to the specified file
318 * @param inFile File object to save to
319 * @return true if successful
321 private boolean exportFile(File inFile)
323 FileWriter writer = null;
324 // find out the line separator for this system
325 String lineSeparator = System.getProperty("line.separator");
328 // create and scale model
329 ThreeDModel model = new ThreeDModel(_track);
332 // try to use given altitude cap
333 _altitudeCap = Integer.parseInt(_altitudeCapField.getText());
334 model.setAltitudeCap(_altitudeCap);
336 catch (NumberFormatException nfe) {}
339 // Create file and write basics
340 writer = new FileWriter(inFile);
341 writeStartOfFile(writer, model.getModelSize(), lineSeparator);
343 // write out lat/long lines using model
344 writeLatLongLines(writer, model, lineSeparator);
347 if (_ballsAndSticksButton.isSelected()) {
348 writeDataPointsBallsAndSticks(writer, model, lineSeparator);
351 writeDataPointsTubesAndWalls(writer, model, lineSeparator);
355 UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
356 + " " + _track.getNumPoints() + " " + I18nManager.getText("confirm.save.ok2")
357 + " " + inFile.getAbsolutePath());
360 catch (IOException ioe)
362 JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.save.failed") + ioe.getMessage(),
363 I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
367 // close file ignoring exceptions
372 catch (Exception e) {}
379 * Write the start of the Pov file, including base plane and lights
380 * @param inWriter Writer to use for writing file
381 * @param inModelSize model size
382 * @param inLineSeparator line separator to use
383 * @throws IOException on file writing error
385 private void writeStartOfFile(FileWriter inWriter, double inModelSize, String inLineSeparator)
388 inWriter.write("// Pov file produced by Prune - see http://activityworkshop.net/");
389 inWriter.write(inLineSeparator);
390 inWriter.write(inLineSeparator);
391 // Select font based on user input
392 String fontPath = _fontName.getText();
393 if (fontPath == null || fontPath.equals(""))
395 fontPath = DEFAULT_FONT_FILE;
398 String[] outputLines = {
399 "global_settings { ambient_light rgb <4, 4, 4> }", "",
400 "// Background and camera",
401 "background { color rgb <0, 0, 0> }",
404 " location <" + _cameraX + ", " + _cameraY + ", " + _cameraZ + ">",
405 " look_at <0, 0, 0>",
408 "// Global declares",
409 "#declare lat_line =",
411 " <-" + inModelSize + ", 0.1, 0>,",
412 " <" + inModelSize + ", 0.1, 0>,",
414 " pigment { color rgb <0.5 0.5 0.5> }",
416 "#declare lon_line =",
418 " <0, 0.1, -" + inModelSize + ">,",
419 " <0, 0.1, " + inModelSize + ">,",
421 " pigment { color rgb <0.5 0.5 0.5> }",
423 "#declare point_rod =",
429 " pigment { color rgb <0.5 0.5 0.5> }",
431 // TODO: Export rods to POV? How to store in data?
432 "#declare waypoint_sphere =",
436 " pigment {color rgb <0.1 0.1 1.0>}",
437 " finish { phong 1 }",
440 "#declare track_sphere0 =",
442 " <0, 0, 0>, 0.3", // size should depend on model size
444 " pigment {color rgb <0.2 1.0 0.2>}",
445 " finish { phong 1 }",
448 "#declare track_sphere1 =",
450 " <0, 0, 0>, 0.3", // size should depend on model size
452 " pigment {color rgb <0.6 1.0 0.2>}",
453 " finish { phong 1 }",
456 "#declare track_sphere2 =",
458 " <0, 0, 0>, 0.3", // size should depend on model size
460 " pigment {color rgb <1.0 1.0 0.1>}",
461 " finish { phong 1 }",
464 "#declare track_sphere3 =",
466 " <0, 0, 0>, 0.3", // size should depend on model size
468 " pigment {color rgb <1.0 1.0 1.0>}",
469 " finish { phong 1 }",
472 "#declare track_sphere4 =",
474 " <0, 0, 0>, 0.3", // size should depend on model size
476 " pigment {color rgb <0.1 1.0 1.0>}",
477 " finish { phong 1 }",
480 "#declare track_sphere_t =",
482 " <0, 0, 0>, 0.25", // size should depend on model size
484 " pigment {color rgb <0.6 1.0 0.2>}",
485 " finish { phong 1 }",
488 "#declare wall_colour = rgbt <0.5, 0.5, 0.5, 0.3>;", "",
491 " <-" + inModelSize + ", -0.15, -" + inModelSize + ">, // Near lower left corner",
492 " <" + inModelSize + ", 0.15, " + inModelSize + "> // Far upper right corner",
493 " pigment { color rgb <0.5 0.75 0.8> }",
496 "// Cardinal letters N,S,E,W",
498 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.n") + "\" 0.3, 0",
499 " pigment { color rgb <1 1 1> }",
500 " translate <0, 0.2, " + inModelSize + ">",
503 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.s") + "\" 0.3, 0",
504 " pigment { color rgb <1 1 1> }",
505 " translate <0, 0.2, -" + inModelSize + ">",
508 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.e") + "\" 0.3, 0",
509 " pigment { color rgb <1 1 1> }",
510 " translate <" + (inModelSize * 0.97) + ", 0.2, 0>",
513 " ttf \"" + fontPath + "\" \"" + I18nManager.getText("cardinal.w") + "\" 0.3, 0",
514 " pigment { color rgb <1 1 1> }",
515 " translate <-" + (inModelSize * 1.03) + ", 0.2, 0>",
517 // TODO: Light positions should relate to model size
519 "light_source { <-1, 9, -4> color rgb <0.5 0.5 0.5>}",
520 "light_source { <1, 6, -14> color rgb <0.6 0.6 0.6>}",
521 "light_source { <11, 12, 8> color rgb <0.3 0.3 0.3>}",
524 // write strings to file
525 int numLines = outputLines.length;
526 for (int i=0; i<numLines; i++)
528 inWriter.write(outputLines[i]);
529 inWriter.write(inLineSeparator);
535 * Write out all the lat and long lines to the file
536 * @param inWriter Writer to use for writing file
537 * @param inModel model object for getting lat/long lines
538 * @param inLineSeparator line separator to use
539 * @throws IOException on file writing error
541 private void writeLatLongLines(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
544 inWriter.write("// Latitude and longitude lines:");
545 inWriter.write(inLineSeparator);
546 int numlines = inModel.getLatitudeLines().length;
547 for (int i=0; i<numlines; i++)
549 // write cylinder to file
550 inWriter.write("object { lat_line translate <0, 0, " + inModel.getScaledLatitudeLine(i) + "> }");
551 inWriter.write(inLineSeparator);
553 numlines = inModel.getLongitudeLines().length;
554 for (int i=0; i<numlines; i++)
556 // write cylinder to file
557 inWriter.write("object { lon_line translate <" + inModel.getScaledLongitudeLine(i) + ", 0, 0> }");
558 inWriter.write(inLineSeparator);
560 inWriter.write(inLineSeparator);
565 * Write out all the data points to the file in the balls-and-sticks style
566 * @param inWriter Writer to use for writing file
567 * @param inModel model object for getting data points
568 * @param inLineSeparator line separator to use
569 * @throws IOException on file writing error
571 private void writeDataPointsBallsAndSticks(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
574 inWriter.write("// Data points:");
575 inWriter.write(inLineSeparator);
576 int numPoints = inModel.getNumPoints();
577 for (int i=0; i<numPoints; i++)
579 // ball (different according to type)
580 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_WAYPOINT)
583 inWriter.write("object { waypoint_sphere translate <" + inModel.getScaledHorizValue(i)
584 + "," + inModel.getScaledAltValue(i) + "," + inModel.getScaledVertValue(i) + "> }");
588 // normal track point ball
589 inWriter.write("object { track_sphere" + checkHeightCode(inModel.getPointHeightCode(i))
590 + " translate <" + inModel.getScaledHorizValue(i) + "," + inModel.getScaledAltValue(i)
591 + "," + inModel.getScaledVertValue(i) + "> }");
593 inWriter.write(inLineSeparator);
594 // vertical rod (if altitude positive)
595 if (inModel.getScaledAltValue(i) > 0.0)
597 inWriter.write("object { point_rod translate <" + inModel.getScaledHorizValue(i) + ",0,"
598 + inModel.getScaledVertValue(i) + "> scale <1," + inModel.getScaledAltValue(i) + ",1> }");
599 inWriter.write(inLineSeparator);
602 inWriter.write(inLineSeparator);
607 * Write out all the data points to the file in the tubes-and-walls style
608 * @param inWriter Writer to use for writing file
609 * @param inModel model object for getting data points
610 * @param inLineSeparator line separator to use
611 * @throws IOException on file writing error
613 private void writeDataPointsTubesAndWalls(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
616 inWriter.write("// Data points:");
617 inWriter.write(inLineSeparator);
618 int numPoints = inModel.getNumPoints();
619 int numTrackPoints = 0;
620 // Loop over all points and write out waypoints as balls
621 for (int i=0; i<numPoints; i++)
623 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_WAYPOINT)
626 inWriter.write("object { waypoint_sphere translate <" + inModel.getScaledHorizValue(i)
627 + "," + inModel.getScaledAltValue(i) + "," + inModel.getScaledVertValue(i) + "> }");
628 // vertical rod (if altitude positive)
629 if (inModel.getScaledAltValue(i) > 0.0)
631 inWriter.write(inLineSeparator);
632 inWriter.write("object { point_rod translate <" + inModel.getScaledHorizValue(i) + ",0,"
633 + inModel.getScaledVertValue(i) + "> scale <1," + inModel.getScaledAltValue(i) + ",1> }");
635 inWriter.write(inLineSeparator);
637 else {numTrackPoints++;}
639 inWriter.write(inLineSeparator);
641 // Loop over all the track segments
642 ArrayList<ModelSegment> segmentList = getSegmentList(inModel);
643 Iterator<ModelSegment> segmentIterator = segmentList.iterator();
644 while (segmentIterator.hasNext())
646 ModelSegment segment = segmentIterator.next();
647 int segLength = segment.getNumTrackPoints();
649 // if the track segment is long enough, do a cubic spline sphere sweep
652 // single point in segment - just draw sphere
653 int index = segment.getStartIndex();
654 inWriter.write("object { track_sphere_t"
655 + " translate <" + inModel.getScaledHorizValue(index) + "," + inModel.getScaledAltValue(index)
656 + "," + inModel.getScaledVertValue(index) + "> }");
657 // maybe draw some kind of polygon too or rod?
661 writeSphereSweep(inWriter, inModel, segment, inLineSeparator);
664 // Write wall underneath segment
667 writePolygonWall(inWriter, inModel, segment, inLineSeparator);
674 * Write out a single sphere sweep using either cubic spline or linear spline
675 * @param inWriter Writer to use for writing file
676 * @param inModel model object for getting data points
677 * @param inSegment model segment to draw
678 * @param inLineSeparator line separator to use
679 * @throws IOException on file writing error
681 private static void writeSphereSweep(FileWriter inWriter, ThreeDModel inModel, ModelSegment inSegment, String inLineSeparator)
685 inWriter.write("// Sphere sweep:");
686 inWriter.write(inLineSeparator);
687 String splineType = inSegment.getNumTrackPoints() < 5?"linear_spline":"cubic_spline";
688 inWriter.write("sphere_sweep { "); inWriter.write(splineType);
689 inWriter.write(" " + inSegment.getNumTrackPoints() + ",");
690 inWriter.write(inLineSeparator);
691 // Loop over all points in this segment and write out sphere sweep
692 for (int i=inSegment.getStartIndex(); i<=inSegment.getEndIndex(); i++)
694 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
696 inWriter.write(" <" + inModel.getScaledHorizValue(i) + "," + inModel.getScaledAltValue(i)
697 + "," + inModel.getScaledVertValue(i) + ">, 0.25");
698 inWriter.write(inLineSeparator);
701 inWriter.write(" tolerance 0.1");
702 inWriter.write(inLineSeparator);
703 inWriter.write(" texture { pigment {color rgb <0.6 1.0 0.2>} finish {phong 1} }");
704 inWriter.write(inLineSeparator);
705 inWriter.write(" no_shadow");
706 inWriter.write(inLineSeparator);
708 inWriter.write(inLineSeparator);
713 * Write out a single polygon-based wall for the tubes-and-walls style
714 * @param inWriter Writer to use for writing file
715 * @param inModel model object for getting data points
716 * @param inSegment model segment to draw
717 * @param inLineSeparator line separator to use
718 * @throws IOException on file writing error
720 private static void writePolygonWall(FileWriter inWriter, ThreeDModel inModel, ModelSegment inSegment, String inLineSeparator)
724 inWriter.write(inLineSeparator);
725 inWriter.write("// wall between sweep and floor:");
726 inWriter.write(inLineSeparator);
727 // Loop over all points in this segment again and write out polygons
729 for (int i=inSegment.getStartIndex(); i<=inSegment.getEndIndex(); i++)
731 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
735 double xDiff = inModel.getScaledHorizValue(i) - inModel.getScaledHorizValue(prevIndex);
736 double yDiff = inModel.getScaledVertValue(i) - inModel.getScaledVertValue(prevIndex);
737 double dist = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
740 inWriter.write("polygon {");
741 inWriter.write(" 5, <" + inModel.getScaledHorizValue(prevIndex) + ", 0.0, " + inModel.getScaledVertValue(prevIndex) + ">,");
742 inWriter.write(" <" + inModel.getScaledHorizValue(prevIndex) + ", " + inModel.getScaledAltValue(prevIndex) + ", "
743 + inModel.getScaledVertValue(prevIndex) + ">,");
744 inWriter.write(" <" + inModel.getScaledHorizValue(i) + ", " + inModel.getScaledAltValue(i) + ", "
745 + inModel.getScaledVertValue(i) + ">,");
746 inWriter.write(" <" + inModel.getScaledHorizValue(i) + ", 0.0, " + inModel.getScaledVertValue(i) + ">,");
747 inWriter.write(" <" + inModel.getScaledHorizValue(prevIndex) + ", 0.0, " + inModel.getScaledVertValue(prevIndex) + ">");
748 inWriter.write(" pigment { color wall_colour } no_shadow");
750 inWriter.write(inLineSeparator);
760 * @param inCode height code to check
761 * @return validated height code within range 0 to max
763 private static byte checkHeightCode(byte inCode)
765 final byte maxHeightCode = 4;
766 if (inCode < 0) return 0;
767 if (inCode > maxHeightCode) return maxHeightCode;
773 * Check the given coordinate
774 * @param inString String entered by user
775 * @return validated String value
777 private static String checkCoordinate(String inString)
782 value = Double.parseDouble(inString);
784 catch (Exception e) {} // ignore parse failures
789 * Go through the points making a list of the segment starts and the number of track points in each segment
790 * @param inModel model containing data
791 * @return list of ModelSegment objects
793 private static ArrayList<ModelSegment> getSegmentList(ThreeDModel inModel)
795 ArrayList<ModelSegment> segmentList = new ArrayList<ModelSegment>();
796 if (inModel != null && inModel.getNumPoints() > 0)
798 ModelSegment currSegment = null;
799 int numTrackPoints = 0;
800 for (int i=0; i<inModel.getNumPoints(); i++)
802 if (inModel.getPointType(i) != ThreeDModel.POINT_TYPE_WAYPOINT)
804 if (inModel.getPointType(i) == ThreeDModel.POINT_TYPE_SEGMENT_START || currSegment == null)
807 if (currSegment != null)
809 currSegment.setEndIndex(i-1);
810 currSegment.setNumTrackPoints(numTrackPoints);
811 segmentList.add(currSegment);
814 currSegment = new ModelSegment(i);
819 // Add last segment to list
820 if (currSegment != null && numTrackPoints > 0)
822 currSegment.setEndIndex(inModel.getNumPoints()-1);
823 currSegment.setNumTrackPoints(numTrackPoints);
824 segmentList.add(currSegment);