diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/Chart.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/Chart.java index 5ecb795b..c75c800b 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/Chart.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/Chart.java @@ -877,9 +877,9 @@ public class Chart { * @param plot Plot */ public void addPlot(Plot plot) { - /*if (plot instanceof MapPlot) { + if (plot instanceof MapPlot) { ((MapPlot) plot).setParent(parent); - }*/ + } this.plots.add(plot); } diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/ChartPanel.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/ChartPanel.java index 6b24049f..c3c999fd 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/ChartPanel.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/ChartPanel.java @@ -582,29 +582,26 @@ public class ChartPanel extends JPanel implements IChartPanel{ if (this.chart != null) { Graphics2D g = this.mapBitmap.createGraphics(); - Rectangle2D chartArea; - if (this.chartSize == null) { - chartArea = new Rectangle2D.Double(0.0, 0.0, this.mapBitmap.getWidth(), this.mapBitmap.getHeight()); - } else { - chartArea = new Rectangle2D.Double(0.0, 0.0, this.chartSize.width, this.chartSize.height); - } + Rectangle2D chartArea = new Rectangle2D.Double(0.0, 0.0, width, height); this.chart.draw(g, chartArea); } this.repaint(); } public void paintGraphics(Graphics2D g) { - if (this.chart != null) { - Rectangle2D chartArea; - if (this.chartSize == null) { - chartArea = new Rectangle2D.Double(0.0, 0.0, this.getWidth(), this.getHeight()); - } else { - chartArea = new Rectangle2D.Double(0.0, 0.0, this.chartSize.width, this.chartSize.height); - } - this.chart.draw(g, chartArea); + int width, height; + if (this.chartSize != null) { + height = this.chartSize.height; + width = this.chartSize.width; + } else { + width = this.getWidth(); + height = this.getHeight(); } + + paintGraphics(g, width, height); } + @Override public void paintGraphics(Graphics2D g, int width, int height) { if (this.chart != null) { Rectangle2D chartArea; @@ -614,11 +611,13 @@ public class ChartPanel extends JPanel implements IChartPanel{ } void onComponentResized(ComponentEvent e) { - if (!loading) { - if (this.getWidth() > 0 && this.getHeight() > 0) { - if (this.chart != null) { - //this.paintGraphics(); + if (this.getWidth() > 0 && this.getHeight() > 0) { + if (this.chart != null) { + if (this.chart.hasWebMap()) { this.repaintNew(); + } else { + if (!loading) + this.repaintNew(); } } } 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 f6438b2a..ded8966f 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/GLChartPanel.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/GLChartPanel.java @@ -618,6 +618,7 @@ public class GLChartPanel extends GLJPanel implements IChartPanel{ } } + @Override public void paintGraphics(Graphics2D g, int width, int height) { if (this.chart != null) { Rectangle2D chartArea; diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/IChartPanel.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/IChartPanel.java index ef559094..479305d2 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/IChartPanel.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/IChartPanel.java @@ -5,6 +5,8 @@ */ package org.meteoinfo.chart; +import java.awt.*; + /** * * @author yaqiang @@ -43,4 +45,6 @@ public interface IChartPanel { * Paint graphics */ public abstract void paintGraphics(); + + public abstract void paintGraphics(Graphics2D g, int width, int height); } diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/form/ChartForm.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/form/ChartForm.java index c384c3b7..c55cc3b3 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/form/ChartForm.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/form/ChartForm.java @@ -8,7 +8,7 @@ package org.meteoinfo.chart.form; import org.meteoinfo.chart.ChartPanel; import org.meteoinfo.chart.IChartPanel; import org.meteoinfo.chart.MouseMode; -import org.meteoinfo.chart.jogl.GLChartPanel; +import org.meteoinfo.chart.GLChartPanel; import javax.imageio.ImageIO; import java.awt.*; diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLChartPanel.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLChartPanel.java index ead2d264..af9423d8 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLChartPanel.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/jogl/GLChartPanel.java @@ -28,6 +28,7 @@ import javax.imageio.stream.ImageOutputStream; import javax.swing.*; import java.awt.*; import java.awt.event.*; +import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -806,6 +807,11 @@ public class GLChartPanel extends GLJPanel implements IChartPanel { this.repaint(); } + @Override + public void paintGraphics(Graphics2D g, int width, int height) { + + } + /** * Override repaint method */ diff --git a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/plot/MapPlot.java b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/plot/MapPlot.java index 38b019cd..0a2d05cb 100644 --- a/meteoinfo-chart/src/main/java/org/meteoinfo/chart/plot/MapPlot.java +++ b/meteoinfo-chart/src/main/java/org/meteoinfo/chart/plot/MapPlot.java @@ -56,7 +56,7 @@ public class MapPlot extends AbstractPlot2D implements IWebMapPanel { private boolean antialias; private MapLayer selectedLayer; protected TileLoadListener tileLoadListener = new TileLoadListener(this); - private GLChartPanel parent; + private IChartPanel parent; private float[] lonLim; private float[] latLim; private Graphic boundary; @@ -127,7 +127,7 @@ public class MapPlot extends AbstractPlot2D implements IWebMapPanel { * * @param value ChartPanel */ - public void setParent(GLChartPanel value) { + public void setParent(IChartPanel value) { this.parent = value; } diff --git a/meteoinfo-console/src/main/java/org/meteoinfo/console/jython/JythonUtil.java b/meteoinfo-console/src/main/java/org/meteoinfo/console/jython/JythonUtil.java index 175e73ef..448488ba 100644 --- a/meteoinfo-console/src/main/java/org/meteoinfo/console/jython/JythonUtil.java +++ b/meteoinfo-console/src/main/java/org/meteoinfo/console/jython/JythonUtil.java @@ -1,5 +1,6 @@ package org.meteoinfo.console.jython; +import org.checkerframework.checker.units.qual.C; import org.meteoinfo.ndarray.Array; import org.meteoinfo.ndarray.Complex; import org.meteoinfo.ndarray.DataType; @@ -27,15 +28,7 @@ public class JythonUtil { * @return ArrayComplex */ public static Array toComplexArray(List data) { - if (data.get(0) instanceof PyComplex) { - Array a = Array.factory(DataType.COMPLEX, new int[]{data.size()}); - PyComplex pd; - for (int i = 0; i < data.size(); i++) { - pd = (PyComplex)data.get(i); - a.setObject(i, new Complex(pd.real, pd.imag)); - } - return a; - } else if (data.get(0) instanceof List) { + if (data.get(0) instanceof List) { int ndim = data.size(); int len = ((List) data.get(0)).size(); Array a = Array.factory(DataType.COMPLEX, new int[]{ndim, len}); @@ -43,13 +36,28 @@ public class JythonUtil { for (int i = 0; i < ndim; i++) { List d = (List) data.get(i); for (int j = 0; j < len; j++) { - pd = (PyComplex) d.get(j); - a.setObject(i * len + j, new Complex(pd.real, pd.imag)); + if (d.get(j) instanceof PyComplex) { + pd = (PyComplex) d.get(j); + a.setComplex(i * len + j, new Complex(pd.real, pd.imag)); + } else { + a.setComplex(i * len + j, new Complex((double) d.get(j), 0)); + } + } + } + return a; + } else { + Array a = Array.factory(DataType.COMPLEX, new int[]{data.size()}); + PyComplex pd; + for (int i = 0; i < data.size(); i++) { + if (data.get(i) instanceof PyComplex) { + pd = (PyComplex) data.get(i); + a.setComplex(i, new Complex(pd.real, pd.imag)); + } else { + a.setComplex(i, new Complex((double) data.get(i), 0)); } } return a; } - return null; } } diff --git a/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/MeteoDataType.java b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/MeteoDataType.java index b687ae3a..4feec290 100644 --- a/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/MeteoDataType.java +++ b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/MeteoDataType.java @@ -51,6 +51,7 @@ public enum MeteoDataType { MM5IM, GEOTIFF, BIL, + RADAR, NULL; /** diff --git a/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/CMARadarBaseDataInfo.java b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/CMARadarBaseDataInfo.java index 34682973..7b857f51 100644 --- a/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/CMARadarBaseDataInfo.java +++ b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/CMARadarBaseDataInfo.java @@ -6,10 +6,7 @@ import org.meteoinfo.data.GridArray; import org.meteoinfo.data.GridData; import org.meteoinfo.data.dimarray.Dimension; import org.meteoinfo.data.dimarray.DimensionType; -import org.meteoinfo.data.meteodata.Attribute; -import org.meteoinfo.data.meteodata.DataInfo; -import org.meteoinfo.data.meteodata.IGridDataInfo; -import org.meteoinfo.data.meteodata.Variable; +import org.meteoinfo.data.meteodata.*; import org.meteoinfo.ndarray.*; import org.meteoinfo.ndarray.math.ArrayMath; import org.meteoinfo.ndarray.math.ArrayUtil; @@ -17,6 +14,8 @@ import org.meteoinfo.ndarray.math.ArrayUtil; import java.awt.image.ImagingOpException; import java.io.*; import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -30,14 +29,22 @@ public class CMARadarBaseDataInfo extends DataInfo implements IGridDataInfo { private SiteConfig siteConfig; private TaskConfig taskConfig; private List cutConfigs; - private Map productMap = Stream.of(new Object[][]{{1,"dBT"}, {2,"dBZ"}, + private List radialHeaders; + private final Map productMap = Stream.of(new Object[][]{{1,"dBT"}, {2,"dBZ"}, {3,"V"}, {4,"W"}, {5,"SQI"}, {6,"CPA"}, {7,"ZDR"}, {8,"LDR"}, {9,"CC"}, {10,"PhiDP"}, {11,"KDP"}, {12,"CP"}, {13,"Flag"}, {14,"HCL"}, {15,"CF"}, {16,"SNRH"}, {17,"SNRV"}, {18,"Flag"}, {19,"Flag"}, {20,"Flag"}, {21,"Flag"}, {22,"Flag"}, {23,"Flag"}, {24,"Flag"}, {25,"Flag"}, {26,"Flag"}, {27,"Flag"}, {28,"Flag"}, {29,"Flag"}, {30,"Flag"}, {31,"Flag"}, {32,"Zc"}, {33,"Vc"}, {34,"Wc"}, {35,"ZDRc"}, {0,"Flag"} }).collect(Collectors.toMap(data -> (Integer) data[0], data -> (String) data[1])); - private Map recordMap = new HashMap<>(); + private final Map recordMap = new HashMap<>(); + + /** + * Constructor + */ + public CMARadarBaseDataInfo() { + this.meteoDataType = MeteoDataType.RADAR; + } /** * Get generic header @@ -71,6 +78,14 @@ public class CMARadarBaseDataInfo extends DataInfo implements IGridDataInfo { return this.cutConfigs; } + /** + * Get radial header list + * @return Radial header list + */ + public List getRadialHeaders() { + return this.radialHeaders; + } + /** * Get record map * @return Record map @@ -155,7 +170,7 @@ public class CMARadarBaseDataInfo extends DataInfo implements IGridDataInfo { try { byte[] bytes = new byte[4]; if (fileName.endsWith("bz2")) { - BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(new FileInputStream(fileName)); + BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName))); inputStream.read(bytes); } else { RandomAccessFile raf = new RandomAccessFile(fileName, "r"); @@ -178,7 +193,7 @@ public class CMARadarBaseDataInfo extends DataInfo implements IGridDataInfo { this.fileName = fileName; if (fileName.endsWith(".bz2")) { try { - BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(new FileInputStream(fileName)); + BZip2CompressorInputStream inputStream = new BZip2CompressorInputStream(Files.newInputStream(Paths.get(fileName))); readDataInfo(inputStream); } catch (IOException e) { throw new RuntimeException(e); @@ -212,7 +227,7 @@ public class CMARadarBaseDataInfo extends DataInfo implements IGridDataInfo { for (int i = 0; i < taskConfig.cutNumber; i++) { cutConfigs.add(new CutConfig(raf)); } - List radialHeaders = new ArrayList<>(); + radialHeaders = new ArrayList<>(); while (raf.length() - raf.getFilePointer() > RadialHeader.length) { RadialHeader radialHeader = new RadialHeader(raf); for (int i = 0; i < radialHeader.momentNumber; i++) { @@ -280,7 +295,7 @@ public class CMARadarBaseDataInfo extends DataInfo implements IGridDataInfo { for (int i = 0; i < taskConfig.cutNumber; i++) { cutConfigs.add(new CutConfig(raf)); } - List radialHeaders = new ArrayList<>(); + radialHeaders = new ArrayList<>(); byte[] rhBytes = new byte[RadialHeader.length]; while (raf.read(rhBytes) != -1) { RadialHeader radialHeader = new RadialHeader(rhBytes); @@ -329,6 +344,47 @@ public class CMARadarBaseDataInfo extends DataInfo implements IGridDataInfo { } } + /** + * Get product names + * @return product names + */ + public List getProducts() { + List products = new ArrayList<>(); + for (String product : this.recordMap.keySet()) { + products.add(product); + } + + return products; + } + + /** + * Get scan elevations + * @return Scan elevations + */ + public List getElevations() { + List elevations = new ArrayList<>(); + for (CutConfig cutConfig : this.cutConfigs) { + if (!elevations.contains(cutConfig.elevation)) + elevations.add(cutConfig.elevation); + } + + return elevations; + } + + /** + * Get scan elevations + * @return Scan elevations + */ + public List getElevations(String product) { + RadialRecord radialRecord = this.recordMap.get(product); + List elevations = new ArrayList<>(); + for (List elist : radialRecord.elevation) { + elevations.add(elist.get(0)); + } + + return elevations; + } + @Override public Array read(String varName) { Variable var = this.getVariable(varName); diff --git a/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/RadialRecord.java b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/RadialRecord.java index 5b8fc939..42fc9c9a 100644 --- a/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/RadialRecord.java +++ b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/RadialRecord.java @@ -23,7 +23,7 @@ public class RadialRecord { public List> elevation = new ArrayList<>(); public List> azimuth = new ArrayList<>(); public List distance = new ArrayList<>(); - private List> data = new ArrayList<>(); + private final List> data = new ArrayList<>(); /** * Constructor @@ -114,43 +114,6 @@ public class RadialRecord { return this.data.get(scanIdx); } - /** - * Convert antenna coordinate to cartesian coordinate - * @param r Distances to the center of the radar gates (bins) in meters - * @param a Azimuth angle of the radar in radians - * @param e Elevation angle of the radar in radians - * @return Cartesian coordinate in meters from the radar - */ - public double[] antennaToCartesian(float r, float a, float e) { - double R = 6371.0 * 1000.0 * 4.0 / 3.0; // effective radius of earth in meters. - - double z = Math.pow(r * r + R * R + 2.0 * r * R * Math.sin(e), 0.5) - R; - double s = R * Math.asin(r * Math.cos(e) / (R + z)); // arc length in m. - double x = s * Math.sin(a); - double y = s * Math.cos(a); - - return new double[]{x, y, z}; - } - - /** - * Convert antenna coordinate to cartesian coordinate - * @param r Distances to the center of the radar gates (bins) in meters - * @param a Azimuth angle of the radar in radians - * @param e Elevation angle of the radar in radians - * @param h Altitude of the instrument, above sea level, units:m - * @return Cartesian coordinate in meters from the radar - */ - public double[] antennaToCartesian(float r, float a, float e, float h) { - double R = 6371.0 * 1000.0 * 4.0 / 3.0; // effective radius of earth in meters. - - double z = Math.pow(Math.pow(r * Math.cos(e), 2) + Math.pow(R + h + r * Math.sin(e), 2), 0.5) - R; - double s = R * Math.asin(r * Math.cos(e) / (R + z)); // arc length in m. - double x = s * Math.sin(a); - double y = s * Math.cos(a); - - return new double[]{x, y, z}; - } - /** * Get XYZ data array * @param scanIdx The scan index @@ -171,7 +134,7 @@ public class RadialRecord { a = (float) Math.toRadians(azi.get(i)); e = (float) Math.toRadians(ele.get(i)); for (int j = 0; j < nx; j++) { - xyz = antennaToCartesian(dis.getFloat(j), a, e); + xyz = Transform.antennaToCartesian(dis.getFloat(j), a, e); index.set(0, i, j); r.setFloat(index, (float) xyz[0]); index.set(1, i, j); diff --git a/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/Transform.java b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/Transform.java new file mode 100644 index 00000000..caa8cf76 --- /dev/null +++ b/meteoinfo-data/src/main/java/org/meteoinfo/data/meteodata/radar/Transform.java @@ -0,0 +1,69 @@ +package org.meteoinfo.data.meteodata.radar; + +import org.meteoinfo.ndarray.math.ArrayMath; + +public class Transform { + + static double R = 6371.0 * 1000.0 * 4.0 / 3.0; // effective radius of earth in meters. + + /** + * Convert antenna coordinate to cartesian coordinate + * @param r Distances to the center of the radar gates (bins) in meters + * @param a Azimuth angle of the radar in radians + * @param e Elevation angle of the radar in radians + * @return Cartesian coordinate in meters from the radar + */ + public static double[] antennaToCartesian(float r, float a, float e) { + double z = Math.pow(r * r + R * R + 2.0 * r * R * Math.sin(e), 0.5) - R; + double s = R * Math.asin(r * Math.cos(e) / (R + z)); // arc length in m. + double x = s * Math.sin(a); + double y = s * Math.cos(a); + + return new double[]{x, y, z}; + } + + /** + * Convert antenna coordinate to cartesian coordinate + * @param r Distances to the center of the radar gates (bins) in meters + * @param a Azimuth angle of the radar in radians + * @param e Elevation angle of the radar in radians + * @param h Altitude of the instrument, above sea level, units:m + * @return Cartesian coordinate in meters from the radar + */ + public static double[] antennaToCartesian(float r, float a, float e, float h) { + double R = 6371.0 * 1000.0 * 4.0 / 3.0; // effective radius of earth in meters. + + double z = Math.pow(Math.pow(r * Math.cos(e), 2) + Math.pow(R + h + r * Math.sin(e), 2), 0.5) - R; + double s = R * Math.asin(r * Math.cos(e) / (R + z)); // arc length in m. + double x = s * Math.sin(a); + double y = s * Math.cos(a); + + return new double[]{x, y, z}; + } + + private static double azimuth(float x, float y) { + double az = Math.PI / 2 - Math.atan2(x + y, 1); + if (az < 0) { + az = 2 * Math.PI + az; + } + return Math.toDegrees(az); + } + + /** + * Convert cartesian coordinate to antenna coordinate + * @param x x coordinate in meters + * @param y y coordinate in meters + * @param z z coordinate in meters + * @param h Altitude of the instrument, above sea level, units:m + * @return Antenna coordinate from the radar + */ + public static double[] cartesianToAntenna(float x, float y, float z, float h) { + double ranges = Math.sqrt(Math.pow(R + h, 2) + Math.pow(R + z, 2) - 2 * (R + h) * (R + z) * + Math.cos(Math.sqrt(x * x + y * y) / R)); + double elevation = Math.acos((R + z) * Math.sin(Math.sqrt(x * x + y * y) / R) / ranges) * + 180. / Math.PI; + double azimuth = azimuth(x, y); + + return new double[]{azimuth, ranges, elevation}; + } +} diff --git a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/analysis/GeoComputation.java b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/analysis/GeoComputation.java index 3e97e4dd..650a9827 100644 --- a/meteoinfo-geo/src/main/java/org/meteoinfo/geo/analysis/GeoComputation.java +++ b/meteoinfo-geo/src/main/java/org/meteoinfo/geo/analysis/GeoComputation.java @@ -196,31 +196,33 @@ public class GeoComputation extends org.meteoinfo.geometry.geoprocess.GeoComputa } q1 = q2; } - GridLabel aGL = new GridLabel(); - aGL.setBorder(true); - aGL.setLongitude(isVertical); - aGL.setCoord(IPoint); - if (MIMath.doubleEquals(q1.X, borderList.get(j).Point.X)) { - if (MIMath.doubleEquals(q1.X, clipExtent.minX)) { - aGL.setLabDirection(Direction.Weast); + if (j < borderList.size()) { + GridLabel aGL = new GridLabel(); + aGL.setBorder(true); + aGL.setLongitude(isVertical); + aGL.setCoord(IPoint); + if (MIMath.doubleEquals(q1.X, borderList.get(j).Point.X)) { + if (MIMath.doubleEquals(q1.X, clipExtent.minX)) { + aGL.setLabDirection(Direction.Weast); + } else { + aGL.setLabDirection(Direction.East); + } } else { - aGL.setLabDirection(Direction.East); + if (MIMath.doubleEquals(q1.Y, clipExtent.minY)) { + aGL.setLabDirection(Direction.South); + } else { + aGL.setLabDirection(Direction.North); + } } - } else { - if (MIMath.doubleEquals(q1.Y, clipExtent.minY)) { - aGL.setLabDirection(Direction.South); - } else { - aGL.setLabDirection(Direction.North); - } - } - if (isVertical) { - if (aGL.getLabDirection() == Direction.South || aGL.getLabDirection() == Direction.North) { - gridLabels.add(aGL); - } - } else { - if (aGL.getLabDirection() == Direction.East || aGL.getLabDirection() == Direction.Weast) { - gridLabels.add(aGL); + if (isVertical) { + if (aGL.getLabDirection() == Direction.South || aGL.getLabDirection() == Direction.North) { + gridLabels.add(aGL); + } + } else { + if (aGL.getLabDirection() == Direction.East || aGL.getLabDirection() == Direction.Weast) { + gridLabels.add(aGL); + } } } diff --git a/meteoinfo-lab/milconfig.xml b/meteoinfo-lab/milconfig.xml index 446b21f2..e7420f4f 100644 --- a/meteoinfo-lab/milconfig.xml +++ b/meteoinfo-lab/milconfig.xml @@ -1,7 +1,6 @@ - @@ -14,6 +13,7 @@ + @@ -22,15 +22,17 @@ - - + + + - - + + + @@ -38,5 +40,5 @@
- + diff --git a/meteoinfo-lab/pom.xml b/meteoinfo-lab/pom.xml index 2542faef..a88d94e1 100644 --- a/meteoinfo-lab/pom.xml +++ b/meteoinfo-lab/pom.xml @@ -29,12 +29,16 @@ docking-frames-core 2.0.0 - + + org.slf4j + slf4j-api + 2.0.5 + + + org.slf4j + slf4j-simple + 2.0.5 + 1.8 diff --git a/meteoinfo-lab/pylib/mipylib/dataset/arldatafile.py b/meteoinfo-lab/pylib/mipylib/dataset/arldatafile.py index 0b0c7fa2..d231f242 100644 --- a/meteoinfo-lab/pylib/mipylib/dataset/arldatafile.py +++ b/meteoinfo-lab/pylib/mipylib/dataset/arldatafile.py @@ -5,16 +5,7 @@ from .dimdatafile import DimDataFile class ARLDataFile(DimDataFile): def __init__(self, dataset=None, access='r', arldata=None): - self.dataset = dataset - self.access = access - self._variables = [] - if not dataset is None: - self.filename = dataset.getFileName() - for v in dataset.getDataInfo().getVariables(): - self._variables.append(DimVariable(v)) - self.nvar = dataset.getDataInfo().getVariableNum() - self.fill_value = dataset.getMissingValue() - self.proj = dataset.getProjectionInfo() + super(ARLDataFile, self).__init__(dataset, access) self.arldata = arldata # Write ARL data diff --git a/meteoinfo-lab/pylib/mipylib/dataset/bufrdatafile.py b/meteoinfo-lab/pylib/mipylib/dataset/bufrdatafile.py new file mode 100644 index 00000000..75143c40 --- /dev/null +++ b/meteoinfo-lab/pylib/mipylib/dataset/bufrdatafile.py @@ -0,0 +1,117 @@ + +from .dimdatafile import DimDataFile + + +class BUFRDataFile(DimDataFile): + + def __init__(self, dataset=None, access='r', bufrdata=None): + super(BUFRDataFile, self).__init__(dataset, access) + self.bufrdata = bufrdata + + def write_indicator(self, bufrlen, edition=3): + """ + Write indicator section with arbitrary length. + + :param bufrlen: (*int*) The total length of the message. + :param edition: (*int*) Bruf edition. + + :returns: (*int*) Indicator section length. + """ + return self.bufrdata.writeIndicatorSection(bufrlen, edition) + + def rewrite_indicator(self, bufrlen, edition=3): + """ + Write indicator section with correct length. + + :param bufrlen: (*int*) The total length of the message. + :param edition: (*int*) Bruf edition. + """ + self.bufrdata.reWriteIndicatorSection(bufrlen, edition) + + def write_identification(self, **kwargs): + """ + Write identification section. + + :param length: (*int*) Section length + :param master_table: (*int*) Master table + :param subcenter_id: (*int*) Subcenter id + :param center_id: (*int*) Center id + :param update: (*int*) Update sequency + :param optional: (*int*) Optional + :param category: (*int*) Category + :param sub_category: (*int*) Sub category + :param master_table_version: (*int*) Master table version + :param local_table_version: (*int*) Local table version + :param year: (*int*) Year + :param month: (*int*) Month + :param day: (*int*) Day + :param hour: (*int*) Hour + :param minute: (*int*) Minute + + :returns: (*int*) Section length + """ + length = kwargs.pop('length', 18) + master_table = kwargs.pop('master_table', 0) + subcenter_id = kwargs.pop('subcenter_id', 0) + center_id = kwargs.pop('center_id', 74) + update = kwargs.pop('update', 0) + optional = kwargs.pop('optional', 0) + category = kwargs.pop('category', 7) + sub_category = kwargs.pop('sub_category', 0) + master_table_version = kwargs.pop('master_table_version', 11) + local_table_version = kwargs.pop('local_table_version', 1) + year = kwargs.pop('year', 2016) + month = kwargs.pop('month', 1) + day = kwargs.pop('day', 1) + hour = kwargs.pop('hour', 0) + minute = kwargs.pop('minute', 0) + return self.bufrdata.writeIdentificationSection(length, master_table, subcenter_id, center_id, \ + update, optional, category, sub_category, master_table_version, \ + local_table_version, year, month, day, hour, minute) + + def write_datadescription(self, n, datatype, descriptors): + """ + Write data description section + + :param n: (*int*) Numer of dataset. + :param datatype: (*int*) Data type. + :param descriptors: (*list*) Data descriptors. + """ + return self.bufrdata.writeDataDescriptionSection(n, datatype, descriptors) + + def write_datahead(self, len): + """ + Write data header with arbitrary data length. + + :param len: (*int*) Data section length. + + :returns: (*int*) Data section head length - always 4. + """ + return self.bufrdata.writeDataSectionHead(len) + + def rewrite_datahead(self, len): + """ + Write data header with correct data length. + + :param len: (*int*) Data section length. + """ + self.bufrdata.reWriteDataSectionHead(len) + + def write_data(self, value, nbits=None): + """ + Write data. + + :param value: (*int*) Value. + :param nbits: (*int*) Bit number. + + :returns: (*int*) Data value length. + """ + return self.bufrdata.write(value, nbits) + + def write_end(self): + """ + Write end section ('7777'). + + :returns: (*int*) End section length - always 4. + """ + return self.bufrdata.writeEndSection() \ No newline at end of file diff --git a/meteoinfo-lab/pylib/mipylib/dataset/midata$py.class b/meteoinfo-lab/pylib/mipylib/dataset/midata$py.class index ce41f947..8d5461ff 100644 Binary files a/meteoinfo-lab/pylib/mipylib/dataset/midata$py.class and b/meteoinfo-lab/pylib/mipylib/dataset/midata$py.class differ diff --git a/meteoinfo-lab/pylib/mipylib/dataset/midata.py b/meteoinfo-lab/pylib/mipylib/dataset/midata.py index 69f59c5a..3c62d7d3 100644 --- a/meteoinfo-lab/pylib/mipylib/dataset/midata.py +++ b/meteoinfo-lab/pylib/mipylib/dataset/midata.py @@ -8,7 +8,7 @@ import os import datetime -from org.meteoinfo.data.meteodata import MeteoDataInfo +from org.meteoinfo.data.meteodata import MeteoDataInfo, MeteoDataType from org.meteoinfo.ndarray import DataType from org.meteoinfo.data.dimarray import Dimension, DimensionType from org.meteoinfo.data.meteodata.arl import ARLDataInfo @@ -24,6 +24,9 @@ import mipylib.miutil as miutil from mipylib.numeric.core import NDArray, DimArray, PyTableData from dimdatafile import DimDataFile, DimDataFiles +from arldatafile import ARLDataFile +from bufrdatafile import BUFRDataFile +from radardatafile import RadarDataFile import mipylib.migl as migl __all__ = [ @@ -113,13 +116,16 @@ def addfile(fname, access='r', dtype='netcdf', keepopen=False, **kwargs): meteodata = MeteoDataInfo() meteodata.openData(fname, keepopen) - datafile = DimDataFile(meteodata, access=access) + if meteodata.getDataInfo().getDataType() == MeteoDataType.RADAR: + datafile = RadarDataFile(meteodata, access=access) + else: + datafile = DimDataFile(meteodata, access=access) return datafile elif access == 'c': if dtype == 'arl': arldata = ARLDataInfo() arldata.createDataFile(fname) - datafile = DimDataFile(arldata=arldata) + datafile = ARLDataFile(arldata=arldata) elif dtype == 'bufr': bufrdata = BufrDataInfo() if os.path.exists(fname): @@ -127,9 +133,9 @@ def addfile(fname, access='r', dtype='netcdf', keepopen=False, **kwargs): os.remove(fname) except: info=sys.exc_info() - print info[0],":",info[1] + print(info[0],":",info[1]) bufrdata.createDataFile(fname) - datafile = DimDataFile(bufrdata=bufrdata) + datafile = BUFRDataFile(bufrdata=bufrdata) else: version = kwargs.pop('version', 'netcdf3') if version == 'netcdf3': diff --git a/meteoinfo-lab/pylib/mipylib/dataset/radardatafile.py b/meteoinfo-lab/pylib/mipylib/dataset/radardatafile.py new file mode 100644 index 00000000..ada413f2 --- /dev/null +++ b/meteoinfo-lab/pylib/mipylib/dataset/radardatafile.py @@ -0,0 +1,30 @@ + +from .dimdatafile import DimDataFile + + +class RadarDataFile(DimDataFile): + + def __init__(self, dataset=None, access='r'): + super(RadarDataFile, self).__init__(dataset, access) + self.datainfo = dataset.getDataInfo() + + def get_products(self): + """ + Get product names. + + :return: Product names. + """ + return list(self.datainfo.getProducts()) + + def get_elevations(self, product=None): + """ + Get scan elevation angles. + + :param product: (*Str*) Product name. Default is None. + + :return: Scan elevation angles. + """ + if product is None: + return list(self.datainfo.getElevations()) + else: + return list(self.datainfo.getElevations(product)) diff --git a/meteoinfo-lab/pylib/mipylib/numeric/core/numeric$py.class b/meteoinfo-lab/pylib/mipylib/numeric/core/numeric$py.class index 86f678c0..3563e52a 100644 Binary files a/meteoinfo-lab/pylib/mipylib/numeric/core/numeric$py.class and b/meteoinfo-lab/pylib/mipylib/numeric/core/numeric$py.class differ diff --git a/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py b/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py index 51f1e002..5160b9eb 100644 --- a/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py +++ b/meteoinfo-lab/pylib/mipylib/numeric/core/numeric.py @@ -104,11 +104,11 @@ def array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0): if len(object) > 0: if isinstance(object[0], datetime.datetime): object = miutil.dates2nums(object) - elif isinstance(object[0], PyComplex): - a = NDArray(JythonUtil.toComplexArray(object)) elif isinstance(object[0], (list, tuple)): - if isinstance(object[0][0], PyComplex): + if miutil.iscomplex(object[0]): a = NDArray(JythonUtil.toComplexArray(object)) + elif miutil.iscomplex(object): + a = NDArray(JythonUtil.toComplexArray(object)) if isinstance(dtype, basestring): dtype = _dtype.DataType(dtype) diff --git a/meteoinfo-lab/pylib/mipylib/numeric/lib/function_base.py b/meteoinfo-lab/pylib/mipylib/numeric/lib/function_base.py index 30c2aba1..f48b9383 100644 --- a/meteoinfo-lab/pylib/mipylib/numeric/lib/function_base.py +++ b/meteoinfo-lab/pylib/mipylib/numeric/lib/function_base.py @@ -1,9 +1,10 @@ from ..core import numeric as _nx +from ..core import dtype from ..core._ndarray import NDArray from ..core.fromnumeric import (ravel, nonzero) from org.meteoinfo.ndarray.math import ArrayMath -__all__ = ['extract', 'place', 'grid_edge'] +__all__ = ['angle','extract', 'place', 'grid_edge'] def extract(condition, arr): @@ -112,3 +113,51 @@ def grid_edge(x, y): yy[xn + yn + xn:] = y[::-1] return xx, yy + +def angle(z, deg=False): + """ + Return the angle of the complex argument. + + Parameters + ---------- + z : array_like + A complex number or sequence of complex numbers. + deg : bool, optional + Return angle in degrees if True, radians if False (default). + + Returns + ------- + angle : ndarray or scalar + The counterclockwise angle from the positive real axis on the complex + plane in the range ``(-pi, pi]``, with dtype as double. + + See Also + -------- + arctan2 + absolute + + Notes + ----- + Although the angle of the complex number 0 is undefined, ``angle(0)`` + returns the value 0. + + Examples + -------- + >>> np.angle([1.0, 1.0j, 1+1j]) # in radians + array([ 0. , 1.57079633, 0.78539816]) # may vary + >>> np.angle(1+1j, deg=True) # in degrees + 45.0 + + """ + z = _nx.asanyarray(z) + if z.dtype == dtype.complex: + zimag = z.imag + zreal = z.real + else: + zimag = 0 + zreal = z + + a = _nx.arctan2(zimag, zreal) + if deg: + a *= 180 / _nx.pi + return a diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure$py.class b/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure$py.class index d42a0dae..cfb40b9a 100644 Binary files a/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure$py.class and b/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure$py.class differ diff --git a/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure.py b/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure.py index 9f974ba8..d02f792f 100644 --- a/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure.py +++ b/meteoinfo-lab/pylib/mipylib/plotlib/_glfigure.py @@ -14,7 +14,7 @@ from ._mapaxes import MapAxes from ._axes3d import Axes3D from ._axes3dgl import Axes3DGL -from java.awt import Font +from java.awt import Font, GraphicsEnvironment __all__ = ['GLFigure'] @@ -478,10 +478,11 @@ class GLFigure(GLChartPanel): self.axes.append(ax) self.getChart().addPlot(ax._axes) self.getChart().setCurrentPlot(self.getChart().getPlots().size()) - if isinstance(ax, Axes3DGL): - self.set_mousemode("rotate") - else: - self.set_mousemode("pan") + if not GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadless(): + if isinstance(ax, Axes3DGL): + self.set_mousemode("rotate") + else: + self.set_mousemode("pan") def remove_axes(self, ax=None): """ 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 610a6cce..ff4d6faf 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 @@ -352,7 +352,7 @@ public class FigureDockable extends DefaultSingleCDockable { * * @param cp ChartPanel */ - public void setCurrentFigure(GLChartPanel cp) { + public void setCurrentFigure(JPanel cp) { if (this.tabbedPanel.getTabCount() > 0) { JScrollPane sp = new JScrollPane(cp); this.tabbedPanel.setComponentAt(this.tabbedPanel.getSelectedIndex(), sp);