diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java index b8da5456..6300fc5b 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLPlot.java @@ -2504,7 +2504,16 @@ public class GLPlot extends Plot { if (((GraphicCollection3D) graphic).isSphere()) { this.drawSpheres(gl, graphic); } else { - this.drawPoints(gl, graphic); + //this.drawPoints(gl, graphic); + if (!this.renderMap.containsKey(graphic)) { + renderMap.put(graphic, new PointRender(gl, (GraphicCollection3D) graphic)); + } + PointRender pointRender = (PointRender) renderMap.get(graphic); + pointRender.setTransform(this.transform, this.alwaysUpdateBuffers); + pointRender.setOrthographic(this.orthographic); + pointRender.setLighting(this.lighting); + pointRender.updateMatrix(); + pointRender.draw(); } break; case POLYLINE_Z: diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/render/jogl/PointRender.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/render/jogl/PointRender.java index d6f5c1eb..e45d5804 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/render/jogl/PointRender.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/render/jogl/PointRender.java @@ -1,11 +1,35 @@ package org.meteoinfo.chart.render.jogl; +import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; +import com.jogamp.opengl.util.GLBuffers; import org.meteoinfo.chart.graphic.GraphicCollection3D; +import org.meteoinfo.chart.jogl.Program; +import org.meteoinfo.chart.jogl.Transform; +import org.meteoinfo.chart.jogl.Utils; +import org.meteoinfo.geometry.graphic.Graphic; +import org.meteoinfo.geometry.legend.*; +import org.meteoinfo.geometry.shape.PointZ; +import org.meteoinfo.geometry.shape.PointZShape; +import org.meteoinfo.geometry.shape.Polyline; +import org.meteoinfo.geometry.shape.PolylineZShape; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; public class PointRender extends JOGLGraphicRender { - private GraphicCollection3D pointGraphics; + private GraphicCollection3D graphics; + private IntBuffer vbo; + private Program program; + private int vertexNum; + private int sizePosition; + private int sizeColor; + private int sizeNormal; + private float[] vertexColor; + private float pointSize; /** * Constructor @@ -14,6 +38,15 @@ public class PointRender extends JOGLGraphicRender { */ public PointRender(GL2 gl) { super(gl); + + if (useShader) { + try { + this.compileShaders(); + } catch (Exception e) { + e.printStackTrace(); + } + } + initVertexBuffer(); } /** @@ -23,12 +56,113 @@ public class PointRender extends JOGLGraphicRender { * @param pointGraphics 3D point graphics */ public PointRender(GL2 gl, GraphicCollection3D pointGraphics) { - super(gl); - this.pointGraphics = pointGraphics; + this(gl); + + this.graphics = pointGraphics; + this.vertexNum = pointGraphics.getNumGraphics(); + PointBreak pb = (PointBreak) this.graphics.getGraphicN(0).getLegend(); + this.pointSize = pb.getSize(); + this.updateVertexColor(); + } + + void compileShaders() throws Exception { + String vertexShaderCode = Utils.loadResource("/shaders/surface/vertex.vert"); + String fragmentShaderCode = Utils.loadResource("/shaders/surface/surface.frag"); + program = new Program("surface", vertexShaderCode, fragmentShaderCode); + } + + private void initVertexBuffer() { + vbo = GLBuffers.newDirectIntBuffer(1); + } + + private void updateVertexColor() { + this.vertexColor = new float[this.vertexNum * 4]; + int i = 0; + float[] color; + for (Graphic graphic : this.graphics.getGraphics()) { + PointBreak pb = (PointBreak) graphic.getLegend(); + color = pb.getColor().getRGBComponents(null); + System.arraycopy(color, 0, vertexColor, i * 4, 4); + i++; + } + } + + private float[] getVertexPosition() { + float[] vertexData = new float[this.vertexNum * 3]; + int i = 0; + for (Graphic graphic : this.graphics.getGraphics()) { + PointZShape shape = (PointZShape) graphic.getShape(); + PointZ p = (PointZ) shape.getPoint(); + vertexData[i] = transform.transform_x((float) p.X); + vertexData[i + 1] = transform.transform_y((float) p.Y); + vertexData[i + 2] = transform.transform_z((float) p.Z); + i += 3; + } + + return vertexData; + } + + @Override + public void setTransform(Transform transform, boolean alwaysUpdateBuffers) { + boolean updateBuffer = true; + if (!alwaysUpdateBuffers && this.transform != null && this.transform.equals(transform)) + updateBuffer = false; + + super.setTransform((Transform) transform.clone()); + + if (updateBuffer) { + float[] vertexData = this.getVertexPosition(); + FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(vertexData); + sizePosition = vertexBuffer.capacity() * Float.BYTES; + + FloatBuffer colorBuffer = GLBuffers.newDirectFloatBuffer(vertexColor); + sizeColor = colorBuffer.capacity() * Float.BYTES; + int totalSize = sizePosition + sizeColor; + + gl.glGenBuffers(1, vbo); + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo.get(0)); + gl.glBufferData(GL.GL_ARRAY_BUFFER, totalSize, null, GL.GL_STATIC_DRAW); + gl.glBufferSubData(GL.GL_ARRAY_BUFFER, 0, sizePosition, vertexBuffer); + gl.glBufferSubData(GL.GL_ARRAY_BUFFER, sizePosition, sizeColor, colorBuffer); + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); + } + } + + void setUniforms() { + } @Override public void draw() { + if (useShader) { // not working now + program.use(gl); + setUniforms(); + gl.glUseProgram(0); + } else { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo.get(0)); + + // enable vertex arrays + gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); + gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0); + gl.glEnableClientState(GL2.GL_COLOR_ARRAY); + gl.glColorPointer(4, GL.GL_FLOAT, 0, sizePosition); + + boolean lightEnabled = this.lighting.isEnable(); + if (lightEnabled) { + this.lighting.stop(gl); + } + gl.glPointSize(this.pointSize * this.dpiScale); + gl.glDrawArrays(GL.GL_POINTS, 0, this.vertexNum); + + if (lightEnabled) { + this.lighting.start(gl); + } + + gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); + gl.glDisableClientState(GL2.GL_COLOR_ARRAY); + + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); + } } } diff --git a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layout/LayoutMap.java b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layout/LayoutMap.java index 038930f6..7b2e2f5b 100644 --- a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layout/LayoutMap.java +++ b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/layout/LayoutMap.java @@ -1326,7 +1326,7 @@ public class LayoutMap extends LayoutElement { } /** - * Set grid label positiont + * Set grid label position * * @param value Grid label position */ diff --git a/meteoinfo-lab/milconfig.xml b/meteoinfo-lab/milconfig.xml index 10f92a7d..a4155e49 100644 --- a/meteoinfo-lab/milconfig.xml +++ b/meteoinfo-lab/milconfig.xml @@ -1,32 +1,34 @@ - - - - - - - - - - + + + + + - - - - - + + + + + + + + + + - + + - + + diff --git a/meteoinfo-lab/pylib/mipylib/dataframe/index.py b/meteoinfo-lab/pylib/mipylib/dataframe/index.py index 075cf9fb..c324d6ff 100644 --- a/meteoinfo-lab/pylib/mipylib/dataframe/index.py +++ b/meteoinfo-lab/pylib/mipylib/dataframe/index.py @@ -1,9 +1,9 @@ -#----------------------------------------------------- +# ----------------------------------------------------- # Author: Yaqiang Wang # Date: 2018-7-18 # Purpose: MeteoInfo index module # Note: Jython -#----------------------------------------------------- +# ----------------------------------------------------- from org.meteoinfo.dataframe import Index as MIIndex from org.meteoinfo.dataframe import DateTimeIndex as MIDateTimeIndex @@ -15,8 +15,9 @@ import numbers import mipylib.numeric as np import mipylib.miutil as miutil + class Index(object): - + @staticmethod def factory(data=None, name='Index', index=None): """ @@ -32,7 +33,7 @@ class Index(object): return DateTimeIndex(index=index) else: return Index(index=index) - + def __init__(self, data=None, name='Index', index=None): """ Index @@ -57,22 +58,22 @@ class Index(object): @name.setter def name(self, value): self._index.setName(value) - + def __len__(self): return self._index.size() - + def __iter__(self): """ provide iteration over the values of the Index """ return iter(self._index) - + def __str__(self): return self.__repr__() - + def __repr__(self): return self._index.toString() - + def __getitem__(self, k): if isinstance(k, int): return self.data[k] @@ -82,17 +83,17 @@ class Index(object): sidx = self.__len__() + sidx eidx = self.__len__() if k.stop is None else k.stop if eidx < 0: - eidx = self.__len__() + eidx + eidx = self.__len__() + eidx step = 1 if k.step is None else k.step r = self._index.subIndex(sidx, eidx, step) return Index.factory(index=r) - + def __eq__(self, other): if isinstance(other, numbers.Number): return np.NDArray(self._index.equal(other)) else: return False - + def index(self, v): """ Get index of a value. @@ -120,14 +121,14 @@ class Index(object): r = self._index.getIndices(key.asarray()) else: r = self._index.getIndices(key) - if outkeys: + if outkeys: return list(r[0]), list(r[1]) else: return list(r[0]) - + def fill_keylist(self, rdata, rfdata): return self._index.fillKeyList(rdata.asarray(), rfdata) - + def get_format(self): """ Get value to string format. @@ -135,7 +136,7 @@ class Index(object): :returns: (*string*) Format string. """ return self._index.getFormat() - + def set_format(self, format): """ Set value to string format. @@ -143,10 +144,11 @@ class Index(object): :param format: (*string*) Format string. """ self._index.setFormat(format) - + + ############################################ class DateTimeIndex(Index): - + def __init__(self, data=None, name='Index', start=None, end=None, periods=None, freq='D', index=None): if index is None: if not data is None: @@ -169,7 +171,7 @@ class DateTimeIndex(Index): self._index = index self.data = miutil.pydate(list(self._index.getData())) self._index.setName(name) - + def index(self, v): """ Get index of a value. @@ -183,7 +185,7 @@ class DateTimeIndex(Index): else: v = miutil.str2jdate(v) return self._index.indexOf(v) - + def get_loc(self, key, outkeys=False): """ Get integer location, slice or boolean mask for requested label. @@ -201,11 +203,11 @@ class DateTimeIndex(Index): elif isinstance(key, (list, tuple, np.NDArray)) and isinstance(key[0], datetime.datetime): key = miutil.jdatetime(key) r = self._index.getIndices(key) - if outkeys: + if outkeys: return list(r[0]), list(r[1]) else: return list(r[0]) - + @property def year(self): """ @@ -213,7 +215,7 @@ class DateTimeIndex(Index): """ r = self._index.getYear() return Index(index=r) - + @property def month(self): """ @@ -221,7 +223,7 @@ class DateTimeIndex(Index): """ r = self._index.getMonth() return Index(index=r) - + @property def day(self): """ @@ -229,7 +231,7 @@ class DateTimeIndex(Index): """ r = self._index.getDay() return Index(index=r) - + @property def hour(self): """ @@ -237,7 +239,7 @@ class DateTimeIndex(Index): """ r = self._index.getHour() return Index(index=r) - + @property def minute(self): """ @@ -245,7 +247,7 @@ class DateTimeIndex(Index): """ r = self._index.getMinute() return Index(index=r) - + @property def second(self): """ @@ -254,7 +256,7 @@ class DateTimeIndex(Index): r = self._index.getSecond() return Index(index=r) - + ############################################# def date_range(start=None, end=None, periods=None, freq='D'): """ @@ -269,4 +271,3 @@ def date_range(start=None, end=None, periods=None, freq='D'): """ r = DateTimeIndex(start=start, end=end, periods=periods, freq=freq) return r - \ No newline at end of file diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class index 8938f832..babb2550 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 4bcdb2ff..9f310913 100644 --- a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py +++ b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py @@ -1599,16 +1599,16 @@ class EarthAxes3D(Axes3DGL): def __init__(self, *args, **kwargs): kwargs['aspect'] = 'equal' - if not kwargs.has_key('bgcolor'): + if 'bgcolor' not in kwargs.keys(): kwargs['bgcolor'] = 'k' kwargs['clip_plane'] = False kwargs['axis'] = False - if not kwargs.has_key('distance'): + if 'distance' not in kwargs.keys(): kwargs['distance'] = 500 super(EarthAxes3D, self).__init__(*args, **kwargs) image = kwargs.pop('image', 'world_topo.jpg') - if not image is None: + if image is not None: if not os.path.exists(image): image = os.path.join(migl.get_map_folder(), image) if os.path.exists(image): @@ -1650,7 +1650,7 @@ class EarthAxes3D(Axes3DGL): :return: Longitude and latitude lines. """ - nlon = (int)(360. / lon_delta) + nlon = int(360. / lon_delta) lons = np.zeros([nlon, npoints]) lats = np.zeros([nlon, npoints]) alts = np.zeros([nlon, npoints]) + offset @@ -1662,7 +1662,7 @@ class EarthAxes3D(Axes3DGL): idx += 1 self.plot(lons, lats, alts, **kwargs) - nlat = (int)(180. / lat_delta) + nlat = int(180. / lat_delta) lons = np.zeros([nlat, npoints]) lats = np.zeros([nlat, npoints]) alts = np.zeros([nlat, npoints]) + offset