View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.ui;
39  
40  import static org.apache.commons.math3.util.FastMath.PI;
41  
42  import ffx.ui.behaviors.MouseBehaviorCallback;
43  import java.awt.Color;
44  import java.awt.Font;
45  import java.util.Iterator;
46  import org.jogamp.java3d.Appearance;
47  import org.jogamp.java3d.Bounds;
48  import org.jogamp.java3d.BranchGroup;
49  import org.jogamp.java3d.Font3D;
50  import org.jogamp.java3d.FontExtrusion;
51  import org.jogamp.java3d.Geometry;
52  import org.jogamp.java3d.Group;
53  import org.jogamp.java3d.Material;
54  import org.jogamp.java3d.Shape3D;
55  import org.jogamp.java3d.Text3D;
56  import org.jogamp.java3d.Transform3D;
57  import org.jogamp.java3d.TransformGroup;
58  import org.jogamp.java3d.utils.geometry.Cone;
59  import org.jogamp.java3d.utils.geometry.Cylinder;
60  import org.jogamp.java3d.utils.geometry.Sphere;
61  import org.jogamp.java3d.utils.picking.PickTool;
62  import org.jogamp.java3d.utils.universe.ViewingPlatform;
63  import org.jogamp.vecmath.AxisAngle4f;
64  import org.jogamp.vecmath.Color3f;
65  import org.jogamp.vecmath.Matrix3d;
66  import org.jogamp.vecmath.Vector3d;
67  
68  /**
69   * The GraphicsAxis class encapsulates the 3D Axis that is used to display and control
70   * rotation/translation in the global frame.
71   *
72   * @author Michael J. Schnieders
73   */
74  public final class GraphicsAxis extends Group implements MouseBehaviorCallback {
75  
76    public Matrix3d matrix = new Matrix3d();
77    private ViewingPlatform viewingPlatform;
78    private BranchGroup axisBranchGroup = new BranchGroup();
79    private TransformGroup axisTransformGroup = new TransformGroup();
80    private Transform3D axisTransform3D = new Transform3D();
81    private Vector3d axisVector3d = new Vector3d(-0.7, -0.6, -1.25);
82  
83    /**
84     * Constructor for GraphicsAxis.
85     *
86     * @param viewingPlatform a {@link org.jogamp.java3d.utils.universe.ViewingPlatform} object.
87     * @param bounds a {@link org.jogamp.java3d.Bounds} object.
88     */
89    GraphicsAxis(ViewingPlatform viewingPlatform, Bounds bounds) {
90      this.viewingPlatform = viewingPlatform;
91      setCapability(Group.ENABLE_PICK_REPORTING);
92      createAxis();
93      setBounds(bounds);
94      axisTransform3D.setTranslation(axisVector3d);
95      axisTransform3D.setScale(0.015);
96      axisTransformGroup.setTransform(axisTransform3D);
97      axisTransformGroup.addChild(this);
98      axisTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
99      axisTransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
100     axisTransformGroup.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
101     axisBranchGroup.setCapability(BranchGroup.ALLOW_DETACH);
102     axisBranchGroup.setCapability(BranchGroup.ENABLE_PICK_REPORTING);
103     axisBranchGroup.addChild(axisTransformGroup);
104     axisBranchGroup.compile();
105     this.viewingPlatform.getViewPlatformTransform().addChild(axisBranchGroup);
106   }
107 
108   /** center */
109   public void center() {
110     axisTransform3D.setIdentity();
111     axisTransform3D.setScale(0.015);
112     axisTransform3D.setTranslation(axisVector3d);
113     axisTransformGroup.setTransform(axisTransform3D);
114   }
115 
116   /** {@inheritDoc} */
117   public void transformChanged(int type, Transform3D viewTransform) {
118     viewTransform.get(matrix);
119     matrix.invert();
120     viewTransform.set(matrix);
121     axisTransform3D.set(viewTransform);
122     axisTransform3D.setTranslation(axisVector3d);
123     axisTransform3D.setScale(0.015);
124     axisTransformGroup.setTransform(axisTransform3D);
125   }
126 
127   /** {@inheritDoc} */
128   public void transformClicked(int type, Transform3D transform) {
129     transformChanged(type, transform);
130   }
131 
132   /** {@inheritDoc} */
133   public void transformDoubleClicked(int type, Transform3D transform) {
134     transformChanged(type, transform);
135   }
136 
137   /** createAxis */
138   private void createAxis() {
139     Appearance ap = new Appearance();
140     Color3f col = new Color3f(Color.lightGray.getRGBColorComponents(new float[3]));
141     Color3f black = new Color3f(Color.black.getRGBColorComponents(new float[3]));
142     Color3f white = new Color3f(Color.white.getRGBColorComponents(new float[3]));
143     Material mat = new Material(col, black, col, white, 50.0f);
144     mat.setLightingEnable(true);
145     ap.setMaterial(mat);
146     // X-Axis
147     Cone xcone = new Cone(2.0f, 3.0f, ap);
148     xcone.setUserData(this);
149     Transform3D xconeT3d = new Transform3D();
150     xconeT3d.setTranslation(new Vector3d(10.0f, 0.0f, 0.0f));
151     xconeT3d.setRotation(new AxisAngle4f(0.0f, 0.0f, 1.0f, (float) PI / -2.0f));
152     TransformGroup xconeTG = new TransformGroup(xconeT3d);
153     xconeTG.addChild(xcone);
154     Cylinder xcylinder = new Cylinder(1.0f, 9.0f, ap);
155     xcylinder.setUserData(this);
156     Transform3D xcyT3d = new Transform3D();
157     xcyT3d.setTranslation(new Vector3d(4.5, 0.0, 0.0));
158     xcyT3d.setRotation(new AxisAngle4f(0.0f, 0.0f, 1.0f, (float) PI / 2.0f));
159     TransformGroup xcyTG = new TransformGroup(xcyT3d);
160     xcyTG.addChild(xcylinder);
161     setCapabilities(xcone, xcylinder);
162     addChild(xconeTG);
163     addChild(xcyTG);
164     // Y-Axis
165     Cone ycone = new Cone(2.0f, 3.0f, ap);
166     ycone.setUserData(this);
167     Transform3D yconeT3d = new Transform3D();
168     yconeT3d.setTranslation(new Vector3d(0.0f, 10.0f, 0.0f));
169     TransformGroup yconeTG = new TransformGroup(yconeT3d);
170     yconeTG.addChild(ycone);
171     Cylinder ycylinder = new Cylinder(1.0f, 9.0f, ap);
172     ycylinder.setUserData(this);
173     Transform3D ycyT3d = new Transform3D();
174     ycyT3d.setTranslation(new Vector3d(0.0, 4.5, 0.0));
175     TransformGroup ycyTG = new TransformGroup(ycyT3d);
176     ycyTG.addChild(ycylinder);
177     setCapabilities(ycone, ycylinder);
178     addChild(yconeTG);
179     addChild(ycyTG);
180     // Z-Axis
181     Cone zcone = new Cone(2.0f, 3.0f, ap);
182     zcone.setUserData(this);
183     Transform3D zconeT3d = new Transform3D();
184     zconeT3d.setTranslation(new Vector3d(0.0f, 0.0f, 10.0f));
185     zconeT3d.setRotation(new AxisAngle4f(1.0f, 0.0f, 0.0f, (float) PI / 2.0f));
186     TransformGroup zconeTG = new TransformGroup(zconeT3d);
187     zconeTG.addChild(zcone);
188     Cylinder zcylinder = new Cylinder(1.0f, 9.0f, ap);
189     zcylinder.setUserData(this);
190     Transform3D zcyT3d = new Transform3D();
191     zcyT3d.setTranslation(new Vector3d(0.0, 0.0, 4.5));
192     zcyT3d.setRotation(new AxisAngle4f(1.0f, 0.0f, 0.0f, (float) PI / 2.0f));
193     TransformGroup zcyTG = new TransformGroup(zcyT3d);
194     zcyTG.addChild(zcylinder);
195     setCapabilities(zcone, zcylinder);
196     addChild(zconeTG);
197     addChild(zcyTG);
198     Sphere sphere = new Sphere(1.0f, ap);
199     if (!sphere.getShape().getGeometry(0).isCompiled()
200         && !sphere.getShape().getGeometry(0).isLive()) {
201       PickTool.setCapabilities(sphere.getShape(), PickTool.INTERSECT_COORD);
202     }
203     addChild(sphere);
204     // Labels
205     ap = new Appearance();
206     col = new Color3f(Color.green.getRGBColorComponents(new float[3]));
207     mat = new Material(col, black, col, white, 50.0f);
208     mat.setLightingEnable(true);
209     ap.setMaterial(mat);
210     Font font = new Font("Arial", Font.PLAIN, 4);
211     Font3D font3d = new Font3D(font, new FontExtrusion());
212     addChild(createAxisLabel("X", font3d, ap, 11.0, 0.0, 0.0));
213     addChild(createAxisLabel("Y", font3d, ap, 0.0, 11.0, 0.0));
214     addChild(createAxisLabel("Z", font3d, ap, 0.0, 0.0, 11.0));
215   }
216 
217   private TransformGroup createAxisLabel(
218       String letter, Font3D font3d, Appearance ap, double x, double y, double z) {
219     Text3D text = new Text3D(font3d, letter);
220     text.setUserData(this);
221     Transform3D t3D = new Transform3D();
222     t3D.setTranslation(new Vector3d(x, y, z));
223     TransformGroup tg = new TransformGroup(t3D);
224     Shape3D text3d = new Shape3D(text, ap);
225     text3d.setUserData(this);
226     for (Iterator<Geometry> e = text3d.getAllGeometries(); e.hasNext(); ) {
227       Geometry g = e.next();
228       g.setCapability(Geometry.ALLOW_INTERSECT);
229     }
230     text3d.setCapability(Shape3D.ENABLE_PICK_REPORTING);
231     text3d.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
232     tg.addChild(text3d);
233     return tg;
234   }
235 
236   private void setCapabilities(Cone cone, Cylinder cylinder) {
237     if (!cone.getShape(0).getGeometry(0).isLive()
238         && !cone.getShape(0).getGeometry(0).isCompiled()) {
239       PickTool.setCapabilities(cone.getShape(0), PickTool.INTERSECT_COORD);
240       cone.getShape(0).setUserData(this);
241       PickTool.setCapabilities(cone.getShape(1), PickTool.INTERSECT_COORD);
242       cone.getShape(1).setUserData(this);
243       PickTool.setCapabilities(cylinder.getShape(0), PickTool.INTERSECT_COORD);
244       cylinder.getShape(0).setUserData(this);
245       PickTool.setCapabilities(cylinder.getShape(1), PickTool.INTERSECT_COORD);
246       cylinder.getShape(1).setUserData(this);
247       PickTool.setCapabilities(cylinder.getShape(2), PickTool.INTERSECT_COORD);
248       cylinder.getShape(2).setUserData(this);
249     }
250   }
251 
252   /**
253    * showAxis
254    *
255    * @param b a boolean.
256    */
257   void showAxis(boolean b) {
258     if (b && !axisBranchGroup.isLive()) {
259       viewingPlatform.getViewPlatformTransform().addChild(axisBranchGroup);
260     } else if (!b && axisBranchGroup.isLive()) {
261       axisBranchGroup.detach();
262     }
263   }
264 }