/*
* Project Info: http://jcae.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.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* (C) Copyright 2008, by EADS France
*/
package org.jcae.vtk;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.SwingUtilities;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector4d;
import org.jcae.geometry.BoundingPolytope;
import vtk.vtkActor;
import vtk.vtkAssembly;
import vtk.vtkCanvas;
import vtk.vtkCellArray;
import vtk.vtkCoincidentTopologyResolutionPainter;
import vtk.vtkConeSource;
import vtk.vtkDataArray;
import vtk.vtkDoubleArray;
import vtk.vtkFileOutputWindow;
import vtk.vtkFloatArray;
import vtk.vtkIdTypeArray;
import vtk.vtkInformation;
import vtk.vtkInformationDoubleVectorKey;
import vtk.vtkInformationIntegerKey;
import vtk.vtkIntArray;
import vtk.vtkNativeLibrary;
import vtk.vtkObjectBase;
import vtk.vtkOutputWindow;
import vtk.vtkPNGWriter;
import vtk.vtkPainter;
import vtk.vtkPainterPolyDataMapper;
import vtk.vtkPlane;
import vtk.vtkPlaneCollection;
import vtk.vtkPoints;
import vtk.vtkPolyData;
import vtk.vtkPolyDataMapper;
import vtk.vtkPolyLine;
import vtk.vtkProperty;
import vtk.vtkRenderer;
import vtk.vtkTransform;
import vtk.vtkTransformFilter;
import vtk.vtkWindowToImageFilter;
/**
*
* @author Jerome Robert
*/
public class Utils
{
private final static Logger LOGGER = Logger.getLogger(Utils.class.getName());
public static Canvas retrieveCanvas(ComponentEvent e)
{
Component c = e.getComponent();
if(c instanceof Canvas)
return (Canvas)c;
else
throw new NoSuchElementException("Found "+c.getClass()+
" when "+vtkCanvas.class+" expected.");
}
public static void computeRay(vtkRenderer renderer, Point pickPosition, Point3d origin, Vector3d direction)
{
renderer.SetDisplayPoint(pickPosition.x, pickPosition.y, 0);
renderer.DisplayToWorld();
double[] vertex = renderer.GetWorldPoint();
origin.x = vertex[0];
origin.y = vertex[1];
origin.z = vertex[2];
renderer.SetDisplayPoint(pickPosition.x, pickPosition.y, 1);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
direction.x = vertex[0] - origin.x;
direction.y = vertex[1] - origin.y;
direction.z = vertex[2] - origin.z;
}
public static float[] CanvasGetZBuffer(vtkCanvas canvas, int[] firstPoint, int[] secondPoint)
{
vtkFloatArray zbuffer = new vtkFloatArray();
canvas.GetRenderWindow().GetZbufferData(firstPoint[0], firstPoint[1], secondPoint[0], secondPoint[1], zbuffer);
return zbuffer.GetJavaArray();
}
/**
* Use vtkPropertySetColor instead
* @param actor
* @param color
* @deprecated
*/
@Deprecated
public static void setColorActor(vtkActor actor, Color color)
{
if (LOGGER.isLoggable(Level.FINEST))
LOGGER.log(Level.FINEST, "Attach color "+color+" (opacity="+color.getAlpha()+" to actor "+actor);
actor.GetProperty().SetColor((double) color.getRed() / 255., (double) color.getGreen() / 255., (double) color.getBlue() / 255.);
actor.GetProperty().SetOpacity((double) color.getAlpha() / 255.);
}
public static boolean intToBoolean(int value)
{
return value != 0;
}
public static int booleanToInt(boolean value)
{
return (value) ? 1 : 0;
}
public static boolean isMeshCoherent(float[] points, int[] indices)
{
boolean[] flags = new boolean[points.length/3];
// Init
Arrays.fill(flags, false);
for (int i = 0; i < indices.length;)
{
// The number of points of the polygon
int nb = indices[i];
// Check out of bound
if (i + nb >= indices.length)
return false;
// Explore the polygon
for (int j = i + 1; j < i + nb + 1; j++)
// Check out of bound
if (indices[j] >= points.length)
return false;
else
flags[indices[j]] = true;
i = i + nb + 1;
}
// Check if all the points are used
for (boolean flag : flags)
if (!flag)
return false;
return true;
}
public static void vtkPropertySetColor(vtkProperty property, Color color)
{
if (LOGGER.isLoggable(Level.FINEST))
LOGGER.log(Level.FINEST, "Set property "+property+" to color "+color+" (opacity="+color.getAlpha()+")");
property.SetColor((double) color.getRed() / 255., (double) color.getGreen() / 255., (double) color.getBlue() / 255.);
property.SetOpacity((double) color.getAlpha() / 255.);
}
public static void loadVTKLibraries()
{
vtkNativeLibrary.LoadNativeLibraries();
}
public static void main(final String[] args)
{
loadVTKLibraries();
}
/** Create a dummy canvas with single actor */
public static vtkCanvas createDummyCanvas(vtkActor actor)
{
final vtkCanvas canvas = new vtkCanvas()
{
/** Workaround for http://www.vtk.org/Bug/view.php?id=6268 */
@Override
public void setSize(int x, int y)
{
super.setSize(x, y);
Lock();
rw.SetSize(x, y);
iren.SetSize(x, y);
iren.ConfigureEvent();
UnLock();
}
};
// a renderer for the data
final vtkRenderer ren1 = canvas.GetRenderer();
ren1.AddActor(actor);
// background color white
ren1.SetBackground(1, 1, 1);
// Make the canvas resizable with a splitter
//layout
canvas.setMinimumSize(new Dimension(0, 0));
canvas.setPreferredSize(new Dimension(0, 0));
ren1.ResetCamera();
return canvas;
}
/**
* Transform z from eyes coordinates to screen coordinates (the z-buffer value)
* @param ze the z in eyes coordinnates
* @param n near plane distance
* @param f far plane distance
* @return
*/
public static double eyeZToNormalizedEyeZ(double ze, double n, double f)
{
return (f + n) / (f - n) - 2 * f * n / (f - n) / ze;
}
/**
* Used to compute the tolerance for VTK picking
* @param canvas
* @param tolerance in percentage of error of distance in function of (f - n)
* @return the epsilon error in z space coordinates (z in [0,1])
*/
public static double computeTolerance(vtkCanvas canvas, double tolerance)
{
double[] range = canvas.GetRenderer().GetActiveCamera().GetClippingRange();
double n = range[0];
double f = range[1];
double distance = canvas.GetRenderer().GetActiveCamera().GetDistance();
double distanceTolerance = tolerance * (f - n);
// Compute the z of the focal point (point of interest)
double d1 = eyeZToNormalizedEyeZ(distance, n, f);
// Compute the z of the distance tolerance
// If we are before the far we take distance + distanceTolerance else we take -
double d2 = (distance + distanceTolerance < f) ? distance + distanceTolerance : distance - distanceTolerance;
d2 = eyeZToNormalizedEyeZ(d2, n, f);
// Compute the delta tolerance for the z-buffer value
return Math.abs(d1 - d2);
}
/**
* Compute the epsilon of the depth in screen coordinates (z mapped to [0,1])
* giving a distance in camera space coordinates.
* @param distance the distance on z to the camera where the delta is computed.
* @param delta the distance in camera space coordinates.
* @param n near plane distance
* @param f far plane distance
* @return
* @see Mathematics for 3D Game Programming and Compute Graphics book.
*/
public static double computeZDistance(double distance, double delta, double n, double f)
{
return (2 * f * n * delta) / ((f + n) * distance * (distance + delta));
}
public static vtkPlaneCollection computeClippingPlane(Canvas canvas, Point pressPosition, Point releasePosition)
{
// Compute the clipping planes
vtkRenderer render = canvas.GetRenderer();
vtkPlaneCollection planes = new vtkPlaneCollection();
vtkPlane plane = null;
double[] p1;
double[] p2;
double[] p3;
/**
* These are the two points in the screen that define the different clipping planes
*/
int[][] pos1 =
{
{
pressPosition.x, pressPosition.y
}, // Left plane
{
releasePosition.x, pressPosition.y
}, // Top plane
{
releasePosition.x, releasePosition.y
}, // Right plane
{
pressPosition.x, releasePosition.y
} // Bottom plane
};
int[][] pos2 =
{
{
pressPosition.x, releasePosition.y
},
{
pressPosition.x, pressPosition.y
},
{
releasePosition.x, pressPosition.y
},
{
releasePosition.x, releasePosition.y
}
};
for (int i = 0; i < 4; ++i)
{
plane = new vtkPlane();
render.SetDisplayPoint(pos1[i][0], pos1[i][1], 0.);
render.DisplayToWorld();
p1 = render.GetWorldPoint();
render.SetDisplayPoint(pos1[i][0], pos1[i][1], 1.);
render.DisplayToWorld();
p2 = render.GetWorldPoint();
render.SetDisplayPoint(pos2[i][0], pos2[i][1], 1.);
render.DisplayToWorld();
p3 = render.GetWorldPoint();
// Compute two vectors of the plane
Vector3d v1 = new Vector3d();
Vector3d v2 = new Vector3d();
Vector3d n = new Vector3d();
v1.set(p2);
v2.set(p1);
n.set(p3);
v1.sub(v2);
v2.sub(n);
// Compute cross product (the normal of the plane) between p1 and p2
n.cross(v1, v2);
n.normalize();
plane.SetNormal(n.x, n.y, n.z);
plane.SetOrigin(p1);
planes.AddItem(plane);
}
return planes;
}
/**
* Compute the epsilon error on screen coordinates of the Z-buffer
* @param nbits the number of bits of the Z-buffer
* @return
*/
public static double computeZBufferError(int nbit)
{
return 1. / (Math.pow(2., (double)nbit) - 1.);
}
public static void addOffset(int[] indices, int offset)
{
for(int i = 0 ; i < indices.length ; ++i)
indices[i] += offset;
}
// left plane = frustumPlanes[0]
// right plane = frustumPlanes[1]
// top plane = frustumPlanes[2]
// bottom plane = frustumPlanes[3]
// front plane = frustumPlanes[4]
// back plane = frustumPlanes[5]
/**
* Return the bouding polytope representing the frustum. The planes are created as follow :
* left, right, top, bottom, front, back.
* @param points
* @return
*/
public static BoundingPolytope computePolytope(double[] points)
{
BoundingPolytope frustum = new BoundingPolytope();
Vector3d a1 = new Vector3d(points[0],points[1],points[2]);
Vector3d a2 = new Vector3d(points[4],points[5],points[6]);
Vector3d b1 = new Vector3d(points[8],points[9],points[10]);
Vector3d b2 = new Vector3d(points[12],points[13],points[14]);
Vector3d c1 = new Vector3d(points[16],points[17],points[18]);
Vector3d c2 = new Vector3d(points[20],points[21],points[22]);
Vector3d d1 = new Vector3d(points[24],points[25],points[26]);
Vector3d d2 = new Vector3d(points[28],points[29],points[30]);
Vector4d[] planes = new Vector4d[] {
computePlane(a1,b1,a2),
computePlane(d1,c1,d2),
computePlane(b1,d1,b2),
computePlane(c1,a1,c2),
computePlane(c1,d1,a1),
computePlane(d2,c2,b2),
};
frustum.setPlanes(planes);
return frustum;
}
/**
* Compute the plane giving three points of the plane.
* The normal is computed as follow : (b-a)^(c-a)
* @param a
* @param b
* @param c
* @return
*/
static Vector4d computePlane(Vector3d a, Vector3d b, Vector3d c)
{
Vector4d plane = new Vector4d();
Vector3d ab = new Vector3d();
ab.sub(b, a);
Vector3d ac = new Vector3d();
ac.sub(c, a);
Vector3d n = new Vector3d();
n.cross(ab, ac);
n.normalize();
plane.set(n);
plane.w = - a.dot(n);
return plane;
}
public static double[] computeVerticesFrustum(double x0, double y0,
double x1, double y1, vtkRenderer renderer)
{
double X0 = Math.min(x0, x1);
double Y0 = Math.min(y0, y1);
double X1 = Math.max(x0, x1);
double Y1 = Math.max(y0, y1);
//compute world coordinates of the pick volume
double[] verts = new double[32];
double[] vertex = new double[4];
renderer.SetDisplayPoint(X0, Y0, 0);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 0, 4);
renderer.SetDisplayPoint(X0, Y0, 1);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 4, 4);
renderer.SetDisplayPoint(X0, Y1, 0);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 8, 4);
renderer.SetDisplayPoint(X0, Y1, 1);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 12, 4);
renderer.SetDisplayPoint(X1, Y0, 0);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 16, 4);
renderer.SetDisplayPoint(X1, Y0, 1);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 20, 4);
renderer.SetDisplayPoint(X1, Y1, 0);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 24, 4);
renderer.SetDisplayPoint(X1, Y1, 1);
renderer.DisplayToWorld();
vertex = renderer.GetWorldPoint();
System.arraycopy(vertex, 0, verts, 28, 4);
return verts;
}
private final static double offsetFactor, offsetValue;
static
{
String s = System.getProperty("org.jcae.vtk.offsetFactor");
double d = 1.0;
if(s != null)
try
{
d = Double.parseDouble(s);
}
catch(NumberFormatException ex){}
offsetFactor = d;
s = System.getProperty("org.jcae.vtk.offsetValue");
d = 1.0;
if(s != null)
try
{
d = Double.parseDouble(s);
}
catch(NumberFormatException ex){}
offsetValue = d;
}
public static double getOffsetFactor()
{
return offsetFactor;
}
public static double getOffsetValue()
{
return offsetValue;
}
public static BufferedImage takeScreenshot(final vtkCanvas canvas) throws IOException
{
File f = File.createTempFile("screen", ".png");
f.deleteOnExit();
takeScreenshot(canvas, f.getPath());
f.delete();
return ImageIO.read(f);
}
/**
* Synchronously take a snapshot of a 3D view
* @param canvas
* @param onDone something to be executed when the screenshot has been taken
*/
public static void takeScreenshot(final vtkCanvas canvas, final String fileName)
{
goToAWTThread(new Runnable() {
@Override
public void run()
{
final vtkWindowToImageFilter w2i = new vtkWindowToImageFilter();
final vtkPNGWriter writer = new vtkPNGWriter();
w2i.SetInput(canvas.getIren().GetRenderWindow());
writer.SetInputConnection(w2i.GetOutputPort());
writer.SetFileName(fileName);
if (!canvas.isWindowSet())
canvas.Render();
canvas.lock();
w2i.Update();
canvas.unlock();
writer.Write();
}
});
}
/**
* This methods permit to be sure the runnable is executed on the principal awt thread.
* If we are already in, it just call run of runnable and if not it makes a
* swing invoke and wait.
* Warning : You can lock the canvas if you need in the run method of runnable.
* Do not lock the canvas outside this because it can makes dead locks.
* @param runnable
*/
public static void goToAWTThread(Runnable runnable)
{
if (!SwingUtilities.isEventDispatchThread())
{
//Thread.dumpStack();
/*System.err.println(
"WARNING ! : you try to render on a different thread than the"+
"thread that creates the renderView. Making an invokeLater to"+
" render on the thread that creates the renderView");*/
try {
SwingUtilities.invokeAndWait(runnable);
} catch (InterruptedException ex) {
ex.printStackTrace();
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
} catch (InvocationTargetException ex) {
ex.printStackTrace();
LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
}
}
else
runnable.run();
}
//this 2 fields should be final. They can't be because vtk library may not
//have been loaded before this class
private static vtkInformationIntegerKey RESOLVE_COINCIDENT_TOPOLOGY;
private static vtkInformationDoubleVectorKey POLYGON_OFFSET_PARAMETERS;
private static class PolygonOffsetHandler
{
private vtkPainter painter;
private double factor, value;
public PolygonOffsetHandler(vtkPainter painter, double factor, double value) {
this.painter = painter;
this.factor = factor;
this.value = value;
}
public void event()
{
if(RESOLVE_COINCIDENT_TOPOLOGY == null)
{
vtkCoincidentTopologyResolutionPainter dummy =
new vtkCoincidentTopologyResolutionPainter();
RESOLVE_COINCIDENT_TOPOLOGY = dummy.RESOLVE_COINCIDENT_TOPOLOGY();
POLYGON_OFFSET_PARAMETERS = dummy.POLYGON_OFFSET_PARAMETERS();
}
vtkInformation info = painter.GetInformation();
//If you want to know who call the event uncomment this line
//System.out.println(new Throwable().getStackTrace()[2]+ " " + (info == null));
//info is null when this is called by vtkVisibleCellSelector.Select
if(info != null)
{
// change info may trigger rebuild events in VTK so we check if
// it's really necessary
if(info.Get(RESOLVE_COINCIDENT_TOPOLOGY) != 1)
info.Set(RESOLVE_COINCIDENT_TOPOLOGY, 1);
if(info.Get(POLYGON_OFFSET_PARAMETERS, 0) != factor ||
info.Get(POLYGON_OFFSET_PARAMETERS, 1) != value)
info.Set(POLYGON_OFFSET_PARAMETERS, factor, value, 0);
}
}
}
/**
* Set the polygon offset of a mapper.
* Warning this method has a side effect. After calling it changes made on
* the mapper may not be propagated to delegate painters
*/
public static void setPolygonOffset(vtkPainterPolyDataMapper pm,
double factor, double value)
{
vtkPainter painter = pm.GetPainter();
pm.AddObserver("StartEvent",
new PolygonOffsetHandler(painter, factor, value), "event");
}
/** Create a dummy cone actor
* @return
*/
public static vtkActor createDummyActor()
{
// create sphere geometry
vtkConeSource cone = new vtkConeSource();
cone.SetHeight(3.0);
cone.SetRadius(1.0);
cone.SetResolution(10);
// map to graphics objects
vtkPolyDataMapper map = new vtkPolyDataMapper();
map.SetInputConnection(cone.GetOutputPort());
// actor coordinates geometry, properties, transformation
vtkActor aSphere = new vtkActor();
aSphere.SetMapper(map);
aSphere.GetProperty().SetColor(0, 0, 1); // color blue
return aSphere;
}
/** Create a dummy cone actor */
public static vtkAssembly createDummyAssembly(int n, int m)
{
vtkAssembly assembly = new vtkAssembly();
assembly.SetPickable(0);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
vtkActor actor = createDummyActor();
actor.SetPosition(4 * i, 4 * j, 0);
actor.SetPickable(1);
assembly.AddPart(actor);
}
return assembly;
}
/** Same as createDummyAssembly, but add actors directly in the scene */
public static void addDummyCones(int n, int m, vtkRenderer renderer)
{
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
{
// create sphere geometry
vtkConeSource cone = new vtkConeSource();
cone.SetHeight(3.0);
cone.SetRadius(1.0);
cone.SetResolution(50);
vtkTransformFilter filter = new vtkTransformFilter();
vtkTransform transform = new vtkTransform();
transform.Translate(4 * (i + 1), 4 * (j + 1), 0);
filter.SetTransform(transform);
filter.SetInputConnection(cone.GetOutputPort());
vtkPolyDataMapper map = new vtkPolyDataMapper();
map.SetInputConnection(filter.GetOutputPort());
vtkActor actor = new vtkActor();
actor.SetMapper(map);
if (i == 0 && j == 0)
actor.GetProperty().SetColor(0, 1, 0);
actor.PickableOn();
renderer.AddActor(actor);
}
}
/** Create vertices cells to be used as input from createCells */
public static int[] createVerticesCells(int numberOfVertices)
{
int[] toReturn = new int[numberOfVertices * 2];
int k = 0;
for (int i = 0; i < numberOfVertices; i++)
{
toReturn[k++] = 1;
toReturn[k++] = i;
}
return toReturn;
}
/** Create a vtkPoints array from floats */
public static vtkPoints createPoints(float[] points)
{
vtkPoints vtkPoints = new vtkPoints();
vtkFloatArray d = new vtkFloatArray();
d.SetJavaArray(points);
d.SetNumberOfComponents(3);
vtkPoints.SetData(d);
delete(d);
return vtkPoints;
}
/** Create a vtkPoints array from doubles */
public static vtkPoints createPoints(double[] points)
{
vtkPoints vtkPoints = new vtkPoints();
vtkDoubleArray d = new vtkDoubleArray();
d.SetJavaArray(points);
d.SetNumberOfComponents(3);
vtkPoints.SetData(d);
delete(d);
return vtkPoints;
}
public static int[] createQuadsCells(int nbrOfCells)
{
int[] indices = new int[nbrOfCells * 5];
int offset = 0;
for(int i = 0 ; i < indices.length ; )
{
indices[i++] = 4;
indices[i++] = offset++;
indices[i++] = offset++;
indices[i++] = offset++;
indices[i++] = offset++;
}
return indices;
}
/** Create an index array for quads to be used as input from createCells */
public static int[] createQuadsCells(int[] cells, int offsetID)
{
int k = 0;
int nCell = cells.length / 4;
int[] fCells = new int[nCell * 5];
for (int i = 0; i < nCell * 4;)
{
fCells[k++] = 4;
fCells[k++] = cells[i++] + offsetID;
fCells[k++] = cells[i++] + offsetID;
fCells[k++] = cells[i++] + offsetID;
fCells[k++] = cells[i++] + offsetID;
}
return fCells;
}
/**
* Compute the VTK tolerance for point pickers to have a box of size size in pixel.
* @param renderer
* @return
*/ public static double getTolerance(vtkRenderer renderer, int pixelSize)
{
int[] size = renderer.GetSize();
// The diagonal of the renderer
double diagonal = Math.sqrt(size[0]*size[0] + size[1]*size[1]);
return ((double) pixelSize) / (diagonal * 2.);
}
public static int[] createTriangleCells(int nbrOfCells)
{
int[] indices = new int[nbrOfCells * 4];
int offset = 0;
for(int i = 0 ; i < indices.length ; )
{
indices[i++] = 3;
indices[i++] = offset++;
indices[i++] = offset++;
indices[i++] = offset++;
}
return indices;
}
/** Create an index array for triangles to be used as input from createCells */
public static int[] createTriangleCells(int[] cells, int offsetID)
{
int k = 0;
int nCell = cells.length / 3;
int[] fCells = new int[nCell * 4];
for (int i = 0; i < nCell * 3; i += 3)
{
fCells[k++] = 3;
fCells[k++] = cells[i] + offsetID;
fCells[k++] = cells[i + 1] + offsetID;
fCells[k++] = cells[i + 2] + offsetID;
}
return fCells;
}
/** Create an index array for beams to be used as input from createCells */
public static int[] createBeamCells(int numberOfBeam)
{
int k = 0;
int[] fCells = new int[3 * numberOfBeam];
for (int i = 0; i < fCells.length ; )
{
fCells[i++] = 2;
fCells[i++] = k++;
fCells[i++] = k++;
}
return fCells;
}
/**
* Create an index array for beams to be used as input from createCells
* change {a, b, c, d} to {2, a, b, 2, c, d}
*/
public static int[] createBeamCells(int[] beams)
{
int numberOfBeam = beams.length / 2;
int k = 0;
int j = 0;
int[] fCells = new int[3 * numberOfBeam];
for (int i = 0; i < numberOfBeam; i++)
{
fCells[k++] = 2;
fCells[k++] = beams[j++];
fCells[k++] = beams[j++];
}
return fCells;
}
/** Create a vtkCellArray from indexes */
public static vtkCellArray createCells(int cellNumber, int[] cells)
{
vtkCellArray vtkCells = new vtkCellArray();
vtkIdTypeArray array = new vtkIdTypeArray();
vtkIntArray intArray = new vtkIntArray();
intArray.SetJavaArray(cells);
array.DeepCopy(intArray);
vtkCells.SetCells(cellNumber, array);
delete(array);
delete(intArray);
return vtkCells;
}
/** Create a vtkPolyLine from indexes */
public static vtkPolyLine createPolyLine(int nbOfPoints, int offset)
{
vtkPolyLine line = new vtkPolyLine();
// TODO: do not do it in java
line.GetPointIds().SetNumberOfIds(nbOfPoints);
for (int i = 0; i < nbOfPoints; ++i)
line.GetPointIds().SetId(i, i + offset);
return line;
}
public static int[] getValues(vtkIdTypeArray idarray)
{
vtkIntArray iarray = new vtkIntArray();
iarray.DeepCopy(idarray);
int[] toReturn = iarray.GetJavaArray();
delete(iarray);
return toReturn;
}
public static vtkIdTypeArray setValues(int[] values)
{
vtkIntArray iarray = new vtkIntArray();
iarray.SetJavaArray(values);
vtkIdTypeArray array = new vtkIdTypeArray();
array.DeepCopy(iarray);
return array;
}
public static int[] getValues(vtkCellArray array)
{
//The underlying vtkIdTypeArray may be longer the expected and
//getValues(vtkIdTypeArray) won't know it, so we squeeze it before.
array.Squeeze();
vtkIdTypeArray data = array.GetData();
int[] toReturn = getValues(data);
return toReturn;
}
public static float[] getValues(vtkPoints points)
{
vtkDataArray array = points.GetData();
//TODO not sure it's always a float[] array
float[] toReturn = ((vtkFloatArray) array).GetJavaArray();
delete(array);
return toReturn;
}
/**
* Remove size of cell from the cell array.
* Convert {2, 4, 5, 3, 7, 8, 9} to {4, 5, 7, 8, 9}.
* Use it only on cell array containing only one type of cells
*/
public static int[] stripCellArray(int[] indices)
{
if(indices.length == 0)
return new int[0];
//Compute the size of the ouput array
int t = indices[0];
int tp = t + 1;
int n = indices.length / tp;
int[] toReturn = new int[n * t];
for (int i = 0; i < n; i++)
System.arraycopy(indices, i * tp + 1, toReturn, i * t, t);
return toReturn;
}
public static double[] floatToDouble(float[] array)
{
double[] toReturn = new double[array.length];
for (int i = 0; i < array.length; i++)
toReturn[i] = array[i];
return toReturn;
}
/** Redirect VTK log to a file */
public static void setVTKLogFile(String fileName)
{
vtkFileOutputWindow output = new vtkFileOutputWindow();
output.SetFileName(fileName);
new vtkOutputWindow().SetInstance(output);
}
/**
* Tag a vtkObjectBase so it will be deleted at the native level at the
* next vtkGlobalJavaHash.GC() call. Such call is normally triggered by
* vtkJavaGarbageCollector.
* As JVM doesn't monitor the native memory usage, VTK object may never be
* deleted if the Java garbage collector is not triggered by other java
* object creation. This methods allows to manually tag a vtkObject as
* removable without actually removing it.
*/
public static void delete(vtkObjectBase o)
{
VTKMemoryManager.delete(o);
}
}