001/**
002 * GeomSSBatch -- Class that allows GeomSS to run a script in batch (background) mode.
003 * 
004 * Copyright (C) 2009-2025, by Joseph A. Huwaldt. All rights reserved.
005 * 
006 * This library is free software; you can redistribute it and/or modify it under the terms
007 * of the GNU Lesser General Public License as published by the Free Software Foundation;
008 * either version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful, but WITHOUT ANY
011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
012 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
013 * 
014 * You should have received a copy of the GNU Lesser General Public License along with
015 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place -
016 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html
017 */
018package geomss.app;
019
020import bsh.*;
021import geomss.GeomSSApp;
022import geomss.GeomSSScene;
023import geomss.geom.GeomElement;
024import geomss.geom.GeomList;
025import geomss.geom.GeomUtil;
026import geomss.geom.GeometryList;
027import geomss.geom.reader.GeomReader;
028import geomss.geom.reader.GeomReaderFactory;
029import geomss.geom.reader.XGSSGeomReader;
030import geomss.j3d.*;
031import jahuwaldt.js.param.Parameter;
032import jahuwaldt.swing.MacOSUtilities;
033import jahuwaldt.swing.Preferences;
034import java.awt.Color;
035import java.awt.Component;
036import java.awt.Frame;
037import java.awt.Window;
038import java.io.File;
039import java.io.IOException;
040import java.util.ArrayList;
041import java.util.List;
042import static java.util.Objects.isNull;
043import static java.util.Objects.nonNull;
044import static java.util.Objects.requireNonNull;
045import java.util.ResourceBundle;
046import javax.measure.quantity.Length;
047import javax.measure.unit.NonSI;
048import javax.measure.unit.SI;
049import javax.measure.unit.Unit;
050import javolution.util.FastMap;
051
052/**
053 * This class will run a GeomSS BeanShell script in batch (background or non-interactive)
054 * mode.
055 * 
056 * <p> Modified by: Joseph A. Huwaldt </p>
057 * 
058 * @author Joseph A. Huwaldt, Date: September 7, 2010
059 * @version February 17, 2025
060 */
061public class GeomSSBatch extends Thread {
062
063    /**
064     * The length unit options for this program.
065     */
066    public static final Unit[] LENGTH_UNITS = {SI.MILLIMETER, SI.CENTIMETER, SI.METER, SI.KILOMETER,
067        NonSI.INCH, NonSI.FOOT, NonSI.YARD, NonSI.NAUTICAL_MILE, NonSI.MILE};
068
069    //  Reference to the script file we are going to run.
070    private final File _scriptFile;
071
072    //  The BeanShell interpreter for running the script file.
073    private final Interpreter _bsh = new Interpreter();
074
075    //  The scene interface for this application.
076    private final PublicScene _scene = new PublicScene();
077
078    //  The main application's resource bundle.
079    private final ResourceBundle _resBundle;
080
081    //  The preferences for this application.
082    private final AppPreferences _prefs = new AppPreferences();
083
084    /**
085     * Construct a new batch script running thread.
086     *
087     * @param resBundle  The main application's resource bundle. May not be null.
088     * @param scriptFile The existing script file to be run. May not be null.
089     * @throws EvalError if there is a problem setting up BeanShell.
090     */
091    public GeomSSBatch(ResourceBundle resBundle, File scriptFile) throws EvalError {
092        _resBundle = requireNonNull(resBundle);
093        _scriptFile = requireNonNull(scriptFile);
094        initializeBeanShell(resBundle.getString("appName"), _bsh, new PublicAppInterface());
095    }
096
097    /**
098     * The run() method just sits and waits for incoming connections and hands each one
099     * off to a new ServerJobRunner thread to handle it.
100     */
101    @Override
102    public void run() {
103        try {
104            //  Run the script file.
105            _bsh.source(_scriptFile.getAbsolutePath());
106        } catch (Exception e) {
107            e.printStackTrace();
108        }
109    }
110
111    /**
112     * Provides the initial setup of the BeanShell environment required by GeomSS.
113     *
114     * @param appName      The name of this application. May not be null.
115     * @param bsh          A reference to the BeanShell interpreter to be configured.
116     * @param appInterface The interface to GeomSS application methods such as "print".
117     * @throws bsh.EvalError BeanShell evaluation error.
118     */
119    public static void initializeBeanShell(String appName, Interpreter bsh, GeomSSApp appInterface) throws EvalError {
120
121        requireNonNull(appName);
122        requireNonNull(appInterface);
123        
124        bsh.eval("bsh.prompt=\"%\";");
125        bsh.eval("import java.util.*;");
126        bsh.eval("import java.util.List;"); // Give java.util.List priority over java.awt.List.
127        bsh.eval("import javax.measure.unit.Unit;");
128        bsh.eval("static import javax.measure.unit.SI.*;");
129        bsh.eval("static import javax.measure.unit.NonSI.*;");
130        bsh.eval("import javax.measure.quantity.*;");
131        bsh.eval("import javolution.text.TypeFormat");
132        bsh.eval("static import javolution.lang.MathLib.*;");
133        bsh.eval("import jahuwaldt.tools.math.MathTools;");
134        bsh.eval("import jahuwaldt.js.param.*;");
135        bsh.eval("import geomss.*;");
136        bsh.eval("import geomss.geom.*;");
137        bsh.eval("import geomss.geom.Point;");
138        bsh.eval("import geomss.geom.reader.*;");
139        bsh.eval("import geomss.geom.nurbs.*;");
140        bsh.eval("import geomss.geom.cst.*;");
141        bsh.eval("import geomss.ui.*;");
142        bsh.eval("static import geomss.ui.Colors.*;");
143        bsh.eval("static import geomss.GeomSSUtil.*;");
144        bsh.eval("static import geomss.j3d.ProjectionPolicy.*;");
145        bsh.eval("static import geomss.j3d.SurfaceColorType.*;");
146        bsh.eval("importCommands(\"/geomss/app/GeomSSCommands\");");   //  Import standard GeomSS command scripts.
147        bsh.eval("importCommands(\"/geomss/app/GeomSSCommands/creators\");");  //  Import GeomSS creator command scripts.
148        bsh.eval("importCommands(\"/geomss/app/GeomSSCommands/utils\");"); //  Import GeomSS utility command scripts.
149        bsh.eval("GeomSSApp gApp = null;");
150        bsh.set("gApp", appInterface);
151        bsh.eval("GeomSSScene gScene = gApp.getScene();");
152
153        //  Add the MacOS application support Commands folder to the classpath (if it exists).
154        if (MacOSUtilities.isMacOS()) {
155            File commandsDir = new File("~/Library/Application Support");
156            commandsDir = new File(commandsDir, appName + "/Commands");
157            if (commandsDir.exists()) {
158                bsh.eval("addClassPath(\"" + commandsDir.getParent() + "\");");
159                bsh.eval("importCommands(\"/Commands\");");
160            }
161        }
162
163    }
164    
165    /**
166     * Method that reads in a data file and return the resulting data structure.
167     *
168     * @param resBundle The main application's resource bundle. May not be null.
169     * @param parent    The parent frame for dialogs (null is fine).
170     * @param theFile   The file to be read in. If <code>null</code> is passed, this
171     *                  method will do nothing.
172     * @return The list of geometry read in or null if nothing was read in.
173     * @throws IOException if unable to read in the geometry data.
174     */
175    public static GeometryList readGeometryData(ResourceBundle resBundle, Component parent, File theFile) throws IOException {
176        requireNonNull(resBundle);
177        GeometryList data = null;
178
179        if (nonNull(theFile)) {
180            GeomReader reader = GeomReaderFactory.getReader(theFile);
181            if (isNull(reader))
182                return null;
183
184            if (!reader.isUnitAware()) {
185                //  Ask the user to select the units for the file.
186                Unit<Length> unit = GeomUtil.getDefaultUnit();
187
188                ChooseUnitDialog<Length> dialog = new ChooseUnitDialog(parent, resBundle.getString("chooseUnitsTitle"),
189                        resBundle.getString("chooseUnitsMsg"),
190                        resBundle.getString("lengthUnitsLabel"), LENGTH_UNITS, unit);
191                dialog.setVisible(true);
192
193                unit = dialog.getSelected();
194                dialog.dispose();
195                if (isNull(unit))
196                    return null;
197
198                //  Store the selected unit in the reader.
199                reader.setFileUnits(unit);
200            }
201
202            //  Read in the data.
203            data = reader.read(theFile);
204
205            //  Attach any warning messages to the user data.
206            List<String> warnings = reader.getWarnings();
207            if (!warnings.isEmpty())
208                data.putUserData("IGESWarnings", warnings);
209        }
210
211        return data;
212    }
213
214    /**
215     * Method that writes out geometry to a data file using a specific GeomReader
216     * instance.
217     *
218     * @param resBundle The main application's resource bundle. May not be null.
219     * @param parent    The parent frame for dialogs (null is fine).
220     * @param geometry  The geometry object to be written out. May not be null.
221     * @param theFile   The file to be written to. May not be null.
222     * @param writer    The GeomReader to use to write out the file. May not be null.
223     * @throws IOException if unable to write the geometry data.
224     */
225    public static void writeGeometryData(ResourceBundle resBundle, Component parent,
226            GeometryList geometry, File theFile, GeomReader writer) throws IOException {
227
228        requireNonNull(geometry);
229        requireNonNull(theFile);
230        if (!writer.isUnitAware()) {
231            //  Ask the user to select the units for the file.
232            Unit<Length> unit = GeomUtil.getDefaultUnit();
233
234            ChooseUnitDialog<Length> dialog = new ChooseUnitDialog(parent, resBundle.getString("chooseUnitsTitle"),
235                    resBundle.getString("chooseUnitsMsg"),
236                    resBundle.getString("lengthUnitsLabel"), LENGTH_UNITS, unit);
237            dialog.setVisible(true);
238
239            unit = dialog.getSelected();
240            dialog.dispose();
241            if (isNull(unit))
242                return;
243
244            //  Convert the geometry to the selected unit.
245            geometry = geometry.to(unit);
246        }
247
248        //  Write the geometry to the file.
249        writer.write(theFile, geometry);
250    }
251
252    /**
253     * Save the specified BeanShell global workspace to the specified XGSS file.
254     *
255     * @param resBundle The main application's resource bundle. May not be null.
256     * @param bsh The BeanShell interpreter. May not be null.
257     * @param theFile The file to save the workspace to. May not be null.
258     */
259    static void saveWorkspace(ResourceBundle resBundle, Interpreter bsh, File theFile) throws IOException, UtilEvalError {
260
261        requireNonNull(resBundle);
262        requireNonNull(bsh);
263        requireNonNull(theFile);
264        
265        FastMap<String, Object> vars = new FastMap();
266        FastMap<String, GeomElement> geom = new FastMap();
267        try {
268            //  Extract the workspace variables into a pair of Maps.
269            extractVariableMaps(bsh, geom, vars);
270            if (geom.isEmpty() && vars.isEmpty()) {
271                //  Nothing to be saved.
272                bsh.println(resBundle.getString("nothingToSaveMsg"));
273                return;
274            }
275
276            //  Write out the model input file.
277            XGSSGeomReader writer = new XGSSGeomReader();
278            writer.write(theFile, geom, vars);
279
280        } finally {
281            FastMap.recycle(vars);
282            FastMap.recycle(geom);
283        }
284
285    }
286
287    /**
288     * Load the specified XGSS file into the specified BeanShell interpreter workspace.
289     *
290     * @param resBundle The main application's resource bundle. May not be null.
291     * @param bsh The BeanShell interpreter. May not be null.
292     * @param theFile The file to load the workspace from. May not be null.
293     */
294    static void loadWorkspace(ResourceBundle resBundle, Interpreter bsh, File theFile) throws IOException, EvalError {
295
296        requireNonNull(resBundle);
297        requireNonNull(bsh);
298        requireNonNull(theFile);
299        
300        //  Read in the geometry and any workspace variables.
301        XGSSGeomReader reader = new XGSSGeomReader();
302        FastMap<String, Object> workspace = (FastMap<String, Object>)reader.readWorkspace(theFile);
303
304        try {
305            //  Store all the variables into the BeanShell worksapce.
306            for (String varName : workspace.keySet())
307                bsh.set(varName, workspace.get(varName));
308
309        } finally {
310            FastMap.recycle(workspace);
311        }
312    }
313
314    /**
315     * Method that gets all the variables from the specified BeanShell interpreter and
316     * stores them in the supplied pair of Maps.
317     *
318     * @param bsh  The BeanShell interpreter to extract the global workspace from.
319     * @param geom The map to contain all the geometry variables by variable name.
320     * @param vars The map to contain on the non-geometry variables by variable name.
321     * @throws UtilEvalError
322     */
323    static void extractVariableMaps(Interpreter bsh, FastMap<String, GeomElement> geom,
324            FastMap<String, Object> vars) throws UtilEvalError {
325        //  Get all the variables and store them in a pair of Maps.
326
327        requireNonNull(bsh);
328        requireNonNull(geom);
329        requireNonNull(vars);
330        
331        // Get the namespace.
332        NameSpace namespace = bsh.getNameSpace();
333
334        //  Create a list of all the geometry elements in the namespace.
335        for (String varName : namespace.getVariableNames()) {
336            Object var = namespace.getVariable(varName);
337            //  Ignore the standard variables that are not user created.
338            if (!varName.equals("$_") && !varName.equals("gApp")
339                    && !varName.equals("gScene") && !varName.equals("bsh")) {
340                //  Pick out the variables that are of GeomElement type.
341                if (var instanceof GeomElement) {
342                    GeomElement geometry = (GeomElement)var;
343                    geom.put(varName, geometry);
344                } else {
345                    if (var instanceof Primitive)
346                        var = ((Primitive)var).getValue();
347                    vars.put(varName, var);
348                }
349            }
350        }
351    }
352
353    /**
354     * A class that serves as the public interface (in BeanShell) for this application.
355     */
356    private class PublicAppInterface implements GeomSSApp {
357
358        //  A list of available point geometry writers.
359        private final List<GeomReader> _geomWriters = new ArrayList();
360
361        public PublicAppInterface() {
362            //  Get the list of data readers that are available.
363            GeomReader[] allReaders = GeomReaderFactory.getAllReaders();
364
365            //  Loop over all the readers.
366            if (nonNull(allReaders)) {
367                for (GeomReader reader : allReaders) {
368                    if (reader.canWriteData()) {
369                        //  Found a "writer".
370                        _geomWriters.add(reader);
371                    }
372                }
373            }
374
375        }
376
377        /**
378         * Return a reference to the 3D scene.
379         */
380        @Override
381        public GeomSSScene getScene() {
382            return _scene;
383        }
384
385        /**
386         * Return the parent Frame for this application. This version always returns null.
387         */
388        @Override
389        public Frame getParentFrame() {
390            return null;
391        }
392
393        /**
394         * Return a reference to the preferences for the GeomSS application.
395         */
396        @Override
397        public Preferences getPreferences() {
398            return _prefs;
399        }
400
401        /**
402         * Return the resource bundle for this application containing the localized
403         * application Strings.
404         */
405        @Override
406        public ResourceBundle getResourceBundle() {
407            return _resBundle;
408        }
409
410        /**
411         * Add the supplied window to the Windows menu of the main application. This
412         * version does nothing since there is no Windows menu in a batch application.
413         *
414         * @param window The window to be added to the Windows menu.
415         */
416        @Override
417        public void addToWindowsMenu(Window window) {
418            
419        }
420
421        /**
422         * Quit or exit the application after properly saving preferences, etc.
423         */
424        @Override
425        public void quit() {
426            System.exit(0);
427        }
428
429        /**
430         * Read in a geometry file and return a GeometryList instance. All exceptions are
431         * handled by this method. This implementation does nothing.
432         *
433         * @param theFile The file to be read in. If <code>null</code> is passed, this
434         *                method will do nothing.
435         * @return A GeometryList object containing the geometry read in from the file or
436         *         <code>null</code> if the user cancels the read at any point or if an
437         *         exception of any kind is thrown.
438         */
439        @Override
440        public GeometryList readGeomFile(File theFile) {
441            GeometryList geom = null;
442            try {
443                geom = readGeometryData(_resBundle, null, theFile);
444            } catch (Exception e) {
445                e.printStackTrace();
446            }
447            return geom;
448        }
449
450        /**
451         * Write out geometry to the specified file using the specified GeometryList
452         * instance (some GeomReader classes have specific requirements for the contents
453         * of this list). All exceptions are handled by this method.
454         *
455         * @param geometry The geometry object to be written out.
456         * @param theFile  The file to be written to.
457         * @param writer   The GeomReader to use to write out the file.
458         */
459        @Override
460        public void writeGeomFile(GeometryList geometry, File theFile, GeomReader writer) {
461            try {
462                writeGeometryData(_resBundle, null, geometry, theFile, writer);
463            } catch (IOException e) {
464                e.printStackTrace();
465            }
466        }
467
468        /**
469         * Returns a list of all known GeomReader objects that are capable of writing to a
470         * file.
471         */
472        @Override
473        public List<GeomReader> getAllGeomWriters() {
474            return _geomWriters;
475        }
476
477        /**
478         * Save the entire global workspace to an XGSS file. All defined geometry and
479         * non-geometry variables in the global workspace will be saved to the specified
480         * file.
481         *
482         * @param theFile The file to write the workspace to in XGSS format.
483         */
484        @Override
485        public void saveWorkspace(File theFile) {
486            try {
487                //  Save the workspace to the specified file.
488                GeomSSBatch.saveWorkspace(_resBundle, _bsh, theFile);
489
490            } catch (Exception e) {
491                e.printStackTrace();
492            }
493        }
494
495        /**
496         * Load the specified XGSS file into the current global workspace. All the
497         * geometry and non-geometry variables in the specified XGSS file will be loaded
498         * into the current global workspace. Any existing variables with the same names
499         * will be silently overwritten.
500         *
501         * @param theFile The XGSS file to load into the current workspace.
502         */
503        @Override
504        public void loadWorkspace(File theFile) {
505            try {
506                //  Load in the specified file.
507                GeomSSBatch.loadWorkspace(_resBundle, _bsh, theFile);
508
509            } catch (Exception e) {
510                e.printStackTrace();
511            }
512        }
513
514        /**
515         * Save a copy of the current 3D view as a PNG file.
516         */
517        @Override
518        public void saveAsPNG() {
519            //  Do nothing in batch mode.
520        }
521
522        /**
523         * Save a copy of the current 3D view as a PNG file.
524         *
525         * @param file The file to be saved.
526         */
527        @Override
528        public void saveAsPNG(File file) {
529            //  Do nothing in batch mode.
530        }
531
532        /**
533         * Save a copy of the current 3D view as a JPEG file.
534         */
535        @Override
536        public void saveAsJPEG() {
537            //  Do nothing in batch mode.
538        }
539
540        /**
541         * Save a copy of the current 3D view as a JPEG file.
542         *
543         * @param file The file to be saved.
544         */
545        @Override
546        public void saveAsJPEG(File file) {
547            //  Do nothing in batch mode.
548        }
549
550        /**
551         * Print the current 3D view. The user will be asked to supply information on the
552         * print settings.
553         */
554        @Override
555        public void print() {
556            //  Do nothing in batch mode.
557        }
558
559        /**
560         * Positions the input window at the location stored in the preferences using the
561         * supplied key (with "PosX" and "PosY" appended). If the preference key isn't
562         * found or if the returned values can not be turned into numbers, the
563         * setLocationByPlatform() flag is set for the window.
564         *
565         * @param prefsKey The prefix for the preference key to use ("PosX" and "PosY"
566         *                 will be appended in order to retrieve the actual preference
567         *                 values).
568         * @param window   The window to be positioned using the preference values.
569         * @see Window#setLocationByPlatform(boolean) 
570         */
571        @Override
572        public void posWindowFromPrefs(String prefsKey, Window window) {
573            //  Do nothing in batch mode.
574        }
575
576        /**
577         * Save the location of the specified window in the application preferences using
578         * the supplied key (with "PosX" and "PosY" appended).
579         *
580         * @param prefsKey The prefix for the preference key to use ("PosX" and "PosY"
581         *                 will be appended in order to save the actual preference
582         *                 values).
583         * @param window   The window for which the position is to be saved in the
584         *                 preferences.
585         */
586        @Override
587        public void savePrefsWindowPos(String prefsKey, Window window) {
588            //  Do nothing in batch mode.
589        }
590        
591    }   //  end PublicAppInterface
592
593    /**
594     * A class that serves as the public interface (in BeanShell) for this application's
595     * 3D scene.
596     */
597    public static class PublicScene implements GeomSSScene {
598
599        private boolean isMirrored = false;
600        private RenderType renderType = RenderType.SOLID_PLUS_WIREFRAME;
601        private ProjectionPolicy _policy = ProjectionPolicy.PERSPECTIVE_PROJECTION;
602
603        @Override
604        public void draw(GeomElement newGeom) {
605            //  Do nothing in batch mode.
606        }
607
608        @Override
609        public void draw(GeomElement newGeom, boolean erase) {
610            //  Do nothing in batch mode.
611        }
612
613        @Override
614        public void erase() {
615            //  Do nothing in batch mode.
616        }
617
618        /**
619         * Erases the specified geometry from the 3D scene (if possible).
620         */
621        @Override
622        public void erase(GeomElement geometry) {
623            //  Do nothing in batch mode.
624        }
625
626        /**
627         * Centers the geometry in the display.
628         */
629        @Override
630        public void center() {
631            //  Do nothing in batch mode.
632        }
633
634        /**
635         * Centers the geometry in the display and zooms until the geometry fills the
636         * display.
637         */
638        @Override
639        public void centerAndZoom() {
640            //  Do nothing in batch mode.
641        }
642
643        /**
644         * Pick items from the scene by control-clicking with the mouse. Returns a list of
645         * selected items.
646         */
647        @Override
648        public GeomList pick() {
649            //  Returns an empty list.
650            return GeomList.newInstance();
651        }
652
653        /**
654         * Sets a flag indicating that the geometry is mirrored about the XZ plane of
655         * symmetry.
656         */
657        @Override
658        public void setMirrored(boolean mirrored) {
659            isMirrored = mirrored;
660        }
661
662        /**
663         * Returns a flag indicating if the geometry display is currently mirrored about
664         * the XZ plane of symmetry or not.
665         */
666        @Override
667        public boolean isMirrored() {
668            return isMirrored;
669        }
670
671        /**
672         * Sets {@link geomss.j3d.RenderType rendering type} for all the objects currently
673         * displayed in the entire scene.
674         */
675        @Override
676        public void setRenderType(RenderType type) {
677            renderType = type;
678        }
679
680        /**
681         * Returns the {@link geomss.j3d.RenderType rendering type} for the 1st item in
682         * the scene.
683         */
684        @Override
685        public RenderType getRenderType() {
686            return renderType;
687        }
688
689        /**
690         * Sets the color used when rendering points.
691         */
692        @Override
693        public void setPointColor(Color color) {
694            J3DGeomGroup.setPointColor(color);
695        }
696
697        /**
698         * Returns the color used when rendering points.
699         */
700        @Override
701        public Color getPointColor() {
702            return J3DGeomGroup.getDefaultRenderingPrefs().getPointColor();
703        }
704
705        /**
706         * Set the size that Point objects are rendered in pixels.
707         */
708        @Override
709        public void setPointSize(int pixels) {
710            J3DGeomGroup.setPointSize(pixels);
711        }
712
713        /**
714         * Return the size that Point objects are rendered in pixels.
715         */
716        @Override
717        public int getPointSize() {
718            return J3DGeomGroup.getDefaultRenderingPrefs().getPointSize();
719        }
720
721        /**
722         * Sets the color used when rendering curves and lines.
723         */
724        @Override
725        public void setLineColor(Color color) {
726            J3DGeomGroup.setLineColor(color);
727        }
728
729        /**
730         * Returns the color used when rendering curves and lines.
731         */
732        @Override
733        public Color getLineColor() {
734            return J3DGeomGroup.getDefaultRenderingPrefs().getLineColor();
735        }
736
737        /**
738         * Set the width that line/curve objects are rendered in pixels.
739         */
740        @Override
741        public void setLineWidth(int pixels) {
742            J3DGeomGroup.setLineWidth(pixels);
743        }
744
745        /**
746         * Return the width that line/curve objects are rendered in pixels.
747         */
748        @Override
749        public int getLineWidth() {
750            return J3DGeomGroup.getDefaultRenderingPrefs().getLineWidth();
751        }
752
753        /**
754         * Set the tolerance used when drawing parametric objects such as curves and
755         * surfaces. This tolerance is used when determining how to subdivide parametric
756         * objects for rendering. If the input value is <code>null</code> or equal to
757         * <code>0</code>, it will be silently ignored.
758         */
759        @Override
760        public void setDrawTolerance(Parameter<Length> tol) {
761            J3DGeomGroup.setDrawTolerance(tol);
762        }
763
764        /**
765         * Return the tolerance used when drawing parametric objects such as curves and
766         * surfaces. This tolerance is used when determining how to subdivide parametric
767         * objects for rendering.
768         */
769        @Override
770        public Parameter<Length> getDrawTolerance() {
771            return J3DGeomGroup.getDefaultRenderingPrefs().getDrawTolerance();
772        }
773
774        /**
775         * Retrieves the current projection policy for this scene. returns
776         */
777        @Override
778        public ProjectionPolicy getProjectionPolicy() {
779            return _policy;
780        }
781
782        /**
783         * Sets the projection policy for this scene. This specifies the type of
784         * projection transform that will be generated. A value of PARALLEL_PROJECTION
785         * specifies that a parallel projection transform is generated. A value of
786         * PERSPECTIVE_PROJECTION specifies that a perspective projection transform is
787         * generated.
788         *
789         * @param policy The new projection policy, one of PARALLEL_PROJECTION or
790         *               PERSPECTIVE_PROJECTION.
791         */
792        @Override
793        public void setProjectionPolicy(ProjectionPolicy policy) {
794            _policy = policy;
795        }
796
797        /**
798         * Set the color (of the specified type) used to render surfaces and point-arrays.
799         *
800         * @param colorType The aspect or type of the surface color that is being set.
801         * @param color     The color to use for the specified type of surface color. The
802         *                  alpha is ignored.
803         * @see #setSurfaceAlpha
804         */
805        @Override
806        public void setSurfaceColor(SurfaceColorType colorType, Color color) {
807            J3DRenderingPrefs prefs = J3DGeomGroup.getDefaultRenderingPrefs();
808            J3DGeomGroup.setDefaultRenderingPrefs(prefs.changeSurfaceColor(colorType, color));
809        }
810
811        /**
812         * Get the color (of the specified type) used to render surfaces and point-arrays.
813         *
814         * @param colorType The aspect or type of the surface color that is being set. If
815         *                  AMBIENT_AND_DIFFUSE is passed in, then only the ambient color
816         *                  is returned!
817         * @return The color used for the specified type of surface color. Alpha is
818         *         ignored.
819         * @see #getSurfaceAlpha
820         */
821        @Override
822        public Color getSurfaceColor(SurfaceColorType colorType) {
823            return J3DGeomGroup.getDefaultRenderingPrefs().getSurfaceColor(colorType);
824        }
825
826        /**
827         * Set the alpha or transparency used to render surfaces and point-arrays.
828         *
829         * @param alpha The alpha value to use (0.0=completely transparent, 1.0=completely
830         *              opaque).
831         */
832        @Override
833        public void setSurfaceAlpha(float alpha) {
834            J3DRenderingPrefs prefs = J3DGeomGroup.getDefaultRenderingPrefs();
835            J3DGeomGroup.setDefaultRenderingPrefs(prefs.changeSurfaceAlpha(alpha));
836        }
837
838        /**
839         * Get the alpha or transparency used when rendering surfaces or point-arrays.
840         *
841         * @return The alpha value used (0.0=completely transparent, 1.0=completely
842         *         opaque).
843         */
844        @Override
845        public float getSurfaceAlpha() {
846            return J3DGeomGroup.getDefaultRenderingPrefs().getSurfaceAlpha();
847        }
848
849        /**
850         * Set the shininess used when rendering surfaces and point-arrays.
851         *
852         * @param shininess The shininess to use in the range [0.0, 1.0] where 0.0 is not
853         *                  shiny and 1.0 is very shiny. Values outside this range are
854         *                  clamped.
855         */
856        @Override
857        public void setSurfaceShininess(float shininess) {
858            J3DRenderingPrefs prefs = J3DGeomGroup.getDefaultRenderingPrefs();
859            J3DGeomGroup.setDefaultRenderingPrefs(prefs.changeSurfaceShininess(shininess));
860        }
861
862        /**
863         * Get the shininess used when rendering surfaces and point-arrays.
864         *
865         * @return The shininess to use in the range [0.0, 1.0] where 0.0 is not shiny and
866         *         1.0 is very shiny.
867         */
868        @Override
869        public float getSurfaceShininess() {
870            return J3DGeomGroup.getDefaultRenderingPrefs().getSurfaceShininess();
871        }
872    }
873
874}