add Transform for graphics

This commit is contained in:
wyq 2024-06-19 00:02:00 +08:00
parent 1cee1c2994
commit c3f4e3b526
17 changed files with 472 additions and 107 deletions

View File

@ -18,6 +18,8 @@ import org.meteoinfo.data.mapdata.webmap.GeoPosition;
import org.meteoinfo.data.mapdata.webmap.GeoUtil;
import org.meteoinfo.data.mapdata.webmap.IWebMapPanel;
import org.meteoinfo.data.mapdata.webmap.TileLoadListener;
import org.meteoinfo.geometry.graphic.Transform;
import org.meteoinfo.projection.*;
import org.meteoinfo.render.java2d.Draw;
import org.meteoinfo.chart.graphic.GeoGraphicCollection;
import org.meteoinfo.geometry.graphic.Graphic;
@ -25,10 +27,6 @@ import org.meteoinfo.geometry.graphic.GraphicCollection;
import org.meteoinfo.chart.graphic.GraphicProjectionUtil;
import org.meteoinfo.geometry.legend.*;
import org.meteoinfo.geometry.shape.*;
import org.meteoinfo.projection.KnownCoordinateSystems;
import org.meteoinfo.projection.ProjectionInfo;
import org.meteoinfo.projection.ProjectionUtil;
import org.meteoinfo.projection.Reproject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
@ -646,6 +644,41 @@ public class MapPlot extends Plot2D implements IWebMapPanel {
graphic.draw(g, area, this.tileLoadListener);
}
/**
* Add a graphic
*
* @param g Graphic
*/
@Override
public Graphic addGraphic(Graphic graphic) {
Transform transform = graphic.getTransform();
if (transform != null && transform.isValid()) {
GeoTransform geoTransform = (GeoTransform) transform;
graphic = GraphicProjectionUtil.projectClipGraphic(graphic, geoTransform.getSourceProj(),
geoTransform.getTargetProj());
}
return super.addGraphic(graphic);
}
/**
* Add a graphic by index
*
* @param idx Index
* @param g Graphic
*/
@Override
public Graphic addGraphic(int idx, Graphic graphic) {
Transform transform = graphic.getTransform();
if (transform != null && transform.isValid()) {
GeoTransform geoTransform = (GeoTransform) transform;
GraphicProjectionUtil.projectClipGraphic(graphic, geoTransform.getSourceProj(),
geoTransform.getTargetProj());
}
return super.addGraphic(idx, graphic);
}
/**
* Add a graphic
*
@ -656,12 +689,12 @@ public class MapPlot extends Plot2D implements IWebMapPanel {
public Graphic addGraphic(Graphic graphic, ProjectionInfo proj) {
ProjectionInfo toProj = this.getProjInfo();
if (proj.equals(toProj)) {
this.addGraphic(graphic);
super.addGraphic(graphic);
return graphic;
} else {
Graphic nGraphic = GraphicProjectionUtil.projectClipGraphic(graphic, proj, toProj);
if (nGraphic != null) {
this.addGraphic(nGraphic);
super.addGraphic(nGraphic);
}
return nGraphic;
}

View File

@ -7,10 +7,7 @@ import org.meteoinfo.chart.graphic.GeoGraphicCollection;
import org.meteoinfo.geometry.geoprocess.GeoComputation;
import org.meteoinfo.geometry.graphic.Graphic;
import org.meteoinfo.geometry.shape.Shape;
import org.meteoinfo.projection.ProjectionInfo;
import org.meteoinfo.projection.ProjectionNames;
import org.meteoinfo.projection.ProjectionUtil;
import org.meteoinfo.projection.Reproject;
import org.meteoinfo.projection.*;
import org.meteoinfo.table.DataColumn;
import org.meteoinfo.table.DataRow;
import org.meteoinfo.table.DataTable;
@ -21,6 +18,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
public class GraphicProjectionUtil extends ProjectionUtil {
/**
* Project graphic
*

View File

@ -39,6 +39,7 @@ package org.meteoinfo.geometry.graphic;
protected ColorBreak legend;
protected GeneralPath clipPath;
protected Graphic clipGraphic;
protected Transform transform;
private ResizeAbility _resizeAbility = ResizeAbility.RESIZE_ALL;
protected int handle;
// </editor-fold>
@ -101,6 +102,22 @@ package org.meteoinfo.geometry.graphic;
updateResizeAbility();
}
/**
* Get transform
* @return Transform
*/
public Transform getTransform() {
return this.transform;
}
/**
* Set transform
* @param value Transform
*/
public void setTransform(Transform value) {
this.transform = value;
}
/**
* Get clip path
* @return Clip path

View File

@ -100,6 +100,7 @@ public class GraphicCollection extends Graphic implements Iterator {
*/
public void setGraphics(List<Graphic> value) {
this.graphics = value;
this.updateExtent();
}
/**

View File

@ -167,10 +167,10 @@ public class Line2DGraphic extends Graphic {
}
/**
* Get data
* @return Data
* Get color data array
* @return Color data array
*/
public Array getData() {
public Array getColorData() {
return this.cData;
}

View File

@ -8,6 +8,7 @@ import org.meteoinfo.geometry.legend.PointBreak;
import org.meteoinfo.geometry.shape.PointShape;
import org.meteoinfo.geometry.shape.PolylineShape;
import org.meteoinfo.geometry.shape.Shape;
import org.meteoinfo.geometry.shape.ShapeTypes;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.ndarray.IndexIterator;
@ -47,7 +48,6 @@ public class Point2DGraphicCollection extends GraphicCollection {
this();
this.xData = xData;
this.yData = yData;
this.legend = pointBreak;
this.updateGraphics(pointBreak);
}
@ -55,6 +55,20 @@ public class Point2DGraphicCollection extends GraphicCollection {
* Constructor
* @param xData X data
* @param yData Y data
* @param pointBreak Point break
*/
public Point2DGraphicCollection(Array xData, Array yData, List<ColorBreak> cbs) {
this();
this.xData = xData;
this.yData = yData;
this.updateGraphics(cbs);
}
/**
* Constructor
*
* @param xData X data
* @param yData Y data
* @param cData Color data
* @param ls Legend scheme
*/
@ -63,10 +77,18 @@ public class Point2DGraphicCollection extends GraphicCollection {
this.xData = xData;
this.yData = yData;
this.cData = cData;
this.legendScheme = ls;
this.updateGraphics(ls);
}
/**
* Return has color data array or not
*
* @return Has color data array of not
*/
public boolean hasColorData() {
return this.cData != null;
}
/**
* Get x data
* @return X data
@ -75,6 +97,15 @@ public class Point2DGraphicCollection extends GraphicCollection {
return this.xData;
}
/**
* Set x data
* @param xData X data
*/
public void setXData(Array xData) {
this.xData = xData;
updateShape();
}
/**
* Get y data
* @return Y data
@ -84,18 +115,36 @@ public class Point2DGraphicCollection extends GraphicCollection {
}
/**
* Set data
* @return Data
* Set y data
* @param yData Y data
*/
public Array getData() {
public void setYData(Array yData) {
this.yData = yData;
updateShape();
}
/**
* Get color data
* @return Color data
*/
public Array getColorData() {
return this.cData;
}
protected void updateShape() {
if (this.hasColorData()) {
updateGraphics(this.legendScheme);
} else {
updateGraphics((PointBreak) this.legend);
}
}
protected void updateGraphics() {
updateGraphics((PointBreak) this.legend);
}
protected void updateGraphics(PointBreak pointBreak) {
this.legend = pointBreak;
this.graphics = new ArrayList<>();
List<PointD> points = new ArrayList<>();
IndexIterator xIter = this.xData.getIndexIterator();
@ -112,6 +161,35 @@ public class Point2DGraphicCollection extends GraphicCollection {
}
}
protected void updateGraphics(List<ColorBreak> cbs) {
this.graphics = new ArrayList<>();
List<PointD> points = new ArrayList<>();
IndexIterator xIter = this.xData.getIndexIterator();
IndexIterator yIter = this.yData.getIndexIterator();
double x, y;
if (cbs.size() == this.xData.getSize()) {
int i = 0;
while (xIter.hasNext()) {
x = xIter.getDoubleNext();
y = yIter.getDoubleNext();
if (Double.isNaN(x) || Double.isNaN(y)) {
continue;
}
PointShape shape = new PointShape(new PointD(x, y));
this.add(new Point2DGraphic(shape, (PointBreak) cbs.get(i)));
i += 1;
}
LegendScheme ls = new LegendScheme();
ls.setLegendBreaks(cbs);
ls.setLegendType(LegendType.UNIQUE_VALUE);
ls.setShapeType(ShapeTypes.POINT);
this.singleLegend = false;
this.legendScheme = ls;
} else {
updateGraphics((PointBreak) cbs.get(0));
}
}
protected void updateGraphics(LegendScheme ls) {
this.graphics = new ArrayList<Graphic>();
PointShape ps;
@ -143,7 +221,7 @@ public class Point2DGraphicCollection extends GraphicCollection {
}
}
}
this.setSingleLegend(false);
this.setLegendScheme(ls);
this.singleLegend = false;
this.legendScheme = ls;
}
}

