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 Tetrahedron implements Polyhedron {
030        private static double TETRAHEDRAL_ANGLE = Math.acos(-1.0/3.0);
031        private static int[] lineLoop1 = {0,1,2,3,0,2};
032        private static int[] lineLoop2 = {1,3};
033
034        private double circumscribedRadius = 1.0;
035
036        /**
037         * Returns the radius of a circumscribed sphere, that goes
038         * through all vertices
039         * @return the cirumscribedRadius
040         */
041        @Override
042        public double getCirumscribedRadius() {
043                return circumscribedRadius;
044        }
045
046        /**
047         * Set the radius of a circumscribed sphere, that goes
048         * through all vertices
049         * @param cirumscribedRadius the cirumscribedRadius to set
050         */
051        public void setCirumscribedRadius(double cirumscribedRadius) {
052                this.circumscribedRadius = cirumscribedRadius;
053        }
054        /**
055         * Returns the radius of an inscribed sphere, that is tangent to each
056         * of the tetrahedrons's faces
057         * @return the inscribedRadius
058         */
059        public double getInscribedRadius() {
060                double side = getSideLengthFromCircumscribedRadius(circumscribedRadius);
061                return getInscribedRadiusFromSideLength(side);
062        }
063
064        /**
065         * Sets the radius of an inscribed sphere, that is tangent to each
066         * of the tetrahedron's faces
067         * @param inscribedRadius the inscribedRadius to set
068         */
069        public void setInscribedRadius(double radius) {
070                double side = getSideLengthFromInscribedRadius(radius);
071                this.circumscribedRadius = getCircumscribedRadiusFromSideLength(side);
072        }
073
074        /**
075         * Returns the radius of a sphere, that is tangent to each
076         * of the tetrahedron's edges
077         *
078         * @return the midRadius
079         */
080        public double getMidRadius() {
081                double side = getSideLengthFromCircumscribedRadius(circumscribedRadius);
082                return getMiddleRadiusFromSideLength(side);
083        }
084
085        /**
086         * Sets the radius of radius of a sphere, that is tangent to each
087         * of the tetrahedron's edges
088         * @param midRadius the midRadius to set
089         */
090        public void setMidRadius(double radius) {
091                double side = getSideLengthFromMiddleRadius(radius);
092                this.circumscribedRadius = getCircumscribedRadiusFromSideLength(side);
093        }
094
095        /**
096         * Returns the vertices of an n-fold polygon of given radius and center
097         * @param n
098         * @param radius
099         * @param center
100         * @return
101         */
102        @Override
103        public  Point3d[] getVertices() {
104                double x = getSideLengthFromCircumscribedRadius(circumscribedRadius)/2;
105                double z = x/Math.sqrt(2);
106                Point3d[] tetrahedron = new Point3d[4];
107                tetrahedron[0] = new Point3d(-x,  0, -z);
108                tetrahedron[1] = new Point3d( x,  0, -z);
109                tetrahedron[2] = new Point3d( 0, -x,  z);
110                tetrahedron[3] = new Point3d( 0,  x,  z);
111                Point3d centroid = SuperPosition.centroid(tetrahedron);
112
113                // rotate tetrahedron to align one vertex with the +z axis
114                Matrix3d m = new Matrix3d();
115                m.rotX(0.5 * TETRAHEDRAL_ANGLE);
116                for (Point3d p: tetrahedron) {
117                        p.sub(centroid);
118                        m.transform(p);
119                }
120                return tetrahedron;
121        };
122
123        @Override
124        public List<int[]> getLineLoops() {
125                return Arrays.asList(lineLoop1, lineLoop2);
126        }
127
128        @Override
129        public int getViewCount() {
130                return 3;
131        }
132
133        @Override
134        public String getViewName(int index) {
135                String name;
136                switch (index) {
137                case 0:  name = "Front 3-fold axis vertex-centered";
138                break;
139                case 1:  name = "Back 3-fold axis face-centered";
140                break;
141                case 2:  name = "Side 2-fold axis edge-centered";
142                break;
143                default: throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
144                }
145                return name;
146        }
147
148        @Override
149        public Matrix3d getViewMatrix(int index) {
150                Matrix3d m = new Matrix3d();
151                switch (index) {
152                case 0:  m.setIdentity(); // front vertex-centered
153                break;
154                case 1:  m.rotX(Math.PI); // back face-centered
155                break;
156                case 2: double angle = Math.PI - 0.5 * TETRAHEDRAL_ANGLE; // Side edge-centered
157                m.rotX(angle);
158                break;
159                default: throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
160                }
161                return m;
162        }
163
164        private static double getSideLengthFromInscribedRadius(double radius) {
165                return radius * Math.sqrt(24);
166        }
167
168        private static double getInscribedRadiusFromSideLength(double sideLength) {
169                return sideLength / Math.sqrt(24);
170        }
171
172        private static double getSideLengthFromMiddleRadius(double radius) {
173                return radius * Math.sqrt(8);
174        }
175
176        private static double getMiddleRadiusFromSideLength(double sideLength) {
177                return sideLength / Math.sqrt(8);
178        }
179
180        private static double getSideLengthFromCircumscribedRadius(double radius) {
181                return radius / Math.sqrt(3.0/8.0);
182        }
183
184        private static double getCircumscribedRadiusFromSideLength(double sideLength) {
185                return sideLength * Math.sqrt(3.0/8.0);
186        }
187
188}