All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metsci.glimpse.painter.track.StaticParticlePainter Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * Copyright (c) 2016, Metron, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Metron, Inc. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.metsci.glimpse.painter.track;

import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;

import com.metsci.glimpse.axis.Axis2D;
import com.metsci.glimpse.context.GlimpseBounds;
import com.metsci.glimpse.painter.base.GlimpseDataPainter2D;
import com.metsci.glimpse.support.color.GlimpseColor;
import com.metsci.glimpse.util.primitives.LongsArray;
import com.metsci.glimpse.util.units.time.TimeStamp;

/**
 * 

Displays a static set of tracks with associated timestamp, x position, and y position. Unlike * {@link TrackPainter}, each track must have an xy position for the same set of timestamps. This * allows ParticlePainter to be more efficient in this case.

* *

The set of particles cannot be modified once ParticlePainter is constructed, but a custom time slice of * the particles may be displayed via {@code StaticParticlePainter#displayTimeRange(long, long)}.

* * @author ulman * */ public class StaticParticlePainter extends GlimpseDataPainter2D { protected IntBuffer firstData; protected IntBuffer countData; protected FloatBuffer positionData; protected FloatBuffer colorData; protected LongsArray timeData; protected int countTimes; protected int countParticles; protected TimeStamp startTime; protected TimeStamp endTime; protected int startIndex; protected int endIndex; protected int glBufferHandleData = -1; protected int glBufferHandleColor = -1; protected boolean glInitialized; protected float[] color; protected float lineWidth; public StaticParticlePainter( TimeStamp[] time, float[][] xPositions, float[][] yPositions ) { this( time, xPositions, yPositions, null ); } /** * * @param time common array of times (each particle must have an x/y position for each time) * @param xPositions square array of x positions indexed as [particleIndex][timeIndex] (second index must match size of time array) * @param yPositions square array of y positions indexed as [particleIndex][timeIndex] (second index must match size of time array) * @param colors color values indexed as [particleIndex][timeIndex][rgba] */ public StaticParticlePainter( TimeStamp[] time, float[][] xPositions, float[][] yPositions, float[][][] colors ) { this.countTimes = time.length; this.countParticles = xPositions[0].length; assert ( countTimes == xPositions.length && countTimes == yPositions.length ); this.positionData = FloatBuffer.allocate( countTimes * countParticles * 2 ); this.timeData = new LongsArray( countTimes ); // load data into time array for ( int t = 0; t < countTimes; t++ ) { this.timeData.append( time[t].toPosixMillis( ) ); } // load data into array particle-wise (x/y positions for each particle are contiguous) for ( int p = 0; p < countParticles; p++ ) { for ( int t = 0; t < countTimes; t++ ) { this.positionData.put( xPositions[p][t] ); this.positionData.put( yPositions[p][t] ); } } this.firstData = IntBuffer.allocate( countParticles ); this.countData = IntBuffer.allocate( countParticles ); for ( int p = 0; p < countParticles; p++ ) { this.countData.put( 0 ); this.firstData.put( 0 ); } if ( colors != null ) { this.colorData = FloatBuffer.allocate( countTimes * countParticles * 4 ); for ( int p = 0; p < countParticles; p++ ) { for ( int t = 0; t < countTimes; t++ ) { for ( int c = 0; c < 4; c++ ) { this.colorData.put( colors[p][t][c] ); } } } } } public void setColor( float[] color ) { this.color = color; } public void setLineWidth( float lineWidth ) { this.lineWidth = lineWidth; } public void displayTimeRange( long startMillis, long endMillis ) { startIndex = Arrays.binarySearch( timeData.a, 0, timeData.n, startMillis ); if ( startIndex < 0 ) startIndex = - ( startIndex + 1 ); if ( startIndex > timeData.n - 1 ) startIndex = timeData.n - 1; if ( startIndex > 0 && timeData.v( startIndex ) > startMillis ) startIndex--; endIndex = Arrays.binarySearch( timeData.a, 0, timeData.n, endMillis ); if ( endIndex < 0 ) endIndex = - ( endIndex + 1 ); if ( endIndex > timeData.n - 1 ) endIndex = timeData.n - 1; if ( endIndex < timeData.n - 1 && timeData.v( endIndex ) < endMillis ) endIndex++; int size = endIndex - startIndex + 1; for ( int p = 0; p < countParticles; p++ ) { this.firstData.put( p, ( countTimes * p + startIndex ) ); this.countData.put( p, size ); } } public void displayTimeRange( TimeStamp startTime, TimeStamp endTime ) { this.displayTimeRange( startTime.toPosixMillis( ), endTime.toPosixMillis( ) ); } @Override public void paintTo( GL2 gl, GlimpseBounds bounds, Axis2D axis ) { if ( startIndex == 0 && endIndex == 0 ) return; if ( startIndex == countParticles - 1 && endIndex == countParticles - 1 ) return; if ( !glInitialized ) { // create a new device buffer handle int[] bufferHandle = new int[1]; gl.glGenBuffers( 1, bufferHandle, 0 ); glBufferHandleData = bufferHandle[0]; // copy data from the host buffer into the device buffer gl.glBindBuffer( GL2.GL_ARRAY_BUFFER, glBufferHandleData ); gl.glBufferData( GL2.GL_ARRAY_BUFFER, countTimes * countParticles * 2 * BYTES_PER_FLOAT, positionData.rewind( ), GL2.GL_STATIC_DRAW ); if ( colorData != null ) { // create a new device buffer handle int[] bufferHandleColor = new int[1]; gl.glGenBuffers( 1, bufferHandleColor, 0 ); glBufferHandleColor = bufferHandleColor[0]; // copy data from the host buffer into the device buffer gl.glBindBuffer( GL2.GL_ARRAY_BUFFER, glBufferHandleColor ); gl.glBufferData( GL2.GL_ARRAY_BUFFER, countTimes * countParticles * 4 * BYTES_PER_FLOAT, colorData.rewind( ), GL2.GL_STATIC_DRAW ); } glInitialized = true; // we no longer need the buffers once data is loaded onto gpu positionData = null; colorData = null; } gl.glEnableClientState( GL2.GL_VERTEX_ARRAY ); gl.glBindBuffer( GL2.GL_ARRAY_BUFFER, glBufferHandleData ); gl.glVertexPointer( 2, GL2.GL_FLOAT, 0, 0 ); if ( glBufferHandleColor != -1 ) { gl.glEnableClientState( GL2.GL_COLOR_ARRAY ); gl.glBindBuffer( GL2.GL_ARRAY_BUFFER, glBufferHandleColor ); gl.glColorPointer( 4, GL2.GL_FLOAT, 0, 0 ); } else { GlimpseColor.glColor( gl, color ); } gl.glLineWidth( lineWidth ); firstData.rewind( ); countData.rewind( ); gl.glMultiDrawArrays( GL.GL_LINE_STRIP, firstData, countData, countParticles ); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy