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 radius 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 radius 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         * @return
096         */
097        @Override
098        public Point3d[] getVertices() {
099                Point3d[] octahedron = new Point3d[6];
100            octahedron[0] = new Point3d(-cirumscribedRadius, 0, 0);
101            octahedron[1] = new Point3d( cirumscribedRadius, 0, 0);
102            octahedron[2] = new Point3d(0, -cirumscribedRadius, 0);
103            octahedron[3] = new Point3d(0,  cirumscribedRadius, 0);
104            octahedron[4] = new Point3d(0, 0, -cirumscribedRadius);
105            octahedron[5] = new Point3d(0, 0,  cirumscribedRadius);
106
107                return octahedron;
108        };
109
110        @Override
111        public List<int[]> getLineLoops() {
112                return Arrays.asList(lineLoop1);
113        }
114
115        public Point3d getC4Axis(double scale) {
116                return new Point3d(0, 0, cirumscribedRadius*scale);
117        }
118        public Point3d getC3Axis(double scale) {
119                double s = 1/Math.sqrt(1 + Math.sqrt(2));
120                return new Point3d(cirumscribedRadius*scale*s, cirumscribedRadius*scale*s, cirumscribedRadius*scale*s);
121        }
122        public Point3d getC2Axis(double scale) {
123                double s = 1/Math.sqrt(2);
124                return new Point3d(cirumscribedRadius*scale*s, cirumscribedRadius*scale*s, 0);
125        }
126
127        @Override
128        public int getViewCount() {
129                return 3;
130        }
131
132        @Override
133        public String getViewName(int index) {
134                String name;
135                switch (index) {
136                case 0:  name = "4-fold axis vertex-centered";
137                break;
138                case 1:  name = "3-fold axis face-centered";
139                break;
140                case 2:  name = "2-fold axis edge-centered";
141                break;
142                default: throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
143                }
144                return name;
145        }
146
147        @Override
148        public Matrix3d getViewMatrix(int index) {
149                Matrix3d m = new Matrix3d();
150                switch (index) {
151                case 0:
152                        m.setIdentity(); // C4 vertex-centered
153                        break;
154                case 1:
155                        m.rotX(-0.5 * TETRAHEDRAL_ANGLE); // C3 face-centered  2.0*Math.PI/3
156                        Matrix3d m1 = new Matrix3d();
157                        m1.rotZ(Math.PI/4);
158                        m.mul(m1);
159                        break;
160                case 2:
161                        m.rotY(Math.PI/4); // side face-centered
162                        break;
163                default:
164                        throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
165                }
166                return m;
167        }
168
169        private static double getSideLengthFromInscribedRadius(double radius) {
170                return radius * 6 / Math.sqrt(6);
171        }
172
173        private static double getInscribedRadiusFromSideLength(double sideLength) {
174                return sideLength / 6 * Math.sqrt(6);
175        }
176
177        private static double getSideLengthFromMiddleRadius(double radius) {
178                return radius * 2;
179        }
180
181        private static double getMiddleRadiusFromSideLength(double sideLength) {
182                return sideLength / 2;
183        }
184
185        private static double getSideLengthFromCircumscribedRadius(double radius) {
186                return radius * 2 / Math.sqrt(2);
187        }
188
189        private static double getCircumscribedRadiusFromSideLength(double sideLength) {
190                return sideLength / 2 * Math.sqrt(2);
191        }
192}