add isosurface function

This commit is contained in:
wyq 2019-09-21 17:42:49 +08:00
parent fc59cdb39a
commit 47ebdc43d0
17 changed files with 3718 additions and 55 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\micaps">
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\qaqc"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\sunphotometer"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\trajstat"/>
@ -21,22 +21,22 @@
<OpenedFiles>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\two_yaxis.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contourf_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\layer_image.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\traj_4.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_6.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_elev.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_5.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\isosurface_1.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\two_yaxis.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contourf_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\layer_image.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\traj_4.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_6.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_elev.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_5.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\isosurface_1.py"/>
</RecentFiles>
</File>
<Font>
<TextFont FontName="宋体" FontSize="15"/>
</Font>
<Startup MainFormLocation="-3,2" MainFormSize="1393,832"/>
<Startup MainFormLocation="-7,-7" MainFormSize="1293,693"/>
</MeteoInfo>

View File

@ -7,8 +7,9 @@
#-----------------------------------------------------
from org.meteoinfo.chart.plot import GraphicFactory
from org.meteoinfo.legend import BreakTypes
from org.meteoinfo.legend import BreakTypes, LegendManage
from org.meteoinfo.layer import LayerTypes
from org.meteoinfo.shape import ShapeTypes
from org.meteoinfo.chart.jogl import Plot3DGL, GLForm, JOGLUtil
from javax.swing import WindowConstants
from java.awt import Font, Color, BasicStroke
@ -98,6 +99,31 @@ class Axes3DGL(Axes3D):
'''
self.axes.setAngleX(elevation)
def set_lighting(self, enable, **kwargs):
'''
Set lighting.
:param enable: (*boolean*) Set lighting enable or not.
:param position: (*list of float*) Lighting position.
:param ambient: (*list of float*) Ambient light.
:param diffuse: (*list of float*) Diffuse light.
:param specular: (*list of float*) Specular light.
'''
lighting = self.axes.getLighting()
lighting.setEnable(enable)
position = kwargs.pop('position', None)
if not position is None:
lighting.setPosition(position)
ambient = kwargs.pop('ambient', None)
if not ambient is None:
lighting.setAmbient(ambient)
diffuse = kwargs.pop('diffuse', None)
if not diffuse is None:
lighting.setDiffuse(diffuse)
specular = kwargs.pop('specular', None)
if not specular is None:
lighting.setSpecular(specular)
def plot_layer(self, layer, **kwargs):
'''
Plot a layer in 3D axes.
@ -135,6 +161,63 @@ class Axes3DGL(Axes3D):
if visible:
self.add_graphic(graphics)
return graphics
def plot_isosurface(self, *args, **kwargs):
'''
creates a three-dimensional isosurface plot
:param x: (*array_like*) Optional. X coordinate array.
:param y: (*array_like*) Optional. Y coordinate array.
:param z: (*array_like*) Optional. Z coordinate array.
:param data: (*array_like*) 3D data array.
:param cmap: (*string*) Color map string.
:param xyaxis: (*boolean*) Draw x and y axis or not.
:param zaxis: (*boolean*) Draw z axis or not.
:param grid: (*boolean*) Draw grid or not.
:param boxed: (*boolean*) Draw boxed or not.
:param mesh: (*boolean*) Draw mesh line or not.
:returns: Legend
'''
if len(args) <= 3:
x = args[0].dimvalue(2)
y = args[0].dimvalue(1)
z = args[0].dimvalue(0)
data = args[0]
isovalue = args[1]
args = args[2:]
else:
x = args[0]
y = args[1]
z = args[2]
data = args[3]
isovalue = args[4]
args = args[5:]
cmap = plotutil.getcolormap(**kwargs)
cvalue = kwargs.pop('cvalue', None)
if not cvalue is None:
if len(args) > 0:
level_arg = args[0]
if isinstance(level_arg, int):
cn = level_arg
ls = LegendManage.createLegendScheme(data.min(), data.max(), cn, cmap)
else:
if isinstance(level_arg, NDArray):
level_arg = level_arg.aslist()
ls = LegendManage.createLegendScheme(data.min(), data.max(), level_arg, cmap)
else:
ls = LegendManage.createLegendScheme(data.min(), data.max(), cmap)
ls = ls.convertTo(ShapeTypes.Polygon)
edge = kwargs.pop('edge', True)
kwargs['edge'] = edge
plotutil.setlegendscheme(ls, **kwargs)
else:
ls = plotutil.getlegendbreak('polygon', **kwargs)[0]
graphics = JOGLUtil.isosurface(data.asarray(), x.asarray(), y.asarray(), z.asarray(), isovalue, ls)
visible = kwargs.pop('visible', True)
if visible:
self.add_graphic(graphics)
return graphics
def view(self):
'''

Binary file not shown.

View File

@ -0,0 +1,57 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl;
import java.util.ArrayList;
import java.util.List;
import org.meteoinfo.chart.plot3d.GraphicCollection3D;
import org.meteoinfo.global.Extent3D;
import org.meteoinfo.global.MIMath;
import org.meteoinfo.shape.PointZ;
/**
*
* @author yaqiang
*/
public class IsosurfaceGraphics extends GraphicCollection3D {
private List<PointZ[]> triangles = new ArrayList<>();
/**
* Constructor
*/
public IsosurfaceGraphics() {
this.allTriangle = true;
}
/**
* Get triangles
* @return Triangles
*/
public List<PointZ[]> getTriangles() {
return this.triangles;
}
/**
* Set triangles
* @param value Triangles
*/
public void setTriangles(List<PointZ[]> value) {
this.triangles = value;
}
/**
* Add a triangle
* @param triangle Triangle
*/
public void addTriangle(PointZ[] triangle) {
this.triangles.add(triangle);
Extent3D extent = MIMath.getExtent(triangle);
if (this.triangles.size() == 1)
this.setExtent(extent);
else
this.setExtent(MIMath.getLagerExtent(extent, this.getExtent()));
}
}

View File

@ -6,21 +6,23 @@
package org.meteoinfo.chart.jogl;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureIO;
import java.io.File;
import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.meteoinfo.chart.jogl.mc.MarchingCubes;
import org.meteoinfo.chart.plot3d.GraphicCollection3D;
import org.meteoinfo.global.Extent;
import org.meteoinfo.global.Extent3D;
import org.meteoinfo.layer.ImageLayer;
import org.meteoinfo.legend.ColorBreak;
import org.meteoinfo.legend.PolygonBreak;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.shape.Graphic;
import org.meteoinfo.shape.GraphicCollection;
import org.meteoinfo.shape.ImageShape;
import org.meteoinfo.shape.PointZ;
import org.meteoinfo.shape.PolygonZShape;
/**
*
@ -64,4 +66,69 @@ public class JOGLUtil {
return graphics;
}
/**
* Create isosurface graphics
* @param data 3d data array
* @param x X coordinates
* @param y Y coordinates
* @param z Z coordinates
* @param isoLevel iso level
* @param pb Polygon break
* @return Graphics
*/
public static GraphicCollection isosurface(Array data, Array x, Array y, Array z,
float isoLevel, PolygonBreak pb) {
List<float[]> vertices = MarchingCubes.marchingCubes(data, x, y, z, isoLevel);
IsosurfaceGraphics graphics = new IsosurfaceGraphics();
graphics.setLegendBreak(pb);
float[] v1, v2, v3;
for (int i = 0; i < vertices.size(); i += 3) {
PointZ[] points = new PointZ[3];
v1 = vertices.get(i);
v2 = vertices.get(i + 1);
v3 = vertices.get(i + 2);
points[0] = new PointZ(v1[0], v1[1], v1[2]);
points[1] = new PointZ(v2[0], v2[1], v2[2]);
points[2] = new PointZ(v3[0], v3[1], v3[2]);
graphics.addTriangle(points);
}
return graphics;
}
/**
* Create isosurface graphics
* @param data 3d data array
* @param x X coordinates
* @param y Y coordinates
* @param z Z coordinates
* @param isoLevel iso level
* @param pb Polygon break
* @return Graphics
*/
public static GraphicCollection isosurface_bak(Array data, Array x, Array y, Array z,
float isoLevel, PolygonBreak pb) {
List<float[]> vertices = MarchingCubes.marchingCubes(data, x, y, z, isoLevel);
GraphicCollection3D graphics = new GraphicCollection3D();
pb.setColor(Color.cyan);
float[] v1, v2, v3;
for (int i = 0; i < vertices.size(); i += 3) {
PolygonZShape ps = new PolygonZShape();
List<PointZ> points = new ArrayList<>();
v1 = vertices.get(i);
v2 = vertices.get(i + 1);
v3 = vertices.get(i + 2);
points.add(new PointZ(v1[0], v1[1], v1[2]));
points.add(new PointZ(v2[0], v2[1], v2[2]));
points.add(new PointZ(v3[0], v3[1], v3[2]));
points.add(new PointZ(v1[0], v1[1], v1[2]));
ps.setPoints(points);
Graphic graphic = new Graphic(ps, pb);
graphics.add(graphic);
}
graphics.setAllTriangle(true);
return graphics;
}
}

View File

@ -0,0 +1,308 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl;
import com.jogamp.opengl.GL2;
import java.awt.Color;
import java.util.List;
/**
*
* @author Yaqiang Wang
*/
public class Lighting {
private boolean enable;
private int light;
float[] ambient;
float[] diffuse;
float[] specular;
float[] position;
float[] mat_ambient;
float[] mat_specular;
float mat_shininess;
/**
* Constructor
*/
public Lighting() {
this(false);
}
/**
* Constructor
* @param far Far light position or not
*/
public Lighting(boolean far) {
this.enable = false;
this.light = GL2.GL_LIGHT0;
//this.ambient = new float[]{0.f, 0.f, 0.f, 1.f};
this.ambient = new float[]{0.2f, 0.2f, 0.2f, 1.f};
this.diffuse = new float[]{1.f, 1.f, 1.f, 1.f};
this.specular = new float[]{1.f, 1.f, 1.f, 1.f};
if (far)
this.position = new float[]{0.f, 0.f, 1.f, 0.f};
else
this.position = new float[]{0.f, 1.f, 0.f, 1.f};
this.mat_ambient = new float[]{0.f, 0.f, 0.f, 0.f};
this.mat_specular = new float[]{ 1.0f, 1.0f, 1.0f, 1.0f };
this.mat_shininess = 50.0f;
}
/**
* Get enable lighting or not
*
* @return Boolean
*/
public boolean isEnable() {
return this.enable;
}
/**
* Set enable lighting or not
*
* @param value Boolean
*/
public void setEnable(boolean value) {
this.enable = value;
}
/**
* Get ambient
*
* @return Ambient
*/
public float[] getAmbient() {
return this.ambient;
}
/**
* Set ambient
*
* @param value Ambient
*/
public void setAmbient(float[] value) {
this.ambient = value;
}
/**
* Set ambient
*
* @param value Ambient
*/
public void setAmbient(List value) {
if (value.size() < 4) {
return;
}
this.ambient = new float[]{(float) value.get(0), (float) value.get(1), (float) value.get(2),
(float) value.get(3)};
}
/**
* Set ambient
*
* @param value Color
*/
public void setAmbient(Color value) {
this.ambient = value.getRGBComponents(null);
}
/**
* Get diffuse
*
* @return Diffuse
*/
public float[] getDiffuse() {
return this.diffuse;
}
/**
* Set diffuse
*
* @param value Diffuse
*/
public void setDiffuse(float[] value) {
this.diffuse = value;
}
/**
* Set diffuse
*
* @param value Diffuse
*/
public void setDiffuse(List value) {
if (value.size() < 4) {
return;
}
this.diffuse = new float[]{(float) value.get(0), (float) value.get(1), (float) value.get(2),
(float) value.get(3)};
}
/**
* Set diffuse
*
* @param value Color
*/
public void setDiffuse(Color value) {
this.diffuse = value.getRGBComponents(null);
}
/**
* Get specular
*
* @return Specular
*/
public float[] getSpecular() {
return this.specular;
}
/**
* Set specular
*
* @param value Specular
*/
public void setSpecular(float[] value) {
this.specular = value;
}
/**
* Set specular
*
* @param value Specular
*/
public void setSpecular(List value) {
if (value.size() < 4) {
return;
}
this.specular = new float[]{(float) value.get(0), (float) value.get(1), (float) value.get(2),
(float) value.get(3)};
}
/**
* Set specular
*
* @param value Color
*/
public void setSpecular(Color value) {
this.specular = value.getRGBComponents(null);
}
/**
* Get position
*
* @return Position
*/
public float[] getPosition() {
return this.position;
}
/**
* Set position
*
* @param value Position
*/
public void setPosition(float[] value) {
this.position = value;
}
/**
* Set position
*
* @param value Position
*/
public void setPosition(List value) {
if (value.size() < 4) {
return;
}
this.position = new float[]{(float) value.get(0), (float) value.get(1), (float) value.get(2),
(float) value.get(3)};
}
/**
* Set material ambient light
* @param value Material ambient light
*/
public void setMat_Ambient(float[] value) {
this.mat_ambient = value;
}
/**
* Set material ambient light
*
* @param value Material ambient light
*/
public void setMat_Ambient(List value) {
if (value.size() < 4) {
return;
}
this.mat_ambient = new float[]{(float) value.get(0), (float) value.get(1), (float) value.get(2),
(float) value.get(3)};
}
/**
* Set material specular light
* @param value Material specular light
*/
public void setMat_Specular(float[] value) {
this.mat_specular = value;
}
/**
* Set material specular light
*
* @param value Material specular light
*/
public void setMat_Specular(List value) {
if (value.size() < 4) {
return;
}
this.mat_specular = new float[]{(float) value.get(0), (float) value.get(1), (float) value.get(2),
(float) value.get(3)};
}
/**
* Set material shininess
* @param value Material shininess
*/
public void setMat_Shininess(float value) {
this.mat_shininess = value;
}
/**
* Start the lighting
*
* @param gl GL2
*/
public void start(GL2 gl) {
gl.glEnable(GL2.GL_LIGHTING);
gl.glEnable(this.light);
gl.glEnable(GL2.GL_DEPTH_TEST);
gl.glLightfv(this.light, GL2.GL_AMBIENT, ambient, 0);
gl.glLightfv(this.light, GL2.GL_SPECULAR, specular, 0);
gl.glLightfv(this.light, GL2.GL_DIFFUSE, diffuse, 0);
gl.glLightfv(this.light, GL2.GL_POSITION, position, 0);
//Material
gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_AMBIENT, mat_ambient, 0);
//gl.glMaterialfv(GL2.GL_FRONT, GL2.GL_SPECULAR, mat_specular, 0);
//gl.glMaterialf(GL2.GL_FRONT, GL2.GL_SHININESS, mat_shininess);
}
/**
* Stop light
* @param gl GL2
*/
public void stop(GL2 gl) {
gl.glDisable(GL2.GL_LIGHTING);
gl.glDisable(GL2.GL_LIGHT0);
}
}

View File

@ -99,6 +99,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
private int height;
float tickSpace = 5.0f;
float tickLen = 0.08f;
private Lighting lighting = new Lighting();
// </editor-fold>
// <editor-fold desc="Constructor">
@ -193,7 +194,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
public void setLineBoxColor(Color value) {
this.lineboxColor = value;
}
/**
* Get if draw bounding box or not
*
@ -211,8 +212,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
public void setDrawBoundingBox(boolean value) {
this.drawBoundingBox = value;
}
/**
* Set display X/Y axis or not
*
@ -557,6 +557,24 @@ public class Plot3DGL extends Plot implements GLEventListener {
this.zAxis.setMinMaxValue(min, max);
}
/**
* Get lighting set
*
* @return Lighting set
*/
public Lighting getLighting() {
return this.lighting;
}
/**
* Set lighting set
*
* @param value Lighting set
*/
public void setLighting(Lighting value) {
this.lighting = value;
}
// </editor-fold>
// <editor-fold desc="methods">
/**
@ -702,7 +720,12 @@ public class Plot3DGL extends Plot implements GLEventListener {
this.updateMatrix(gl);
this.drawLegend(gl);
gl.glFlush();
gl.glFlush();
//Set lighting
if (this.lighting != null && this.lighting.isEnable()) {
this.lighting.start(gl);
}
}
/**
@ -749,7 +772,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
return (float) Math.sqrt(Math.pow(sx2 - sx1, 2) + Math.pow(sy2 - sy1, 2));
}
private float toScreenAngle(float x1, float y1, float z1, float x2, float y2, float z2) {
float[] coord = toScreen(x1, y1, z1);
float sx1 = coord[0];
@ -758,7 +781,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
float sx2 = coord[0];
float sy2 = coord[1];
return (float) MeteoMath.uv2ds(sx2 - sx1, sy2 - sy1)[0];
return (float) MeteoMath.uv2ds(sx2 - sx1, sy2 - sy1)[0];
}
private int getLabelGap(Font font, List<ChartText> labels, double len) {
@ -937,8 +960,9 @@ public class Plot3DGL extends Plot implements GLEventListener {
float angle = this.toScreenAngle(-1.0f, y, -1.0f, 1.0f, y, -1.0f);
angle = y < 0 ? 270 - angle : 90 - angle;
float yShift = Math.min(-strWidth, -strWidth);
if (this.angleX <= -120)
if (this.angleX <= -120) {
yShift = -yShift;
}
drawString(gl, label, 0.0f, y1, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
}
@ -1023,13 +1047,14 @@ public class Plot3DGL extends Plot implements GLEventListener {
//Draw y axis label
label = this.yAxis.getLabel();
if (label != null) {
if (label != null) {
strWidth += this.tickSpace;
float angle = this.toScreenAngle(x, -1.0f, -1.0f, x, 1.0f, -1.0f);
angle = x > 0 ? 270 - angle : 90 - angle;
float yShift = Math.min(-strWidth, -strWidth);
if (this.angleX <= -120)
if (this.angleX <= -120) {
yShift = -yShift;
}
drawString(gl, label, x1, 0.0f, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
}
}
@ -1150,14 +1175,14 @@ public class Plot3DGL extends Plot implements GLEventListener {
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
XAlign xAlign, YAlign yAlign, float xShift, float yShift) {
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx,
vy, vz, xAlign, yAlign, xShift, yShift);
vy, vz, xAlign, yAlign, xShift, yShift);
}
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
XAlign xAlign, YAlign yAlign) {
return drawString(gl, str, font, color, vx, vy, vz, xAlign, yAlign, 0, 0);
}
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
XAlign xAlign, YAlign yAlign, float xShift, float yShift) {
//Get screen coordinates
@ -1192,23 +1217,23 @@ public class Plot3DGL extends Plot implements GLEventListener {
return rect;
}
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
XAlign xAlign, YAlign yAlign, float angle) {
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx, vy, vz, xAlign, yAlign, angle, 0, 0);
}
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
XAlign xAlign, YAlign yAlign, float angle, float xShift, float yShift) {
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx, vy,
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx, vy,
vz, xAlign, yAlign, angle, xShift, yShift);
}
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
XAlign xAlign, YAlign yAlign, float angle) {
return drawString(gl, str, font, color, vx, vy, vz, xAlign, yAlign, angle, 0, 0);
}
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
XAlign xAlign, YAlign yAlign, float angle, float xShift, float yShift) {
//Get screen coordinates
@ -1221,14 +1246,15 @@ public class Plot3DGL extends Plot implements GLEventListener {
textRenderer.beginRendering(this.width, this.height);
textRenderer.setColor(color);
textRenderer.setSmoothing(true);
Rectangle2D rect = textRenderer.getBounds(str.subSequence(0, str.length()));
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glPushMatrix();
gl.glTranslatef(x, y, 0.0f);
if (angle != 0) {
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
Rectangle2D rect = textRenderer.getBounds(str.subSequence(0, str.length()));
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glPushMatrix();
gl.glTranslatef(x, y, 0.0f);
if (angle != 0) {
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
}
x = 0; y = 0;
x = 0;
y = 0;
switch (xAlign) {
case CENTER:
x -= rect.getWidth() * 0.5;
@ -1247,9 +1273,9 @@ public class Plot3DGL extends Plot implements GLEventListener {
}
x += xShift;
y += yShift;
textRenderer.draw(str, (int)x, (int)y);
textRenderer.draw(str, (int) x, (int) y);
textRenderer.endRendering();
gl.glPopMatrix();
gl.glPopMatrix();
return rect;
}
@ -1273,18 +1299,25 @@ public class Plot3DGL extends Plot implements GLEventListener {
Graphic gg = graphic.getGraphicN(0);
this.drawGraphic(gl, gg);
} else {
boolean isDraw = true;
if (graphic instanceof GraphicCollection3D) {
GraphicCollection3D gg = (GraphicCollection3D) graphic;
if (gg.isAllQuads()) {
this.drawQuadsPolygons(gl, gg);
isDraw = false;
if (graphic instanceof IsosurfaceGraphics) {
this.drawIsosurface(gl, (IsosurfaceGraphics)graphic);
} else {
boolean isDraw = true;
if (graphic instanceof GraphicCollection3D) {
GraphicCollection3D gg = (GraphicCollection3D) graphic;
if (gg.isAllQuads()) {
this.drawQuadsPolygons(gl, gg);
isDraw = false;
} else if (gg.isAllTriangle()) {
this.drawTrianglePolygons(gl, gg);
isDraw = false;
}
}
}
if (isDraw) {
for (int i = 0; i < graphic.getNumGraphics(); i++) {
Graphic gg = graphic.getGraphicN(i);
this.drawGraphic(gl, gg);
if (isDraw) {
for (int i = 0; i < graphic.getNumGraphics(); i++) {
Graphic gg = graphic.getGraphicN(i);
this.drawGraphic(gl, gg);
}
}
}
}
@ -1493,6 +1526,82 @@ public class Plot3DGL extends Plot implements GLEventListener {
}
}
private void drawTrianglePolygons(GL2 gl, GraphicCollection3D graphic) {
PointZ p;
for (int i = 0; i < graphic.getNumGraphics(); i++) {
Graphic gg = graphic.getGraphicN(i);
if (extent.intersects(gg.getExtent())) {
PolygonZShape shape = (PolygonZShape) gg.getShape();
PolygonBreak pb = (PolygonBreak) gg.getLegend();
for (PolygonZ poly : (List<PolygonZ>) shape.getPolygons()) {
drawTriangle(gl, poly, pb);
}
}
}
}
private void drawTriangle(GL2 gl, PolygonZ aPG, PolygonBreak aPGB) {
PointZ p;
float[] rgba = aPGB.getColor().getRGBComponents(null);
if (aPGB.isDrawFill()) {
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
gl.glBegin(GL2.GL_TRIANGLES);
for (int i = 0; i < aPG.getOutLine().size(); i++) {
p = ((List<PointZ>) aPG.getOutLine()).get(i);
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
}
gl.glEnd();
}
if (aPGB.isDrawOutline()) {
rgba = aPGB.getOutlineColor().getRGBComponents(null);
gl.glLineWidth(aPGB.getOutlineSize());
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
gl.glBegin(GL2.GL_LINE_STRIP);
for (int i = 0; i < aPG.getOutLine().size(); i++) {
p = ((List<PointZ>) aPG.getOutLine()).get(i);
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
}
gl.glEnd();
}
}
private void drawTriangle(GL2 gl, PointZ[] points, PolygonBreak aPGB) {
PointZ p;
float[] rgba = aPGB.getColor().getRGBComponents(null);
if (aPGB.isDrawFill()) {
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
gl.glBegin(GL2.GL_TRIANGLES);
for (int i = 0; i < 3; i++) {
p = points[i];
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
}
gl.glEnd();
}
if (aPGB.isDrawOutline()) {
rgba = aPGB.getOutlineColor().getRGBComponents(null);
gl.glLineWidth(aPGB.getOutlineSize());
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
gl.glBegin(GL2.GL_LINE_STRIP);
for (int i = 0; i < 3; i++) {
p = points[i];
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
}
gl.glEnd();
}
}
private void drawIsosurface(GL2 gl, IsosurfaceGraphics isosurface) {
List<PointZ[]> triangles = isosurface.getTriangles();
PolygonBreak pgb = (PolygonBreak)isosurface.getLegendBreak();
//this.lighting.setEnable(true);
this.lighting.setMat_Ambient(pgb.getColor().getRGBComponents(null));
for (PointZ[] triangle : triangles) {
this.drawTriangle(gl, triangle, pgb);
}
}
private void drawImage(GL2 gl, Graphic graphic) {
ImageShape ishape = (ImageShape) graphic.getShape();
BufferedImage image = ishape.getImage();
@ -1697,7 +1806,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
caption = tLabels.get(idx);
}
if (ls.getLegendType() == LegendType.UniqueValue) {
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
x + lWidth, yy + barHeight * 0.5f, 0, XAlign.LEFT, YAlign.CENTER, 5, 0);
} else {
rgba = Color.black.getRGBComponents(null);
@ -1707,10 +1816,10 @@ public class Plot3DGL extends Plot implements GLEventListener {
gl.glVertex2f(x + lWidth * 0.5f, yy + barHeight);
gl.glVertex2f(x + lWidth, yy + barHeight);
gl.glEnd();
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
x + lWidth, yy + barHeight, 0, XAlign.LEFT, YAlign.CENTER, 5, 0);
}
idx += 1;
}
yy += barHeight;

View File

@ -0,0 +1,799 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl.mc;
import java.io.*;
import java.util.ArrayList;
/**
* Created by Primoz on 11. 07. 2016.
*/
public class BenchmarkHandler {
public static void benchmarkChar(File inputFile, File outFile, final int[] size, final float voxSize[], final char isoValue, int nThreadsMin, int nThreadsMax, int iterations) {
char[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new char[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = (char) in.readByte();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldChar(size);
}
final char[] finalScalarField = scalarField;
System.out.println("PROGRESS: Performing benchmark.");
StringBuilder benchmarkResults = new StringBuilder();
for (int nThreads = nThreadsMin; nThreads <= nThreadsMax; nThreads++) {
final ArrayList<Double> times = new ArrayList<>();
for (int it = 0; it < iterations; it++) {
// TIMER
final long start = System.currentTimeMillis();
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesChar(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Time measurement
long end= System.currentTimeMillis();
times.add((end - start) / 1000.0);
}
double sumTime = 0.0, avgTime;
for (int i = 0; i < times.size(); i++) {
sumTime += times.get(i);
}
// Average time
avgTime = sumTime / iterations;
// Standard deviation
double sd = 0;
for (int i = 0; i < times.size(); i++) {
sd += Math.pow((times.get(i) - avgTime), 2);
}
sd = Math.sqrt(sd / iterations);
System.out.println("Threads: " + nThreads);
System.out.println("Iterations: " + iterations);
System.out.println("Average time: " + avgTime + "s");
System.out.println("Standard deviation: " + sd);
System.out.println("-------------------------------------------------------------");
benchmarkResults.append("Threads: " + nThreads);
benchmarkResults.append("Iterations: " + iterations);
benchmarkResults.append("Average time: " + avgTime + "s");
benchmarkResults.append("Standard deviation: " + sd);
benchmarkResults.append("-------------------------------------------------------------");
}
System.out.println("PROGRESS: Writing results to output file.");
if (outFile != null) {
try {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outFile));
osw.write(benchmarkResults.toString());
}
catch (Exception e) {
System.out.println("Something went wrong while writing the results to file.");
return;
}
}
}
public static void benchmarkShort(File inputFile, File outFile, final int[] size, final float voxSize[], final short isoValue, int nThreadsMin, int nThreadsMax, int iterations) {
short[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new short[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readShort();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldShort(size);
}
final short[] finalScalarField = scalarField;
System.out.println("PROGRESS: Performing benchmark.");
StringBuilder benchmarkResults = new StringBuilder();
for (int nThreads = nThreadsMin; nThreads <= nThreadsMax; nThreads++) {
final ArrayList<Double> times = new ArrayList<>();
for (int it = 0; it < iterations; it++) {
// TIMER
final long start = System.currentTimeMillis();
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesShort(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Time measurement
long end= System.currentTimeMillis();
times.add((end - start) / 1000.0);
}
double sumTime = 0.0, avgTime;
for (int i = 0; i < times.size(); i++) {
sumTime += times.get(i);
}
// Average time
avgTime = sumTime / iterations;
// Standard deviation
double sd = 0;
for (int i = 0; i < times.size(); i++) {
sd += Math.pow((times.get(i) - avgTime), 2);
}
sd = Math.sqrt(sd / iterations);
System.out.println("Threads: " + nThreads);
System.out.println("Iterations: " + iterations);
System.out.println("Average time: " + avgTime + "s");
System.out.println("Standard deviation: " + sd);
System.out.println("-------------------------------------------------------------");
benchmarkResults.append("Threads: " + nThreads);
benchmarkResults.append("Iterations: " + iterations);
benchmarkResults.append("Average time: " + avgTime + "s");
benchmarkResults.append("Standard deviation: " + sd);
benchmarkResults.append("-------------------------------------------------------------");
}
System.out.println("PROGRESS: Writing results to output file.");
if (outFile != null) {
try {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outFile));
osw.write(benchmarkResults.toString());
}
catch (Exception e) {
System.out.println("Something went wrong while writing the results to file.");
return;
}
}
}
public static void benchmarkInt(File inputFile, File outFile, final int[] size, final float voxSize[], final int isoValue, int nThreadsMin, int nThreadsMax, int iterations) {
int[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new int[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readInt();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldInt(size);
}
final int[] finalScalarField = scalarField;
System.out.println("PROGRESS: Performing benchmark.");
StringBuilder benchmarkResults = new StringBuilder();
for (int nThreads = nThreadsMin; nThreads <= nThreadsMax; nThreads++) {
final ArrayList<Double> times = new ArrayList<>();
for (int it = 0; it < iterations; it++) {
// TIMER
final long start = System.currentTimeMillis();
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesInt(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Time measurement
long end= System.currentTimeMillis();
times.add((end - start) / 1000.0);
}
double sumTime = 0.0, avgTime;
for (int i = 0; i < times.size(); i++) {
sumTime += times.get(i);
}
// Average time
avgTime = sumTime / iterations;
// Standard deviation
double sd = 0;
for (int i = 0; i < times.size(); i++) {
sd += Math.pow((times.get(i) - avgTime), 2);
}
sd = Math.sqrt(sd / iterations);
System.out.println("Threads: " + nThreads);
System.out.println("Iterations: " + iterations);
System.out.println("Average time: " + avgTime + "s");
System.out.println("Standard deviation: " + sd);
System.out.println("-------------------------------------------------------------");
benchmarkResults.append("Threads: " + nThreads);
benchmarkResults.append("Iterations: " + iterations);
benchmarkResults.append("Average time: " + avgTime + "s");
benchmarkResults.append("Standard deviation: " + sd);
benchmarkResults.append("-------------------------------------------------------------");
}
System.out.println("PROGRESS: Writing results to output file.");
if (outFile != null) {
try {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outFile));
osw.write(benchmarkResults.toString());
}
catch (Exception e) {
System.out.println("Something went wrong while writing the results to file.");
return;
}
}
}
public static void benchmarkFloat(File inputFile, File outFile, final int[] size, final float voxSize[], final float isoValue, final int nThreadsMin, int nThreadsMax, int iterations) {
float[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new float[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readFloat();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldFloat(size);
}
final float[] finalScalarField = scalarField;
System.out.println("PROGRESS: Performing benchmark.");
StringBuilder benchmarkResults = new StringBuilder();
for (int nThreads = nThreadsMin; nThreads <= nThreadsMax; nThreads++) {
final ArrayList<Double> times = new ArrayList<>();
for (int it = 0; it < iterations; it++) {
// TIMER
final long start = System.currentTimeMillis();
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesFloat(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Time measurement
long end= System.currentTimeMillis();
times.add((end - start) / 1000.0);
}
double sumTime = 0.0, avgTime;
for (int i = 0; i < times.size(); i++) {
sumTime += times.get(i);
}
// Average time
avgTime = sumTime / iterations;
// Standard deviation
double sd = 0;
for (int i = 0; i < times.size(); i++) {
sd += Math.pow((times.get(i) - avgTime), 2);
}
sd = Math.sqrt(sd / iterations);
System.out.println("Threads: " + nThreads);
System.out.println("Iterations: " + iterations);
System.out.println("Average time: " + avgTime + "s");
System.out.println("Standard deviation: " + sd);
System.out.println("-------------------------------------------------------------");
benchmarkResults.append("Threads: " + nThreads);
benchmarkResults.append("Iterations: " + iterations);
benchmarkResults.append("Average time: " + avgTime + "s");
benchmarkResults.append("Standard deviation: " + sd);
benchmarkResults.append("-------------------------------------------------------------");
}
System.out.println("PROGRESS: Writing results to output file.");
if (outFile != null) {
try {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outFile));
osw.write(benchmarkResults.toString());
}
catch (Exception e) {
System.out.println("Something went wrong while writing the results to file.");
return;
}
}
}
public static void benchmarkDouble(File inputFile, File outFile, final int[] size, final float voxSize[], final double isoValue, int nThreadsMin, int nThreadsMax, int iterations) {
double[] scalarField;
if (inputFile != null) {
try {
int idx = 0;
scalarField = new double[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readDouble();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldDouble(size);
}
final double[] finalScalarField = scalarField;
System.out.println("PROGRESS: Performing benchmark.");
StringBuilder benchmarkResults = new StringBuilder();
for (int nThreads = nThreadsMin; nThreads <= nThreadsMax; nThreads++) {
final ArrayList<Double> times = new ArrayList<>();
for (int it = 0; it < iterations; it++) {
// TIMER
final long start = System.currentTimeMillis();
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesDouble(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Time measurement
long end= System.currentTimeMillis();
times.add((end - start) / 1000.0);
}
double sumTime = 0.0, avgTime;
for (int i = 0; i < times.size(); i++) {
sumTime += times.get(i);
}
// Average time
avgTime = sumTime / iterations;
// Standard deviation
double sd = 0;
for (int i = 0; i < times.size(); i++) {
sd += Math.pow((times.get(i) - avgTime), 2);
}
sd = Math.sqrt(sd / iterations);
System.out.println("Threads: " + nThreads);
System.out.println("Iterations: " + iterations);
System.out.println("Average time: " + avgTime + "s");
System.out.println("Standard deviation: " + sd);
System.out.println("-------------------------------------------------------------");
benchmarkResults.append("Threads: " + nThreads);
benchmarkResults.append("Iterations: " + iterations);
benchmarkResults.append("Average time: " + avgTime + "s");
benchmarkResults.append("Standard deviation: " + sd);
benchmarkResults.append("-------------------------------------------------------------");
}
System.out.println("PROGRESS: Writing results to output file.");
if (outFile != null) {
try {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outFile));
osw.write(benchmarkResults.toString());
}
catch (Exception e) {
System.out.println("Something went wrong while writing the results to file.");
return;
}
}
}
}

View File

@ -0,0 +1,23 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl.mc;
import java.util.ArrayList;
/**
* Created by Primoz on 8.7.2016.
*/
abstract class CallbackMC implements Runnable {
private ArrayList<float []> vertices;
void setVertices(ArrayList<float []> vertices) {
this.vertices = vertices;
}
ArrayList<float []> getVertices() {
return this.vertices;
}
}

View File

@ -0,0 +1,537 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl.mc;
import java.io.*;
import java.util.ArrayList;
/**
* Created by Primoz on 11. 07. 2016.
*/
public class ExtractHandler {
public static void extractHandlerChar(File inputFile, File outFile, final int[] size, final float voxSize[], final char isoValue, int nThreads) {
char[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new char[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = (char) in.readByte();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldChar(size);
}
final char[] finalScalarField = scalarField;
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
System.out.println("PROGRESS: Executing marching cubes.");
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesChar(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("PROGRESS: Writing results to output file.");
outputToFile(results, outFile);
}
public static void extractHandlerShort(File inputFile, File outFile, final int[] size, final float voxSize[], final short isoValue, int nThreads) {
short[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new short[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readShort();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldShort(size);
}
final short[] finalScalarField = scalarField;
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
System.out.println("PROGRESS: Executing marching cubes.");
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesShort(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("PROGRESS: Writing results to output file.");
outputToFile(results, outFile);
}
public static void extractHandlerInt(File inputFile, File outFile, final int[] size, final float voxSize[], final int isoValue, int nThreads) {
int[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new int[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readInt();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldInt(size);
}
final int[] finalScalarField = scalarField;
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
System.out.println("PROGRESS: Executing marching cubes.");
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesInt(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
System.out.println("PROGRESS: Reading input data.");
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("PROGRESS: Writing results to output file.");
outputToFile(results, outFile);
}
public static void extractHandlerFloat(File inputFile, File outFile, final int[] size, final float voxSize[], final float isoValue, final int nThreads) {
float[] scalarField;
if (inputFile != null) {
System.out.println("PROGRESS: Reading input data.");
try {
int idx = 0;
scalarField = new float[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readFloat();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldFloat(size);
}
final float[] finalScalarField = scalarField;
// TIMER
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
System.out.println("PROGRESS: Executing marching cubes.");
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesFloat(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("PROGRESS: Writing results to output file.");
outputToFile(results, outFile);
}
public static void extractHandlerDouble(File inputFile, File outFile, final int[] size, final float voxSize[], final double isoValue, int nThreads) {
double[] scalarField;
if (inputFile != null) {
try {
int idx = 0;
scalarField = new double[size[0] * size[1] * size[2]];
DataInputStream in = new DataInputStream(new FileInputStream(inputFile));
while (in.available() > 0) {
// Size does not match
if (idx >= scalarField.length) {
in.close();
System.out.println("Invalid volume size was specified.");
return;
}
scalarField[idx++] = in.readDouble();
}
in.close();
// Size does not match
if (idx != scalarField.length) {
System.out.println("Invalid volume size was specified.");
return;
}
}
catch (Exception e) {
System.out.println("Something went wrong while reading the volume");
return;
}
}
else {
System.out.println("PROGRESS: Generating volume data.");
scalarField = VolumeGenerator.generateScalarFieldDouble(size);
}
final double[] finalScalarField = scalarField;
// TIMER
ArrayList<Thread> threads = new ArrayList<>();
final ArrayList<ArrayList<float []>> results = new ArrayList<>();
// Thread work distribution
int remainder = size[2] % nThreads;
int segment = size[2] / nThreads;
// Z axis offset for vertice position calculation
int zAxisOffset = 0;
System.out.println("PROGRESS: Executing marching cubes.");
for (int i = 0; i < nThreads; i++) {
// Distribute remainder among first (remainder) threads
int segmentSize = (remainder-- > 0) ? segment + 1 : segment;
// Padding needs to be added to correctly close the gaps between segments
final int paddedSegmentSize = (i != nThreads - 1) ? segmentSize + 1 : segmentSize;
// Finished callback
final CallbackMC callback = new CallbackMC() {
@Override
public void run() {
results.add(getVertices());
}
};
// Java...
final int finalZAxisOffset = zAxisOffset;
// Start the thread
Thread t = new Thread() {
public void run() {
MarchingCubes.marchingCubesDouble(finalScalarField, new int[]{size[0], size[1], paddedSegmentSize}, size[2], voxSize, isoValue, finalZAxisOffset, callback);
}
};
threads.add(t);
t.start();
// Correct offsets for next iteration
zAxisOffset += segmentSize;
}
// Join the threads
for (int i = 0; i <threads.size(); i ++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("PROGRESS: Writing results to output file.");
outputToFile(results, outFile);
}
private static void outputToFile(ArrayList<ArrayList<float[]>> results, File outFile) {
try {
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(outFile));
int idx = 0;
for (int i = 0; i < results.size(); i++) {
ArrayList<float[]> resSeg = results.get(i);
for (int j = 0; j < resSeg.size(); j++) {
if (idx % 3 == 0) {
stream.write(("f " + (idx + 1) + " " + (idx + 2) + " " + (idx + 3) + "\n").getBytes());
}
idx ++;
stream.write(("v " + resSeg.get(j)[0] + " " + resSeg.get(j)[1] + " " + resSeg.get(j)[2] + "\n").getBytes());
}
}
stream.flush();
stream.close();
}
catch (Exception e) {
System.out.println("Something went wrong while writing to the output file");
return;
}
}
}

View File

@ -0,0 +1,287 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl.mc;
import java.io.File;
public class Main {
private static String usage = "This script may be executed in either benchmark or extract mode. Mode is specified by the first parameter [benchmark, extract].\nParameters: \n\t-input-vol\t Specifies path to the input volume. If this parameter is set volume dimensions(-vol-dim), data type(-data-type) and iso value(-iso) must also be given.\n\t-vol-dim\t Specifies the generated/read volume dimensions. Dimensions should be given as unsigned integers in format; -vol-dim X Y Z.\n\t-data-type\t Specifies the input file or generated data type. Options [char, uchar, short, ushort, int, uint, float, double].\n\t-vox-dim\t Specifies voxel dimensions used in mesh construction. Dimensions should be given as floating point numbers in format: -vox-dim X Y Z.\n\t-nThread\t Number of threads used in Marching cubes algorithm.This parameter can be either given as a single unsigned integer value or two unsigned integer values in benchmark mode, specifying the range of thread executions that will be tested.\n\t-iter\t\t Used only in benchmark mode to determine how many iterations should be executed for each configuration.\n\t-iso\t\t Isovalue that is used as a threshold for determining active voxels. Type should match the data type.\n\t-o\t\t Path to output file. In extract mode the mesh is written to file in .obj format [required]. In benchmark mode the results are written to file.\n";;
private static boolean isUint (String input) {
try {
return (Integer.parseInt(input) >= 0);
} catch (NumberFormatException e) {
return false;
}
}
private static boolean isFloat (String input) {
try {
Float.parseFloat(input);
return true;
} catch (NumberFormatException e) {
return false;
}
}
public static void main(String[] args) {
if (args.length < 1) {
System.out.println(usage);
return;
} else if (args[0].equals("-help")) {
System.out.println(usage);
}
// Benchmark or extract mode
boolean benchmark = false;
// Default num of threads is max available
int nThreadsMin = java.lang.Thread.activeCount();
if (nThreadsMin == 0) {
nThreadsMin = 1;
}
int nThreadsMax = nThreadsMin;
File inputFile = null;
File outFile = null;
String type = null;
String isoValueStr = null;
int iterations = 10; // Default 10 iterations per benchmark
boolean customSizeSpecified = false;
int[] size = {64, 64, 64};
float[] voxSize = {1.0f, 1.0f, 1.0f};
//region PARAMETER PARSING
// Read execution type
if (args[0].equals("benchmark")) {
benchmark = true;
} else if (!args[0].equals("extract")) {
System.out.println("Invalid execution type. Valid options [extract, benchmark]");
return;
}
// Flag parsing
for (int i = 1; i < args.length; i++) {
if (args[i].equals("-input-vol")) {
// Volume path specified
// Output file path is specified
if (i + 1 >= args.length || args[i + 1].charAt(0) == '-') {
System.out.println("Missing file path after -input-vol flag.");
return;
}
// Store the file name and offset iterator
inputFile = new File(args[++i]);
if (!inputFile.exists() || inputFile.isDirectory()) {
System.out.println("Specified volume file does not exist.");
return;
}
} else if (args[i].equals("-vol-dim")) {
// Volume dimensions are given
if (i + 3 >= args.length || args[i + 1].charAt(0) == '-' || args[i + 2].charAt(0) == '-' || args[i + 3].charAt(0) == '-') {
System.out.println("Missing volume dimensions after -vol-dim flag.");
return;
}
String x = (args[++i]);
String y = (args[++i]);
String z = (args[++i]);
if (!isUint(x) || !isUint(y) || !isUint(z)) {
System.out.println("Invalid volume dimensions format. Specify dimensions as three unsigned integers.");
return;
}
customSizeSpecified = true;
size[0] = Integer.parseInt(x);
size[1] = Integer.parseInt(y);
size[2] = Integer.parseInt(z);
} else if (args[i].equals("-vox-dim")) {
// Voxel dimensions are given
if (i + 3 >= args.length) {
System.out.println("Missing voxel dimensions after -vox-dim flag.");
return;
}
String x = args[++i];
String y = args[++i];
String z = args[++i];
if (!isFloat(x) || !isFloat(y) || !isFloat(z)) {
System.out.println("Invalid voxel dimensions format. Specify voxel dimensions as three positive floats.");
return;
}
voxSize[0] = Float.parseFloat(x);
voxSize[0] = Float.parseFloat(y);
voxSize[0] = Float.parseFloat(z);
} else if (args[i].equals("-nThread")) {
// Number of threads is given
// FIRST VALUE
if (i + 1 >= args.length || args[i + 1].charAt(0) == '-') {
System.out.println("Missing number or range of threads after -nThread flag.");
return;
}
// Validate first number
String tmp = args[++i];
if (!isUint(tmp)) {
System.out.println("Invalid nThread value format. Specify unsigned integer value or two if range.");
return;
}
// Parse C-str
nThreadsMin = Integer.parseInt(tmp);
// SECOND VALUE (If given)
if (i + 1 < args.length && args[i + 1].charAt(0) != '-') {
// Validate second number
tmp = args[++i];
if (!isUint(tmp)) {
System.out.println("Invalid nThread value format. Specify unsigned integer value or two if range.");
return;
}
// Parse C-str
nThreadsMax = Integer.parseInt(tmp);
} else {
nThreadsMax = nThreadsMin;
}
} else if (args[i].equals("-iso")) {
// ISO value is given
if (i + 1 >= args.length) {
System.out.println("Missing iso value after -iso flag.");
return;
}
isoValueStr = args[++i];
if (!isFloat(isoValueStr)) {
System.out.println("Invalid iso value format. Please specify float.");
return;
}
} else if (args[i].equals("-iter")) {
// ISO value is given
if (i + 1 >= args.length) {
System.out.println("Missing number of iterations after -iter flag.");
return;
}
String iterationsStr = args[++i];
if (!isUint(iterationsStr)) {
System.out.println("Invalid iterations value format. Please specify unsigned integer.");
return;
}
iterations = Integer.parseInt(iterationsStr);
} else if (args[i].equals("-o")) {
// Output file path is specified
if (i + 1 >= args.length || args[i + 1].charAt(0) == '-') {
System.out.println("Missing file path after -o flag.");
return;
}
// Store the file name and offset iterator
outFile = new File(args[++i]);
if (outFile.getParentFile() != null && !outFile.getParentFile().exists()) {
System.out.println("Specified output file path is invaild.");
}
} else if (args[i].equals("-data-type")) {
// Volume data type is specified
if (i + 1 >= args.length || args[i + 1].charAt(0) == '-') {
System.out.println("Missing type after -data-type flag.");
return;
}
// Data type is specified (char, uchar, short, ushort, int, uint, float, double)
if (!args[i + 1].equals("char") && !args[i + 1].equals("uchar") && !args[i + 1].equals("short") && !args[i + 1].equals("ushort") && args[i + 1].equals("uint") && args[i + 1].equals("float") && args[i + 1].equals("double")) {
System.out.println("Invalid data type. Available data types: char, uchar, short, ushort, int, uint, float, double.");
return;
}
type = args[++i];
} else {
System.out.println("Unknown parameter: " + args[i]);
return;
}
}
if (inputFile != null && (!customSizeSpecified || type == null || isoValueStr == null)) {
System.out.println("If custom volume is imported, you must input volume dimensions(-vol-dim), data type (-data-type) and iso value (-iso).");
return;
}
//endregion
if (benchmark) {
switch (type) {
case "char":
BenchmarkHandler.benchmarkChar(inputFile, outFile, size, voxSize, (char) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMin, nThreadsMax, iterations);
break;
case "uchar":
BenchmarkHandler.benchmarkChar(inputFile, outFile, size, voxSize, (char) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMin, nThreadsMax, iterations);
break;
case "short":
BenchmarkHandler.benchmarkShort(inputFile, outFile, size, voxSize, (short) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMin, nThreadsMax, iterations);
break;
case "ushort":
BenchmarkHandler.benchmarkShort(inputFile, outFile, size, voxSize, (short) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMin, nThreadsMax, iterations);
break;
case "int":
BenchmarkHandler.benchmarkInt(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0), nThreadsMin, nThreadsMax, iterations);
break;
case "uint":
BenchmarkHandler.benchmarkInt(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0), nThreadsMin, nThreadsMax, iterations);
break;
case "float":
BenchmarkHandler.benchmarkFloat(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Float.parseFloat(isoValueStr) : 0.5f), nThreadsMin, nThreadsMax, iterations);
break;
case "double":
BenchmarkHandler.benchmarkDouble(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Double.parseDouble(isoValueStr) : 0.5), nThreadsMin, nThreadsMax, iterations);
break;
}
} else {
if (outFile == null) {
System.out.println("To extract the data the output file path is needed (-o).");
return;
}
switch (type) {
case "char":
ExtractHandler.extractHandlerChar(inputFile, outFile, size, voxSize, (char) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMax);
break;
case "uchar":
ExtractHandler.extractHandlerChar(inputFile, outFile, size, voxSize, (char) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMax);
break;
case "short":
ExtractHandler.extractHandlerShort(inputFile, outFile, size, voxSize, (short) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMax);
break;
case "ushort":
ExtractHandler.extractHandlerShort(inputFile, outFile, size, voxSize, (short) ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0.5), nThreadsMax);
break;
case "int":
ExtractHandler.extractHandlerInt(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0), nThreadsMax);
break;
case "uint":
ExtractHandler.extractHandlerInt(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Integer.parseInt(isoValueStr) : 0), nThreadsMax);
break;
case "float":
ExtractHandler.extractHandlerFloat(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Float.parseFloat(isoValueStr) : 0.5f), nThreadsMax);
break;
case "double":
ExtractHandler.extractHandlerDouble(inputFile, outFile, size, voxSize, ((isoValueStr != null) ? Double.parseDouble(isoValueStr) : 0.5), nThreadsMax);
break;
}
}
}
}

View File

@ -0,0 +1,928 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl.mc;
import java.util.ArrayList;
import org.meteoinfo.ndarray.Array;
/**
* Created by Primoz on 11. 07. 2016.
*/
public class MarchingCubes {
static float[] lerp(float[] vec1, float[] vec2, float alpha){
return new float[]{vec1[0] + (vec2[0] - vec1[0]) * alpha, vec1[1] + (vec2[1] - vec1[1]) * alpha, vec1[2] + (vec2[2] - vec1[2]) * alpha};
}
static void marchingCubesChar(char[] values, int[] volDim, int volZFull, float[] voxDim, char isoLevel, int offset, CallbackMC callback) {
ArrayList<float[]> vertices = new ArrayList<>();
// Actual position along edge weighted according to function values.
float vertList[][] = new float[12][3];
// Calculate maximal possible axis value (used in vertice normalization)
float maxX = voxDim[0] * (volDim[0] - 1);
float maxY = voxDim[1] * (volDim[1] - 1);
float maxZ = voxDim[2] * (volZFull - 1);
float maxAxisVal = Math.max(maxX, Math.max(maxY, maxZ));
// Volume iteration
for (int z = 0; z < volDim[2] - 1; z++) {
for (int y = 0; y < volDim[1] - 1; y++) {
for (int x = 0; x < volDim[0] - 1; x++) {
// Indices pointing to cube vertices
// pyz ___________________ pxyz
// /| /|
// / | / |
// / | / |
// pz /___|______________/pxz|
// | | | |
// | | | |
// | py |______________|___| pxy
// | / | /
// | / | /
// | / | /
// |/__________________|/
// p px
int p = x + (volDim[0] * y) + (volDim[0] * volDim[1] * (z + offset)),
px = p + 1,
py = p + volDim[0],
pxy = py + 1,
pz = p + volDim[0] * volDim[1],
pxz = px + volDim[0] * volDim[1],
pyz = py + volDim[0] * volDim[1],
pxyz = pxy + volDim[0] * volDim[1];
// X Y Z
float position[] = new float[]{x * voxDim[0], y * voxDim[1], (z + offset) * voxDim[2]};
// Voxel intensities
char value0 = values[p],
value1 = values[px],
value2 = values[py],
value3 = values[pxy],
value4 = values[pz],
value5 = values[pxz],
value6 = values[pyz],
value7 = values[pxyz];
// Voxel is active if its intensity is above isolevel
int cubeindex = 0;
if (value0 > isoLevel) cubeindex |= 1;
if (value1 > isoLevel) cubeindex |= 2;
if (value2 > isoLevel) cubeindex |= 8;
if (value3 > isoLevel) cubeindex |= 4;
if (value4 > isoLevel) cubeindex |= 16;
if (value5 > isoLevel) cubeindex |= 32;
if (value6 > isoLevel) cubeindex |= 128;
if (value7 > isoLevel) cubeindex |= 64;
// Fetch the triggered edges
int bits = TablesMC.MC_EDGE_TABLE[cubeindex];
// If no edge is triggered... skip
if (bits == 0) continue;
// Interpolate the positions based od voxel intensities
float mu = 0.5f;
// bottom of the cube
if ((bits & 1) != 0) {
mu = (isoLevel - value0) / (value1 - value0);
vertList[0] = lerp(position, new float[]{position[0] + voxDim[0], position[1], position[2]}, mu);
}
if ((bits & 2) != 0) {
mu = (isoLevel - value1) / (value3 - value1);
vertList[1] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 4) != 0) {
mu = (isoLevel - value2) / (value3 - value2);
vertList[2] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 8) != 0) {
mu = (isoLevel - value0) / (value2 - value0);
vertList[3] = lerp(position, new float[]{position[0], position[1] + voxDim[1], position[2]}, mu);
}
// top of the cube
if ((bits & 16) != 0) {
mu = (isoLevel - value4) / (value5 - value4);
vertList[4] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 32) != 0) {
mu = (isoLevel - value5) / (value7 - value5);
vertList[5] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 64) != 0) {
mu = (isoLevel - value6) / (value7 - value6);
vertList[6] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 128) != 0) {
mu = (isoLevel - value4) / (value6 - value4);
vertList[7] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// vertical lines of the cube
if ((bits & 256) != 0) {
mu = (isoLevel - value0) / (value4 - value0);
vertList[8] = lerp(position, new float[]{position[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 512) != 0) {
mu = (isoLevel - value1) / (value5 - value1);
vertList[9] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 1024) != 0) {
mu = (isoLevel - value3) / (value7 - value3);
vertList[10] = lerp(new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1]+ voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 2048) != 0) {
mu = (isoLevel - value2) / (value6 - value2);
vertList[11] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// construct triangles -- get correct vertices from triTable.
int i = 0;
// "Re-purpose cubeindex into an offset into triTable."
cubeindex <<= 4;
while (TablesMC.MC_TRI_TABLE[cubeindex + i] != -1) {
int index1 = TablesMC.MC_TRI_TABLE[cubeindex + i];
int index2 = TablesMC.MC_TRI_TABLE[cubeindex + i + 1];
int index3 = TablesMC.MC_TRI_TABLE[cubeindex + i + 2];
// Add triangles vertices normalized with the maximal possible value
vertices.add(new float[] {vertList[index3][0] / maxAxisVal - 0.5f, vertList[index3][1] / maxAxisVal - 0.5f, vertList[index3][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index2][0] / maxAxisVal - 0.5f, vertList[index2][1] / maxAxisVal - 0.5f, vertList[index2][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index1][0] / maxAxisVal - 0.5f, vertList[index1][1] / maxAxisVal - 0.5f, vertList[index1][2] / maxAxisVal - 0.5f});
i += 3;
}
}
}
}
callback.setVertices(vertices);
callback.run();
}
static void marchingCubesShort(short[] values, int[] volDim, int volZFull, float[] voxDim, short isoLevel, int offset, CallbackMC callback) {
ArrayList<float[]> vertices = new ArrayList<>();
// Actual position along edge weighted according to function values.
float vertList[][] = new float[12][3];
// Calculate maximal possible axis value (used in vertice normalization)
float maxX = voxDim[0] * (volDim[0] - 1);
float maxY = voxDim[1] * (volDim[1] - 1);
float maxZ = voxDim[2] * (volZFull - 1);
float maxAxisVal = Math.max(maxX, Math.max(maxY, maxZ));
// Volume iteration
for (int z = 0; z < volDim[2] - 1; z++) {
for (int y = 0; y < volDim[1] - 1; y++) {
for (int x = 0; x < volDim[0] - 1; x++) {
// Indices pointing to cube vertices
// pyz ___________________ pxyz
// /| /|
// / | / |
// / | / |
// pz /___|______________/pxz|
// | | | |
// | | | |
// | py |______________|___| pxy
// | / | /
// | / | /
// | / | /
// |/__________________|/
// p px
int p = x + (volDim[0] * y) + (volDim[0] * volDim[1] * (z + offset)),
px = p + 1,
py = p + volDim[0],
pxy = py + 1,
pz = p + volDim[0] * volDim[1],
pxz = px + volDim[0] * volDim[1],
pyz = py + volDim[0] * volDim[1],
pxyz = pxy + volDim[0] * volDim[1];
// X Y Z
float position[] = new float[]{x * voxDim[0], y * voxDim[1], (z + offset) * voxDim[2]};
// Voxel intensities
short value0 = values[p],
value1 = values[px],
value2 = values[py],
value3 = values[pxy],
value4 = values[pz],
value5 = values[pxz],
value6 = values[pyz],
value7 = values[pxyz];
// Voxel is active if its intensity is above isolevel
int cubeindex = 0;
if (value0 > isoLevel) cubeindex |= 1;
if (value1 > isoLevel) cubeindex |= 2;
if (value2 > isoLevel) cubeindex |= 8;
if (value3 > isoLevel) cubeindex |= 4;
if (value4 > isoLevel) cubeindex |= 16;
if (value5 > isoLevel) cubeindex |= 32;
if (value6 > isoLevel) cubeindex |= 128;
if (value7 > isoLevel) cubeindex |= 64;
// Fetch the triggered edges
int bits = TablesMC.MC_EDGE_TABLE[cubeindex];
// If no edge is triggered... skip
if (bits == 0) continue;
// Interpolate the positions based od voxel intensities
float mu = 0.5f;
// bottom of the cube
if ((bits & 1) != 0) {
mu = (isoLevel - value0) / (value1 - value0);
vertList[0] = lerp(position, new float[]{position[0] + voxDim[0], position[1], position[2]}, mu);
}
if ((bits & 2) != 0) {
mu = (isoLevel - value1) / (value3 - value1);
vertList[1] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 4) != 0) {
mu = (isoLevel - value2) / (value3 - value2);
vertList[2] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 8) != 0) {
mu = (isoLevel - value0) / (value2 - value0);
vertList[3] = lerp(position, new float[]{position[0], position[1] + voxDim[1], position[2]}, mu);
}
// top of the cube
if ((bits & 16) != 0) {
mu = (isoLevel - value4) / (value5 - value4);
vertList[4] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 32) != 0) {
mu = (isoLevel - value5) / (value7 - value5);
vertList[5] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 64) != 0) {
mu = (isoLevel - value6) / (value7 - value6);
vertList[6] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 128) != 0) {
mu = (isoLevel - value4) / (value6 - value4);
vertList[7] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// vertical lines of the cube
if ((bits & 256) != 0) {
mu = (isoLevel - value0) / (value4 - value0);
vertList[8] = lerp(position, new float[]{position[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 512) != 0) {
mu = (isoLevel - value1) / (value5 - value1);
vertList[9] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 1024) != 0) {
mu = (isoLevel - value3) / (value7 - value3);
vertList[10] = lerp(new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1]+ voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 2048) != 0) {
mu = (isoLevel - value2) / (value6 - value2);
vertList[11] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// construct triangles -- get correct vertices from triTable.
int i = 0;
// "Re-purpose cubeindex into an offset into triTable."
cubeindex <<= 4;
while (TablesMC.MC_TRI_TABLE[cubeindex + i] != -1) {
int index1 = TablesMC.MC_TRI_TABLE[cubeindex + i];
int index2 = TablesMC.MC_TRI_TABLE[cubeindex + i + 1];
int index3 = TablesMC.MC_TRI_TABLE[cubeindex + i + 2];
// Add triangles vertices normalized with the maximal possible value
vertices.add(new float[] {vertList[index3][0] / maxAxisVal - 0.5f, vertList[index3][1] / maxAxisVal - 0.5f, vertList[index3][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index2][0] / maxAxisVal - 0.5f, vertList[index2][1] / maxAxisVal - 0.5f, vertList[index2][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index1][0] / maxAxisVal - 0.5f, vertList[index1][1] / maxAxisVal - 0.5f, vertList[index1][2] / maxAxisVal - 0.5f});
i += 3;
}
}
}
}
callback.setVertices(vertices);
callback.run();
}
static void marchingCubesInt(int[] values, int[] volDim, int volZFull, float[] voxDim, int isoLevel, int offset, CallbackMC callback) {
ArrayList<float[]> vertices = new ArrayList<>();
// Actual position along edge weighted according to function values.
float vertList[][] = new float[12][3];
// Calculate maximal possible axis value (used in vertice normalization)
float maxX = voxDim[0] * (volDim[0] - 1);
float maxY = voxDim[1] * (volDim[1] - 1);
float maxZ = voxDim[2] * (volZFull - 1);
float maxAxisVal = Math.max(maxX, Math.max(maxY, maxZ));
// Volume iteration
for (int z = 0; z < volDim[2] - 1; z++) {
for (int y = 0; y < volDim[1] - 1; y++) {
for (int x = 0; x < volDim[0] - 1; x++) {
// Indices pointing to cube vertices
// pyz ___________________ pxyz
// /| /|
// / | / |
// / | / |
// pz /___|______________/pxz|
// | | | |
// | | | |
// | py |______________|___| pxy
// | / | /
// | / | /
// | / | /
// |/__________________|/
// p px
int p = x + (volDim[0] * y) + (volDim[0] * volDim[1] * (z + offset)),
px = p + 1,
py = p + volDim[0],
pxy = py + 1,
pz = p + volDim[0] * volDim[1],
pxz = px + volDim[0] * volDim[1],
pyz = py + volDim[0] * volDim[1],
pxyz = pxy + volDim[0] * volDim[1];
// X Y Z
float position[] = new float[]{x * voxDim[0], y * voxDim[1], (z + offset) * voxDim[2]};
// Voxel intensities
int value0 = values[p],
value1 = values[px],
value2 = values[py],
value3 = values[pxy],
value4 = values[pz],
value5 = values[pxz],
value6 = values[pyz],
value7 = values[pxyz];
// Voxel is active if its intensity is above isolevel
int cubeindex = 0;
if (value0 > isoLevel) cubeindex |= 1;
if (value1 > isoLevel) cubeindex |= 2;
if (value2 > isoLevel) cubeindex |= 8;
if (value3 > isoLevel) cubeindex |= 4;
if (value4 > isoLevel) cubeindex |= 16;
if (value5 > isoLevel) cubeindex |= 32;
if (value6 > isoLevel) cubeindex |= 128;
if (value7 > isoLevel) cubeindex |= 64;
// Fetch the triggered edges
int bits = TablesMC.MC_EDGE_TABLE[cubeindex];
// If no edge is triggered... skip
if (bits == 0) continue;
// Interpolate the positions based od voxel intensities
float mu = 0.5f;
// bottom of the cube
if ((bits & 1) != 0) {
mu = (isoLevel - value0) / (value1 - value0);
vertList[0] = lerp(position, new float[]{position[0] + voxDim[0], position[1], position[2]}, mu);
}
if ((bits & 2) != 0) {
mu = (isoLevel - value1) / (value3 - value1);
vertList[1] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 4) != 0) {
mu = (isoLevel - value2) / (value3 - value2);
vertList[2] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 8) != 0) {
mu = (isoLevel - value0) / (value2 - value0);
vertList[3] = lerp(position, new float[]{position[0], position[1] + voxDim[1], position[2]}, mu);
}
// top of the cube
if ((bits & 16) != 0) {
mu = (isoLevel - value4) / (value5 - value4);
vertList[4] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 32) != 0) {
mu = (isoLevel - value5) / (value7 - value5);
vertList[5] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 64) != 0) {
mu = (isoLevel - value6) / (value7 - value6);
vertList[6] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 128) != 0) {
mu = (isoLevel - value4) / (value6 - value4);
vertList[7] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// vertical lines of the cube
if ((bits & 256) != 0) {
mu = (isoLevel - value0) / (value4 - value0);
vertList[8] = lerp(position, new float[]{position[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 512) != 0) {
mu = (isoLevel - value1) / (value5 - value1);
vertList[9] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 1024) != 0) {
mu = (isoLevel - value3) / (value7 - value3);
vertList[10] = lerp(new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1]+ voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 2048) != 0) {
mu = (isoLevel - value2) / (value6 - value2);
vertList[11] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// construct triangles -- get correct vertices from triTable.
int i = 0;
// "Re-purpose cubeindex into an offset into triTable."
cubeindex <<= 4;
while (TablesMC.MC_TRI_TABLE[cubeindex + i] != -1) {
int index1 = TablesMC.MC_TRI_TABLE[cubeindex + i];
int index2 = TablesMC.MC_TRI_TABLE[cubeindex + i + 1];
int index3 = TablesMC.MC_TRI_TABLE[cubeindex + i + 2];
// Add triangles vertices normalized with the maximal possible value
vertices.add(new float[] {vertList[index3][0] / maxAxisVal - 0.5f, vertList[index3][1] / maxAxisVal - 0.5f, vertList[index3][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index2][0] / maxAxisVal - 0.5f, vertList[index2][1] / maxAxisVal - 0.5f, vertList[index2][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index1][0] / maxAxisVal - 0.5f, vertList[index1][1] / maxAxisVal - 0.5f, vertList[index1][2] / maxAxisVal - 0.5f});
i += 3;
}
}
}
}
callback.setVertices(vertices);
callback.run();
}
static void marchingCubesFloat(float[] values, int[] volDim, int volZFull, float[] voxDim, float isoLevel, int offset, CallbackMC callback) {
ArrayList<float[]> vertices = new ArrayList<>();
// Actual position along edge weighted according to function values.
float vertList[][] = new float[12][3];
// Calculate maximal possible axis value (used in vertice normalization)
float maxX = voxDim[0] * (volDim[0] - 1);
float maxY = voxDim[1] * (volDim[1] - 1);
float maxZ = voxDim[2] * (volZFull - 1);
float maxAxisVal = Math.max(maxX, Math.max(maxY, maxZ));
// Volume iteration
for (int z = 0; z < volDim[2] - 1; z++) {
for (int y = 0; y < volDim[1] - 1; y++) {
for (int x = 0; x < volDim[0] - 1; x++) {
// Indices pointing to cube vertices
// pyz ___________________ pxyz
// /| /|
// / | / |
// / | / |
// pz /___|______________/pxz|
// | | | |
// | | | |
// | py |______________|___| pxy
// | / | /
// | / | /
// | / | /
// |/__________________|/
// p px
int p = x + (volDim[0] * y) + (volDim[0] * volDim[1] * (z + offset)),
px = p + 1,
py = p + volDim[0],
pxy = py + 1,
pz = p + volDim[0] * volDim[1],
pxz = px + volDim[0] * volDim[1],
pyz = py + volDim[0] * volDim[1],
pxyz = pxy + volDim[0] * volDim[1];
// X Y Z
float position[] = new float[]{x * voxDim[0], y * voxDim[1], (z + offset) * voxDim[2]};
// Voxel intensities
float value0 = values[p],
value1 = values[px],
value2 = values[py],
value3 = values[pxy],
value4 = values[pz],
value5 = values[pxz],
value6 = values[pyz],
value7 = values[pxyz];
// Voxel is active if its intensity is above isolevel
int cubeindex = 0;
if (value0 > isoLevel) cubeindex |= 1;
if (value1 > isoLevel) cubeindex |= 2;
if (value2 > isoLevel) cubeindex |= 8;
if (value3 > isoLevel) cubeindex |= 4;
if (value4 > isoLevel) cubeindex |= 16;
if (value5 > isoLevel) cubeindex |= 32;
if (value6 > isoLevel) cubeindex |= 128;
if (value7 > isoLevel) cubeindex |= 64;
// Fetch the triggered edges
int bits = TablesMC.MC_EDGE_TABLE[cubeindex];
// If no edge is triggered... skip
if (bits == 0) continue;
// Interpolate the positions based od voxel intensities
float mu = 0.5f;
// bottom of the cube
if ((bits & 1) != 0) {
mu = (float) ((isoLevel - value0) / (value1 - value0));
vertList[0] = lerp(position, new float[]{position[0] + voxDim[0], position[1], position[2]}, mu);
}
if ((bits & 2) != 0) {
mu = (float) ((isoLevel - value1) / (value3 - value1));
vertList[1] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 4) != 0) {
mu = (float) ((isoLevel - value2) / (value3 - value2));
vertList[2] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 8) != 0) {
mu = (float) ((isoLevel - value0) / (value2 - value0));
vertList[3] = lerp(position, new float[]{position[0], position[1] + voxDim[1], position[2]}, mu);
}
// top of the cube
if ((bits & 16) != 0) {
mu = (float) ((isoLevel - value4) / (value5 - value4));
vertList[4] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 32) != 0) {
mu = (float) ((isoLevel - value5) / (value7 - value5));
vertList[5] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 64) != 0) {
mu = (float) ((isoLevel - value6) / (value7 - value6));
vertList[6] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 128) != 0) {
mu = (float) ((isoLevel - value4) / (value6 - value4));
vertList[7] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// vertical lines of the cube
if ((bits & 256) != 0) {
mu = (float) ((isoLevel - value0) / (value4 - value0));
vertList[8] = lerp(position, new float[]{position[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 512) != 0) {
mu = (float) ((isoLevel - value1) / (value5 - value1));
vertList[9] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 1024) != 0) {
mu = (float) ((isoLevel - value3) / (value7 - value3));
vertList[10] = lerp(new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1]+ voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 2048) != 0) {
mu = (float) ((isoLevel - value2) / (value6 - value2));
vertList[11] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// construct triangles -- get correct vertices from triTable.
int i = 0;
// "Re-purpose cubeindex into an offset into triTable."
cubeindex <<= 4;
while (TablesMC.MC_TRI_TABLE[cubeindex + i] != -1) {
int index1 = TablesMC.MC_TRI_TABLE[cubeindex + i];
int index2 = TablesMC.MC_TRI_TABLE[cubeindex + i + 1];
int index3 = TablesMC.MC_TRI_TABLE[cubeindex + i + 2];
// Add triangles vertices normalized with the maximal possible value
vertices.add(new float[] {vertList[index3][0] / maxAxisVal - 0.5f, vertList[index3][1] / maxAxisVal - 0.5f, vertList[index3][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index2][0] / maxAxisVal - 0.5f, vertList[index2][1] / maxAxisVal - 0.5f, vertList[index2][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index1][0] / maxAxisVal - 0.5f, vertList[index1][1] / maxAxisVal - 0.5f, vertList[index1][2] / maxAxisVal - 0.5f});
i += 3;
}
}
}
}
callback.setVertices(vertices);
callback.run();
}
static void marchingCubesDouble(double[] values, int[] volDim, int volZFull, float[] voxDim, double isoLevel, int offset, CallbackMC callback) {
ArrayList<float[]> vertices = new ArrayList<>();
// Actual position along edge weighted according to function values.
float vertList[][] = new float[12][3];
// Calculate maximal possible axis value (used in vertice normalization)
float maxX = voxDim[0] * (volDim[0] - 1);
float maxY = voxDim[1] * (volDim[1] - 1);
float maxZ = voxDim[2] * (volZFull - 1);
float maxAxisVal = Math.max(maxX, Math.max(maxY, maxZ));
// Volume iteration
for (int z = 0; z < volDim[2] - 1; z++) {
for (int y = 0; y < volDim[1] - 1; y++) {
for (int x = 0; x < volDim[0] - 1; x++) {
// Indices pointing to cube vertices
// pyz ___________________ pxyz
// /| /|
// / | / |
// / | / |
// pz /___|______________/pxz|
// | | | |
// | | | |
// | py |______________|___| pxy
// | / | /
// | / | /
// | / | /
// |/__________________|/
// p px
int p = x + (volDim[0] * y) + (volDim[0] * volDim[1] * (z + offset)),
px = p + 1,
py = p + volDim[0],
pxy = py + 1,
pz = p + volDim[0] * volDim[1],
pxz = px + volDim[0] * volDim[1],
pyz = py + volDim[0] * volDim[1],
pxyz = pxy + volDim[0] * volDim[1];
// X Y Z
float position[] = new float[]{x * voxDim[0], y * voxDim[1], (z + offset) * voxDim[2]};
// Voxel intensities
double value0 = values[p],
value1 = values[px],
value2 = values[py],
value3 = values[pxy],
value4 = values[pz],
value5 = values[pxz],
value6 = values[pyz],
value7 = values[pxyz];
// Voxel is active if its intensity is above isolevel
int cubeindex = 0;
if (value0 > isoLevel) cubeindex |= 1;
if (value1 > isoLevel) cubeindex |= 2;
if (value2 > isoLevel) cubeindex |= 8;
if (value3 > isoLevel) cubeindex |= 4;
if (value4 > isoLevel) cubeindex |= 16;
if (value5 > isoLevel) cubeindex |= 32;
if (value6 > isoLevel) cubeindex |= 128;
if (value7 > isoLevel) cubeindex |= 64;
// Fetch the triggered edges
int bits = TablesMC.MC_EDGE_TABLE[cubeindex];
// If no edge is triggered... skip
if (bits == 0) continue;
// Interpolate the positions based od voxel intensities
float mu = 0.5f;
// bottom of the cube
if ((bits & 1) != 0) {
mu = (float) ((isoLevel - value0) / (value1 - value0));
vertList[0] = lerp(position, new float[]{position[0] + voxDim[0], position[1], position[2]}, mu);
}
if ((bits & 2) != 0) {
mu = (float) ((isoLevel - value1) / (value3 - value1));
vertList[1] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 4) != 0) {
mu = (float) ((isoLevel - value2) / (value3 - value2));
vertList[2] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, mu);
}
if ((bits & 8) != 0) {
mu = (float) ((isoLevel - value0) / (value2 - value0));
vertList[3] = lerp(position, new float[]{position[0], position[1] + voxDim[1], position[2]}, mu);
}
// top of the cube
if ((bits & 16) != 0) {
mu = (float) ((isoLevel - value4) / (value5 - value4));
vertList[4] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 32) != 0) {
mu = (float) ((isoLevel - value5) / (value7 - value5));
vertList[5] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 64) != 0) {
mu = (float) ((isoLevel - value6) / (value7 - value6));
vertList[6] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 128) != 0) {
mu = (float) ((isoLevel - value4) / (value6 - value4));
vertList[7] = lerp(new float[]{position[0], position[1], position[2] + voxDim[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// vertical lines of the cube
if ((bits & 256) != 0) {
mu = (float) ((isoLevel - value0) / (value4 - value0));
vertList[8] = lerp(position, new float[]{position[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 512) != 0) {
mu = (float) ((isoLevel - value1) / (value5 - value1));
vertList[9] = lerp(new float[]{position[0] + voxDim[0], position[1], position[2]}, new float[]{position[0] + voxDim[0], position[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 1024) != 0) {
mu = (float) ((isoLevel - value3) / (value7 - value3));
vertList[10] = lerp(new float[]{position[0] + voxDim[0], position[1] + voxDim[1], position[2]}, new float[]{position[0] + voxDim[0], position[1]+ voxDim[1], position[2] + voxDim[2]}, mu);
}
if ((bits & 2048) != 0) {
mu = (float) ((isoLevel - value2) / (value6 - value2));
vertList[11] = lerp(new float[]{position[0], position[1] + voxDim[1], position[2]}, new float[]{position[0], position[1] + voxDim[1], position[2] + voxDim[2]}, mu);
}
// construct triangles -- get correct vertices from triTable.
int i = 0;
// "Re-purpose cubeindex into an offset into triTable."
cubeindex <<= 4;
while (TablesMC.MC_TRI_TABLE[cubeindex + i] != -1) {
int index1 = TablesMC.MC_TRI_TABLE[cubeindex + i];
int index2 = TablesMC.MC_TRI_TABLE[cubeindex + i + 1];
int index3 = TablesMC.MC_TRI_TABLE[cubeindex + i + 2];
// Add triangles vertices normalized with the maximal possible value
vertices.add(new float[] {vertList[index3][0] / maxAxisVal - 0.5f, vertList[index3][1] / maxAxisVal - 0.5f, vertList[index3][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index2][0] / maxAxisVal - 0.5f, vertList[index2][1] / maxAxisVal - 0.5f, vertList[index2][2] / maxAxisVal - 0.5f});
vertices.add(new float[] {vertList[index1][0] / maxAxisVal - 0.5f, vertList[index1][1] / maxAxisVal - 0.5f, vertList[index1][2] / maxAxisVal - 0.5f});
i += 3;
}
}
}
}
callback.setVertices(vertices);
callback.run();
}
public static ArrayList<float[]> marchingCubes(Array values, Array xc, Array yc, Array zc, float isoLevel) {
ArrayList<float[]> vertices = new ArrayList<>();
// Actual position along edge weighted according to function values.
float vertList[][] = new float[12][3];
int[] shape = values.getShape();
int[] volDim = new int[]{shape[2], shape[1], shape[0]};
// Volume iteration
float xx, yy, zz;
for (int z = 0; z < volDim[2] - 1; z++) {
zz = zc.getFloat(z);
for (int y = 0; y < volDim[1] - 1; y++) {
yy = yc.getFloat(y);
for (int x = 0; x < volDim[0] - 1; x++) {
xx = xc.getFloat(x);
// Indices pointing to cube vertices
// pyz ___________________ pxyz
// /| /|
// / | / |
// / | / |
// pz /___|______________/pxz|
// | | | |
// | | | |
// | py |______________|___| pxy
// | / | /
// | / | /
// | / | /
// |/__________________|/
// p px
int p = x + (volDim[0] * y) + (volDim[0] * volDim[1] * z),
px = p + 1,
py = p + volDim[0],
pxy = py + 1,
pz = p + volDim[0] * volDim[1],
pxz = px + volDim[0] * volDim[1],
pyz = py + volDim[0] * volDim[1],
pxyz = pxy + volDim[0] * volDim[1];
// X, Y, Z position
//float position[] = new float[]{xx, yy, zz};
// Voxel intensities
float value0 = values.getFloat(p),
value1 = values.getFloat(px),
value2 = values.getFloat(py),
value3 = values.getFloat(pxy),
value4 = values.getFloat(pz),
value5 = values.getFloat(pxz),
value6 = values.getFloat(pyz),
value7 = values.getFloat(pxyz);
// Voxel is active if its intensity is above isolevel
int cubeindex = 0;
if (value0 > isoLevel) cubeindex |= 1;
if (value1 > isoLevel) cubeindex |= 2;
if (value2 > isoLevel) cubeindex |= 8;
if (value3 > isoLevel) cubeindex |= 4;
if (value4 > isoLevel) cubeindex |= 16;
if (value5 > isoLevel) cubeindex |= 32;
if (value6 > isoLevel) cubeindex |= 128;
if (value7 > isoLevel) cubeindex |= 64;
// Fetch the triggered edges
int bits = TablesMC.MC_EDGE_TABLE[cubeindex];
// If no edge is triggered... skip
if (bits == 0) continue;
// Interpolate the positions based od voxel intensities
float mu = 0.5f;
// bottom of the cube
if ((bits & 1) != 0) {
mu = (float) ((isoLevel - value0) / (value1 - value0));
vertList[0] = lerp(new float[]{xx, yy, zz}, new float[]{xc.getFloat(x + 1), yy, zz}, mu);
}
if ((bits & 2) != 0) {
mu = (float) ((isoLevel - value1) / (value3 - value1));
vertList[1] = lerp(new float[]{xc.getFloat(x + 1), yy, zz}, new float[]{xc.getFloat(x + 1), yc.getFloat(y + 1), zz}, mu);
}
if ((bits & 4) != 0) {
mu = (float) ((isoLevel - value2) / (value3 - value2));
vertList[2] = lerp(new float[]{xx, yc.getFloat(y + 1), zz}, new float[]{xc.getFloat(x + 1), yc.getFloat(y + 1), zz}, mu);
}
if ((bits & 8) != 0) {
mu = (float) ((isoLevel - value0) / (value2 - value0));
vertList[3] = lerp(new float[]{xx, yy, zz}, new float[]{xx, yc.getFloat(y + 1), zz}, mu);
}
// top of the cube
if ((bits & 16) != 0) {
mu = (float) ((isoLevel - value4) / (value5 - value4));
vertList[4] = lerp(new float[]{xx, yy, zc.getFloat(z + 1)}, new float[]{xc.getFloat(x + 1), yy, zc.getFloat(z + 1)}, mu);
}
if ((bits & 32) != 0) {
mu = (float) ((isoLevel - value5) / (value7 - value5));
vertList[5] = lerp(new float[]{xc.getFloat(x + 1), yy, zc.getFloat(z + 1)}, new float[]{xc.getFloat(x + 1), yc.getFloat(y + 1), zc.getFloat(z + 1)}, mu);
}
if ((bits & 64) != 0) {
mu = (float) ((isoLevel - value6) / (value7 - value6));
vertList[6] = lerp(new float[]{xx, yc.getFloat(y + 1), zc.getFloat(z + 1)}, new float[]{xc.getFloat(x + 1), yc.getFloat(y + 1), zc.getFloat(z + 1)}, mu);
}
if ((bits & 128) != 0) {
mu = (float) ((isoLevel - value4) / (value6 - value4));
vertList[7] = lerp(new float[]{xx, yy, zc.getFloat(z + 1)}, new float[]{xx, yc.getFloat(y + 1), zc.getFloat(z + 1)}, mu);
}
// vertical lines of the cube
if ((bits & 256) != 0) {
mu = (float) ((isoLevel - value0) / (value4 - value0));
vertList[8] = lerp(new float[]{xx, yy, zz}, new float[]{xx, yy, zc.getFloat(z + 1)}, mu);
}
if ((bits & 512) != 0) {
mu = (float) ((isoLevel - value1) / (value5 - value1));
vertList[9] = lerp(new float[]{xc.getFloat(x + 1), yy, zz}, new float[]{xc.getFloat(x + 1), yy, zc.getFloat(z + 1)}, mu);
}
if ((bits & 1024) != 0) {
mu = (float) ((isoLevel - value3) / (value7 - value3));
vertList[10] = lerp(new float[]{xc.getFloat(x + 1), yc.getFloat(y + 1), zz}, new float[]{xc.getFloat(x + 1), yc.getFloat(y + 1), zc.getFloat(z + 1)}, mu);
}
if ((bits & 2048) != 0) {
mu = (float) ((isoLevel - value2) / (value6 - value2));
vertList[11] = lerp(new float[]{xx, yc.getFloat(y + 1), zz}, new float[]{xx, yc.getFloat(y + 1), zc.getFloat(z + 1)}, mu);
}
// construct triangles -- get correct vertices from triTable.
int i = 0;
// "Re-purpose cubeindex into an offset into triTable."
cubeindex <<= 4;
while (TablesMC.MC_TRI_TABLE[cubeindex + i] != -1) {
int index1 = TablesMC.MC_TRI_TABLE[cubeindex + i];
int index2 = TablesMC.MC_TRI_TABLE[cubeindex + i + 1];
int index3 = TablesMC.MC_TRI_TABLE[cubeindex + i + 2];
// Add triangles vertices
vertices.add(new float[] {vertList[index3][0], vertList[index3][1], vertList[index3][2]});
vertices.add(new float[] {vertList[index2][0], vertList[index2][1], vertList[index2][2]});
vertices.add(new float[] {vertList[index1][0], vertList[index1][1], vertList[index1][2]});
i += 3;
}
}
}
}
return vertices;
}
}

View File

@ -0,0 +1,303 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl.mc;
/**
* Created by Primoz on 7.7.2016.
*/
public class TablesMC {
static int[] MC_EDGE_TABLE = {
0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c,
0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c,
0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc,
0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c,
0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc,
0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460,
0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0,
0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230,
0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190,
0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
static int[] MC_TRI_TABLE = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1,
3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1,
3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1,
3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1,
9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1,
9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1,
2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1,
8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1,
9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1,
4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1,
3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1,
1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1,
4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1,
4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1,
9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1,
1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1,
5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1,
2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1,
9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1,
0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1,
2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1,
10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1,
4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1,
5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1,
5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1,
9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1,
0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1,
1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1,
10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1,
8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1,
2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1,
7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1,
9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1,
2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1,
11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1,
9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1,
5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1,
11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1,
11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1,
1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1,
9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1,
5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1,
2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1,
0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1,
5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1,
6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1,
0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1,
3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1,
6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1,
5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1,
1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1,
10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1,
6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1,
1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1,
8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1,
7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1,
3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1,
5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1,
0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1,
9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1,
8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1,
5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1,
0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1,
6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1,
10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1,
10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1,
8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1,
1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1,
3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1,
0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1,
10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1,
0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1,
3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1,
6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1,
9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1,
8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1,
3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1,
6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1,
0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1,
10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1,
10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1,
1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1,
2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1,
7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1,
7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1,
2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1,
1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1,
11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1,
8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1,
0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1,
7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1,
10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1,
2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1,
6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1,
7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1,
2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1,
1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1,
10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1,
10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1,
0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1,
7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1,
6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1,
8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1,
9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1,
6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1,
4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1,
10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1,
8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1,
0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1,
1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1,
8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1,
10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1,
4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1,
10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1,
5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1,
11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1,
9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1,
6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1,
7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1,
3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1,
7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1,
9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1,
3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1,
6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1,
9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1,
1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1,
4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1,
7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1,
6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1,
3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1,
0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1,
6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1,
0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1,
11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1,
6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1,
5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1,
9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1,
1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1,
1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1,
10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1,
0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1,
5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1,
10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1,
11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1,
0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1,
9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1,
7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1,
2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1,
8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1,
9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1,
9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1,
1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1,
9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1,
9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1,
5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1,
0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1,
10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1,
2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1,
0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1,
0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1,
9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1,
5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1,
3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1,
5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1,
8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1,
0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1,
9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1,
0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1,
1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1,
3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1,
4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1,
9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1,
11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1,
11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1,
2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1,
9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1,
3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1,
1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1,
4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1,
4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1,
0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1,
3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1,
3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1,
0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1,
9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1,
1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
}

View File

@ -0,0 +1,116 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.meteoinfo.chart.jogl.mc;
/**
* Created by Primoz on 11. 07. 2016.
*/
public class VolumeGenerator {
public static char[] generateScalarFieldChar(int []size) {
final char[] scalarField = new char[size[0] * size[1] * size[2]];
float axisMin = -10;
float axisMax = 10;
float axisRange = axisMax - axisMin;
for (int k = 0; k < size[0]; k++) {
for (int j = 0; j < size[1]; j++) {
for (int i = 0; i < size[2]; i++) {
// actual values
char x = (char) (axisMin + axisRange * i / (size[0] - 1));
char y = (char) (axisMin + axisRange * j / (size[1] - 1));
char z = (char) (axisMin + axisRange * k / (size[2] - 1));
scalarField[k + size[1] * (j + size[2] * i)] = (char) (x * x + y * y - z * z - 25);
}
}
}
return scalarField;
}
public static short[] generateScalarFieldShort(int []size) {
final short[] scalarField = new short[size[0] * size[1] * size[2]];
float axisMin = -10;
float axisMax = 10;
float axisRange = axisMax - axisMin;
for (int k = 0; k < size[0]; k++) {
for (int j = 0; j < size[1]; j++) {
for (int i = 0; i < size[2]; i++) {
// actual values
short x = (short) (axisMin + axisRange * i / (size[0] - 1));
short y = (short) (axisMin + axisRange * j / (size[1] - 1));
short z = (short) (axisMin + axisRange * k / (size[2] - 1));
scalarField[k + size[1] * (j + size[2] * i)] = (short) (x * x + y * y - z * z - 25);
}
}
}
return scalarField;
}
public static int[] generateScalarFieldInt(int []size) {
final int[] scalarField = new int[size[0] * size[1] * size[2]];
float axisMin = -10;
float axisMax = 10;
float axisRange = axisMax - axisMin;
for (int k = 0; k < size[0]; k++) {
for (int j = 0; j < size[1]; j++) {
for (int i = 0; i < size[2]; i++) {
// actual values
int x = (int) (axisMin + axisRange * i / (size[0] - 1));
int y = (int) (axisMin + axisRange * j / (size[1] - 1));
int z = (int) (axisMin + axisRange * k / (size[2] - 1));
scalarField[k + size[1] * (j + size[2] * i)] = (int) (x * x + y * y - z * z - 25);
}
}
}
return scalarField;
}
public static float[] generateScalarFieldFloat(int []size) {
final float[] scalarField = new float[size[0] * size[1] * size[2]];
float axisMin = -10;
float axisMax = 10;
float axisRange = axisMax - axisMin;
for (int k = 0; k < size[0]; k++) {
for (int j = 0; j < size[1]; j++) {
for (int i = 0; i < size[2]; i++) {
// actual values
float x = axisMin + axisRange * i / (size[0] - 1);
float y = axisMin + axisRange * j / (size[1] - 1);
float z = axisMin + axisRange * k / (size[2] - 1);
scalarField[k + size[1] * (j + size[2] * i)] = x * x + y * y - z * z - 25;
}
}
}
return scalarField;
}
public static double[] generateScalarFieldDouble(int []size) {
final double[] scalarField = new double[size[0] * size[1] * size[2]];
double axisMin = -10;
double axisMax = 10;
double axisRange = axisMax - axisMin;
for (int k = 0; k < size[0]; k++) {
for (int j = 0; j < size[1]; j++) {
for (int i = 0; i < size[2]; i++) {
// actual values
double x = axisMin + axisRange * i / (size[0] - 1);
double y = axisMin + axisRange * j / (size[1] - 1);
double z = axisMin + axisRange * k / (size[2] - 1);
scalarField[k + size[1] * (j + size[2] * i)] = (x * x + y * y - z * z - 25);
}
}
}
return scalarField;
}
}

View File

@ -18,9 +18,9 @@ public class GraphicCollection3D extends GraphicCollection{
private double zValue;
private String zdir;
private List<Number> sePoint;
private boolean allQuads;
private boolean allTriangle;
private boolean allConvexPolygon;
protected boolean allQuads;
protected boolean allTriangle;
protected boolean allConvexPolygon;
/**
* Constructor

View File

@ -571,6 +571,52 @@ public class MIMath {
return extent;
}
/**
* Get extent of the points
*
* @param points
* @return Extent
*/
public static Extent3D getExtent(PointZ[] points) {
PointZ p = points[0];
double minx = p.X;
double maxx = p.X;
double miny = p.Y;
double maxy = p.Y;
double minz = p.Z;
double maxz = p.Z;
for (int i = 1; i < points.length; i++) {
if (minx > p.X) {
minx = p.M;
}
if (maxx < p.X) {
maxx = p.M;
}
if (miny > p.Y) {
miny = p.Y;
}
if (maxy < p.Y) {
maxy = p.Y;
}
if (minz > p.Z) {
minz = p.Z;
}
if (maxz < p.Z) {
maxz = p.Z;
}
}
Extent3D extent = new Extent3D();
extent.minX = minx;
extent.maxX = maxx;
extent.minY = miny;
extent.maxY = maxy;
extent.minZ = minz;
extent.maxZ = maxz;
return extent;
}
/**
* Determine if two extent cross each other