package org.gephi.visualization.octree; import com.jogamp.opengl.GL2; import com.jogamp.opengl.glu.GLU; import com.jogamp.opengl.util.gl2.GLUT; import org.gephi.visualization.model.node.NodeModel; /** * * @author mbastian */ public class Octant { //Static protected static final long ONEOVERPHI = 106039; protected static final float TRIM_THRESHOLD = 1000; protected static final float TRIM_RATIO = 0.3f; //LeafId protected int leafId = Octree.NULL_ID; //Coordinates protected float size; protected float posX; protected float posY; protected float posZ; protected int depth; //Children protected Octant[] children; //Stats protected int nodeCount = 0; //Data protected NodeModel[] nodes; protected int[] nodesGarbage; protected int nodesGarbageLength; protected int nodesLength; //Flags protected boolean visible; public Octant(int depth, float posX, float posY, float posZ, float size) { this.size = size; this.posX = posX; this.posY = posY; this.posZ = posZ; this.depth = depth; } protected void addNode(NodeModel nodeModel) { int id; if (nodesGarbageLength > 0) { id = removeGarbage(); } else { id = nodesLength++; growNodes(id); } nodes[id] = nodeModel; nodeCount++; nodeModel.setOctantId(id); } protected void removeNode(NodeModel nodeModel) { int id = nodeModel.getOctantId(); nodeModel.setOctantId(Octree.NULL_ID); nodes[id] = null; nodeCount--; addGarbage(id); trimNodes(); } protected void clear() { nodes = null; nodesGarbage = null; nodesLength = 0; nodesGarbage = null; nodesGarbageLength = 0; nodeCount = 0; } protected boolean isEmpty() { return nodeCount == 0; } public float getPosX() { return posX; } public float getPosY() { return posY; } public float getPosZ() { return posZ; } public float getSize() { return size; } protected void displayOctant(GL2 gl) { float quantum = size / 2; gl.glBegin(GL2.GL_QUAD_STRIP); gl.glVertex3f(posX + quantum, posY + quantum, posZ + quantum); gl.glVertex3f(posX + quantum, posY - quantum, posZ + quantum); gl.glVertex3f(posX + quantum, posY + quantum, posZ - quantum); gl.glVertex3f(posX + quantum, posY - quantum, posZ - quantum); gl.glVertex3f(posX - quantum, posY + quantum, posZ - quantum); gl.glVertex3f(posX - quantum, posY - quantum, posZ - quantum); gl.glVertex3f(posX - quantum, posY + quantum, posZ + quantum); gl.glVertex3f(posX - quantum, posY - quantum, posZ + quantum); gl.glVertex3f(posX + quantum, posY + quantum, posZ + quantum); gl.glVertex3f(posX + quantum, posY - quantum, posZ + quantum); gl.glEnd(); gl.glBegin(GL2.GL_QUADS); gl.glVertex3f(posX - quantum, posY + quantum, posZ - quantum); gl.glVertex3f(posX - quantum, posY + quantum, posZ + quantum); gl.glVertex3f(posX + quantum, posY + quantum, posZ + quantum); gl.glVertex3f(posX + quantum, posY + quantum, posZ - quantum); gl.glVertex3f(posX - quantum, posY - quantum, posZ + quantum); gl.glVertex3f(posX - quantum, posY - quantum, posZ - quantum); gl.glVertex3f(posX + quantum, posY - quantum, posZ - quantum); gl.glVertex3f(posX + quantum, posY - quantum, posZ + quantum); gl.glEnd(); } protected void displayOctantInfo(GL2 gl, GLU glu) { GLUT glut = new GLUT(); float quantum = size / 2; float height = 15; gl.glPushMatrix(); gl.glTranslatef(posX - quantum, posY + quantum - height, posZ + quantum); gl.glScalef(0.1f, 0.1f, 0.1f); gl.glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glut.glutStrokeString(GLUT.STROKE_MONO_ROMAN, "ID: " + leafId); gl.glPopMatrix(); height += 15; gl.glPushMatrix(); gl.glTranslatef(posX - quantum, posY + quantum - height, posZ + quantum); gl.glScalef(0.1f, 0.1f, 0.1f); gl.glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glut.glutStrokeString(GLUT.STROKE_MONO_ROMAN, "objectsCount: " + nodeCount); gl.glPopMatrix(); } private void addGarbage(int index) { if (nodesGarbage == null) { nodesGarbage = new int[10]; } else if (nodesGarbageLength == nodesGarbage.length) { final int newLength = (int) Math.min(Math.max((ONEOVERPHI * nodesGarbage.length) >>> 16, nodesGarbageLength + 1), Integer.MAX_VALUE); final int t[] = new int[newLength]; System.arraycopy(nodesGarbage, 0, t, 0, nodesGarbage.length); nodesGarbage = t; } nodesGarbage[nodesGarbageLength++] = index; } private int removeGarbage() { return nodesGarbage[--nodesGarbageLength]; } private void growNodes(final int index) { if (nodes == null) { nodes = new NodeModel[10]; } else if (index >= nodes.length) { final int newLength = (int) Math.min(Math.max((ONEOVERPHI * nodes.length) >>> 16, index + 1), Integer.MAX_VALUE); final NodeModel t[] = new NodeModel[newLength]; System.arraycopy(nodes, 0, t, 0, nodes.length); nodes = t; } } private void trimNodes() { if (nodesLength >= TRIM_THRESHOLD && ((float) nodeCount) / nodesLength < TRIM_RATIO) { NodeModel t[] = new NodeModel[nodeCount]; if (nodeCount > 0) { int c = 0; for (int i = 0; i < nodes.length; i++) { NodeModel n = nodes[i]; if (n != null) { n.setOctantId(c); t[c++] = n; } } } nodesLength = t.length; nodes = t; nodesGarbage = null; nodesGarbageLength = 0; } } }