arrow head scaled when arrow length less than arrow head length

This commit is contained in:
wyq 2022-01-26 15:01:28 +08:00
parent 193ce56a55
commit a40301857f
19 changed files with 329 additions and 87 deletions

View File

@ -408,8 +408,7 @@ public class ChartWindArrow {
g.draw(rect);
}
}
//Draw.drawArraw(this.color, new PointF(x, y), this.windArrow, g, zoom);
Draw.drawArraw(new PointF(x, y), windArrow, arrowBreak, g, zoom);
Draw.drawArrow(new PointF(x, y), windArrow, arrowBreak, g, zoom);
g.setColor(this.labelColor);
Draw.drawString(g, this.label, x, y + dim.height + this.labelSep);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, rendering);

View File

@ -1,10 +1,58 @@
package org.meteoinfo.chart.jogl;
import org.meteoinfo.geometry.graphic.Graphic;
import org.meteoinfo.projection.KnownCoordinateSystems;
import org.meteoinfo.projection.ProjectionInfo;
import org.meteoinfo.projection.ProjectionUtil;
public class MapPlot3D extends Plot3DGL {
private ProjectionInfo projInfo = KnownCoordinateSystems.geographic.world.WGS1984;
private ProjectionInfo projInfo;
/**
* Constructor
*/
public MapPlot3D() {
super();
this.projInfo = KnownCoordinateSystems.geographic.world.WGS1984;
}
/**
* Constructor
* @param projInfo Projection info
*/
public MapPlot3D(ProjectionInfo projInfo) {
super();
this.projInfo = projInfo;
}
/**
* 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;
}
/**
* Add a graphic
*
* @param graphic The graphic
* @param proj The graphic projection
*/
public void addGraphic(Graphic graphic, ProjectionInfo proj) {
if (proj.equals(this.projInfo)) {
super.addGraphic(graphic);
} else {
Graphic nGraphic = ProjectionUtil.projectGraphic(graphic, proj, this.projInfo);
super.addGraphic(nGraphic);
}
}
}

View File