View File

@ -0,0 +1,12 @@
package org.meteoinfo.geometry.graphic;
import org.meteoinfo.common.PointD;
public abstract class Transform {
public abstract boolean isValid();
public abstract PointD transform(double x, double y);
public abstract Transform inverted();
}

View File

@ -1,32 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MeteoInfo File="milconfig.xml" Type="configurefile">
<Path OpenPath="D:\Working\MIScript\Jython\mis\common_math\interpolate">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\gridshow"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\plot"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\radar"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\radar\cinrad"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\dataframe"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\wind"/>
<Path OpenPath="D:\Working\MIScript\Jython\mis\plot_types\pcolor">
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\arrow"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io\matlab"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\meteo\calc"/>
<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\interpolate"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\io"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\scatter"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map\geoshow"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\map"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\wind"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\contour"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types"/>
<RecentFolder Folder="D:\Working\MIScript\Jython\mis\plot_types\pcolor"/>
</Path>
<File>
<OpenedFiles>
<OpenedFile File="D:\Working\MIScript\Jython\mis\meteo\calc\velocity_potential_1.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\meteo\calc\velocity_potential_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\meteo\calc\stream_function_3.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\scatter\scatterm_2.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\scatter\scatter_map_proj.py"/>
<OpenedFile File="D:\Working\MIScript\Jython\mis\plot_types\contour\contourf_hatch.py"/>
</OpenedFiles>
<RecentFiles>
<RecentFile File="D:\Working\MIScript\Jython\mis\meteo\calc\velocity_potential_1.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\meteo\calc\velocity_potential_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\meteo\calc\stream_function_3.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\scatter\scatterm_2.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\scatter\scatter_map_proj.py"/>
<RecentFile File="D:\Working\MIScript\Jython\mis\plot_types\contour\contourf_hatch.py"/>
</RecentFiles>
</File>
<Font>

