mirror of
https://github.com/meteoinfo/MeteoInfo.git
synced 2025-12-08 20:36:05 +00:00
add isosurface function
This commit is contained in:
parent
fc59cdb39a
commit
47ebdc43d0
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<MeteoInfo File="milconfig.xml" Type="configurefile">
|
<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\qaqc"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\sunphotometer"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\sunphotometer"/>
|
||||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\trajstat"/>
|
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\trajstat"/>
|
||||||
@ -21,22 +21,22 @@
|
|||||||
<OpenedFiles>
|
<OpenedFiles>
|
||||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\two_yaxis.py"/>
|
<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\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\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_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>
|
</OpenedFiles>
|
||||||
<RecentFiles>
|
<RecentFiles>
|
||||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\two_yaxis.py"/>
|
<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\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\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_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>
|
</RecentFiles>
|
||||||
</File>
|
</File>
|
||||||
<Font>
|
<Font>
|
||||||
<TextFont FontName="宋体" FontSize="15"/>
|
<TextFont FontName="宋体" FontSize="15"/>
|
||||||
</Font>
|
</Font>
|
||||||
<Startup MainFormLocation="-3,2" MainFormSize="1393,832"/>
|
<Startup MainFormLocation="-7,-7" MainFormSize="1293,693"/>
|
||||||
</MeteoInfo>
|
</MeteoInfo>
|
||||||
|
|||||||
Binary file not shown.
@ -7,8 +7,9 @@
|
|||||||
#-----------------------------------------------------
|
#-----------------------------------------------------
|
||||||
|
|
||||||
from org.meteoinfo.chart.plot import GraphicFactory
|
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.layer import LayerTypes
|
||||||
|
from org.meteoinfo.shape import ShapeTypes
|
||||||
from org.meteoinfo.chart.jogl import Plot3DGL, GLForm, JOGLUtil
|
from org.meteoinfo.chart.jogl import Plot3DGL, GLForm, JOGLUtil
|
||||||
from javax.swing import WindowConstants
|
from javax.swing import WindowConstants
|
||||||
from java.awt import Font, Color, BasicStroke
|
from java.awt import Font, Color, BasicStroke
|
||||||
@ -98,6 +99,31 @@ class Axes3DGL(Axes3D):
|
|||||||
'''
|
'''
|
||||||
self.axes.setAngleX(elevation)
|
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):
|
def plot_layer(self, layer, **kwargs):
|
||||||
'''
|
'''
|
||||||
Plot a layer in 3D axes.
|
Plot a layer in 3D axes.
|
||||||
@ -136,6 +162,63 @@ class Axes3DGL(Axes3D):
|
|||||||
self.add_graphic(graphics)
|
self.add_graphic(graphics)
|
||||||
return 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):
|
def view(self):
|
||||||
'''
|
'''
|
||||||
Open GLForm
|
Open GLForm
|
||||||
|
|||||||
Binary file not shown.
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,21 +6,23 @@
|
|||||||
package org.meteoinfo.chart.jogl;
|
package org.meteoinfo.chart.jogl;
|
||||||
|
|
||||||
import com.jogamp.opengl.GL2;
|
import com.jogamp.opengl.GL2;
|
||||||
import com.jogamp.opengl.util.texture.Texture;
|
import java.awt.Color;
|
||||||
import com.jogamp.opengl.util.texture.TextureIO;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.meteoinfo.chart.jogl.mc.MarchingCubes;
|
||||||
import org.meteoinfo.chart.plot3d.GraphicCollection3D;
|
import org.meteoinfo.chart.plot3d.GraphicCollection3D;
|
||||||
import org.meteoinfo.global.Extent;
|
import org.meteoinfo.global.Extent;
|
||||||
import org.meteoinfo.global.Extent3D;
|
import org.meteoinfo.global.Extent3D;
|
||||||
import org.meteoinfo.layer.ImageLayer;
|
import org.meteoinfo.layer.ImageLayer;
|
||||||
import org.meteoinfo.legend.ColorBreak;
|
import org.meteoinfo.legend.ColorBreak;
|
||||||
|
import org.meteoinfo.legend.PolygonBreak;
|
||||||
|
import org.meteoinfo.ndarray.Array;
|
||||||
import org.meteoinfo.shape.Graphic;
|
import org.meteoinfo.shape.Graphic;
|
||||||
import org.meteoinfo.shape.GraphicCollection;
|
import org.meteoinfo.shape.GraphicCollection;
|
||||||
import org.meteoinfo.shape.ImageShape;
|
import org.meteoinfo.shape.ImageShape;
|
||||||
import org.meteoinfo.shape.PointZ;
|
import org.meteoinfo.shape.PointZ;
|
||||||
|
import org.meteoinfo.shape.PolygonZShape;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -64,4 +66,69 @@ public class JOGLUtil {
|
|||||||
|
|
||||||
return graphics;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -99,6 +99,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
private int height;
|
private int height;
|
||||||
float tickSpace = 5.0f;
|
float tickSpace = 5.0f;
|
||||||
float tickLen = 0.08f;
|
float tickLen = 0.08f;
|
||||||
|
private Lighting lighting = new Lighting();
|
||||||
|
|
||||||
// </editor-fold>
|
// </editor-fold>
|
||||||
// <editor-fold desc="Constructor">
|
// <editor-fold desc="Constructor">
|
||||||
@ -212,7 +213,6 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
this.drawBoundingBox = value;
|
this.drawBoundingBox = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set display X/Y axis or not
|
* Set display X/Y axis or not
|
||||||
*
|
*
|
||||||
@ -557,6 +557,24 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
this.zAxis.setMinMaxValue(min, max);
|
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>
|
||||||
// <editor-fold desc="methods">
|
// <editor-fold desc="methods">
|
||||||
/**
|
/**
|
||||||
@ -703,6 +721,11 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
this.drawLegend(gl);
|
this.drawLegend(gl);
|
||||||
|
|
||||||
gl.glFlush();
|
gl.glFlush();
|
||||||
|
|
||||||
|
//Set lighting
|
||||||
|
if (this.lighting != null && this.lighting.isEnable()) {
|
||||||
|
this.lighting.start(gl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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);
|
float angle = this.toScreenAngle(-1.0f, y, -1.0f, 1.0f, y, -1.0f);
|
||||||
angle = y < 0 ? 270 - angle : 90 - angle;
|
angle = y < 0 ? 270 - angle : 90 - angle;
|
||||||
float yShift = Math.min(-strWidth, -strWidth);
|
float yShift = Math.min(-strWidth, -strWidth);
|
||||||
if (this.angleX <= -120)
|
if (this.angleX <= -120) {
|
||||||
yShift = -yShift;
|
yShift = -yShift;
|
||||||
|
}
|
||||||
drawString(gl, label, 0.0f, y1, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
|
drawString(gl, label, 0.0f, y1, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1028,8 +1052,9 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
float angle = this.toScreenAngle(x, -1.0f, -1.0f, x, 1.0f, -1.0f);
|
float angle = this.toScreenAngle(x, -1.0f, -1.0f, x, 1.0f, -1.0f);
|
||||||
angle = x > 0 ? 270 - angle : 90 - angle;
|
angle = x > 0 ? 270 - angle : 90 - angle;
|
||||||
float yShift = Math.min(-strWidth, -strWidth);
|
float yShift = Math.min(-strWidth, -strWidth);
|
||||||
if (this.angleX <= -120)
|
if (this.angleX <= -120) {
|
||||||
yShift = -yShift;
|
yShift = -yShift;
|
||||||
|
}
|
||||||
drawString(gl, label, x1, 0.0f, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
|
drawString(gl, label, x1, 0.0f, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1228,7 +1253,8 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
if (angle != 0) {
|
if (angle != 0) {
|
||||||
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||||
}
|
}
|
||||||
x = 0; y = 0;
|
x = 0;
|
||||||
|
y = 0;
|
||||||
switch (xAlign) {
|
switch (xAlign) {
|
||||||
case CENTER:
|
case CENTER:
|
||||||
x -= rect.getWidth() * 0.5;
|
x -= rect.getWidth() * 0.5;
|
||||||
@ -1272,6 +1298,9 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
if (graphic.getNumGraphics() == 1) {
|
if (graphic.getNumGraphics() == 1) {
|
||||||
Graphic gg = graphic.getGraphicN(0);
|
Graphic gg = graphic.getGraphicN(0);
|
||||||
this.drawGraphic(gl, gg);
|
this.drawGraphic(gl, gg);
|
||||||
|
} else {
|
||||||
|
if (graphic instanceof IsosurfaceGraphics) {
|
||||||
|
this.drawIsosurface(gl, (IsosurfaceGraphics)graphic);
|
||||||
} else {
|
} else {
|
||||||
boolean isDraw = true;
|
boolean isDraw = true;
|
||||||
if (graphic instanceof GraphicCollection3D) {
|
if (graphic instanceof GraphicCollection3D) {
|
||||||
@ -1279,6 +1308,9 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
if (gg.isAllQuads()) {
|
if (gg.isAllQuads()) {
|
||||||
this.drawQuadsPolygons(gl, gg);
|
this.drawQuadsPolygons(gl, gg);
|
||||||
isDraw = false;
|
isDraw = false;
|
||||||
|
} else if (gg.isAllTriangle()) {
|
||||||
|
this.drawTrianglePolygons(gl, gg);
|
||||||
|
isDraw = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isDraw) {
|
if (isDraw) {
|
||||||
@ -1289,6 +1321,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void drawGraphic(GL2 gl, Graphic graphic) {
|
private void drawGraphic(GL2 gl, Graphic graphic) {
|
||||||
Shape shape = graphic.getGraphicN(0).getShape();
|
Shape shape = graphic.getGraphicN(0).getShape();
|
||||||
@ -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) {
|
private void drawImage(GL2 gl, Graphic graphic) {
|
||||||
ImageShape ishape = (ImageShape) graphic.getShape();
|
ImageShape ishape = (ImageShape) graphic.getShape();
|
||||||
BufferedImage image = ishape.getImage();
|
BufferedImage image = ishape.getImage();
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
287
MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/Main.java
Normal file
287
MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/Main.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 };
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,9 +18,9 @@ public class GraphicCollection3D extends GraphicCollection{
|
|||||||
private double zValue;
|
private double zValue;
|
||||||
private String zdir;
|
private String zdir;
|
||||||
private List<Number> sePoint;
|
private List<Number> sePoint;
|
||||||
private boolean allQuads;
|
protected boolean allQuads;
|
||||||
private boolean allTriangle;
|
protected boolean allTriangle;
|
||||||
private boolean allConvexPolygon;
|
protected boolean allConvexPolygon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
|||||||
@ -572,6 +572,52 @@ public class MIMath {
|
|||||||
return extent;
|
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
|
* Determine if two extent cross each other
|
||||||
*
|
*
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user