edu.mines.jtk.sgl.EllipsoidGlyph Maven / Gradle / Ivy
/****************************************************************************
Copyright 2009, Colorado School of Mines and others.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
****************************************************************************/
package edu.mines.jtk.sgl;
import java.nio.FloatBuffer;
import edu.mines.jtk.ogl.*;
import edu.mines.jtk.util.*;
import static edu.mines.jtk.ogl.Gl.*;
import static edu.mines.jtk.util.ArrayMath.*;
/**
* A glyph for fast rendering of ellipsoids (including spheres).
* This class is especially useful in any node that must render a large
* number of ellipsoids. Such a node would first construct a single
* ellipsoid glyph, and then call one of the glyph's draw methods for
* each ellipsoid to be rendered.
*
* Internally, each ellipsoid is drawn by transforming an approximation to
* a unit sphere (with radius one) that has been precomputed and stored in
* an OpenGL display list.
*
* The unit sphere is approximated by recursively subdividing the triangular
* faces of an octahedron. The quality of the approximation increases with
* the number of subdivisions, and the number of triangles increases by a
* factor of four with each subdivision.
*
* @author Dave Hale, Colorado School of Mines
* @version 2009.08.12
*/
public class EllipsoidGlyph {
/**
* Constructs an ellipsoid glyph with default quality of four subdivisions.
*/
public EllipsoidGlyph() {
this(4);
}
/**
* Constructs an ellipsoid glyph with specified quality.
* @param m the quality = the number of subdivisions.
*/
public EllipsoidGlyph(int m) {
makeTransformMatrix();
makeUnitSphere(m);
}
/**
* Returns the number of vertices used to approximate this glyph.
* @return the number of vertices.
*/
public int countVertices() {
return _nv;
}
/**
* Gets the vertices of the unit sphere used to approximate this glyph.
* @return array of packed (x,y,z) coordinates of vertices; by reference,
* not by copy. The array length is 3 times the number of vertices.
*/
public float[] getVertices() {
return _xyz;
}
/**
* Draws a unit sphere centered at the origin.
*/
public void draw() {
if (_displayList==null) {
FloatBuffer xyz = Direct.newFloatBuffer(3*_nv);
xyz.put(_xyz); xyz.rewind();
_displayList = new GlDisplayList();
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glNewList(_displayList.list(),GL_COMPILE);
glVertexPointer(3,GL_FLOAT,0,xyz);
glNormalPointer(GL_FLOAT,0,xyz);
glDrawArrays(GL_TRIANGLES,0,_nv);
glEndList();
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
glCallList(_displayList.list());
}
/**
* Draws a sphere centered at a specified point with specified radius.
* @param cx x coordinate of the center point.
* @param cy y coordinate of the center point.
* @param cz z coordinate of the center point.
* @param r radius of the sphere.
*/
public void draw(float cx, float cy, float cz, float r) {
draw(cx,cy,cz,r,r,r);
}
/**
* Draws an axis-aligned ellipsoid centered at a specified point.
* The lengths of the specified semi-principal axes must be positive.
* @param cx x coordinate of the center point.
* @param cy y coordinate of the center point.
* @param cz z coordinate of the center point.
* @param dx semi-principal length in direction of x axis.
* @param dy semi-principal length in direction of y axis.
* @param dz semi-principal length in direction of z axis.
*/
public void draw(
float cx, float cy, float cz,
float dx, float dy, float dz)
{
glPushMatrix();
glTranslatef(cx,cy,cz);
glScalef(dx,dy,dz);
draw();
glPopMatrix();
}
/**
* Draws an arbitrary ellipsoid centered at a specified point.
* The semi-principal axes of the ellipsoid are represented by three
* vectors u, v, and w. The lengths of these three vectors are the
* semi-principal lengths of the ellipsoid, and must be non-zero.
* @param cx x coordinate of the center point.
* @param cy y coordinate of the center point.
* @param cz z coordinate of the center point.
* @param ux x component of vector u.
* @param uy y component of vector u.
* @param uz z component of vector u.
* @param vx x component of vector v.
* @param vy y component of vector v.
* @param vz z component of vector v.
* @param wx x component of vector w.
* @param wy y component of vector w.
* @param wz z component of vector w.
*/
public void draw(
float cx, float cy, float cz,
float ux, float uy, float uz,
float vx, float vy, float vz,
float wx, float wy, float wz)
{
// Ensure vectors u, v, and w form a right-handed coordinate system.
// This is necessary to keep triangle vertices in counter-clockwise
// order as viewed from outside the ellipsoid.
if (ux*(vy*wz-vz*wy)+uy*(vz*wx-vx*wz)+uz*(vx*wy-vy*wx)<0.0) {
ux = -ux; uy = -uy; uz = -uz;
vx = -vx; vy = -vy; vz = -vz;
wx = -wx; wy = -wy; wz = -wz;
}
// The transformation matrix.
_m[ 0] = ux; _m[ 4] = vx; _m[ 8] = wx; _m[12] = cx;
_m[ 1] = uy; _m[ 5] = vy; _m[ 9] = wy; _m[13] = cy;
_m[ 2] = uz; _m[ 6] = vz; _m[10] = wz; _m[14] = cz;
// Draw the transformed unit sphere.
glPushMatrix();
glMultMatrixf(_m,0);
draw();
glPopMatrix();
}
///////////////////////////////////////////////////////////////////////////
// private
private float[] _m; // transform matrix used when drawing
private int _nv; // number of vertices for unit sphere
private float[] _xyz; // vertices on the unit sphere
private GlDisplayList _displayList; // draws unit sphere when called
private void makeTransformMatrix() {
_m = new float[16];
_m[15] = 1.0f;
}
private void makeUnitSphere(int m) {
// Buffers for vertices of triangles used to approximate the unit sphere.
// The initial octahedron has 8 triangular faces, each with 3 vertices.
// Each subdivision increases the number of triangles by a factor of 4.
_nv = 8*3;
for (int i=0; i