diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/GraphicFactory.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/GraphicFactory.java index 0e8e9d5f..848ba759 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/GraphicFactory.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/GraphicFactory.java @@ -2850,6 +2850,66 @@ public class GraphicFactory { return graphics; } + /** + * Create image + * + * @param gdata Grid data array + * @param ls Legend scheme + * @return Image + */ + public static BufferedImage createImage(Array gdata, LegendScheme ls) { + gdata = gdata.copyIfView(); + + int width, height, breakNum; + width = gdata.getShape()[1]; + height = gdata.getShape()[0]; + breakNum = ls.getBreakNum(); + double[] breakValue = new double[breakNum]; + Color[] breakColor = new Color[breakNum]; + Color undefColor = Color.white; + for (int i = 0; i < breakNum; i++) { + breakValue[i] = Double.parseDouble(ls.getLegendBreaks().get(i).getEndValue().toString()); + breakColor[i] = ls.getLegendBreaks().get(i).getColor(); + if (ls.getLegendBreaks().get(i).isNoData()) { + undefColor = ls.getLegendBreaks().get(i).getColor(); + } + } + Color defaultColor = breakColor[breakNum - 1]; //Last color + BufferedImage aImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + double oneValue; + Color oneColor; + Index index = gdata.getIndex(); + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + index.set(i, j); + oneValue = gdata.getDouble(index); + if (Double.isNaN(oneValue)) { + oneColor = undefColor; + } else { + oneColor = defaultColor; + if (ls.getLegendType() == LegendType.GRADUATED_COLOR) { + for (int k = 0; k < breakNum - 1; k++) { + if (oneValue < breakValue[k]) { + oneColor = breakColor[k]; + break; + } + } + } else { + for (int k = 0; k < breakNum - 1; k++) { + if (oneValue == breakValue[k]) { + oneColor = breakColor[k]; + break; + } + } + } + } + aImage.setRGB(j, height - i - 1, oneColor.getRGB()); + } + } + + return aImage; + } + /** * Create image * diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/SurfaceGraphics.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/SurfaceGraphics.java index c90325b6..5b962b81 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/SurfaceGraphics.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/graphic/SurfaceGraphics.java @@ -5,6 +5,9 @@ */ package org.meteoinfo.chart.graphic; +import com.jogamp.opengl.GL2; +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.awt.AWTTextureIO; import org.joml.Vector3f; import org.meteoinfo.chart.jogl.Transform; import org.meteoinfo.chart.jogl.pipe.Pipe; @@ -15,6 +18,7 @@ import org.meteoinfo.geometry.legend.PolygonBreak; import org.meteoinfo.geometry.shape.PointZ; import org.meteoinfo.geometry.shape.ShapeTypes; +import java.awt.image.BufferedImage; import java.util.List; import java.util.Vector; @@ -31,6 +35,8 @@ public class SurfaceGraphics extends GraphicCollection3D { private Transform transform; private Vector3f[][] tVertices; private Vector3f[][] normals; + private BufferedImage image; + private Texture texture; /** * Constructor @@ -43,6 +49,7 @@ public class SurfaceGraphics extends GraphicCollection3D { this.edgeInterp = false; this.mesh = false; this.usingLight = true; + this.image = null; } /** @@ -183,6 +190,38 @@ public class SurfaceGraphics extends GraphicCollection3D { this.updateLegendIndex(); } + /** + * Get image + * @return The image + */ + public BufferedImage getImage() { + return this.image; + } + + /** + * Set image + * @param value The image + */ + public void setImage(BufferedImage value) { + this.image = value; + } + + /** + * Get texture + * @return Texture + */ + public Texture getTexture() { + return this.texture; + } + + /** + * Set texture + * @param value Texture + */ + public void setTexture(Texture value) { + this.texture = value; + } + /** * Check if the legend has multiple colors * @@ -296,4 +335,12 @@ public class SurfaceGraphics extends GraphicCollection3D { } } } + + /** + * Update texture from image + * @param gl The JOGL GL2 object + */ + public void updateTexture(GL2 gl) { + this.texture = AWTTextureIO.newTexture(gl.getGLProfile(), this.image, true); + } } diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java index 1002d685..af75066c 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/JOGLUtil.java @@ -191,6 +191,7 @@ public class JOGLUtil { graphics.setZValue(offset); TextureShape ishape = new TextureShape(); ishape.setFileName(layer.getFileName()); + ishape.setImage(layer.getImage()); Extent extent = layer.getExtent(); Extent3D ex3 = new Extent3D(extent.minX + xshift, extent.maxX + xshift, extent.minY, extent.maxY, offset, offset); List coords = new ArrayList<>(); diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java index d088bf6b..e1024b63 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/Plot3DGL.java @@ -2751,51 +2751,102 @@ public class Plot3DGL extends Plot implements GLEventListener { } } - if (pgb.isDrawFill()) { - gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL); - gl.glPolygonOffset(1.0f, 1.0f); - if (surface.isFaceInterp()) { - for (int i = 0; i < dim1 - 1; i++) { - for (int j = 0; j < dim2 - 1; j++) { - gl.glBegin(GL2.GL_QUADS); - rgba = surface.getRGBA(i, j); - gl.glColor4fv(rgba, 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j)), 0); - rgba = surface.getRGBA(i + 1, j); - gl.glColor4fv(rgba, 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j)), 0); - rgba = surface.getRGBA(i + 1, j + 1); - gl.glColor4fv(rgba, 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j + 1)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j + 1)), 0); - rgba = surface.getRGBA(i, j + 1); - gl.glColor4fv(rgba, 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j + 1)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j + 1)), 0); - gl.glEnd(); + BufferedImage image = surface.getImage(); + if (image == null) { + if (pgb.isDrawFill()) { + gl.glEnable(GL2.GL_POLYGON_OFFSET_FILL); + gl.glPolygonOffset(1.0f, 1.0f); + if (surface.isFaceInterp()) { + for (int i = 0; i < dim1 - 1; i++) { + for (int j = 0; j < dim2 - 1; j++) { + gl.glBegin(GL2.GL_QUADS); + rgba = surface.getRGBA(i, j); + gl.glColor4fv(rgba, 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j)), 0); + rgba = surface.getRGBA(i + 1, j); + gl.glColor4fv(rgba, 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j)), 0); + rgba = surface.getRGBA(i + 1, j + 1); + gl.glColor4fv(rgba, 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j + 1)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j + 1)), 0); + rgba = surface.getRGBA(i, j + 1); + gl.glColor4fv(rgba, 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j + 1)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j + 1)), 0); + gl.glEnd(); + } + } + } else { + for (int i = 0; i < dim1 - 1; i++) { + for (int j = 0; j < dim2 - 1; j++) { + gl.glBegin(GL2.GL_QUADS); + rgba = surface.getRGBA(i, j); + gl.glColor4fv(rgba, 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j)), 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j)), 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j + 1)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j + 1)), 0); + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j + 1)), 0); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j + 1)), 0); + gl.glEnd(); + } } } - } else { - for (int i = 0; i < dim1 - 1; i++) { - for (int j = 0; j < dim2 - 1; j++) { - gl.glBegin(GL2.GL_QUADS); - rgba = surface.getRGBA(i, j); - gl.glColor4fv(rgba, 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j)), 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j)), 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j + 1)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j + 1)), 0); - gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j + 1)), 0); - gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j + 1)), 0); - gl.glEnd(); - } + gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL); + } + } else { + Texture texture = surface.getTexture(); + if (texture == null) { + surface.updateTexture(gl); + texture = surface.getTexture(); + } + int idTexture = texture.getTextureObject(); + + gl.glColor3f(1f, 1f, 1f); + gl.glBindTexture(GL2.GL_TEXTURE_2D, idTexture); + + // Texture parameterization + gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); + gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR); + + // Draw image + gl.glBegin(GL2.GL_QUADS); + // Front Face + float float_x, float_y, float_xb, float_yb; + for (int i = 0; i < dim1 - 1; i++) { + for (int j = 0; j < dim2 - 1; j++) { + float_y = (float) (i) / dim1; + //float_y = 1.0f - (float) (i) / dim1; + float_x = (float) (j) / dim2; + float_yb = (float) (i + 1) / dim1; + //float_yb = 1.0f - (float) (i + 1) / dim1; + float_xb = (float) (j + 1) / dim2; + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j)), 0); + gl.glTexCoord2f(float_x, float_y); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j)), 0); + + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j)), 0); + gl.glTexCoord2f(float_x, float_yb); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j)), 0); + + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i + 1, j + 1)), 0); + gl.glTexCoord2f(float_xb, float_yb); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i + 1, j + 1)), 0); + + gl.glNormal3fv(JOGLUtil.toArray(surface.getNormal(i, j + 1)), 0); + gl.glTexCoord2f(float_xb, float_y); + gl.glVertex3fv(JOGLUtil.toArray(surface.getTVertex(i, j + 1)), 0); } } - gl.glDisable(GL2.GL_POLYGON_OFFSET_FILL); + gl.glEnd(); + + // Unbinding the texture + gl.glBindTexture(GL2.GL_TEXTURE_2D, 0); } if (lightEnabled && !surface.isUsingLight()) { @@ -3012,12 +3063,14 @@ public class Plot3DGL extends Plot implements GLEventListener { TextureShape ishape = (TextureShape) graphic.getShape(); Texture texture = ishape.getTexture(); if (texture == null) { - try { + ishape.updateTexture(gl); + texture = ishape.getTexture(); + /*try { ishape.loadTexture(); texture = ishape.getTexture(); } catch (IOException ex) { Logger.getLogger(Plot3DGL.class.getName()).log(Level.SEVERE, null, ex); - } + }*/ } if (texture == null) { return; @@ -3037,17 +3090,17 @@ public class Plot3DGL extends Plot implements GLEventListener { // Draw image gl.glBegin(GL2.GL_QUADS); // Front Face - gl.glTexCoord2f(0.0f, 0.0f); - //gl.glTexCoord2f(0.0f, 1.0f); - gl.glVertex3f(transform.transform_x((float) coords.get(0).X), transform.transform_y((float) coords.get(0).Y), transform.transform_z((float) coords.get(0).Z)); - gl.glTexCoord2f(1.0f, 0.0f); - //gl.glTexCoord2f(1.0f, 1.0f); - gl.glVertex3f(transform.transform_x((float) coords.get(1).X), transform.transform_y((float) coords.get(1).Y), transform.transform_z((float) coords.get(1).Z)); - gl.glTexCoord2f(1.0f, 1.0f); - //gl.glTexCoord2f(1.0f, 0.0f); - gl.glVertex3f(transform.transform_x((float) coords.get(2).X), transform.transform_y((float) coords.get(2).Y), transform.transform_z((float) coords.get(2).Z)); - gl.glTexCoord2f(0.0f, 1.0f); //gl.glTexCoord2f(0.0f, 0.0f); + gl.glTexCoord2f(0.0f, 1.0f); + gl.glVertex3f(transform.transform_x((float) coords.get(0).X), transform.transform_y((float) coords.get(0).Y), transform.transform_z((float) coords.get(0).Z)); + //gl.glTexCoord2f(1.0f, 0.0f); + gl.glTexCoord2f(1.0f, 1.0f); + gl.glVertex3f(transform.transform_x((float) coords.get(1).X), transform.transform_y((float) coords.get(1).Y), transform.transform_z((float) coords.get(1).Z)); + //gl.glTexCoord2f(1.0f, 1.0f); + gl.glTexCoord2f(1.0f, 0.0f); + gl.glVertex3f(transform.transform_x((float) coords.get(2).X), transform.transform_y((float) coords.get(2).Y), transform.transform_z((float) coords.get(2).Z)); + //gl.glTexCoord2f(0.0f, 1.0f); + gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(transform.transform_x((float) coords.get(3).X), transform.transform_y((float) coords.get(3).Y), transform.transform_z((float) coords.get(3).Z)); gl.glEnd(); gl.glFlush(); diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/shape/TextureShape.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/shape/TextureShape.java index 90e48673..3ba89feb 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/shape/TextureShape.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/shape/TextureShape.java @@ -5,8 +5,10 @@ */ package org.meteoinfo.chart.shape; +import com.jogamp.opengl.GL2; import com.jogamp.opengl.util.texture.Texture; import com.jogamp.opengl.util.texture.TextureIO; +import com.jogamp.opengl.util.texture.awt.AWTTextureIO; import org.meteoinfo.geometry.shape.ImageShape; import org.meteoinfo.geometry.shape.ShapeTypes; @@ -81,4 +83,12 @@ public class TextureShape extends ImageShape{ public void loadTexture() throws IOException { this.texture = TextureIO.newTexture(new File(fileName), true); } + + /** + * Update texture from image + * @param gl The JOGL GL2 object + */ + public void updateTexture(GL2 gl) { + this.texture = AWTTextureIO.newTexture(gl.getGLProfile(), this.image, true); + } } diff --git a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/ImageShape.java b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/ImageShape.java index a9c48486..8cb06278 100644 --- a/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/ImageShape.java +++ b/meteoinfo-geometry/src/main/java/org/meteoinfo/geometry/shape/ImageShape.java @@ -16,9 +16,9 @@ import java.util.List; */ public class ImageShape extends PointShape { // - private BufferedImage image; - private Object interp; - private List coords; + protected BufferedImage image; + protected Object interp; + protected List coords; // // /** diff --git a/meteoinfo-lab/milconfig.xml b/meteoinfo-lab/milconfig.xml index e3e61ae1..9dbe9b58 100644 --- a/meteoinfo-lab/milconfig.xml +++ b/meteoinfo-lab/milconfig.xml @@ -1,34 +1,36 @@ - - - + - - - - - + + + + + + + - - - + + + + - - - + + + + @@ -36,5 +38,5 @@
- + diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class index ead5c18c..0924328a 100644 Binary files a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class and b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class differ diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py index 64ead0a4..25e72bf1 100644 --- a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py +++ b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py @@ -12,10 +12,13 @@ from org.meteoinfo.geometry.legend import BreakTypes, BarBreak from org.meteoinfo.geo.legend import LegendManage from org.meteoinfo.geo.layer import LayerTypes from org.meteoinfo.geometry.shape import ShapeTypes +from org.meteoinfo.geometry.graphic import Graphic, GraphicCollection from org.meteoinfo.chart.jogl import Plot3DGL, GLForm, JOGLUtil from org.meteoinfo.math.interpolate import InterpolationMethod +from org.meteoinfo.image import ImageUtil from javax.swing import WindowConstants from java.awt import Font, Color +from java.awt.image import BufferedImage import os import numbers @@ -91,6 +94,12 @@ class Axes3DGL(Axes3D): aspect = kwargs.pop('aspect', None) if not aspect is None: self.axes.setAspectType(AspectType.valueOf(aspect.upper())) + axis = kwargs.pop('axis', True) + if not axis: + self.axes.setDrawBase(False) + self.axes.setBoxed(False) + self.axes.setDisplayXY(False) + self.axes.setDisplayZ(False) def _set_plot(self, plot): ''' @@ -568,6 +577,7 @@ class Axes3DGL(Axes3D): else: interpolation = kwargs.pop('interpolation', None) graphics = JOGLUtil.createTexture(layer, offset, xshift, interpolation) + #graphics = GraphicFactory.createImage(layer, offset, xshift, interpolation) lighting = kwargs.pop('lighting', None) if not lighting is None: @@ -1027,7 +1037,14 @@ class Axes3DGL(Axes3D): if len(args) > 1: level_arg = args[1] else: - level_arg = C + level_arg = args[0] + + facecolor = kwargs.pop('facecolor', None) + if facecolor == 'texturemap': + cdata = kwargs.pop('cdata') + if isinstance(cdata, NDArray) and cdata.ndim == 2: + min = cdata.min() + max = cdata.max() if not level_arg is None: if isinstance(level_arg, int): @@ -1044,12 +1061,25 @@ class Axes3DGL(Axes3D): ls = LegendManage.createLegendScheme(min, max, cn, cmap) ls = ls.convertTo(ShapeTypes.POLYGON) - facecolor = kwargs.pop('facecolor', None) + face_interp = None + image = None if not facecolor is None: face_interp = (facecolor == 'interp') if not face_interp: - if not facecolor in ['flat','texturemap','none']: + if facecolor == 'texturemap': + if isinstance(cdata, NDArray): + if cdata.ndim == 3: + image = ImageUtil.createImage(cdata._array) + else: + image = GraphicFactory.createImage(cdata._array, ls) + elif isinstance(cdata, BufferedImage): + image = cdata + elif isinstance(cdata, GraphicCollection): + image = cdata.getGraphicN(0).getShape().getImage() + else: + image = cdata.getShape().getImage() + elif not facecolor in ['flat','none']: facecolor = plotutil.getcolor(facecolor) ls = LegendManage.createSingleSymbolLegendScheme(ShapeTypes.POLYGON, facecolor, 1) plotutil.setlegendscheme(ls, **kwargs) @@ -1058,6 +1088,8 @@ class Axes3DGL(Axes3D): else: graphics = JOGLUtil.surface(x.asarray(), y.asarray(), z.asarray(), C.asarray(), ls) + if not image is None: + graphics.setImage(image) if face_interp: graphics.setFaceInterp(face_interp) lighting = kwargs.pop('lighting', None)