View File

@ -34,7 +34,7 @@ from mipylib.geolib.milayer import MILayer, MIXYListData
import plotutil
import colors
import mipylib.miutil as miutil
from .graphic import Line2D, Artist
from .graphic import Line2D, Artist, Point2DCollection
__all__ = ['Axes', 'PolarAxes']
@ -1087,12 +1087,12 @@ class Axes(object):
#self._axes.setAutoExtent()
self.stale = True
def add_graphic(self, graphic, projection=None, zorder=None):
def add_graphic(self, graphic, transform=None, zorder=None):
"""
Add a graphic
:param graphic: (*Graphic*) The graphic to be added.
:param projection: (*Projection*) The projection.
:param transform: (*Transform*) The transform. Default is `None`.
:param zorder: (*int*) Z order of the graphic. Default is `None` that the graphic added
to the end.
"""
@ -1103,16 +1103,16 @@ class Axes(object):
if zorder > self.num_graphics():
zorder = self.num_graphics()
if projection is None:
if transform is None:
if zorder is None:
rGraphic = self._axes.addGraphic(graphic)
else:
rGraphic = self._axes.addGraphic(zorder, graphic)
else:
if zorder is None:
rGraphic = self._axes.addGraphic(graphic, projection)
rGraphic = self._axes.addGraphic(graphic, transform)
else:
rGraphic = self._axes.addGraphic(zorder, graphic, projection)
rGraphic = self._axes.addGraphic(zorder, graphic, transform)
#self._axes.setAutoExtent()
self.stale = True
@ -1578,8 +1578,8 @@ class Axes(object):
for i in range(0, n):
ls.getLegendBreaks()[i].setSize(s[i])
# Create graphics
graphics = GraphicFactory.createPoints(xdata, ydata, c.asarray(), ls)
#graphics = GraphicFactory.createPoints(xdata, ydata, c.asarray(), ls)
graphics = Point2DCollection(xdata, ydata, c._array, legend=ls)
else:
alpha = kwargs.pop('alpha', None)
colors = plotutil.getcolors(c, alpha)
@ -1614,8 +1614,8 @@ class Axes(object):
plotutil.setpointlegendbreak(npb, **kwargs)
pbs.append(npb)
# Create graphics
graphics = GraphicFactory.createPoints(xdata, ydata, pbs)
graphics = Point2DCollection(x._array, y._array, legend=ls.getLegendBreak(0))
#graphics = GraphicFactory.createPoints(xdata, ydata, pbs)
graphics = Point2DCollection(xdata, ydata, legend=pbs)
antialias = kwargs.pop('antialias', None)
if antialias is not None:

