From 47ebdc43d0df86bacdfc75afaed241a8b51a8adc Mon Sep 17 00:00:00 2001 From: wyq Date: Sat, 21 Sep 2019 17:42:49 +0800 Subject: [PATCH] add isosurface function --- MeteoInfoLab/milconfig.xml | 12 +- .../pylib/mipylib/plotlib/axes3dgl$py.class | Bin 12340 -> 17471 bytes .../pylib/mipylib/plotlib/axes3dgl.py | 85 +- MeteoInfoLab/pylib/sync.ffs_db | Bin 397 -> 0 bytes .../chart/jogl/IsosurfaceGraphics.java | 57 ++ .../org/meteoinfo/chart/jogl/JOGLUtil.java | 73 +- .../org/meteoinfo/chart/jogl/Lighting.java | 308 ++++++ .../org/meteoinfo/chart/jogl/Plot3DGL.java | 193 +++- .../chart/jogl/mc/BenchmarkHandler.java | 799 +++++++++++++++ .../meteoinfo/chart/jogl/mc/CallbackMC.java | 23 + .../chart/jogl/mc/ExtractHandler.java | 537 ++++++++++ .../org/meteoinfo/chart/jogl/mc/Main.java | 287 ++++++ .../chart/jogl/mc/MarchingCubes.java | 928 ++++++++++++++++++ .../org/meteoinfo/chart/jogl/mc/TablesMC.java | 303 ++++++ .../chart/jogl/mc/VolumeGenerator.java | 116 +++ .../chart/plot3d/GraphicCollection3D.java | 6 +- .../java/org/meteoinfo/global/MIMath.java | 46 + 17 files changed, 3718 insertions(+), 55 deletions(-) delete mode 100644 MeteoInfoLab/pylib/sync.ffs_db create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/IsosurfaceGraphics.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Lighting.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/BenchmarkHandler.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/CallbackMC.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/ExtractHandler.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/Main.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/MarchingCubes.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/TablesMC.java create mode 100644 MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/VolumeGenerator.java diff --git a/MeteoInfoLab/milconfig.xml b/MeteoInfoLab/milconfig.xml index 14563164..755df592 100644 --- a/MeteoInfoLab/milconfig.xml +++ b/MeteoInfoLab/milconfig.xml @@ -1,6 +1,6 @@ - + @@ -21,22 +21,22 @@ - - + + - - + + - + diff --git a/MeteoInfoLab/pylib/mipylib/plotlib/axes3dgl$py.class b/MeteoInfoLab/pylib/mipylib/plotlib/axes3dgl$py.class index b1d1078d14445791e3743b8609c33f64a498e455..d83bf5729afde26dea35d217850f0948c0b21490 100644 GIT binary patch literal 17471 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 W$)9%e&-mxk*vhZ)FQk#>SN|6vX{w_D diff --git a/MeteoInfoLab/pylib/mipylib/plotlib/axes3dgl.py b/MeteoInfoLab/pylib/mipylib/plotlib/axes3dgl.py index a07e4f8e..54244d25 100644 --- a/MeteoInfoLab/pylib/mipylib/plotlib/axes3dgl.py +++ b/MeteoInfoLab/pylib/mipylib/plotlib/axes3dgl.py @@ -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): ''' diff --git a/MeteoInfoLab/pylib/sync.ffs_db b/MeteoInfoLab/pylib/sync.ffs_db deleted file mode 100644 index a545e159594aa236510667d6f04ab117d83706cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 397 zcmZ=ON=I};4VJv)V!m9OvDzU2VRXeOQI@?G z!lE|a;TOvdGL5#}o@?{xJ2+G5wh|D0O;xPAW^hul%t7FYcf?{M^}$(z6<^Bs@Q l*L5mAZ@%IOugS;v7H8@?MfHQ{i#N&WpI`Wh;i*KXF97gGtA79h diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/IsosurfaceGraphics.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/IsosurfaceGraphics.java new file mode 100644 index 00000000..844861fc --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/IsosurfaceGraphics.java @@ -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 triangles = new ArrayList<>(); + + /** + * Constructor + */ + public IsosurfaceGraphics() { + this.allTriangle = true; + } + + /** + * Get triangles + * @return Triangles + */ + public List getTriangles() { + return this.triangles; + } + + /** + * Set triangles + * @param value Triangles + */ + public void setTriangles(List 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())); + } +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java index 4f1f0060..3d8cf6ef 100644 --- a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java @@ -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 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 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 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; + } } diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Lighting.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Lighting.java new file mode 100644 index 00000000..3c761b2c --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Lighting.java @@ -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); + } +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java index 15dc1919..23640d43 100644 --- a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java @@ -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(); // // @@ -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; + } + // // /** @@ -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 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) 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) 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) 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 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; diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/BenchmarkHandler.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/BenchmarkHandler.java new file mode 100644 index 00000000..cd9bc85e --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/BenchmarkHandler.java @@ -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 times = new ArrayList<>(); + + for (int it = 0; it < iterations; it++) { + + // TIMER + final long start = System.currentTimeMillis(); + + ArrayList threads = new ArrayList<>(); + final ArrayList> 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 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 times = new ArrayList<>(); + + for (int it = 0; it < iterations; it++) { + + // TIMER + final long start = System.currentTimeMillis(); + + ArrayList threads = new ArrayList<>(); + final ArrayList> 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 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 times = new ArrayList<>(); + + for (int it = 0; it < iterations; it++) { + + // TIMER + final long start = System.currentTimeMillis(); + + ArrayList threads = new ArrayList<>(); + final ArrayList> 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 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 times = new ArrayList<>(); + + for (int it = 0; it < iterations; it++) { + + // TIMER + final long start = System.currentTimeMillis(); + + ArrayList threads = new ArrayList<>(); + final ArrayList> 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 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 times = new ArrayList<>(); + + for (int it = 0; it < iterations; it++) { + + // TIMER + final long start = System.currentTimeMillis(); + + ArrayList threads = new ArrayList<>(); + final ArrayList> 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 vertices; + + void setVertices(ArrayList vertices) { + this.vertices = vertices; + } + + ArrayList getVertices() { + return this.vertices; + } +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/ExtractHandler.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/ExtractHandler.java new file mode 100644 index 00000000..48c28a5d --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/ExtractHandler.java @@ -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 threads = new ArrayList<>(); + final ArrayList> 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 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 threads = new ArrayList<>(); + final ArrayList> 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 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 threads = new ArrayList<>(); + final ArrayList> 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 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 threads = new ArrayList<>(); + final ArrayList> 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 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 threads = new ArrayList<>(); + final ArrayList> 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 > results, File outFile) { + try { + BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(outFile)); + + int idx = 0; + for (int i = 0; i < results.size(); i++) { + ArrayList 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; + } + } +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/Main.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/Main.java new file mode 100644 index 00000000..2507adac --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/Main.java @@ -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; + } + } + } +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/MarchingCubes.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/MarchingCubes.java new file mode 100644 index 00000000..f9f7caf0 --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/MarchingCubes.java @@ -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 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 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 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 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 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 marchingCubes(Array values, Array xc, Array yc, Array zc, float isoLevel) { + + ArrayList 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; + } +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/TablesMC.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/TablesMC.java new file mode 100644 index 00000000..f76425db --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/TablesMC.java @@ -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 }; +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/VolumeGenerator.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/VolumeGenerator.java new file mode 100644 index 00000000..b5b3bb6b --- /dev/null +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/jogl/mc/VolumeGenerator.java @@ -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; + } +} diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/plot3d/GraphicCollection3D.java b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/plot3d/GraphicCollection3D.java index 846a28ac..617200f9 100644 --- a/MeteoInfoLib/src/main/java/org/meteoinfo/chart/plot3d/GraphicCollection3D.java +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/chart/plot3d/GraphicCollection3D.java @@ -18,9 +18,9 @@ public class GraphicCollection3D extends GraphicCollection{ private double zValue; private String zdir; private List sePoint; - private boolean allQuads; - private boolean allTriangle; - private boolean allConvexPolygon; + protected boolean allQuads; + protected boolean allTriangle; + protected boolean allConvexPolygon; /** * Constructor diff --git a/MeteoInfoLib/src/main/java/org/meteoinfo/global/MIMath.java b/MeteoInfoLib/src/main/java/org/meteoinfo/global/MIMath.java index 9d1e6a36..221901d8 100644 --- a/MeteoInfoLib/src/main/java/org/meteoinfo/global/MIMath.java +++ b/MeteoInfoLib/src/main/java/org/meteoinfo/global/MIMath.java @@ -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