001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.symmetry.geometry;
022
023import javax.vecmath.Matrix3d;
024import javax.vecmath.Point3d;
025import java.util.Arrays;
026import java.util.List;
027
028
029public class Octahedron implements Polyhedron {
030        private static double TETRAHEDRAL_ANGLE = Math.acos(-1.0/3.0);
031        private static int[] lineLoop1 = {2,4,3,5,2,1,3,0,5,1,4,0,2};
032        private double cirumscribedRadius = 1.0;
033
034        /**
035         * Returns the radius of a circumscribed sphere, that goes
036         * through all vertices
037         * @return the cirumscribedRadius
038         */
039        @Override
040        public double getCirumscribedRadius() {
041                return cirumscribedRadius;
042        }
043
044        /**
045         * Set the radius of a circumscribed sphere, that goes
046         * through all vertices
047         * @param cirumscribedRadius the cirumscribedRadius to set
048         */
049        public void setCirumscribedRadius(double cirumscribedRadius) {
050                this.cirumscribedRadius = cirumscribedRadius;
051        }
052        /**
053         * Returns the radius of an inscribed sphere, that is tangent to each
054         * of the octahedron's faces
055         * @return the inscribedRadius
056         */
057        public double getInscribedRadius() {
058                double side = getSideLengthFromCircumscribedRadius(cirumscribedRadius);
059                return getInscribedRadiusFromSideLength(side);
060        }
061
062        /**
063         * Sets the radius of an inscribed sphere, that is tangent to each
064         * of the octahedron's faces
065         * @param inscribedRadius the inscribedRadius to set
066         */
067        public void setInscribedRadius(double radius) {
068                double side = getSideLengthFromInscribedRadius(radius);
069                this.cirumscribedRadius = getCircumscribedRadiusFromSideLength(side);
070        }
071
072        /**
073         * Returns the radius of a sphere, that is tangent to each
074         * of the octahedron's edges
075         *
076         * @return the midRadius
077         */
078        public double getMidRadius() {
079                double side = getSideLengthFromCircumscribedRadius(cirumscribedRadius);
080                return getMiddleRadiusFromSideLength(side);
081        }
082
083        /**
084         * Sets the radius of radius of a sphere, that is tangent to each
085         * of the octahedron's edges
086         * @param midRadius the midRadius to set
087         */
088        public void setMidRadius(double radius) {
089                double side = getSideLengthFromMiddleRadius(radius);
090                this.cirumscribedRadius = getCircumscribedRadiusFromSideLength(side);
091        }
092
093        /**
094         * Returns the vertices of an n-fold polygon of given radius and center
095         * @param n
096         * @param radius
097         * @param center
098         * @return
099         */
100        @Override
101        public Point3d[] getVertices() {
102                Point3d[] octahedron = new Point3d[6];
103            octahedron[0] = new Point3d(-cirumscribedRadius, 0, 0);
104            octahedron[1] = new Point3d( cirumscribedRadius, 0, 0);
105            octahedron[2] = new Point3d(0, -cirumscribedRadius, 0);
106            octahedron[3] = new Point3d(0,  cirumscribedRadius, 0);
107            octahedron[4] = new Point3d(0, 0, -cirumscribedRadius);
108            octahedron[5] = new Point3d(0, 0,  cirumscribedRadius);
109
110                return octahedron;
111        };
112
113        @Override
114        public List<int[]> getLineLoops() {
115                return Arrays.asList(lineLoop1);
116        }
117
118        public Point3d getC4Axis(double scale) {
119                return new Point3d(0, 0, cirumscribedRadius*scale);
120        }
121        public Point3d getC3Axis(double scale) {
122                double s = 1/Math.sqrt(1 + Math.sqrt(2));
123                return new Point3d(cirumscribedRadius*scale*s, cirumscribedRadius*scale*s, cirumscribedRadius*scale*s);
124        }
125        public Point3d getC2Axis(double scale) {
126                double s = 1/Math.sqrt(2);
127                return new Point3d(cirumscribedRadius*scale*s, cirumscribedRadius*scale*s, 0);
128        }
129
130        @Override
131        public int getViewCount() {
132                return 3;
133        }
134
135        @Override
136        public String getViewName(int index) {
137                String name;
138                switch (index) {
139                case 0:  name = "4-fold axis vertex-centered";
140                break;
141                case 1:  name = "3-fold axis face-centered";
142                break;
143                case 2:  name = "2-fold axis edge-centered";
144                break;
145                default: throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
146                }
147                return name;
148        }
149
150        @Override
151        public Matrix3d getViewMatrix(int index) {
152                Matrix3d m = new Matrix3d();
153                switch (index) {
154                case 0:
155                        m.setIdentity(); // C4 vertex-centered
156                        break;
157                case 1:
158                        m.rotX(-0.5 * TETRAHEDRAL_ANGLE); // C3 face-centered  2.0*Math.PI/3
159                        Matrix3d m1 = new Matrix3d();
160                        m1.rotZ(Math.PI/4);
161                        m.mul(m1);
162                        break;
163                case 2:
164                        m.rotY(Math.PI/4); // side face-centered
165                        break;
166                default:
167                        throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
168                }
169                return m;
170        }
171
172        private static double getSideLengthFromInscribedRadius(double radius) {
173                return radius * 6 / Math.sqrt(6);
174        }
175
176        private static double getInscribedRadiusFromSideLength(double sideLength) {
177                return sideLength / 6 * Math.sqrt(6);
178        }
179
180        private static double getSideLengthFromMiddleRadius(double radius) {
181                return radius * 2;
182        }
183
184        private static double getMiddleRadiusFromSideLength(double sideLength) {
185                return sideLength / 2;
186        }
187
188        private static double getSideLengthFromCircumscribedRadius(double radius) {
189                return radius * 2 / Math.sqrt(2);
190        }
191
192        private static double getCircumscribedRadiusFromSideLength(double sideLength) {
193                return sideLength / 2 * Math.sqrt(2);
194        }
195}