View File

@ -8,6 +8,7 @@
import os
import numbers
import functools
from org.meteoinfo.chart import ChartScaleBar, ChartNorthArrow
from org.meteoinfo.chart.plot import GridLabelPosition
@ -19,7 +20,7 @@ from org.meteoinfo.geo.io import GraphicUtil
from org.meteoinfo.geometry.legend import BreakTypes, LegendScheme, LegendType, LegendManage
from org.meteoinfo.geometry.shape import Shape, PolylineShape, PolygonShape, ShapeTypes
from org.meteoinfo.geometry.graphic import Graphic
from org.meteoinfo.projection import ProjectionInfo
from org.meteoinfo.projection import ProjectionInfo, GeoTransform
from org.meteoinfo.common import Extent
from org.meteoinfo.geo.layer import LayerTypes, WebMapLayer
from org.meteoinfo.data.mapdata.webmap import WebMapProvider, DefaultTileFactory, TileFactoryInfo
@ -40,6 +41,20 @@ import mipylib.miutil as miutil
__all__ = ['MapAxes','WebMapProvider']
def _add_transform(func):
"""A decorator that adds and validates the transform keyword argument."""
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
data_proj = kwargs.get('transform', None)
if data_proj is None:
data_proj = kwargs.pop('proj', None)
if data_proj is not None:
transform = GeoTransform(data_proj, self.projection)
kwargs['transform'] = transform
return func(self, *args, **kwargs)
return wrapper
##############################################
class MapAxes(Axes):
"""
@ -93,7 +108,7 @@ class MapAxes(Axes):
if not cutoff is None:
projinfo.setCutoff(cutoff)
self._axes.setProjInfo(projinfo)
self.proj = self._axes.getProjInfo()
self.projection = self._axes.getProjInfo()
xyscale = kwargs.pop('xyscale', 1)
self._axes.setAspect(xyscale)
@ -123,7 +138,7 @@ class MapAxes(Axes):
:returns: (*boolean*) Is lonlat projection or not.
"""
return self.proj.isLonLat()
return self.projection.isLonLat()
def add_layer(self, layer, zorder=None, select=None):
"""
@ -386,7 +401,7 @@ class MapAxes(Axes):
:param z: (*float*) Z coordinate - only used for 3-D axes.
"""
if not self._axes.isLonLatMap():
x, y = migeo.project(x, y, toproj=self.proj)
x, y = migeo.project(x, y, toproj=self.projection)
rect = self._axes.getPositionArea()
r = self._axes.projToScreen(x, y, rect)
@ -530,7 +545,9 @@ class MapAxes(Axes):
if antialias is not None:
graphics.setAntiAlias(antialias)
graphics = self.add_graphic(graphics, projection=layer.proj, zorder=zorder)
transform = GeoTransform(layer.proj, self.projection)
graphics.setTransform(transform)
graphics = self.add_graphic(graphics, zorder=zorder)
graphics.setVisible(visible)
return GeoGraphicCollection(graphics)
else:
@ -587,21 +604,15 @@ class MapAxes(Axes):
if graphic.getNumGraphics() == 1:
graphic = graphic.getGraphicN(0)
if graphic.isCollection():
if self.islonlat():
self._axes.addGraphics(graphic)
else:
graphic = self._axes.addGraphics(graphic, migeo.projinfo())
else:
if self.islonlat():
self._axes.addGraphic(graphic)
else:
graphic = self._axes.addGraphic(graphic, migeo.projinfo())
transform = GeoTransform(migeo.projinfo(), self.projection)
graphic.setTransform(transform)
graphic = self._axes.addGraphic(graphic)
graphic.setVisible(visible)
return graphic
@_add_transform
def plot(self, *args, **kwargs):
"""
Plot lines and/or markers to the map.
@ -615,7 +626,7 @@ class MapAxes(Axes):
:returns: (*VectorLayer*) Line VectorLayer.
"""
fill_value = kwargs.pop('fill_value', -9999.0)
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
is_lonlat = proj.isLonLat()
n = len(args)
xdatalist = []
@ -735,7 +746,8 @@ class MapAxes(Axes):
graphic = GraphicFactory.createLineString(xdata, ydata, lines[0], iscurve)
else: #>1
graphic = GraphicFactory.createLineString(xdata, ydata, lines, iscurve)
graphic = self.add_graphic(graphic, proj)
graphic.transform = transform
graphic = self.add_graphic(graphic)
graphics.append(graphic)
else:
for i in range(0, snum):
@ -743,14 +755,16 @@ class MapAxes(Axes):
xdata = plotutil.getplotdata(xdatalist[i])
ydata = plotutil.getplotdata(ydatalist[i])
graphic = GraphicFactory.createLineString(xdata, ydata, lines[i], iscurve)
graphic = self.add_graphic(graphic, proj)
graphic.transform = transform
graphic = self.add_graphic(graphic)
graphics.append(graphic)
else:
xdata = plotutil.getplotdata(xdatalist[0])
ydata = plotutil.getplotdata(ydatalist[0])
zdata = plotutil.getplotdata(cdata)
graphic = GraphicFactory.createLineString(xdata, ydata, zdata, ls, iscurve)
graphic = self.add_graphic(graphic, proj)
graphic.transform = transform
graphic = self.add_graphic(graphic)
graphics.append(graphic)
antialias = kwargs.pop('antialias', None)
@ -764,6 +778,7 @@ class MapAxes(Axes):
return graphics[0]
@_add_transform
def scatter(self, *args, **kwargs):
"""
Make a scatter plot on a map.
@ -783,10 +798,10 @@ class MapAxes(Axes):
:param edge: (*boolean*) Draw edge of markers or not. Default is True.
:param facecolor: (*Color*) Fill color of markers. Default is black.
:param edgecolor: (*Color*) Edge color of markers. Default is black.
:param proj: (*ProjectionInfo*) Map projection of the data. Default is None.
:param transform: (*ProjectionInfo*) Map projection transform of the data. Default is same with the axes.
:param zorder: (*int*) Z-order of created layer for display.
:returns: (*VectoryLayer*) Point VectoryLayer.
:returns: (*graphic collection*) Graphic collection.
"""
n = len(args)
if n == 1:
@ -836,14 +851,16 @@ class MapAxes(Axes):
ls = plotutil.getlegendscheme(args, a.min(), a.max(), **kwargs)
ls = plotutil.setlegendscheme_point(ls, **kwargs)
proj = kwargs.pop('proj', migeo.projinfo())
# Create graphics
if a.ndim == 0:
graphics = GraphicFactory.createPoints(x._array, y._array, ls.getLegendBreak(0))
#graphics = Point2DCollection(x._array, y._array, legend=ls.getLegendBreak(0))
#graphics = GraphicFactory.createPoints(x._array, y._array, ls.getLegendBreak(0))
graphics = Point2DCollection(x._array, y._array, legend=ls.getLegendBreak(0))
else:
graphics = GraphicFactory.createPoints(x._array, y._array, a._array, ls)
#graphics = Point2DCollection(x._array, y._array, a._array, ls)
#graphics = GraphicFactory.createPoints(x._array, y._array, a._array, ls)
graphics = Point2DCollection(x._array, y._array, a._array, ls)
transform = kwargs.pop('transform', None)
graphics.transform = transform
antialias = kwargs.pop('antialias', None)
if antialias is not None:
@ -851,7 +868,7 @@ class MapAxes(Axes):
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
@ -872,13 +889,14 @@ class MapAxes(Axes):
:param coordinates=['axes'|'figure'|'data'|'inches']: (*string*) Coordinate system and units for
*X, Y*. 'axes' and 'figure' are normalized coordinate system with 0,0 in the lower left and
1,1 in the upper right, 'data' are the axes data coordinates (Default value); 'inches' is
position in the figure in inches, with 0,0 at the lower left corner.
position in the figure in inches, with 0,0 in the lower left corner.
"""
ctext = plotutil.text(x, y, s, **kwargs)
islonlat = kwargs.pop('islonlat', True)
self._axes.addText(ctext, islonlat)
return ctext
@_add_transform
def contour(self, *args, **kwargs):
"""
Plot contours on the map.
@ -922,7 +940,8 @@ class MapAxes(Axes):
graphics = GraphicFactory.createContourLines(x.asarray(), y.asarray(), a.asarray(), ls, smooth)
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
graphics.transform = transform
# Add graphics
antialias = kwargs.pop('antialias', None)
@ -931,12 +950,13 @@ class MapAxes(Axes):
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
return graphics
@_add_transform
def contourf(self, *args, **kwargs):
"""
Plot filled contours on the map.
@ -984,7 +1004,8 @@ class MapAxes(Axes):
a, x, y = np.griddata((x,y), a, **griddata_props)
graphics = GraphicFactory.createContourPolygons(x.asarray(), y.asarray(), a.asarray(), ls, smooth)
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
graphics.transform = transform
# Add graphics
antialias = kwargs.pop('antialias', None)
@ -995,12 +1016,13 @@ class MapAxes(Axes):
zorder = kwargs.pop('zorder', None)
if zorder is None:
zorder = 0
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
return graphics
@_add_transform
def imshow(self, *args, **kwargs):
"""
Display an image on the map.
@ -1066,7 +1088,7 @@ class MapAxes(Axes):
visible = kwargs.pop('visible', True)
interpolation = kwargs.pop('interpolation', None)
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
if isrgb:
if isinstance(rgbdata, (list, tuple)):
rgbd = []
@ -1120,8 +1142,8 @@ class MapAxes(Axes):
if cb.isNoData():
cb.setColor(plotutil.getcolor(fill_color))
if not proj.equals(self.proj):
arr, x, y = migeo.reproject(arr, x, y, fromproj=proj, toproj=self.proj)
if not transform.equals(self.projection):
arr, x, y = migeo.reproject(arr, x, y, fromproj=transform, toproj=self.projection)
extent = [x[0],x[-1],y[0],y[-1]]
igraphic = GraphicFactory.createImage(arr._array, x._array, y._array, ls, extent)
@ -1143,6 +1165,7 @@ class MapAxes(Axes):
return igraphic
@_add_transform
def pcolor(self, *args, **kwargs):
"""
Create a pseudocolor plot of a 2-D array in a MapAxes.
@ -1165,7 +1188,6 @@ class MapAxes(Axes):
:returns: (*VectoryLayer*) Polygon VectoryLayer created from array data.
"""
proj = kwargs.pop('proj', migeo.projinfo())
n = len(args)
if n <= 2:
a = args[0]
@ -1187,25 +1209,28 @@ class MapAxes(Axes):
kwargs['edgecolor'] = None
plotutil.setlegendscheme(ls, **kwargs)
if proj is None or proj.isLonLat():
transform = kwargs.pop('transform', None)
if transform is None or transform.isLonLat():
lonlim = 90
else:
lonlim = 0
#x, y = np.project(x, y, toproj=proj)
graphics = GraphicFactory.createPColorPolygons(x.asarray(), y.asarray(), a.asarray(), ls)
graphics.transform = transform
antialias = kwargs.pop('antialias', None)
if antialias is not None:
graphics.setAntiAlias(antialias)
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
return graphics
@_add_transform
def gridshow(self, *args, **kwargs):
"""
Create a grid plot of a 2-D array in a MapAxes.
@ -1251,17 +1276,20 @@ class MapAxes(Axes):
if antialias is not None:
graphics.setAntiAlias(antialias)
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
graphics.transform = transform
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
if zorder is None:
zorder = 0
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
return graphics
@_add_transform
def quiver(self, *args, **kwargs):
"""
Plot a 2-D field of quiver in a map.
@ -1285,7 +1313,7 @@ class MapAxes(Axes):
"""
cmap = plotutil.getcolormap(**kwargs)
fill_value = kwargs.pop('fill_value', -9999.0)
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
order = kwargs.pop('order', None)
isuv = kwargs.pop('isuv', True)
n = len(args)
@ -1342,6 +1370,7 @@ class MapAxes(Axes):
x, y = np.meshgrid(x, y)
graphics = GraphicFactory.createArrows(x._array, y._array, u._array, v._array, cdata, ls, isuv)
graphics.transform = transform
# Add graphics
antialias = kwargs.pop('antialias', None)
@ -1354,12 +1383,13 @@ class MapAxes(Axes):
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
return graphics
@_add_transform
def barbs(self, *args, **kwargs):
"""
Plot a 2-D field of barbs in a map.
@ -1447,15 +1477,18 @@ class MapAxes(Axes):
if avoidcoll is not None:
graphics.setAvoidCollision(avoidcoll)
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
graphics.transform = transform
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
return graphics
@_add_transform
def streamplot(self, *args, **kwargs):
"""
Plot streamline in a map.
@ -1475,7 +1508,6 @@ class MapAxes(Axes):
:returns: (*VectoryLayer*) Created streamline VectoryLayer.
"""
proj = kwargs.pop('proj', migeo.projinfo())
isuv = kwargs.pop('isuv', True)
density = kwargs.pop('density', 4)
n = len(args)
@ -1528,12 +1560,15 @@ class MapAxes(Axes):
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
transform = kwargs.pop('transform', None)
graphics.transform = transform
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)
return graphics
@_add_transform
def stationmodel(self, smdata, **kwargs):
"""
Plot station model data on the map.
@ -1547,13 +1582,14 @@ class MapAxes(Axes):
:returns: (*graphics*) Station model graphics.
"""
proj = kwargs.pop('proj', migeo.projinfo())
transform = kwargs.pop('transform', None)
size = kwargs.pop('size', 12)
surface = kwargs.pop('surface', True)
color = kwargs.pop('color', 'b')
color = plotutil.getcolor(color)
ls = LegendManage.createSingleSymbolLegendScheme(ShapeTypes.POINT, color, size)
graphics = GraphicFactory.createStationModel(smdata, ls, surface)
graphics.transform = transform
# Add graphics
antialias = kwargs.pop('antialias', None)
@ -1566,7 +1602,7 @@ class MapAxes(Axes):
visible = kwargs.pop('visible', True)
zorder = kwargs.pop('zorder', None)
graphics = self.add_graphic(graphics, projection=proj, zorder=zorder)
graphics = self.add_graphic(graphics, zorder=zorder)
self.set_draw_extent(graphics.getExtent())
graphics.setVisible(visible)

