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 radius 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 radius 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 * @return 100 */ 101 @Override 102 public Point3d[] getVertices() { 103 double x = getSideLengthFromCircumscribedRadius(circumscribedRadius)/2; 104 double z = x/Math.sqrt(2); 105 Point3d[] tetrahedron = new Point3d[4]; 106 tetrahedron[0] = new Point3d(-x, 0, -z); 107 tetrahedron[1] = new Point3d( x, 0, -z); 108 tetrahedron[2] = new Point3d( 0, -x, z); 109 tetrahedron[3] = new Point3d( 0, x, z); 110 Point3d centroid = CalcPoint.centroid(tetrahedron); 111 112 // rotate tetrahedron to align one vertex with the +z axis 113 Matrix3d m = new Matrix3d(); 114 m.rotX(0.5 * TETRAHEDRAL_ANGLE); 115 for (Point3d p: tetrahedron) { 116 p.sub(centroid); 117 m.transform(p); 118 } 119 return tetrahedron; 120 }; 121 122 @Override 123 public List<int[]> getLineLoops() { 124 return Arrays.asList(lineLoop1, lineLoop2); 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 = "Front 3-fold axis vertex-centered"; 137 break; 138 case 1: name = "Back 3-fold axis face-centered"; 139 break; 140 case 2: name = "Side 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: m.setIdentity(); // front vertex-centered 152 break; 153 case 1: m.rotX(Math.PI); // back face-centered 154 break; 155 case 2: double angle = Math.PI - 0.5 * TETRAHEDRAL_ANGLE; // Side edge-centered 156 m.rotX(angle); 157 break; 158 default: throw new IllegalArgumentException("getViewMatrix: index out of range:" + index); 159 } 160 return m; 161 } 162 163 private static double getSideLengthFromInscribedRadius(double radius) { 164 return radius * Math.sqrt(24); 165 } 166 167 private static double getInscribedRadiusFromSideLength(double sideLength) { 168 return sideLength / Math.sqrt(24); 169 } 170 171 private static double getSideLengthFromMiddleRadius(double radius) { 172 return radius * Math.sqrt(8); 173 } 174 175 private static double getMiddleRadiusFromSideLength(double sideLength) { 176 return sideLength / Math.sqrt(8); 177 } 178 179 private static double getSideLengthFromCircumscribedRadius(double radius) { 180 return radius / Math.sqrt(3.0/8.0); 181 } 182 183 private static double getCircumscribedRadiusFromSideLength(double sideLength) { 184 return sideLength * Math.sqrt(3.0/8.0); 185 } 186 187}