update jogl scatter render

This commit is contained in:
wyq 2023-01-28 22:57:57 +08:00
parent 788ae3d51f
commit df767d471f
7 changed files with 202 additions and 56 deletions

View File

@ -2504,7 +2504,16 @@ public class GLPlot extends Plot {
if (((GraphicCollection3D) graphic).isSphere()) { if (((GraphicCollection3D) graphic).isSphere()) {
this.drawSpheres(gl, graphic); this.drawSpheres(gl, graphic);
} else { } 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; break;
case POLYLINE_Z: case POLYLINE_Z:

View File

@ -1,11 +1,35 @@
package org.meteoinfo.chart.render.jogl; package org.meteoinfo.chart.render.jogl;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2; import com.jogamp.opengl.GL2;
import com.jogamp.opengl.util.GLBuffers;
import org.meteoinfo.chart.graphic.GraphicCollection3D; 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 { 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 * Constructor
@ -14,6 +38,15 @@ public class PointRender extends JOGLGraphicRender {
*/ */
public PointRender(GL2 gl) { public PointRender(GL2 gl) {
super(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 * @param pointGraphics 3D point graphics
*/ */
public PointRender(GL2 gl, GraphicCollection3D pointGraphics) { public PointRender(GL2 gl, GraphicCollection3D pointGraphics) {
super(gl); this(gl);
this.pointGraphics = pointGraphics;
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 @Override
public void draw() { 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);
}
} }
} }

View File

@ -1326,7 +1326,7 @@ public class LayoutMap extends LayoutElement {
} }
/** /**
* Set grid label positiont * Set grid label position
* *
* @param value Grid label position * @param value Grid label position
*/ */

View File

@ -1,32 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile"> <MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\io\dataconvert"> <Path OpenPath="D:\Working\MIScript\Jython\mis\dataframe">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\annotate"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\isosurface"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\arrow"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\particles"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\bar"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\scatter"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\model"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\boxplot"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\common_math\stats"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\funny"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\funny"/>
<RecentFolder Folder="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\surf"/>
<RecentFolder Folder="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\toolbox\emips"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\dataconvert"/> <RecentFolder Folder="D:\Working\MIScript\Jython\mis\map\geoshow"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\3d_earth"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\pie"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\dataframe"/>
</Path> </Path>
<File> <File>
<OpenedFiles> <OpenedFiles>
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\main_gui.py"/> <OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\main_gui.py"/>
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\_reload.py"/> <OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\_reload.py"/>
<OpenedFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\emission_panel.py"/> <OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\scatter\scatter3_4.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\dataframe\dataframe_groupby_3.py"/>
</OpenedFiles> </OpenedFiles>
<RecentFiles> <RecentFiles>
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\main_gui.py"/> <RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\main_gui.py"/>
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\_reload.py"/> <RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\_reload.py"/>
<RecentFile File="D:\MyProgram\java\MeteoInfoDev\toolbox\EMIPS\emips\gui\emission_panel.py"/> <RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\scatter\scatter3_4.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\dataframe\dataframe_groupby_3.py"/>
</RecentFiles> </RecentFiles>
</File> </File>
<Font> <Font>

View File

@ -1,9 +1,9 @@
#----------------------------------------------------- # -----------------------------------------------------
# Author: Yaqiang Wang # Author: Yaqiang Wang
# Date: 2018-7-18 # Date: 2018-7-18
# Purpose: MeteoInfo index module # Purpose: MeteoInfo index module
# Note: Jython # Note: Jython
#----------------------------------------------------- # -----------------------------------------------------
from org.meteoinfo.dataframe import Index as MIIndex from org.meteoinfo.dataframe import Index as MIIndex
from org.meteoinfo.dataframe import DateTimeIndex as MIDateTimeIndex from org.meteoinfo.dataframe import DateTimeIndex as MIDateTimeIndex
@ -15,8 +15,9 @@ import numbers
import mipylib.numeric as np import mipylib.numeric as np
import mipylib.miutil as miutil import mipylib.miutil as miutil
class Index(object): class Index(object):
@staticmethod @staticmethod
def factory(data=None, name='Index', index=None): def factory(data=None, name='Index', index=None):
""" """
@ -32,7 +33,7 @@ class Index(object):
return DateTimeIndex(index=index) return DateTimeIndex(index=index)
else: else:
return Index(index=index) return Index(index=index)
def __init__(self, data=None, name='Index', index=None): def __init__(self, data=None, name='Index', index=None):
""" """
Index Index
@ -57,22 +58,22 @@ class Index(object):
@name.setter @name.setter
def name(self, value): def name(self, value):
self._index.setName(value) self._index.setName(value)
def __len__(self): def __len__(self):
return self._index.size() return self._index.size()
def __iter__(self): def __iter__(self):
""" """
provide iteration over the values of the Index provide iteration over the values of the Index
""" """
return iter(self._index) return iter(self._index)
def __str__(self): def __str__(self):
return self.__repr__() return self.__repr__()
def __repr__(self): def __repr__(self):
return self._index.toString() return self._index.toString()
def __getitem__(self, k): def __getitem__(self, k):
if isinstance(k, int): if isinstance(k, int):
return self.data[k] return self.data[k]
@ -82,17 +83,17 @@ class Index(object):
sidx = self.__len__() + sidx sidx = self.__len__() + sidx
eidx = self.__len__() if k.stop is None else k.stop eidx = self.__len__() if k.stop is None else k.stop
if eidx < 0: if eidx < 0:
eidx = self.__len__() + eidx eidx = self.__len__() + eidx
step = 1 if k.step is None else k.step step = 1 if k.step is None else k.step
r = self._index.subIndex(sidx, eidx, step) r = self._index.subIndex(sidx, eidx, step)
return Index.factory(index=r) return Index.factory(index=r)
def __eq__(self, other): def __eq__(self, other):
if isinstance(other, numbers.Number): if isinstance(other, numbers.Number):
return np.NDArray(self._index.equal(other)) return np.NDArray(self._index.equal(other))
else: else:
return False return False
def index(self, v): def index(self, v):
""" """
Get index of a value. Get index of a value.
@ -120,14 +121,14 @@ class Index(object):
r = self._index.getIndices(key.asarray()) r = self._index.getIndices(key.asarray())
else: else:
r = self._index.getIndices(key) r = self._index.getIndices(key)
if outkeys: if outkeys:
return list(r[0]), list(r[1]) return list(r[0]), list(r[1])
else: else:
return list(r[0]) return list(r[0])
def fill_keylist(self, rdata, rfdata): def fill_keylist(self, rdata, rfdata):
return self._index.fillKeyList(rdata.asarray(), rfdata) return self._index.fillKeyList(rdata.asarray(), rfdata)
def get_format(self): def get_format(self):
""" """
Get value to string format. Get value to string format.
@ -135,7 +136,7 @@ class Index(object):
:returns: (*string*) Format string. :returns: (*string*) Format string.
""" """
return self._index.getFormat() return self._index.getFormat()
def set_format(self, format): def set_format(self, format):
""" """
Set value to string format. Set value to string format.
@ -143,10 +144,11 @@ class Index(object):
:param format: (*string*) Format string. :param format: (*string*) Format string.
""" """
self._index.setFormat(format) self._index.setFormat(format)
############################################ ############################################
class DateTimeIndex(Index): class DateTimeIndex(Index):
def __init__(self, data=None, name='Index', start=None, end=None, periods=None, freq='D', index=None): def __init__(self, data=None, name='Index', start=None, end=None, periods=None, freq='D', index=None):
if index is None: if index is None:
if not data is None: if not data is None:
@ -169,7 +171,7 @@ class DateTimeIndex(Index):
self._index = index self._index = index
self.data = miutil.pydate(list(self._index.getData())) self.data = miutil.pydate(list(self._index.getData()))
self._index.setName(name) self._index.setName(name)
def index(self, v): def index(self, v):
""" """
Get index of a value. Get index of a value.
@ -183,7 +185,7 @@ class DateTimeIndex(Index):
else: else:
v = miutil.str2jdate(v) v = miutil.str2jdate(v)
return self._index.indexOf(v) return self._index.indexOf(v)
def get_loc(self, key, outkeys=False): def get_loc(self, key, outkeys=False):
""" """
Get integer location, slice or boolean mask for requested label. 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): elif isinstance(key, (list, tuple, np.NDArray)) and isinstance(key[0], datetime.datetime):
key = miutil.jdatetime(key) key = miutil.jdatetime(key)
r = self._index.getIndices(key) r = self._index.getIndices(key)
if outkeys: if outkeys:
return list(r[0]), list(r[1]) return list(r[0]), list(r[1])
else: else:
return list(r[0]) return list(r[0])
@property @property
def year(self): def year(self):
""" """
@ -213,7 +215,7 @@ class DateTimeIndex(Index):
""" """
r = self._index.getYear() r = self._index.getYear()
return Index(index=r) return Index(index=r)
@property @property
def month(self): def month(self):
""" """
@ -221,7 +223,7 @@ class DateTimeIndex(Index):
""" """
r = self._index.getMonth() r = self._index.getMonth()
return Index(index=r) return Index(index=r)
@property @property
def day(self): def day(self):
""" """
@ -229,7 +231,7 @@ class DateTimeIndex(Index):
""" """
r = self._index.getDay() r = self._index.getDay()
return Index(index=r) return Index(index=r)
@property @property
def hour(self): def hour(self):
""" """
@ -237,7 +239,7 @@ class DateTimeIndex(Index):
""" """
r = self._index.getHour() r = self._index.getHour()
return Index(index=r) return Index(index=r)
@property @property
def minute(self): def minute(self):
""" """
@ -245,7 +247,7 @@ class DateTimeIndex(Index):
""" """
r = self._index.getMinute() r = self._index.getMinute()
return Index(index=r) return Index(index=r)
@property @property
def second(self): def second(self):
""" """
@ -254,7 +256,7 @@ class DateTimeIndex(Index):
r = self._index.getSecond() r = self._index.getSecond()
return Index(index=r) return Index(index=r)
############################################# #############################################
def date_range(start=None, end=None, periods=None, freq='D'): 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) r = DateTimeIndex(start=start, end=end, periods=periods, freq=freq)
return r return r

View File

@ -1599,16 +1599,16 @@ class EarthAxes3D(Axes3DGL):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['aspect'] = 'equal' kwargs['aspect'] = 'equal'
if not kwargs.has_key('bgcolor'): if 'bgcolor' not in kwargs.keys():
kwargs['bgcolor'] = 'k' kwargs['bgcolor'] = 'k'
kwargs['clip_plane'] = False kwargs['clip_plane'] = False
kwargs['axis'] = False kwargs['axis'] = False
if not kwargs.has_key('distance'): if 'distance' not in kwargs.keys():
kwargs['distance'] = 500 kwargs['distance'] = 500
super(EarthAxes3D, self).__init__(*args, **kwargs) super(EarthAxes3D, self).__init__(*args, **kwargs)
image = kwargs.pop('image', 'world_topo.jpg') image = kwargs.pop('image', 'world_topo.jpg')
if not image is None: if image is not None:
if not os.path.exists(image): if not os.path.exists(image):
image = os.path.join(migl.get_map_folder(), image) image = os.path.join(migl.get_map_folder(), image)
if os.path.exists(image): if os.path.exists(image):
@ -1650,7 +1650,7 @@ class EarthAxes3D(Axes3DGL):
:return: Longitude and latitude lines. :return: Longitude and latitude lines.
""" """
nlon = (int)(360. / lon_delta) nlon = int(360. / lon_delta)
lons = np.zeros([nlon, npoints]) lons = np.zeros([nlon, npoints])
lats = np.zeros([nlon, npoints]) lats = np.zeros([nlon, npoints])
alts = np.zeros([nlon, npoints]) + offset alts = np.zeros([nlon, npoints]) + offset
@ -1662,7 +1662,7 @@ class EarthAxes3D(Axes3DGL):
idx += 1 idx += 1
self.plot(lons, lats, alts, **kwargs) self.plot(lons, lats, alts, **kwargs)
nlat = (int)(180. / lat_delta) nlat = int(180. / lat_delta)
lons = np.zeros([nlat, npoints]) lons = np.zeros([nlat, npoints])
lats = np.zeros([nlat, npoints]) lats = np.zeros([nlat, npoints])
alts = np.zeros([nlat, npoints]) + offset alts = np.zeros([nlat, npoints]) + offset