View File

@ -1,4 +1,5 @@
from abc import ABCMeta, abstractmethod
from org.meteoinfo.geometry.graphic import Graphic
__all__ = ['Artist']
@ -21,6 +22,7 @@ class Artist(object):
self._stale = True
self.stale_callback = None
self._animated = False
self._transform = None
@property
def axes(self):
@ -58,3 +60,13 @@ class Artist(object):
if val and self.stale_callback is not None:
self.stale_callback(self, val)
@property
def transform(self):
return self._transform
@transform.setter
def transform(self, val):
self._transform = val
if isinstance(self, Graphic):
self.setTransform(val)

View File

@ -82,3 +82,84 @@ class Point2DCollection(Collection, Point2DGraphicCollection):
Point2DGraphicCollection.__init__(self, self._x._array, self._y._array, legend)
else:
Point2DGraphicCollection.__init__(self, self._x._array, self._y._array, self._cdata._array, legend)
@property
def visible(self):
"""
The artist is visible or not.
"""
return self.isVisible()
@visible.setter
def visible(self, val):
self.setVisible(val)
self.stale = True
@property
def xdata(self):
"""
Return the xdata.
:return: (*array*) xdata.
"""
return self._x
@xdata.setter
def xdata(self, xdata):
"""
Set the xdata.
:param xdata: (*array*) The xdata.
"""
self._x = xdata
self.setXData(xdata._array)
self.stale = True
@property
def ydata(self):
"""
Return the ydata.
:return: (*array*) ydata.
"""
return self._y
@ydata.setter
def ydata(self, ydata):
"""
Set the ydata.
:param ydata: (*array*) The ydata.
"""
self._y = ydata
self.setYData(ydata._array)
self.stale = True
@property
def data(self):
"""
Get x, y data.
:return: x, y data.
"""
return (self._x, self._y)
@data.setter
def data(self, *args):
"""
Set x, y data.
:param xdata: (*array*) X data.
:param ydata: (*array*) Y data.
"""
if len(args) == 1:
xdata = args[0][0]
ydata = args[0][1]
else:
xdata = args[0]
ydata = args[1]
self._x = xdata
self._y = ydata
self.setData(xdata._array, ydata._array)
self.stale = True

