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