diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/GLChartPanel.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/GLChartPanel.java index 6caebcb3..3114ac17 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/GLChartPanel.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/GLChartPanel.java @@ -281,7 +281,7 @@ public class GLChartPanel extends GLJPanel implements IChartPanel{ } /** - * Get if using off screen image double buffering. + * Get if using off-screen image double buffering. * Using double buffering will be faster but lower view quality in * high dpi screen computer. * @@ -292,7 +292,7 @@ public class GLChartPanel extends GLJPanel implements IChartPanel{ } /** - * Set using off screen image double buffering or not. + * Set using off-screen image double buffering or not. * @param value Boolean */ public void setDoubleBuffer(boolean value) { diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/MapGLPlot.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/MapGLPlot.java new file mode 100644 index 00000000..2363b270 --- /dev/null +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/MapGLPlot.java @@ -0,0 +1,390 @@ +package org.meteoinfo.chart.jogl; + +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GL2; +import org.meteoinfo.chart.ChartText; +import org.meteoinfo.chart.graphic.GraphicProjectionUtil; +import org.meteoinfo.chart.plot.MapGridLine; +import org.meteoinfo.chart.plot.MapGridLine3D; +import org.meteoinfo.common.*; +import org.meteoinfo.geometry.graphic.Graphic; +import org.meteoinfo.projection.ProjectionInfo; + +import java.awt.geom.Rectangle2D; +import java.util.List; + +public class MapGLPlot extends GLPlot { + private ProjectionInfo projInfo; + + /** + * Constructor + */ + public MapGLPlot() { + this(ProjectionInfo.LONG_LAT); + } + + /** + * Constructor + * @param projInfo Projection info + */ + public MapGLPlot(ProjectionInfo projInfo) { + super(); + this.gridLine = new MapGridLine3D(); + this.projInfo = projInfo; + updateExtent(); + } + + /** + * Get projection info + * @return Projection info + */ + public ProjectionInfo getProjInfo() { + return this.projInfo; + } + + /** + * Set projection info + * @param value Projection info + */ + public void setProjInfo(ProjectionInfo value) { + this.projInfo = value; + if (!projInfo.isLonLat()) + ((MapGridLine3D) this.gridLine).setProjInfo(projInfo); + } + + /** + * Add a graphic + * + * @param graphic The graphic + * @param proj The graphic projection + */ + @Override + public void addGraphic(Graphic graphic, ProjectionInfo proj) { + if (proj.equals(this.projInfo)) { + super.addGraphic(graphic); + } else { + Graphic nGraphic = GraphicProjectionUtil.projectClipGraphic(graphic, proj, this.projInfo); + super.addGraphic(nGraphic); + } + } + + /** + * Add a graphic + * + * @param index The index + * @param graphic The graphic + * @param proj The graphic projection + */ + @Override + public void addGraphic(int index, Graphic graphic, ProjectionInfo proj) { + if (proj.equals(this.projInfo)) { + super.addGraphic(index, graphic); + } else { + Graphic nGraphic = GraphicProjectionUtil.projectClipGraphic(graphic, proj, this.projInfo); + super.addGraphic(index, nGraphic); + } + } + + /** + * Set draw extent + * + * @param value Extent + */ + @Override + public void setDrawExtent(Extent3D value) { + super.setDrawExtent(value); + + if (!this.projInfo.isLonLat()) { + ((MapGridLine3D) this.gridLine).setExtent(value); + } + } + + @Override + protected void updateExtent() { + super.updateExtent(); + if (!this.projInfo.isLonLat()) { + ((MapGridLine3D) this.gridLine).setExtent(this.drawExtent); + } + } + + @Override + protected void drawXYGridLine(GL2 gl) { + if (this.projInfo.isLonLat()) { + super.drawXYGridLine(gl); + } else { + MapGridLine mapGridLine = (MapGridLine3D) gridLine; + //Longitude + if (mapGridLine.isDrawXLine()) { + if (mapGridLine.getLongitudeLines() != null) { + this.drawGraphics(gl, mapGridLine.getLongitudeLines()); + } + } + //Latitude + if (mapGridLine.isDrawYLine()) { + if (mapGridLine.getLatitudeLines() != null) { + this.drawGraphics(gl, mapGridLine.getLatitudeLines()); + } + } + } + } + + @Override + protected void drawAxis(GL2 gl) { + if (this.projInfo.isLonLat()) { + super.drawAxis(gl); + } else { + float xMin, xMax, yMin, yMax, zMin, zMax; + xMin = this.transform.transform_x((float) axesExtent.minX); + xMax = this.transform.transform_x((float) axesExtent.maxX); + yMin = this.transform.transform_y((float) axesExtent.minY); + yMax = this.transform.transform_y((float) axesExtent.maxY); + zMin = this.transform.transform_z((float) axesExtent.minZ); + zMax = this.transform.transform_z((float) axesExtent.maxZ); + + gl.glDepthFunc(GL.GL_ALWAYS); + + //Draw axis + float[] rgba; + float x, y; + int skip; + XAlign xAlign; + YAlign yAlign; + Rectangle2D rect; + float strWidth, strHeight; + MapGridLine3D mapGridLine = (MapGridLine3D) gridLine; + if (this.displayXY) { + //Draw x/y axis lines + //x axis line + if (this.angleY >= 90 && this.angleY < 270) { + y = yMax; + } else { + y = yMin; + } + rgba = this.xAxis.getLineColor().getRGBComponents(null); + gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); + gl.glLineWidth(this.xAxis.getLineWidth() * this.dpiScale); + gl.glBegin(GL2.GL_LINES); + gl.glVertex3f(xMin, y, zMin); + gl.glVertex3f(xMax, y, zMin); + gl.glEnd(); + + //Longitude axis ticks + float tickLen = this.xAxis.getTickLength() * this.lenScale; + float axisLen = this.toScreenLength(xMin, y, zMin, xMax, y, zMin); + float y1 = y > 0 ? y + tickLen : y - tickLen; + if (this.angleY < 90 || (this.angleY >= 180 && this.angleY < 270)) { + xAlign = XAlign.LEFT; + } else { + xAlign = XAlign.RIGHT; + } + if (this.angleX > -120) { + yAlign = YAlign.TOP; + } else { + yAlign = YAlign.BOTTOM; + } + strWidth = 0.0f; + strHeight = 0.0f; + List lonLabels = mapGridLine.getLongitudeLabels(); + for (int i = 0; i < lonLabels.size(); i++) { + GridLabel gridLabel = lonLabels.get(i); + PointD point = gridLabel.getCoord(); + x = (float) point.X; + if (x < axesExtent.minX || x > axesExtent.maxX) { + continue; + } + x = this.transform.transform_x(x); + + //Draw tick line + rgba = this.xAxis.getLineColor().getRGBComponents(null); + gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); + gl.glLineWidth(this.xAxis.getLineWidth() * this.dpiScale); + gl.glBegin(GL2.GL_LINES); + gl.glVertex3f(x, y, zMin); + gl.glVertex3f(x, y1, zMin); + gl.glEnd(); + + //Draw tick label + rect = drawString(gl, gridLabel.getLabString(), this.xAxis.getTickLabelFont(), + this.xAxis.getTickLabelColor(), x, y1, zMin, xAlign, yAlign); + if (strWidth < rect.getWidth()) { + strWidth = (float) rect.getWidth(); + } + if (strHeight < rect.getHeight()) { + strHeight = (float) rect.getHeight(); + } + } + + //Draw x axis label + ChartText label = this.xAxis.getLabel(); + if (label != null) { + strWidth += this.tickSpace; + float angle = this.toScreenAngle(xMin, y, zMin, xMax, y, zMin); + angle = y < 0 ? 270 - angle : 90 - angle; + float yShift = Math.min(-strWidth, -strWidth); + if (this.angleX <= -120) { + yShift = -yShift; + } + drawString(gl, label, 0.0f, y1, zMin, XAlign.CENTER, yAlign, angle, 0, yShift); + } + + //////////////////////////////////////////// + //y axis line + if (this.angleY >= 180 && this.angleY < 360) { + x = xMax; + } else { + x = xMin; + } + rgba = this.yAxis.getLineColor().getRGBComponents(null); + gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); + gl.glLineWidth(this.yAxis.getLineWidth() * this.dpiScale); + gl.glBegin(GL2.GL_LINES); + gl.glVertex3f(x, yMin, zMin); + gl.glVertex3f(x, yMax, zMin); + gl.glEnd(); + + //y axis ticks + axisLen = this.toScreenLength(x, yMin, zMin, x, yMax, zMin); + tickLen = this.yAxis.getTickLength() * this.lenScale; + float x1 = x > 0 ? x + tickLen : x - tickLen; + if (this.angleY < 90 || (this.angleY >= 180 && this.angleY < 270)) { + xAlign = XAlign.RIGHT; + } else { + xAlign = XAlign.LEFT; + } + if (this.angleX > -120) { + yAlign = YAlign.TOP; + } else { + yAlign = YAlign.BOTTOM; + } + strWidth = 0.0f; + strHeight = 0.0f; + List latLabels = mapGridLine.getLatitudeLabels(); + for (int i = 0; i < latLabels.size(); i++) { + GridLabel gridLabel = latLabels.get(i); + PointD point = gridLabel.getCoord(); + y = (float) point.Y; + if (y < axesExtent.minY || y > axesExtent.maxY) { + continue; + } + y = this.transform.transform_y(y); + + //Draw tick line + rgba = this.yAxis.getLineColor().getRGBComponents(null); + gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); + gl.glLineWidth(this.yAxis.getLineWidth() * this.dpiScale); + gl.glBegin(GL2.GL_LINES); + gl.glVertex3f(x, y, zMin); + gl.glVertex3f(x1, y, zMin); + gl.glEnd(); + + //Draw tick label + rect = drawString(gl, gridLabel.getLabString(), this.yAxis.getTickLabelFont(), + this.yAxis.getTickLabelColor(), x1, y, zMin, xAlign, yAlign); + if (strWidth < rect.getWidth()) { + strWidth = (float) rect.getWidth(); + } + if (strHeight < rect.getHeight()) { + strHeight = (float) rect.getHeight(); + } + } + + //Draw y axis label + label = this.yAxis.getLabel(); + if (label != null) { + strWidth += this.tickSpace; + float angle = this.toScreenAngle(x, yMin, zMin, x, yMax, xMin); + angle = x > 0 ? 270 - angle : 90 - angle; + float yShift = Math.min(-strWidth, -strWidth); + if (this.angleX <= -120) { + yShift = -yShift; + } + drawString(gl, label, x1, 0.0f, zMin, XAlign.CENTER, yAlign, angle, 0, yShift); + } + } + + //Draw z axis + if (this.displayZ) { + //z axis line + if (this.angleY < 90) { + x = xMin; + y = yMax; + } else if (this.angleY < 180) { + x = xMax; + y = yMax; + } else if (this.angleY < 270) { + x = xMax; + y = yMin; + } else { + x = xMin; + y = yMin; + } + rgba = this.zAxis.getLineColor().getRGBComponents(null); + gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); + gl.glLineWidth(this.zAxis.getLineWidth() * this.dpiScale); + gl.glBegin(GL2.GL_LINES); + gl.glVertex3f(x, y, zMin); + gl.glVertex3f(x, y, zMax); + gl.glEnd(); + + //z axis ticks + this.zAxis.updateTickLabels(); + List tlabs = this.zAxis.getTickLabels(); + float axisLen = this.toScreenLength(x, y, zMin, x, y, zMax); + skip = getLabelGap(this.zAxis.getTickLabelFont(), tlabs, axisLen); + float x1 = x; + float y1 = y; + float tickLen = this.zAxis.getTickLength() * this.lenScale; + if (x < 0) { + if (y > 0) { + y1 += tickLen; + } else { + x1 -= tickLen; + } + } else { + if (y > 0) { + x1 += tickLen; + } else { + y1 -= tickLen; + } + } + xAlign = XAlign.RIGHT; + yAlign = YAlign.CENTER; + strWidth = 0.0f; + float v; + for (int i = 0; i < this.zAxis.getTickValues().length; i += skip) { + v = (float) this.zAxis.getTickValues()[i]; + if (v < axesExtent.minZ || v > axesExtent.maxZ) { + continue; + } + v = this.transform.transform_z(v); + if (i == tlabs.size()) { + break; + } + + //Draw tick line + rgba = this.zAxis.getLineColor().getRGBComponents(null); + gl.glColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); + gl.glLineWidth(this.zAxis.getLineWidth() * this.dpiScale); + gl.glBegin(GL2.GL_LINES); + gl.glVertex3f(x, y, v); + gl.glVertex3f(x1, y1, v); + gl.glEnd(); + + //Draw tick label + rect = drawString(gl, tlabs.get(i), x1, y1, v, xAlign, yAlign, -this.tickSpace, 0); + if (strWidth < rect.getWidth()) { + strWidth = (float) rect.getWidth(); + } + } + + //Draw z axis label + ChartText label = this.zAxis.getLabel(); + if (label != null) { + float yShift = strWidth + this.tickSpace * 3; + drawString(gl, label, x1, y1, 0.0f, XAlign.CENTER, YAlign.BOTTOM, 90.f, 0, yShift); + } + } + gl.glDepthFunc(GL2.GL_LEQUAL); + } + } +} diff --git a/meteoinfo-lab/milconfig.xml b/meteoinfo-lab/milconfig.xml index 8fb348e0..47f8a350 100644 --- a/meteoinfo-lab/milconfig.xml +++ b/meteoinfo-lab/milconfig.xml @@ -1,34 +1,34 @@ - - - + - - - + + + + + - + - + @@ -36,5 +36,5 @@
- + diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl$py.class index b0eb6f3b..7284a3d5 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 0bdae603..04b985a1 100644 --- a/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py +++ b/meteoinfo-lab/pylib/mipylib/plotlib/_axes3dgl.py @@ -13,7 +13,7 @@ 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, GLPlot, GLForm, JOGLUtil, EarthPlot3D, MapPlot3D +from org.meteoinfo.chart.jogl import GLPlot, GLForm, JOGLUtil, EarthGLPlot, MapGLPlot from org.meteoinfo.math.interpolate import InterpolationMethod from org.meteoinfo.image import ImageUtil from org.meteoinfo.common import Extent3D @@ -1465,7 +1465,7 @@ class MapAxes3D(Axes3DGL): :param plot: (*EarthPlot3D*) Plot. """ if plot is None: - self._axes = MapPlot3D() + self._axes = MapGLPlot() else: self._axes = plot @@ -1506,7 +1506,7 @@ class EarthAxes3D(Axes3DGL): :param plot: (*EarthPlot3D*) Plot. """ if plot is None: - self._axes = EarthPlot3D() + self._axes = EarthGLPlot() else: self._axes = plot diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/miplot$py.class b/meteoinfo-lab/pylib/mipylib/plotlib/miplot$py.class index 852a1be9..6a8b5004 100644 Binary files a/meteoinfo-lab/pylib/mipylib/plotlib/miplot$py.class and b/meteoinfo-lab/pylib/mipylib/plotlib/miplot$py.class differ diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py b/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py index 5eb4da81..2d0fcefe 100644 --- a/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py +++ b/meteoinfo-lab/pylib/mipylib/plotlib/miplot.py @@ -847,9 +847,9 @@ def axes3d_map(*args, **kwargs): g_axes = ax if not batchmode: - if g_figure is None or isinstance(g_figure, Figure): - glfigure(**kwargs) - g_figure.set_axes(ax) + if g_figure is None: + figure(**kwargs) + g_figure.add_axes(ax) draw_if_interactive() return ax @@ -866,9 +866,9 @@ def axes3d_earth(*args, **kwargs): g_axes = ax if not batchmode: - if g_figure is None or isinstance(g_figure, Figure): - glfigure(**kwargs) - g_figure.set_axes(ax) + if g_figure is None: + figure(**kwargs) + g_figure.add_axes(ax) draw_if_interactive() return ax diff --git a/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FigureDockable.java b/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FigureDockable.java index f4d2ab7c..610a6cce 100644 --- a/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FigureDockable.java +++ b/meteoinfo-lab/src/main/java/org/meteoinfo/lab/gui/FigureDockable.java @@ -21,10 +21,9 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import com.formdev.flatlaf.extras.FlatSVGIcon; -import org.meteoinfo.chart.ChartPanel; +import org.meteoinfo.chart.GLChartPanel; import org.meteoinfo.chart.IChartPanel; import org.meteoinfo.chart.MouseMode; -//import org.meteoinfo.chart.jogl.GLChartPanel; import org.meteoinfo.console.jython.PythonInteractiveInterpreter; import org.meteoinfo.ui.ButtonTabComponent; @@ -192,8 +191,8 @@ public class FigureDockable extends DefaultSingleCDockable { * @return Figure chart panel */ public final IChartPanel addNewFigure(String title, final JPanel cp) { - if (cp instanceof ChartPanel) { - ((ChartPanel)cp).setDoubleBuffer(this.doubleBuffer); + if (cp instanceof GLChartPanel) { + ((GLChartPanel)cp).setDoubleBuffer(this.doubleBuffer); } final JScrollPane sp = new JScrollPane(cp); this.tabbedPanel.add(sp, title); @@ -220,8 +219,8 @@ public class FigureDockable extends DefaultSingleCDockable { public final IChartPanel addFigure(final JPanel ncp) { ((IChartPanel) ncp).setLoading(true); - if (ncp instanceof ChartPanel) { - ((ChartPanel) ncp).setDoubleBuffer(this.doubleBuffer); + if (ncp instanceof GLChartPanel) { + ((GLChartPanel) ncp).setDoubleBuffer(this.doubleBuffer); } int idx = 1; if (this.tabbedPanel.getTabCount() > 0) { @@ -319,10 +318,10 @@ public class FigureDockable extends DefaultSingleCDockable { * @param idx Figure index * @return Figure */ - public ChartPanel getFigure(int idx) { + public GLChartPanel getFigure(int idx) { if (this.tabbedPanel.getTabCount() > idx) { JScrollPane sp = (JScrollPane) this.tabbedPanel.getComponentAt(idx); - return (ChartPanel) sp.getViewport().getView(); + return (GLChartPanel) sp.getViewport().getView(); } else { return null; } @@ -340,8 +339,8 @@ public class FigureDockable extends DefaultSingleCDockable { * Get figures * @return Figures */ - public List getFigures() { - List figures = new ArrayList<>(); + public List getFigures() { + List figures = new ArrayList<>(); for (int i = 0; i < this.tabbedPanel.getTabCount(); i++) { figures.add(this.getFigure(i)); } @@ -353,7 +352,7 @@ public class FigureDockable extends DefaultSingleCDockable { * * @param cp ChartPanel */ - public void setCurrentFigure(ChartPanel cp) { + public void setCurrentFigure(GLChartPanel cp) { if (this.tabbedPanel.getTabCount() > 0) { JScrollPane sp = new JScrollPane(cp); this.tabbedPanel.setComponentAt(this.tabbedPanel.getSelectedIndex(), sp); @@ -375,8 +374,8 @@ public class FigureDockable extends DefaultSingleCDockable { */ public void setDoubleBuffer(boolean doubleBuffer) { this.doubleBuffer = doubleBuffer; - List figures = this.getFigures(); - for (ChartPanel figure : figures) { + List figures = this.getFigures(); + for (GLChartPanel figure : figures) { figure.setDoubleBuffer(this.doubleBuffer); figure.repaintNew(); }