/* * Copyright (C) 2004-2007 The Chemistry Development Kit (CDK) project * * Contact: cdk-devel@lists.sourceforge.net * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.openscience.cdk.geometry.surface; import javax.vecmath.Point3d; /** * Performs a tessellation of the unit sphere. * * This class generates the coordinates of the triangles that will * tessellate the unit sphere. The algorithm is recursive subdivision * of an initial representation which can be tetrahedral, octahedral or * icoshedral. The default is icosahedral. The number of points generated * depends on the level of subdivision. The default is 4 levels and with the * initial icoshedral representation this gives 1536 points. * <p> * The constants for the tetrahedral and icosahedral representations were * taken from http://eeg.sourceforge.net/eegdoc/eeg_toolbox/sphere_tri.html * * @author Rajarshi Guha * @cdk.created 2005-05-08 * @cdk.module extra * @cdk.githash */ public class Tessellate { Triangle[] oldtess; int maxlevel; public Tessellate() { this.oldtess = this.repIco(); this.maxlevel = 4; } public Tessellate(String type, int level) { if (type.equals("tet")) this.oldtess = this.repTet(); else if (type.equals("oct")) this.oldtess = this.repOct(); else if (type.equals("ico")) this.oldtess = this.repIco(); this.maxlevel = level; } private Point3d midpoint(Point3d p1, Point3d p2) { double x,y,z; x = 0.5 * (p1.x + p2.x); y = 0.5 * (p1.y + p2.y); z = 0.5 * (p1.z + p2.z); return( new Point3d(x,y,z) ); } private void normalize(Point3d p) { double mag = p.x*p.x + p.y*p.y + p.z*p.z; if (mag != 0.0) { mag = 1.0 / Math.sqrt(mag); p.x = p.x * mag; p.y = p.y * mag; p.z = p.z * mag; } } public void doTessellate() { for (int j = 1; j < maxlevel; j++) { int oldN = this.oldtess.length; int newN = oldN * 4; Triangle[] newtess = new Triangle[ newN ]; for (int i = 0; i < oldN; i++) { Triangle old = oldtess[i]; Point3d p1 = midpoint(old.p1, old.p3); Point3d p2 = midpoint(old.p1, old.p2); Point3d p3 = midpoint(old.p2, old.p3); normalize(p1); normalize(p2); normalize(p3); newtess[i*4] = new Triangle(old.p1, p2, p1); newtess[i*4+1] = new Triangle(p2, old.p2, p3); newtess[i*4+2] = new Triangle(p1,p2,p3); newtess[i*4+3] = new Triangle(p1,p3,old.p3); } oldtess = new Triangle[newN]; for (int i = 0; i < newN; i++) oldtess[i] = newtess[i]; } } public int getNumberOfTriangles() { return(oldtess.length); } public Triangle[] getTessAsTriangles() { return(oldtess); } public Point3d[] getTessAsPoint3ds() { Point3d[] ret = new Point3d[ getNumberOfTriangles()*3 ]; for (int i = 0; i < getNumberOfTriangles(); i++) { ret[i*3] = oldtess[i].p1; ret[i*3+1] = oldtess[i].p2; ret[i*3+2] = oldtess[i].p3; } return(ret); } private Triangle[] repTet() { double sqrt3 = 0.5773502692; Point3d[] v = { new Point3d(sqrt3, sqrt3, sqrt3), new Point3d(-sqrt3, -sqrt3, sqrt3), new Point3d(-sqrt3,sqrt3,-sqrt3), new Point3d(sqrt3,-sqrt3,-sqrt3) }; Triangle[] rep = { new Triangle( v[0],v[1],v[2] ), new Triangle( v[0],v[3],v[1] ), new Triangle( v[2],v[1],v[3] ), new Triangle( v[3],v[0],v[2] ) }; return(rep); } private Triangle[] repOct() { Point3d[] v = { new Point3d(1.0,0.0,0.0), new Point3d(-1.0,0.0,0.0), new Point3d(0.0,1.0,0.0), new Point3d(0.0,-1.0,0.0), new Point3d(0.0,0.0,1.0), new Point3d(0.0,0.0,-1.0) }; Triangle[] rep = { new Triangle( v[0], v[4], v[2] ), new Triangle( v[2], v[4], v[1] ), new Triangle( v[1], v[4], v[3] ), new Triangle( v[3], v[4], v[0] ), new Triangle( v[0], v[2], v[5] ), new Triangle( v[2], v[1], v[5] ), new Triangle( v[1], v[3], v[5] ), new Triangle( v[3], v[0], v[5] ) }; return(rep); } private Triangle[] repIco() { double tau = 0.8506508084; double one = 0.5257311121; Point3d[] v = { new Point3d( tau, one, 0.0 ), new Point3d( -tau, one, 0.0 ), new Point3d( -tau, -one, 0.0 ), new Point3d( tau, -one, 0.0 ), new Point3d( one, 0.0 , tau ), new Point3d( one, 0.0 , -tau ), new Point3d( -one, 0.0 , -tau ), new Point3d( -one, 0.0 , tau ), new Point3d( 0.0 , tau, one ), new Point3d( 0.0 , -tau, one ), new Point3d( 0.0 , -tau, -one ), new Point3d( 0.0 , tau, -one ) }; Triangle[] rep = { new Triangle( v[4], v[8], v[7] ), new Triangle( v[4], v[7], v[9] ), new Triangle( v[5], v[6], v[11] ), new Triangle( v[5], v[10], v[6] ), new Triangle( v[0], v[4], v[3] ), new Triangle( v[0], v[3], v[5] ), new Triangle( v[2], v[7], v[1] ), new Triangle( v[2], v[1], v[6] ), new Triangle( v[8], v[0], v[11] ), new Triangle( v[8], v[11], v[1] ), new Triangle( v[9], v[10], v[3] ), new Triangle( v[9], v[2], v[10] ), new Triangle( v[8], v[4], v[0] ), new Triangle( v[11], v[0], v[5] ), new Triangle( v[4], v[9], v[3] ), new Triangle( v[5], v[3], v[10] ), new Triangle( v[7], v[8], v[1] ), new Triangle( v[6], v[1], v[11] ), new Triangle( v[7], v[2], v[9] ), new Triangle( v[6], v[10], v[2] ) }; return(rep); } }