View File

@ -0,0 +1,60 @@
package org.meteoinfo.projection;
import org.locationtech.proj4j.BasicCoordinateTransform;
import org.locationtech.proj4j.CoordinateTransform;
import org.locationtech.proj4j.ProjCoordinate;
import org.meteoinfo.common.PointD;
import org.meteoinfo.geometry.graphic.Transform;
public class GeoTransform extends Transform {
protected CoordinateTransform coordinateTransform;
protected ProjectionInfo sourceProj;
protected ProjectionInfo targetProj;
/**
* Constructor
* @param source Source projection info
* @param target Target projection info
*/
public GeoTransform(ProjectionInfo source, ProjectionInfo target) {
this.sourceProj = source;
this.targetProj = target;
this.coordinateTransform = new BasicCoordinateTransform(source.getCoordinateReferenceSystem(),
target.getCoordinateReferenceSystem());
}
/**
* Get source projection
* @return Source projection
*/
public ProjectionInfo getSourceProj() {
return this.sourceProj;
}
/**
* Get target projection
* @return Target projection
*/
public ProjectionInfo getTargetProj() {
return this.targetProj;
}
@Override
public boolean isValid() {
return !sourceProj.equals(targetProj);
}
@Override
public PointD transform(double x, double y) {
ProjCoordinate s = new ProjCoordinate(x, y);
ProjCoordinate t = new ProjCoordinate();
this.coordinateTransform.transform(s, t);
return new PointD(t.x, t.y);
}
@Override
public Transform inverted() {
return new GeoTransform(this.targetProj, this.sourceProj);
}
}

