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"?>
|
||||
<MeteoInfo File="milconfig.xml" Type="configurefile">
|
||||
<Path OpenPath="D:\Working\MIScript\Jython\mis\micaps">
|
||||
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl">
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\qaqc"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\sunphotometer"/>
|
||||
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\trajstat"/>
|
||||
@ -21,22 +21,22 @@
|
||||
<OpenedFiles>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\two_yaxis.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contourf_1.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\layer_image.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\traj_4.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_6.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_elev.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_5.py"/>
|
||||
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\isosurface_1.py"/>
|
||||
</OpenedFiles>
|
||||
<RecentFiles>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\two_yaxis.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\contourf_1.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\layer_image.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\traj_4.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_6.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_elev.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf_5.py"/>
|
||||
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\isosurface_1.py"/>
|
||||
</RecentFiles>
|
||||
</File>
|
||||
<Font>
|
||||
<TextFont FontName="宋体" FontSize="15"/>
|
||||
</Font>
|
||||
<Startup MainFormLocation="-3,2" MainFormSize="1393,832"/>
|
||||
<Startup MainFormLocation="-7,-7" MainFormSize="1293,693"/>
|
||||
</MeteoInfo>
|
||||
|
||||
Binary file not shown.
@ -7,8 +7,9 @@
|
||||
#-----------------------------------------------------
|
||||
|
||||
from org.meteoinfo.chart.plot import GraphicFactory
|
||||
from org.meteoinfo.legend import BreakTypes
|
||||
from org.meteoinfo.legend import BreakTypes, LegendManage
|
||||
from org.meteoinfo.layer import LayerTypes
|
||||
from org.meteoinfo.shape import ShapeTypes
|
||||
from org.meteoinfo.chart.jogl import Plot3DGL, GLForm, JOGLUtil
|
||||
from javax.swing import WindowConstants
|
||||
from java.awt import Font, Color, BasicStroke
|
||||
@ -98,6 +99,31 @@ class Axes3DGL(Axes3D):
|
||||
'''
|
||||
self.axes.setAngleX(elevation)
|
||||
|
||||
def set_lighting(self, enable, **kwargs):
|
||||
'''
|
||||
Set lighting.
|
||||
|
||||
:param enable: (*boolean*) Set lighting enable or not.
|
||||
:param position: (*list of float*) Lighting position.
|
||||
:param ambient: (*list of float*) Ambient light.
|
||||
:param diffuse: (*list of float*) Diffuse light.
|
||||
:param specular: (*list of float*) Specular light.
|
||||
'''
|
||||
lighting = self.axes.getLighting()
|
||||
lighting.setEnable(enable)
|
||||
position = kwargs.pop('position', None)
|
||||
if not position is None:
|
||||
lighting.setPosition(position)
|
||||
ambient = kwargs.pop('ambient', None)
|
||||
if not ambient is None:
|
||||
lighting.setAmbient(ambient)
|
||||
diffuse = kwargs.pop('diffuse', None)
|
||||
if not diffuse is None:
|
||||
lighting.setDiffuse(diffuse)
|
||||
specular = kwargs.pop('specular', None)
|
||||
if not specular is None:
|
||||
lighting.setSpecular(specular)
|
||||
|
||||
def plot_layer(self, layer, **kwargs):
|
||||
'''
|
||||
Plot a layer in 3D axes.
|
||||
@ -135,6 +161,63 @@ class Axes3DGL(Axes3D):
|
||||
if visible:
|
||||
self.add_graphic(graphics)
|
||||
return graphics
|
||||
|
||||
def plot_isosurface(self, *args, **kwargs):
|
||||
'''
|
||||
creates a three-dimensional isosurface plot
|
||||
|
||||
:param x: (*array_like*) Optional. X coordinate array.
|
||||
:param y: (*array_like*) Optional. Y coordinate array.
|
||||
:param z: (*array_like*) Optional. Z coordinate array.
|
||||
:param data: (*array_like*) 3D data array.
|
||||
:param cmap: (*string*) Color map string.
|
||||
:param xyaxis: (*boolean*) Draw x and y axis or not.
|
||||
:param zaxis: (*boolean*) Draw z axis or not.
|
||||
:param grid: (*boolean*) Draw grid or not.
|
||||
:param boxed: (*boolean*) Draw boxed or not.
|
||||
:param mesh: (*boolean*) Draw mesh line or not.
|
||||
|
||||
:returns: Legend
|
||||
'''
|
||||
if len(args) <= 3:
|
||||
x = args[0].dimvalue(2)
|
||||
y = args[0].dimvalue(1)
|
||||
z = args[0].dimvalue(0)
|
||||
data = args[0]
|
||||
isovalue = args[1]
|
||||
args = args[2:]
|
||||
else:
|
||||
x = args[0]
|
||||
y = args[1]
|
||||
z = args[2]
|
||||
data = args[3]
|
||||
isovalue = args[4]
|
||||
args = args[5:]
|
||||
cmap = plotutil.getcolormap(**kwargs)
|
||||
cvalue = kwargs.pop('cvalue', None)
|
||||
if not cvalue is None:
|
||||
if len(args) > 0:
|
||||
level_arg = args[0]
|
||||
if isinstance(level_arg, int):
|
||||
cn = level_arg
|
||||
ls = LegendManage.createLegendScheme(data.min(), data.max(), cn, cmap)
|
||||
else:
|
||||
if isinstance(level_arg, NDArray):
|
||||
level_arg = level_arg.aslist()
|
||||
ls = LegendManage.createLegendScheme(data.min(), data.max(), level_arg, cmap)
|
||||
else:
|
||||
ls = LegendManage.createLegendScheme(data.min(), data.max(), cmap)
|
||||
ls = ls.convertTo(ShapeTypes.Polygon)
|
||||
edge = kwargs.pop('edge', True)
|
||||
kwargs['edge'] = edge
|
||||
plotutil.setlegendscheme(ls, **kwargs)
|
||||
else:
|
||||
ls = plotutil.getlegendbreak('polygon', **kwargs)[0]
|
||||
graphics = JOGLUtil.isosurface(data.asarray(), x.asarray(), y.asarray(), z.asarray(), isovalue, ls)
|
||||
visible = kwargs.pop('visible', True)
|
||||
if visible:
|
||||
self.add_graphic(graphics)
|
||||
return graphics
|
||||
|
||||
def view(self):
|
||||
'''
|
||||
|
||||
Binary file not shown.
@ -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;
|
||||
|
||||
import com.jogamp.opengl.GL2;
|
||||
import com.jogamp.opengl.util.texture.Texture;
|
||||
import com.jogamp.opengl.util.texture.TextureIO;
|
||||
import java.io.File;
|
||||
import java.awt.Color;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.meteoinfo.chart.jogl.mc.MarchingCubes;
|
||||
import org.meteoinfo.chart.plot3d.GraphicCollection3D;
|
||||
import org.meteoinfo.global.Extent;
|
||||
import org.meteoinfo.global.Extent3D;
|
||||
import org.meteoinfo.layer.ImageLayer;
|
||||
import org.meteoinfo.legend.ColorBreak;
|
||||
import org.meteoinfo.legend.PolygonBreak;
|
||||
import org.meteoinfo.ndarray.Array;
|
||||
import org.meteoinfo.shape.Graphic;
|
||||
import org.meteoinfo.shape.GraphicCollection;
|
||||
import org.meteoinfo.shape.ImageShape;
|
||||
import org.meteoinfo.shape.PointZ;
|
||||
import org.meteoinfo.shape.PolygonZShape;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -64,4 +66,69 @@ public class JOGLUtil {
|
||||
|
||||
return graphics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create isosurface graphics
|
||||
* @param data 3d data array
|
||||
* @param x X coordinates
|
||||
* @param y Y coordinates
|
||||
* @param z Z coordinates
|
||||
* @param isoLevel iso level
|
||||
* @param pb Polygon break
|
||||
* @return Graphics
|
||||
*/
|
||||
public static GraphicCollection isosurface(Array data, Array x, Array y, Array z,
|
||||
float isoLevel, PolygonBreak pb) {
|
||||
List<float[]> vertices = MarchingCubes.marchingCubes(data, x, y, z, isoLevel);
|
||||
IsosurfaceGraphics graphics = new IsosurfaceGraphics();
|
||||
graphics.setLegendBreak(pb);
|
||||
float[] v1, v2, v3;
|
||||
for (int i = 0; i < vertices.size(); i += 3) {
|
||||
PointZ[] points = new PointZ[3];
|
||||
v1 = vertices.get(i);
|
||||
v2 = vertices.get(i + 1);
|
||||
v3 = vertices.get(i + 2);
|
||||
points[0] = new PointZ(v1[0], v1[1], v1[2]);
|
||||
points[1] = new PointZ(v2[0], v2[1], v2[2]);
|
||||
points[2] = new PointZ(v3[0], v3[1], v3[2]);
|
||||
graphics.addTriangle(points);
|
||||
}
|
||||
|
||||
return graphics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create isosurface graphics
|
||||
* @param data 3d data array
|
||||
* @param x X coordinates
|
||||
* @param y Y coordinates
|
||||
* @param z Z coordinates
|
||||
* @param isoLevel iso level
|
||||
* @param pb Polygon break
|
||||
* @return Graphics
|
||||
*/
|
||||
public static GraphicCollection isosurface_bak(Array data, Array x, Array y, Array z,
|
||||
float isoLevel, PolygonBreak pb) {
|
||||
List<float[]> vertices = MarchingCubes.marchingCubes(data, x, y, z, isoLevel);
|
||||
GraphicCollection3D graphics = new GraphicCollection3D();
|
||||
pb.setColor(Color.cyan);
|
||||
float[] v1, v2, v3;
|
||||
for (int i = 0; i < vertices.size(); i += 3) {
|
||||
PolygonZShape ps = new PolygonZShape();
|
||||
List<PointZ> points = new ArrayList<>();
|
||||
v1 = vertices.get(i);
|
||||
v2 = vertices.get(i + 1);
|
||||
v3 = vertices.get(i + 2);
|
||||
points.add(new PointZ(v1[0], v1[1], v1[2]));
|
||||
points.add(new PointZ(v2[0], v2[1], v2[2]));
|
||||
points.add(new PointZ(v3[0], v3[1], v3[2]));
|
||||
points.add(new PointZ(v1[0], v1[1], v1[2]));
|
||||
ps.setPoints(points);
|
||||
Graphic graphic = new Graphic(ps, pb);
|
||||
graphics.add(graphic);
|
||||
}
|
||||
graphics.setAllTriangle(true);
|
||||
|
||||
return graphics;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
float tickSpace = 5.0f;
|
||||
float tickLen = 0.08f;
|
||||
private Lighting lighting = new Lighting();
|
||||
|
||||
// </editor-fold>
|
||||
// <editor-fold desc="Constructor">
|
||||
@ -193,7 +194,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
public void setLineBoxColor(Color value) {
|
||||
this.lineboxColor = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get if draw bounding box or not
|
||||
*
|
||||
@ -211,8 +212,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
public void setDrawBoundingBox(boolean value) {
|
||||
this.drawBoundingBox = value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set display X/Y axis or not
|
||||
*
|
||||
@ -557,6 +557,24 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
this.zAxis.setMinMaxValue(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lighting set
|
||||
*
|
||||
* @return Lighting set
|
||||
*/
|
||||
public Lighting getLighting() {
|
||||
return this.lighting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lighting set
|
||||
*
|
||||
* @param value Lighting set
|
||||
*/
|
||||
public void setLighting(Lighting value) {
|
||||
this.lighting = value;
|
||||
}
|
||||
|
||||
// </editor-fold>
|
||||
// <editor-fold desc="methods">
|
||||
/**
|
||||
@ -702,7 +720,12 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
this.updateMatrix(gl);
|
||||
this.drawLegend(gl);
|
||||
|
||||
gl.glFlush();
|
||||
gl.glFlush();
|
||||
|
||||
//Set lighting
|
||||
if (this.lighting != null && this.lighting.isEnable()) {
|
||||
this.lighting.start(gl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -749,7 +772,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
|
||||
return (float) Math.sqrt(Math.pow(sx2 - sx1, 2) + Math.pow(sy2 - sy1, 2));
|
||||
}
|
||||
|
||||
|
||||
private float toScreenAngle(float x1, float y1, float z1, float x2, float y2, float z2) {
|
||||
float[] coord = toScreen(x1, y1, z1);
|
||||
float sx1 = coord[0];
|
||||
@ -758,7 +781,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
float sx2 = coord[0];
|
||||
float sy2 = coord[1];
|
||||
|
||||
return (float) MeteoMath.uv2ds(sx2 - sx1, sy2 - sy1)[0];
|
||||
return (float) MeteoMath.uv2ds(sx2 - sx1, sy2 - sy1)[0];
|
||||
}
|
||||
|
||||
private int getLabelGap(Font font, List<ChartText> labels, double len) {
|
||||
@ -937,8 +960,9 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
float angle = this.toScreenAngle(-1.0f, y, -1.0f, 1.0f, y, -1.0f);
|
||||
angle = y < 0 ? 270 - angle : 90 - angle;
|
||||
float yShift = Math.min(-strWidth, -strWidth);
|
||||
if (this.angleX <= -120)
|
||||
if (this.angleX <= -120) {
|
||||
yShift = -yShift;
|
||||
}
|
||||
drawString(gl, label, 0.0f, y1, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
|
||||
}
|
||||
|
||||
@ -1023,13 +1047,14 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
|
||||
//Draw y axis label
|
||||
label = this.yAxis.getLabel();
|
||||
if (label != null) {
|
||||
if (label != null) {
|
||||
strWidth += this.tickSpace;
|
||||
float angle = this.toScreenAngle(x, -1.0f, -1.0f, x, 1.0f, -1.0f);
|
||||
angle = x > 0 ? 270 - angle : 90 - angle;
|
||||
float yShift = Math.min(-strWidth, -strWidth);
|
||||
if (this.angleX <= -120)
|
||||
if (this.angleX <= -120) {
|
||||
yShift = -yShift;
|
||||
}
|
||||
drawString(gl, label, x1, 0.0f, -1.0f, XAlign.CENTER, yAlign, angle, 0, yShift);
|
||||
}
|
||||
}
|
||||
@ -1150,14 +1175,14 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
|
||||
XAlign xAlign, YAlign yAlign, float xShift, float yShift) {
|
||||
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx,
|
||||
vy, vz, xAlign, yAlign, xShift, yShift);
|
||||
vy, vz, xAlign, yAlign, xShift, yShift);
|
||||
}
|
||||
|
||||
|
||||
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
|
||||
XAlign xAlign, YAlign yAlign) {
|
||||
return drawString(gl, str, font, color, vx, vy, vz, xAlign, yAlign, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
|
||||
XAlign xAlign, YAlign yAlign, float xShift, float yShift) {
|
||||
//Get screen coordinates
|
||||
@ -1192,23 +1217,23 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
|
||||
|
||||
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
|
||||
XAlign xAlign, YAlign yAlign, float angle) {
|
||||
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx, vy, vz, xAlign, yAlign, angle, 0, 0);
|
||||
}
|
||||
|
||||
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
|
||||
|
||||
Rectangle2D drawString(GL2 gl, ChartText text, float vx, float vy, float vz,
|
||||
XAlign xAlign, YAlign yAlign, float angle, float xShift, float yShift) {
|
||||
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx, vy,
|
||||
return drawString(gl, text.getText(), text.getFont(), text.getColor(), vx, vy,
|
||||
vz, xAlign, yAlign, angle, xShift, yShift);
|
||||
}
|
||||
|
||||
|
||||
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
|
||||
XAlign xAlign, YAlign yAlign, float angle) {
|
||||
return drawString(gl, str, font, color, vx, vy, vz, xAlign, yAlign, angle, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
Rectangle2D drawString(GL2 gl, String str, Font font, Color color, float vx, float vy, float vz,
|
||||
XAlign xAlign, YAlign yAlign, float angle, float xShift, float yShift) {
|
||||
//Get screen coordinates
|
||||
@ -1221,14 +1246,15 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
textRenderer.beginRendering(this.width, this.height);
|
||||
textRenderer.setColor(color);
|
||||
textRenderer.setSmoothing(true);
|
||||
Rectangle2D rect = textRenderer.getBounds(str.subSequence(0, str.length()));
|
||||
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(x, y, 0.0f);
|
||||
if (angle != 0) {
|
||||
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||
Rectangle2D rect = textRenderer.getBounds(str.subSequence(0, str.length()));
|
||||
gl.glMatrixMode(GL2.GL_MODELVIEW);
|
||||
gl.glPushMatrix();
|
||||
gl.glTranslatef(x, y, 0.0f);
|
||||
if (angle != 0) {
|
||||
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
x = 0; y = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
switch (xAlign) {
|
||||
case CENTER:
|
||||
x -= rect.getWidth() * 0.5;
|
||||
@ -1247,9 +1273,9 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
}
|
||||
x += xShift;
|
||||
y += yShift;
|
||||
textRenderer.draw(str, (int)x, (int)y);
|
||||
textRenderer.draw(str, (int) x, (int) y);
|
||||
textRenderer.endRendering();
|
||||
gl.glPopMatrix();
|
||||
gl.glPopMatrix();
|
||||
|
||||
return rect;
|
||||
}
|
||||
@ -1273,18 +1299,25 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
Graphic gg = graphic.getGraphicN(0);
|
||||
this.drawGraphic(gl, gg);
|
||||
} else {
|
||||
boolean isDraw = true;
|
||||
if (graphic instanceof GraphicCollection3D) {
|
||||
GraphicCollection3D gg = (GraphicCollection3D) graphic;
|
||||
if (gg.isAllQuads()) {
|
||||
this.drawQuadsPolygons(gl, gg);
|
||||
isDraw = false;
|
||||
if (graphic instanceof IsosurfaceGraphics) {
|
||||
this.drawIsosurface(gl, (IsosurfaceGraphics)graphic);
|
||||
} else {
|
||||
boolean isDraw = true;
|
||||
if (graphic instanceof GraphicCollection3D) {
|
||||
GraphicCollection3D gg = (GraphicCollection3D) graphic;
|
||||
if (gg.isAllQuads()) {
|
||||
this.drawQuadsPolygons(gl, gg);
|
||||
isDraw = false;
|
||||
} else if (gg.isAllTriangle()) {
|
||||
this.drawTrianglePolygons(gl, gg);
|
||||
isDraw = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isDraw) {
|
||||
for (int i = 0; i < graphic.getNumGraphics(); i++) {
|
||||
Graphic gg = graphic.getGraphicN(i);
|
||||
this.drawGraphic(gl, gg);
|
||||
if (isDraw) {
|
||||
for (int i = 0; i < graphic.getNumGraphics(); i++) {
|
||||
Graphic gg = graphic.getGraphicN(i);
|
||||
this.drawGraphic(gl, gg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1493,6 +1526,82 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void drawTrianglePolygons(GL2 gl, GraphicCollection3D graphic) {
|
||||
PointZ p;
|
||||
for (int i = 0; i < graphic.getNumGraphics(); i++) {
|
||||
Graphic gg = graphic.getGraphicN(i);
|
||||
if (extent.intersects(gg.getExtent())) {
|
||||
PolygonZShape shape = (PolygonZShape) gg.getShape();
|
||||
PolygonBreak pb = (PolygonBreak) gg.getLegend();
|
||||
for (PolygonZ poly : (List<PolygonZ>) shape.getPolygons()) {
|
||||
drawTriangle(gl, poly, pb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawTriangle(GL2 gl, PolygonZ aPG, PolygonBreak aPGB) {
|
||||
PointZ p;
|
||||
float[] rgba = aPGB.getColor().getRGBComponents(null);
|
||||
if (aPGB.isDrawFill()) {
|
||||
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
|
||||
gl.glBegin(GL2.GL_TRIANGLES);
|
||||
for (int i = 0; i < aPG.getOutLine().size(); i++) {
|
||||
p = ((List<PointZ>) aPG.getOutLine()).get(i);
|
||||
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
|
||||
}
|
||||
gl.glEnd();
|
||||
}
|
||||
|
||||
if (aPGB.isDrawOutline()) {
|
||||
rgba = aPGB.getOutlineColor().getRGBComponents(null);
|
||||
gl.glLineWidth(aPGB.getOutlineSize());
|
||||
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
|
||||
gl.glBegin(GL2.GL_LINE_STRIP);
|
||||
for (int i = 0; i < aPG.getOutLine().size(); i++) {
|
||||
p = ((List<PointZ>) aPG.getOutLine()).get(i);
|
||||
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
|
||||
}
|
||||
gl.glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void drawTriangle(GL2 gl, PointZ[] points, PolygonBreak aPGB) {
|
||||
PointZ p;
|
||||
float[] rgba = aPGB.getColor().getRGBComponents(null);
|
||||
if (aPGB.isDrawFill()) {
|
||||
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
|
||||
gl.glBegin(GL2.GL_TRIANGLES);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
p = points[i];
|
||||
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
|
||||
}
|
||||
gl.glEnd();
|
||||
}
|
||||
|
||||
if (aPGB.isDrawOutline()) {
|
||||
rgba = aPGB.getOutlineColor().getRGBComponents(null);
|
||||
gl.glLineWidth(aPGB.getOutlineSize());
|
||||
gl.glColor3f(rgba[0], rgba[1], rgba[2]);
|
||||
gl.glBegin(GL2.GL_LINE_STRIP);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
p = points[i];
|
||||
gl.glVertex3f(transform_xf((float) p.X), transform_yf((float) p.Y), transform_zf((float) p.Z));
|
||||
}
|
||||
gl.glEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void drawIsosurface(GL2 gl, IsosurfaceGraphics isosurface) {
|
||||
List<PointZ[]> triangles = isosurface.getTriangles();
|
||||
PolygonBreak pgb = (PolygonBreak)isosurface.getLegendBreak();
|
||||
//this.lighting.setEnable(true);
|
||||
this.lighting.setMat_Ambient(pgb.getColor().getRGBComponents(null));
|
||||
for (PointZ[] triangle : triangles) {
|
||||
this.drawTriangle(gl, triangle, pgb);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawImage(GL2 gl, Graphic graphic) {
|
||||
ImageShape ishape = (ImageShape) graphic.getShape();
|
||||
BufferedImage image = ishape.getImage();
|
||||
@ -1697,7 +1806,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
caption = tLabels.get(idx);
|
||||
}
|
||||
if (ls.getLegendType() == LegendType.UniqueValue) {
|
||||
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
|
||||
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
|
||||
x + lWidth, yy + barHeight * 0.5f, 0, XAlign.LEFT, YAlign.CENTER, 5, 0);
|
||||
} else {
|
||||
rgba = Color.black.getRGBComponents(null);
|
||||
@ -1707,10 +1816,10 @@ public class Plot3DGL extends Plot implements GLEventListener {
|
||||
gl.glVertex2f(x + lWidth * 0.5f, yy + barHeight);
|
||||
gl.glVertex2f(x + lWidth, yy + barHeight);
|
||||
gl.glEnd();
|
||||
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
|
||||
this.drawString(gl, caption, legend.getTickLabelFont(), Color.black,
|
||||
x + lWidth, yy + barHeight, 0, XAlign.LEFT, YAlign.CENTER, 5, 0);
|
||||
}
|
||||
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
yy += barHeight;
|
||||
|
||||
@ -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 String zdir;
|
||||
private List<Number> sePoint;
|
||||
private boolean allQuads;
|
||||
private boolean allTriangle;
|
||||
private boolean allConvexPolygon;
|
||||
protected boolean allQuads;
|
||||
protected boolean allTriangle;
|
||||
protected boolean allConvexPolygon;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
||||
@ -571,6 +571,52 @@ public class MIMath {
|
||||
|
||||
return extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extent of the points
|
||||
*
|
||||
* @param points
|
||||
* @return Extent
|
||||
*/
|
||||
public static Extent3D getExtent(PointZ[] points) {
|
||||
PointZ p = points[0];
|
||||
double minx = p.X;
|
||||
double maxx = p.X;
|
||||
double miny = p.Y;
|
||||
double maxy = p.Y;
|
||||
double minz = p.Z;
|
||||
double maxz = p.Z;
|
||||
for (int i = 1; i < points.length; i++) {
|
||||
if (minx > p.X) {
|
||||
minx = p.M;
|
||||
}
|
||||
if (maxx < p.X) {
|
||||
maxx = p.M;
|
||||
}
|
||||
if (miny > p.Y) {
|
||||
miny = p.Y;
|
||||
}
|
||||
if (maxy < p.Y) {
|
||||
maxy = p.Y;
|
||||
}
|
||||
if (minz > p.Z) {
|
||||
minz = p.Z;
|
||||
}
|
||||
if (maxz < p.Z) {
|
||||
maxz = p.Z;
|
||||
}
|
||||
}
|
||||
|
||||
Extent3D extent = new Extent3D();
|
||||
extent.minX = minx;
|
||||
extent.maxX = maxx;
|
||||
extent.minY = miny;
|
||||
extent.maxY = maxy;
|
||||
extent.minZ = minz;
|
||||
extent.maxZ = maxz;
|
||||
|
||||
return extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if two extent cross each other
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user