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 */
021/**
022 *
023 */
024package org.biojava.nbio.structure.symmetry.geometry;
025
026import javax.vecmath.Matrix3d;
027import javax.vecmath.Point3d;
028import java.util.ArrayList;
029import java.util.List;
030
031
032/**
033 * @author Peter
034 *
035 */
036public class Prism implements Polyhedron {
037        private int n = 3;
038        private double circumscribedRadius = 1.0;
039        private double height = 1.0;
040
041        public Prism(int n) {
042                this.n = n;
043        }
044
045        /**
046         * @return the height
047         */
048        public double getHeight() {
049                return height;
050        }
051
052        /**
053         * @param height the height to set
054         */
055        public void setHeight(double height) {
056                this.height = height;
057        }
058
059        /**
060         * Returns the radius of a circumscribed sphere, that goes
061         * through all vertices
062         * @return the cirumscribedRadius
063         */
064        @Override
065        public double getCirumscribedRadius() {
066                return circumscribedRadius;
067        }
068
069        /**
070         * Set the radius of a circumscribed sphere, that goes
071         * through all vertices
072         * @param cirumscribedRadius the cirumscribedRadius to set
073         */
074        public void setCirumscribedRadius(double cirumscribedRadius) {
075                this.circumscribedRadius = cirumscribedRadius;
076        }
077        /**
078         * Returns the radius of an inscribed sphere, that is tangent to each
079         * of the icosahedron's faces
080         * @return the inscribedRadius
081         */
082        public double getInscribedRadius() {
083                double side = getSideLengthFromCircumscribedRadius(circumscribedRadius, n);
084                return getInscribedRadiusFromSideLength(side, n);
085        }
086
087        /**
088         * Sets the radius of an inscribed sphere, that is tangent to each
089         * of the icosahedron's faces
090         * @param inscribedRadius the inscribedRadius to set
091         */
092        public void setInscribedRadius(double radius) {
093                double side = getSideLengthFromInscribedRadius(radius, n);
094                this.circumscribedRadius = getCircumscribedRadiusFromSideLength(side, n);
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                Point3d[] polygon = new Point3d[2*n];
104                Matrix3d m = new Matrix3d();
105
106                Point3d center = new Point3d(0, 0, height/2);
107
108                for (int i = 0; i < n; i++) {
109                        polygon[i] = new Point3d(0, circumscribedRadius, 0);
110                        m.rotZ(i*2*Math.PI/n);
111                        m.transform(polygon[i]);
112                        polygon[n+i] = new  Point3d(polygon[i]);
113                        polygon[i].sub(center);
114                        polygon[n+i].add(center);
115                }
116
117                return polygon;
118        };
119
120        @Override
121        public List<int[]> getLineLoops() {
122                List<int[]> list = new ArrayList<int[]>();
123                int[] l1 = new int[2*n+2];
124                for (int i = 0; i < n; i++) {
125                        l1[i] = i;
126                }
127                l1[n] = 0;
128                for (int i = 0; i < n; i++) {
129                        l1[n+i+1] = n+i;
130                }
131                l1[2*n+1] = l1[n+1];
132                list.add(l1);
133
134                for (int i = 1; i < n; i++) {
135                        int[] l2 = new int[2];
136                        l2[0] = i;
137                        l2[1] = n+i;
138                        list.add(l2);
139                }
140                return list;
141        }
142
143        /**
144         * Returns the vertices of an n-fold polygon of given radius and center
145         * @return
146         */
147        public static Point3d[] getPolygonVertices(int n, double radius, Point3d center) {
148                Point3d[] polygon = new Point3d[n];
149                Matrix3d m = new Matrix3d();
150
151                for (int i = 0; i < n; i++) {
152                        polygon[i] = new Point3d(0, radius, 0);
153                        m.rotZ(i*2*Math.PI/n);
154                        m.transform(polygon[i]);
155                        polygon[i].add(center);
156                }
157                return polygon;
158        }
159
160        @Override
161        public int getViewCount() {
162                return 4;
163        }
164
165        @Override
166        public String getViewName(int index) {
167                String name;
168                switch (index) {
169                case 0:  name = "Front C" + n + " axis";
170                break;
171                case 1:  name = "Side edge-centered";
172                break;
173                case 2:  name = "Side face-centered";
174                break;
175                case 3:  name = "Back C" + n + " axis";
176                break;
177                default: throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
178                }
179                return name;
180        }
181
182        @Override
183        public Matrix3d getViewMatrix(int index) {
184                Matrix3d m = new Matrix3d();
185                switch (index) {
186                case 0:
187                        m.setIdentity(); // front
188                        break;
189                case 1:
190                        m.rotX(Math.PI/2); // side edge-centered
191                        break;
192                case 2:
193                        m.rotY(Math.PI/n); // side face-centered
194                        Matrix3d m1 = new Matrix3d();
195                        m1.rotX(Math.PI/2);
196                        m.mul(m1);
197                        break;
198                case 3:
199                        m.set(flipX()); // back
200                        break;
201                default:
202                        throw new IllegalArgumentException("getViewMatrix: index out of range:" + index);
203                }
204                return m;
205        }
206
207        // http://www.mathopenref.com/polygonincircle.html
208        private static double getSideLengthFromInscribedRadius(double radius, int n) {
209                if (n == 2) {
210                        return radius;
211                }
212                return radius * 2 * Math.tan(Math.PI/n);
213        }
214
215        private static double getInscribedRadiusFromSideLength(double length, int n) {
216                if (n == 2) {
217                        return length;
218                }
219                return length / (2 * Math.tan(Math.PI/n));
220        }
221
222        // http://www.mathopenref.com/polygonradius.html
223        private static double getSideLengthFromCircumscribedRadius(double radius, int n) {
224                if (n == 2) {
225                        return radius;
226                }
227                return radius * (2 * Math.sin(Math.PI/n));
228        }
229
230        private static double getCircumscribedRadiusFromSideLength(double length, int n) {
231                if (n == 2) {
232                        return length;
233                }
234                return length / (2 * Math.sin(Math.PI/n));
235        }
236
237        private static Matrix3d flipX() {
238                Matrix3d rot = new Matrix3d();
239                rot.m00 = 1;
240                rot.m11 = -1;
241                rot.m22 = -1;
242                return rot;
243        }
244
245}