001/**
002 * Axis -- Representation of a set of axes around a origin of a coordinate system.
003 *
004 * Copyright (C) 2009-2023, 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 *
018 *
019 * This class is based on "org.j3d.renderer.java3d.geom.Axis" which bore the following
020 * notation: J3D.org Copyright (c) 2000 Java Source This source is licensed under the GNU
021 * LGPL v2.1
022 */
023package geomss.app;
024
025import jahuwaldt.j3d.geom.GeometryData;
026import jahuwaldt.j3d.geom.ConeGenerator;
027import jahuwaldt.j3d.geom.CoordinateUtils;
028import jahuwaldt.j3d.geom.CylinderGenerator;
029import java.util.ResourceBundle;
030import org.jogamp.java3d.*;
031import org.jogamp.vecmath.AxisAngle4f;
032import org.jogamp.vecmath.Color3f;
033
034/**
035 * Representation of a set of axes around the coordinates.
036 * <p>
037 * Each axis is color coordinated and the length can be adjusted.
038 * </p>
039 * <p>
040 * X axis: Red<br>
041 * Y axis: Green<br>
042 * Z axis: Blue
043 * </p>
044 *
045 * <p> Modified by: Joseph A.Huwaldt </p>
046 *
047 * @author Jason Taylor, based on the work by Justin Couch
048 * @version June 4, 2023
049 */
050public class Axis extends Group {
051
052    //  The resource bundle for this class.
053    private static final ResourceBundle RB
054            = ResourceBundle.getBundle("geomss.app.AxisResources", java.util.Locale.getDefault());
055
056    /**
057     * The default length of the axis
058     */
059    private static final float DEFAULT_AXIS_LENGTH = 5;
060
061    /**
062     * The scale to apply to the length to get the thickness for the arrows
063     */
064    private static final float DEFAULT_X_SCALE = 0.05f;
065
066    /**
067     * Create a default axis object with each item length 5 from the origin
068     */
069    public Axis() {
070        this(DEFAULT_AXIS_LENGTH, 0);
071    }
072
073    /**
074     * Create an axis object with the given axis length from the origin.
075     *
076     * @param length The length to use. Must be positive
077     */
078    public Axis(float length) {
079        this(length, 0);
080    }
081
082    /**
083     * Create an axis object with the given axis length from the origin. The transparency
084     * of the axis can be controlled through the use of the second parameter.
085     *
086     * @param length       The length to use. Must be positive
087     * @param transparency The amount of transparency in the axis (0=opaque, 1=fully
088     *                     transparent).
089     */
090    public Axis(float length, float transparency) {
091        if (length <= 0)
092            throw new IllegalArgumentException(RB.getString("axisLengthNegative"));
093
094        // Change the thickness in propotion to the length.
095        float X_SIZE = length * DEFAULT_X_SCALE;
096
097        // Create a single item of geometry and then share/rotate as needed
098        //BoxGenerator box_gen = new BoxGenerator(X_SIZE, length, X_SIZE);
099        CylinderGenerator cyl_gen = new CylinderGenerator(length, X_SIZE, 4);
100
101        int format = GeometryArray.COORDINATES | GeometryArray.NORMALS;
102        GeometryData data = new GeometryData();
103        data.geometryType = GeometryData.TRIANGLE_STRIPS;
104        data.geometryComponents = GeometryData.NORMAL_DATA;
105
106        cyl_gen.generate(data);
107
108        CoordinateUtils cu = new CoordinateUtils();
109        cu.translate(data.coordinates,
110                data.vertexCount,
111                0,
112                length / 2,
113                0);
114
115        TriangleStripArray axis_array
116                = new TriangleStripArray(data.vertexCount, format, data.stripCounts);
117
118        axis_array.setCoordinates(0, data.coordinates);
119        axis_array.setNormals(0, data.normals);
120
121        ConeGenerator cone_gen = new ConeGenerator(X_SIZE * 4, X_SIZE * 2, 3);
122        data.geometryType = GeometryData.INDEXED_TRIANGLE_FANS;
123        data.vertexCount = 0;
124        data.coordinates = null;
125        data.normals = null;
126        data.stripCounts = null;
127
128        cone_gen.generate(data);
129
130        cu.translate(data.coordinates,
131                data.vertexCount,
132                0,
133                length + (X_SIZE * 2),
134                0);
135
136        IndexedTriangleStripArray cone_array
137                = new IndexedTriangleStripArray(data.vertexCount,
138                        format,
139                        data.indexesCount,
140                        data.stripCounts);
141
142        cone_array.setCoordinates(0, data.coordinates);
143        cone_array.setNormals(0, data.normals);
144        cone_array.setCoordinateIndices(0, data.indexes);
145        cone_array.setNormalIndices(0, data.indexes);
146
147        Color3f blue = new Color3f(0, 0, 0.8f);
148        Material blue_material = new Material();
149        blue_material.setDiffuseColor(blue);
150        blue_material.setLightingEnable(true);
151
152        Color3f red = new Color3f(0.8f, 0, 0);
153        Material red_material = new Material();
154        red_material.setDiffuseColor(red);
155        red_material.setLightingEnable(true);
156
157        Color3f green = new Color3f(0, 0.8f, 0);
158        Material green_material = new Material();
159        green_material.setDiffuseColor(green);
160        green_material.setLightingEnable(true);
161
162        Appearance x_app = new Appearance();
163        x_app.setMaterial(red_material);
164
165        Appearance y_app = new Appearance();
166        y_app.setMaterial(green_material);
167
168        Appearance z_app = new Appearance();
169        z_app.setMaterial(blue_material);
170
171        if (transparency != 0) {
172            TransparencyAttributes attr
173                    = new TransparencyAttributes(TransparencyAttributes.FASTEST,
174                            transparency);
175
176            x_app.setTransparencyAttributes(attr);
177            y_app.setTransparencyAttributes(attr);
178            z_app.setTransparencyAttributes(attr);
179        }
180
181        Shape3D x_shape = new Shape3D();
182        x_shape.setAppearance(x_app);
183        x_shape.addGeometry(axis_array);
184        x_shape.addGeometry(cone_array);
185
186        Shape3D y_shape = new Shape3D();
187        y_shape.setAppearance(y_app);
188        y_shape.addGeometry(axis_array);
189        y_shape.addGeometry(cone_array);
190
191        Shape3D z_shape = new Shape3D();
192        z_shape.setAppearance(z_app);
193        z_shape.addGeometry(axis_array);
194        z_shape.addGeometry(cone_array);
195
196        // The three axis values are all pointing up along the Y axis. Apply a
197        // transform to X and Z to move them to the correct position.
198        Transform3D tx = new Transform3D();
199        AxisAngle4f angle = new AxisAngle4f();
200
201        // X Axis first
202        angle.set(0, 0, 1, -(float)(Math.PI * 0.5f));
203        tx.setRotation(angle);
204
205        TransformGroup x_tg = new TransformGroup(tx);
206        x_tg.addChild(x_shape);
207
208        angle.set(1, 0, 0, (float)(Math.PI * 0.5f));
209        tx.setRotation(angle);
210
211        TransformGroup z_tg = new TransformGroup(tx);
212        z_tg.addChild(z_shape);
213
214        addChild(x_tg);
215        addChild(y_shape);
216        addChild(z_tg);
217    }
218}