@ -44,6 +44,8 @@ import org.meteoinfo.geometry.legend.*;
import org.meteoinfo.geometry.shape.Shape;
import org.meteoinfo.geometry.shape.*;
import org.meteoinfo.math.meteo.MeteoMath;
import org.meteoinfo.projection.ProjectionInfo;
import org.meteoinfo.projection.ProjectionUtil;
import javax.imageio.ImageIO;
import javax.swing.*;
@ -73,6 +75,7 @@ import static com.jogamp.opengl.GL2ES3.GL_TEXTURE_BASE_LEVEL;
public class Plot3DGL extends Plot implements GLEventListener {
// <editor-fold desc="Variables">
protected ProjectionInfo projInfo;
protected boolean sampleBuffers = false;
protected Color background = Color.white;
protected boolean doScreenShot;
@ -130,6 +133,7 @@ public class Plot3DGL extends Plot implements GLEventListener {
* Constructor
*/
public Plot3DGL() {
this.projInfo = null;
this.doScreenShot = false;
this.legends = new ArrayList<>();
//this.legends.add(new ChartColorBar(new LegendScheme(ShapeTypes.Polygon, 5)));
@ -173,6 +177,21 @@ public class Plot3DGL extends Plot implements GLEventListener {
// </editor-fold>
// <editor-fold desc="GetSet">
/**
* 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;
}
/**
* Get is sample buffers or not
@ -967,6 +986,21 @@ public class Plot3DGL extends Plot implements GLEventListener {
this.setDrawExtent((Extent3D) this.extent.clone());
}
/**
* Add a graphic
*
* @param graphic The graphic
* @param proj The graphic projection
*/
public void addGraphic(Graphic graphic, ProjectionInfo proj) {
if (proj == null || proj.equals(this.projInfo)) {
addGraphic(graphic);
} else {
Graphic nGraphic = ProjectionUtil.projectGraphic(graphic, proj, this.projInfo);
addGraphic(nGraphic);
}
}
/**
* Remove a graphic by index
*

View File

@ -430,7 +430,7 @@ public class Plot2D extends AbstractPlot2D {
double[] sXY = projToScreen(p.X, p.Y, area);
PointF pf = new PointF((float) sXY[0], (float) sXY[1]);
float zoom = aPB.getSize() / 10;
Draw.drawArraw(pf, aPS, aPB, g, zoom);
Draw.drawArrow(pf, aPS, aPB, g, zoom);
}
private void drawPolyline(Graphics2D g, PolylineShape aPLS, PointBreak aPB, Rectangle2D area) {

View File

@ -631,7 +631,7 @@ public class Draw {
g.setColor(aColor);
g.draw(new Line2D.Float(sP.X, sP.Y, eP.X, eP.Y));
drawArraw(g, eP, angle);
drawArrow(g, eP, angle);
return new Rectangle2D.Double(Math.min(sP.X, eP.X), Math.min(sP.Y, eP.Y),
Math.abs(eP.X - sP.X), Math.abs(eP.Y - sP.Y));
@ -656,17 +656,17 @@ public class Draw {
* Draw wind arrow
*
* @param sP Start point
* @param aArraw The arrow
* @param arrow The arrow
* @param pb PointBreak
* @param g Graphics2D
* @param zoom Zoom
* @return Border rectangle
*/
public static Rectangle2D drawArraw(PointF sP, WindArrow aArraw, ArrowBreak pb, Graphics2D g, double zoom) {
public static Rectangle2D drawArrow(PointF sP, WindArrow arrow, ArrowBreak pb, Graphics2D g, double zoom) {
PointF eP = new PointF(0, 0);
//PointF eP1 = new PointF(0, 0);
double len = aArraw.length;
double angle = aArraw.angle + 180;
double len = arrow.length;
double angle = arrow.angle + 180;
if (angle >= 360) {
angle -= 360;
}
@ -686,19 +686,23 @@ public class Draw {
g.draw(new Line2D.Float(sP.X, sP.Y, eP.X, eP.Y));
float headWidth = pb.getHeadWidth();
float headLength = pb.getHeadLength();
if (len < headLength && pb.isAutoScale()) {
headWidth = headWidth * (float) len / headLength;
headLength = (float) len;
}
drawArraw(g, eP, angle, headLength, headWidth, pb.getOverhang());
return new Rectangle2D.Double(Math.min(sP.X, eP.X), Math.min(sP.Y, eP.Y),
Math.abs(eP.X - sP.X), Math.abs(eP.Y - sP.Y));
}
/**
* Draw arraw
* Draw arrow
*
* @param g Graphics2D
* @param sP Start point
* @param angle Angle
*/
public static void drawArraw(Graphics2D g, PointF sP, double angle) {
public static void drawArrow(Graphics2D g, PointF sP, double angle) {
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 5);
Rectangle.Float rect = new Rectangle.Float(-4, -4, 8, 8);
PointF[] pt = new PointF[5];

View File

@ -4826,7 +4826,7 @@ public class MapView extends JPanel implements IWebMapPanel {
sPoint.X = (float) xy[0];
sPoint.Y = (float) xy[1];
//Draw.drawArraw(aColor, sPoint, aArraw, g, zoom);
Draw.drawArraw(sPoint, aArraw, aPB, g, zoom);
Draw.drawArrow(sPoint, aArraw, aPB, g, zoom);
}
break;
case UNIQUE_VALUE:
@ -4843,7 +4843,7 @@ public class MapView extends JPanel implements IWebMapPanel {
sPoint.Y = (float) xy[1];
aPB = (ArrowBreak) aLS.getLegendBreak(aArraw.getLegendIndex());
Draw.drawArraw(sPoint, aArraw, aPB, g, zoom);
Draw.drawArrow(sPoint, aArraw, aPB, g, zoom);
/*String vStr = aLayer.getCellValue(aLS.getFieldName(), shapeIdx).toString().trim();
if (vStr.isEmpty()) {

View File

@ -405,7 +405,7 @@ public class GeoProjectionUtil {
if (oLayer.getLabelPoints().size() > 0) {
if (projectLabels) {
oLayer.setLabelPoints(ProjectionUtil.projectGraphics(oLayer.getLabelPoints(), fromProj, toProj));
oLayer.setLabelPoints(ProjectionUtil.projectGraphic(oLayer.getLabelPoints(), fromProj, toProj));
} else {
oLayer.setLabelPoints(new ArrayList<>(oLayer.getLabelPoints()));
}
@ -639,7 +639,7 @@ public class GeoProjectionUtil {
oLayer.getAttributeTable().setTable(aTable);
if (oLayer.getLabelPoints().size() > 0) {
oLayer.setLabelPoints(ProjectionUtil.projectGraphics(oLayer.getLabelPoints(), fromProj, toProj));
oLayer.setLabelPoints(ProjectionUtil.projectGraphic(oLayer.getLabelPoints(), fromProj, toProj));
}
}

View File

@ -15,6 +15,7 @@ public class ArrowBreak extends PointBreak {
private float headWidth;
private float headLength;
private float overhang;
private boolean autoScale;
// </editor-fold>
// <editor-fold desc="Constructor">
/**
@ -23,10 +24,9 @@ public class ArrowBreak extends PointBreak {
public ArrowBreak() {
super();
this.outlineColor = null;
this.width = 1;
this.headWidth = this.width * 5;
this.headLength = this.headWidth * 1.5f;
this.initWidth(1);
this.overhang = 0;
this.autoScale = true;
}
/**
@ -55,6 +55,7 @@ public class ArrowBreak extends PointBreak {
this.headWidth = this.width * 5;
this.headLength = this.headWidth * 1.5f;
this.overhang = 0;
this.autoScale = true;
}
// </editor-fold>
// <editor-fold desc="Get Set Methods">
@ -121,7 +122,33 @@ public class ArrowBreak extends PointBreak {
public void setOverhang(float value) {
this.overhang = value;
}
/**
* Get whether automatically scale the arrow size
* @return Whether automatically scale the arrow size
*/
public boolean isAutoScale() {
return this.autoScale;
}
/**
* Set whether automatically scale the arrow size
* @param value Whether automatically scale the arrow size
*/
public void setAutoScale(boolean value) {
this.autoScale = value;
}
// </editor-fold>
// <editor-fold desc="Methods">
/**
* Initialize width
* @param width Width
*/
public void initWidth(float width) {
this.width = width;
this.headWidth = this.width * 5;
this.headLength = this.headWidth * 5 / 3;
}
// </editor-fold>
}

View File

@ -284,7 +284,7 @@ public class PolygonShape extends Shape implements Cloneable {
*
* @param polygons polygon list
*/
public void setPolygons(List<Polygon> polygons) {
public void setPolygons(List<? extends Polygon> polygons) {
_polygons = polygons;
updatePartsPoints();
}

View File

@ -1,30 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\bar">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\array"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\satellite"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\scatter"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart\axis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\wind">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\contour"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\3d_earth"/>
<RecentFolder Folder="D:\Temp\LaSW\script"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\bar"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo\wrf"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\chart\axis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\scatter"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\arrow"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\wind"/>
</Path>
<File>
<OpenedFiles>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volumeplot_1.py"/>
<OpenedFile File="D:\Temp\LaSW\script\typhoon_map_volume.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\wind\quiver_2.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\3d\jogl\volumeplot_1.py"/>
<RecentFile File="D:\Temp\LaSW\script\typhoon_map_volume.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\wind\quiver_2.py"/>
</RecentFiles>
</File>
<Font>

View File

@ -692,6 +692,7 @@ class Axes(object):
ax2.axes.getAxis(Location.LEFT).setVisible(False)
ax2.axes.getAxis(Location.TOP).setVisible(False)
axis = ax2.axes.getAxis(Location.RIGHT)
axis.setDrawTickLine(True)
axis.setDrawTickLabel(True)
axis.setDrawLabel(True)
return ax2
@ -952,13 +953,17 @@ class Axes(object):
self.axes.addGraphic(patch)
self.axes.setAutoExtent()
def add_graphic(self, graphic):
def add_graphic(self, graphic, projection=None):
'''
Add a graphic
:param graphic: (*Graphic*) The graphic to be added.
:param projection: (*Projection*) The projection
'''
if projection is None:
self.axes.addGraphic(graphic)
else:
self.axes.addGraphic(graphic, projection)
def get_graphics(self):
'''

View File

@ -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, GLForm, JOGLUtil, EarthPlot3D
from org.meteoinfo.chart.jogl import Plot3DGL, GLForm, JOGLUtil, EarthPlot3D, MapPlot3D
from org.meteoinfo.math.interpolate import InterpolationMethod
from org.meteoinfo.image import ImageUtil
from org.meteoinfo.common import Extent3D
@ -33,7 +33,7 @@ import mipylib.numeric as np
from mipylib import migl
from mipylib.geolib import migeo
__all__ = ['Axes3DGL','EarthAxes3D']
__all__ = ['Axes3DGL','MapAxes3D','EarthAxes3D']
class Axes3DGL(Axes3D):
@ -653,7 +653,8 @@ class Axes3DGL(Axes3D):
visible = kwargs.pop('visible', True)
if visible:
self.add_graphic(graphics)
projection = kwargs.pop('projection', migeo.projinfo())
self.add_graphic(graphics, projection)
return graphics
def plot_layer(self, layer, **kwargs):
@ -1556,6 +1557,37 @@ class Axes3DGL(Axes3D):
form.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
form.setVisible(True)
class MapAxes3D(Axes3DGL):
"""
Map 3D axes.
"""
def __init__(self, *args, **kwargs):
super(MapAxes3D, self).__init__(*args, **kwargs)
projection = kwargs.pop('projection', None)
if not projection is None:
self.axes.setProjInfo(projection)
def _set_plot(self, plot):
"""
Set plot.
:param plot: (*EarthPlot3D*) Plot.
"""
if plot is None:
self.axes = MapPlot3D()
else:
self.axes = plot
@property
def axestype(self):
return '3d_Map'
@property
def projection(self):
return self.axes.getProjInfo()
class EarthAxes3D(Axes3DGL):
"""
Earth spherical 3D axes.

View File

@ -26,7 +26,7 @@ from org.meteoinfo.chart.form import ChartForm
from org.meteoinfo.geometry.shape import ShapeTypes
from ._axes import Axes, PolarAxes
from ._axes3d import Axes3D
from ._axes3dgl import Axes3DGL, EarthAxes3D
from ._axes3dgl import Axes3DGL, MapAxes3D, EarthAxes3D
from ._figure import Figure
from ._glfigure import GLFigure
from ._mapaxes import MapAxes
@ -1329,15 +1329,18 @@ def axes3d(*args, **kwargs):
"""
opengl = kwargs.pop('opengl', True)
if opengl:
projection = kwargs.pop('projection', None)
projection = kwargs.get('projection', None)
if projection is None:
earth = kwargs.pop('earth', False)
else:
earth = projection == 'earth'
if earth:
projection == 'earth'
if projection is None:
return axes3dgl(*args, **kwargs)
elif projection == 'earth':
return axes3d_earth(*args, **kwargs)
else:
return axes3dgl(*args, **kwargs)
return axes3d_map(*args, **kwargs)
else:
kwargs['axestype'] = '3d'
return axes(*args, **kwargs)
@ -1361,6 +1364,25 @@ def axes3dgl(*args, **kwargs):
draw_if_interactive()
return ax
def axes3d_map(*args, **kwargs):
"""
Add an map 3d axes with JOGL to the figure.
:returns: The axes.
"""
global g_axes
ax = MapAxes3D(*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)
draw_if_interactive()
return ax
def axes3d_earth(*args, **kwargs):
"""
Add an earth 3d axes with JOGL to the figure.

View File

@ -654,10 +654,12 @@ def point2arrow(pb, **kwargs):
'''
arrowbreak = ArrowBreak(pb)
width = kwargs.pop('width', 1.)
arrowbreak.setWidth(width)
headwidth = kwargs.pop('headwidth', width * 5.)
arrowbreak.initWidth(width)
headwidth = kwargs.pop('headwidth', None)
if not headwidth is None:
arrowbreak.setHeadWidth(headwidth)
headlength = kwargs.pop('headlength', headwidth * 1.5)
headlength = kwargs.pop('headlength', None)
if not headlength is None:
arrowbreak.setHeadLength(headlength)
overhang = kwargs.pop('overhang', None)
if not overhang is None:

View File

@ -529,6 +529,59 @@ public class ProjectionUtil {
* @return Projected polygon shape
*/
public static PolygonShape projectPolygonShape(PolygonShape aPGS, ProjectionInfo fromProj, ProjectionInfo toProj) {
if (aPGS instanceof PolygonZShape) {
List<PolygonZ> polygons = new ArrayList<>();
for (int i = 0; i < aPGS.getPolygons().size(); i++) {
PolygonZ aPG = (PolygonZ) aPGS.getPolygons().get(i);
PolygonZ bPG = null;
for (int r = 0; r < aPG.getRingNumber(); r++) {
List<PointZ> pList = (List<PointZ>) aPG.getRings().get(r);
List<PointZ> newPoints = new ArrayList<>();
for (int j = 0; j < pList.size(); j++) {
double[][] points = new double[1][];
PointZ wPoint = pList.get(j);
points[0] = new double[]{wPoint.X, wPoint.Y};
try {
Reproject.reprojectPoints(points, fromProj, toProj, 0, points.length);
if (!Double.isNaN(points[0][0]) || !Double.isInfinite(points[0][0]) ||
!Double.isNaN(points[0][1]) || !Double.isInfinite(points[0][1])) {
wPoint = new PointZ();
wPoint.X = points[0][0];
wPoint.Y = points[0][1];
newPoints.add(wPoint);
}
} catch (Exception e) {
break;
}
}
if (r == 0) {
if (newPoints.size() > 2) {
bPG = new PolygonZ();
bPG.setOutLine(newPoints);
} else {
break;
}
} else {
if (newPoints.size() > 2) {
bPG.addHole(newPoints);
}
}
}
if (bPG != null) {
polygons.add(bPG);
}
}
if (polygons.size() > 0) {
((PolygonZShape) aPGS).setPolygons(polygons);
return aPGS;
} else {
return null;
}
} else {
List<Polygon> polygons = new ArrayList<>();
for (int i = 0; i < aPGS.getPolygons().size(); i++) {
Polygon aPG = aPGS.getPolygons().get(i);
@ -580,6 +633,7 @@ public class ProjectionUtil {
return null;
}
}
}
/**
* Project graphic
@ -590,11 +644,23 @@ public class ProjectionUtil {
* @return Projected graphic
*/
public static Graphic projectGraphic(Graphic graphic, ProjectionInfo fromProj, ProjectionInfo toProj) {
if (graphic instanceof GraphicCollection) {
GraphicCollection newGCollection = new GraphicCollection();
for (Graphic aGraphic : ((GraphicCollection) graphic).getGraphics()) {
aGraphic.setShape(projectShape(aGraphic.getShape(), fromProj, toProj));
if (aGraphic.getShape() != null) {
newGCollection.add(aGraphic);
}
}
return newGCollection;
} else {
Shape shape = projectShape(graphic.getShape(), fromProj, toProj);
return new Graphic(shape, graphic.getLegend());
}
}
public static GraphicCollection projectGraphics(GraphicCollection aGCollection, ProjectionInfo fromProj, ProjectionInfo toProj) {
public static GraphicCollection projectGraphic(GraphicCollection aGCollection, ProjectionInfo fromProj, ProjectionInfo toProj) {
GraphicCollection newGCollection = new GraphicCollection();
for (Graphic aGraphic : aGCollection.getGraphics()) {
aGraphic.setShape(projectShape(aGraphic.getShape(), fromProj, toProj));
@ -606,7 +672,7 @@ public class ProjectionUtil {
return newGCollection;
}
public static List<Graphic> projectGraphics(List<Graphic> graphics, ProjectionInfo fromProj, ProjectionInfo toProj) {
public static List<Graphic> projectGraphic(List<Graphic> graphics, ProjectionInfo fromProj, ProjectionInfo toProj) {
List<Graphic> newGraphics = new ArrayList<>();
for (Graphic aGraphic : graphics) {
Shape aShape = projectShape(aGraphic.getShape(), fromProj, toProj);
@ -634,6 +700,7 @@ public class ProjectionUtil {
break;
case POLYGON:
case POLYGON_M:
case POLYGON_Z:
case RECTANGLE:
newShape = projectPolygonShape((PolygonShape) aShape, fromProj, toProj);
break;