View File

@ -946,6 +946,43 @@ public class ProjectionUtil {
* @return Projected graphic
*/
public static Graphic projectClipGraphic(Graphic graphic, ProjectionInfo fromProj, ProjectionInfo toProj) {
if (graphic instanceof GraphicCollection) {
try {
List<Graphic> graphics = new ArrayList<>();
for (Graphic aGraphic : ((GraphicCollection) graphic).getGraphics()) {
List<? extends Shape> shapes = projectClipShape(aGraphic.getShape(), fromProj, toProj);
if (shapes != null && shapes.size() > 0) {
aGraphic.setShape(shapes.get(0));
graphics.add(aGraphic);
}
}
((GraphicCollection) graphic).setGraphics(graphics);
return graphic;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
} else {
List<? extends Shape> shapes = projectClipShape(graphic.getShape(), fromProj, toProj);
if (shapes != null && shapes.size() > 0) {
graphic.setShape(shapes.get(0));
return graphic;
} else {
return null;
}
}
}
/**
* Project graphic
*
* @param graphic The graphic
* @param fromProj From projection
* @param toProj To projection
* @return Projected graphic
*/
public static Graphic projectClipGraphic_old(Graphic graphic, ProjectionInfo fromProj, ProjectionInfo toProj) {
if (graphic instanceof GraphicCollection) {
try {
Graphic newGCollection = graphic.getClass().getDeclaredConstructor().newInstance();