netcdf流场展示

说明

        海洋数值预报里面,数据格式一般都为nc文件格式,存储的为科学数据,这些数据都是网格化的数据。由于有些网格点是陆地,如果用图片方式去展示流场的化,合理的方式是将这些陆地剔除。由于一些客户端软件可以做到,这里不考虑。这里提供两个软件可供参考。

       一个是jzy3d , 里面使用ContourPictureGenerator可生成想要的等值面,返回的为BufferedImage,当然流场方向还需自己处理。

另外一个是wcontour,可生成等值面,需要自己生成BufferedImage,再利用Contour.tracingStreamline获取流场曲线,再自己在BufferedImage上绘制。


代码

	@Override
	protected Object wrapperRaw(CacheDataStore dataStore) {

		double[] lons = Arrays.copyOf(dataStore.windLons, dataStore.windLons.length);
		double[] lats = Arrays.copyOf(dataStore.windLats, dataStore.windLats.length);

		// double[] lf, double[] rt,
		double[] lf = getLfAndRtPts(lons, lats).get(0);
		double[] rt = getLfAndRtPts(lons, lats).get(1);
		// int rows, int cols, double[] contourVals,
		int rows = lons.length;
		int cols = lats.length;

		double[][] data = genNorm(dataStore.wind_u, dataStore.wind_v, lons.length, lats.length, 10000, _undefData);

		lons = initArr(rows);
		lats = initArr(cols);
		
		List<PolyLine> lines = Contour.tracingStreamline(maskTable(dataStore.wind_u, 10000, _undefData), 
				maskTable(dataStore.wind_v, 10000, _undefData), 
				lons, 
				lats, 
				_undefData, 1);
		
		BufferedImage img = ImgContourUtils.drawContourImage(maskTableEq(data, Math.abs(_undefData), Double.NaN), lons.length, lats.length, "");
		
		ImgContourUtils.drawLines(img, lines);
		
		//ImgContourUtils.drawArc(img, dataStore.wind_u, dataStore.wind_v, lons.length, lats.length, _undefData);
		
		ImgContourUtils.saveImage(img, "d:\\temp\\flow2.png");
		
		return img;
		
		
	}


import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.jzy3d.colors.Color;
import org.jzy3d.colors.ColorMapper;
import org.jzy3d.colors.colormaps.ColorMapRainbow;
import org.jzy3d.contour.AbstractContourGenerator;
import org.jzy3d.contour.DefaultContourColoringPolicy;
import org.jzy3d.contour.IContourColoringPolicy;
import org.jzy3d.contour.IContourPictureGenerator;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.Range;
import org.jzy3d.plot3d.builder.Mapper;
import org.jzy3d.plot3d.builder.concrete.OrthonormalTessellator;
import org.jzy3d.plot3d.primitives.Shape;

import wContour.Global.PointD;
import wContour.Global.PolyLine;

public class ImgContourUtils {

	public static BufferedImage getContourFilledImage(double[][] data, int m, int n, String path) {

		OrthonormalTessellator tesselator = new OrthonormalTessellator();

		// bottom, top, mid surface
		Shape surface = (Shape) tesselator.build(toCoordList(data, n, m));
		ColorMapper localColorMapper = new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new Color(1.0F, 1.0F, 1.0F, 1.0F));
		System.out.println("max=" + surface.getBounds().getZmax());
		System.out.println("min=" + surface.getBounds().getZmin());

		CustomMapperContourPictureGenerator a = new CustomMapperContourPictureGenerator(new CustomMapper(data, n, m), new Range(0, n), new Range(0, m));

		IContourColoringPolicy policy = new DefaultContourColoringPolicy(localColorMapper);
		// BufferedImage img = a.getContourImage(policy, n, m, 10);
		// BufferedImage img = a.getFilledContourImage(policy, n, m, new
		// double[]{-10,30,40,50,60,70,80,90});
		BufferedImage img = a.getFilledContourImage(policy, n, m, 10);

		System.out.println(img);
		updateAlpha(m, n, data, Double.NaN, img);
		saveImage(img, path);

		return img;
	}

	public static BufferedImage drawContourImage(double[][] data, int m, int n, String path) {

		OrthonormalTessellator tesselator = new OrthonormalTessellator();

		Shape surface = (Shape) tesselator.build(toCoordList(data, n, m));
		ColorMapper localColorMapper = new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new Color(1.0F, 1.0F, 1.0F, 1.0F));
		System.out.println("max=" + surface.getBounds().getZmax());
		System.out.println("min=" + surface.getBounds().getZmin());

		CustomMapperContourPictureGenerator a = new CustomMapperContourPictureGenerator(new CustomMapper(data, n, m), new Range(0, n), new Range(0, m));
		IContourColoringPolicy policy = new DefaultContourColoringPolicy(localColorMapper);

		BufferedImage img = a.getFilledContourImage(policy, n, m, 10);

		updateAlpha(m, n, data, Double.NaN, img);

		return img;

	}

	public static class CustomMapper extends Mapper {
		private double[][] data;
		private int m;
		private int n;

		public CustomMapper(double[][] data, int m, int n) {
			this.data = data;
			this.m = m;
			this.n = n;
		}

		public final double f(double x, double y) {
			if (x >= m || x < 0 || y >= n || y < 0) {
				// System.out.println(x + "," + y);
			}
			return this.data[(int) Math.min(data.length - 1, Math.max(0, x))][(int) Math.min(data[0].length - 1, Math.max(0, y))];
		}
	}

	public static List<Coord3d> toCoordList(double[][] z, int m, int n) {

		List<Coord3d> ret = new ArrayList<Coord3d>();
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {

				ret.add(new Coord3d(i, j, z[i][j]));
			}
		}

		return ret;

	}

	public static void saveImage(BufferedImage img, String path) {
		try {
			File outputfile = new File(path);
			ImageIO.write(img, "png", outputfile);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public static BufferedImage drawLines(int xRes, int yRes, double[][] vals, double _undef, List<PolyLine> polyLines) {

		BufferedImage img = buildImage(xRes, yRes, vals, _undef);
		drawLines(img, polyLines);

		return img;
	}

	public static void drawLines(BufferedImage img, List<PolyLine> polyLines) {
		Graphics2D g2d = img.createGraphics();
		List<int[]> xs = toIntArrsX(polyLines, img.getWidth());
		List<int[]> ys = toIntArrsY(polyLines, img.getHeight());
		g2d.setColor(java.awt.Color.blue);
		for (int i = 0; i < xs.size(); i = i + 12) {
			g2d.drawPolyline(xs.get(i), ys.get(i), xs.get(i).length);

			int[] xPoints = xs.get(i);
			int[] yPoints = ys.get(i);
			int alen = xs.get(i).length;
			// break;
			{
				int len = 12;
				for (int j = 0; j < alen; j = j + 50) {
					if (j > 0 && j < alen - 2 && j % len == 0) {
						// Draw arraw
						java.awt.Point aP = new java.awt.Point(xPoints[j], yPoints[j]);
						java.awt.Point bPoint = new java.awt.Point(xPoints[j + 1], yPoints[j + 1]);
						double U = bPoint.x - aP.x;
						double V = bPoint.y - aP.y;
						double angle = Math.atan((V) / (U)) * 180 / Math.PI;
						angle = angle + 90;
						if (U < 0) {
							angle = angle + 180;
						}

						if (angle >= 360) {
							angle = angle - 360;
						}

						if (Double.isNaN(angle)) {
							continue;
						}

						java.awt.Point eP1 = new java.awt.Point();
						double aSize = 8;
						eP1.x = (int) (aP.x - aSize * Math.sin((angle + 20.0) * Math.PI / 180));
						eP1.y = (int) (aP.y + aSize * Math.cos((angle + 20.0) * Math.PI / 180));
						g2d.drawLine(aP.x, aP.y, eP1.x, eP1.y);

						eP1.x = (int) (aP.x - aSize * Math.sin((angle - 20.0) * Math.PI / 180));
						eP1.y = (int) (aP.y + aSize * Math.cos((angle - 20.0) * Math.PI / 180));
						g2d.drawLine(aP.x, aP.y, eP1.x, eP1.y);
						// System.out.println(Math.abs(aP.x - eP1.x) + "," +
						// Math.abs(aP.y - eP1.y));
					}
				}
			}
		}

		g2d.dispose();

	}

	public static void drawArc(BufferedImage img, double[][] windU, double[][] windV, int m, int n, double mask) {
		Graphics2D g2d = img.createGraphics();
		g2d.setColor(java.awt.Color.yellow);
		for (int i = 0; i < m; i = i + 24) {
			for (int j = 0; j < n; j = j + 24) {
				double u = windU[j][i];
				double v = windV[j][i];
				if (Double.isNaN(u) || Double.isNaN(v) || Math.abs(u) == Math.abs(mask) || Math.abs(v) == Math.abs(mask)) {
					continue;
				}
				g2d.drawString(getStringByAngle(u, v), i, n - 1 -j);
			}
		}
		g2d.dispose();

	}
	
	public static void drawArc(BufferedImage img, double[][] data, int m, int n, double mask) {
		Graphics2D g2d = img.createGraphics();
		g2d.setColor(java.awt.Color.yellow);
		for (int i = 0; i < m; i = i + 24) {
			for (int j = 0; j < n; j = j + 24) {
				
				double u = data[j][i];
				if (Double.isNaN(u) ||  Math.abs(u) == Math.abs(mask) ) {
					continue;
				}
				u = 360 -data[j][i] * 0.1;
				g2d.drawString(getAngleByVal(u), i, n - 1 -j);
			}
		}
		g2d.dispose();
	}

	private static String getStringByAngle(double x, double y) {
		if (x > 0) {
			if (y == 0) {
				return "→";
			} else if (y > 0) {
				return "↗";
			}
			return "↘";
		} else if (x < 0) {
			if (y == 0) {
				return "←";
			} else if (y > 0) {
				return "↖";
			}
			return "↙";
		} else {
			if (y >= 0) {
				return "↑";
			}
			return "↓";
		}

	}

	static String getAngleByVal(double v){
		if( v < 0){
			return "→";
		}
		if( v >= 0 && v < 45){
			return "→";
		}else if( v <= 90){
			if( v == 90){
				return "↑";
			}
			return "↗";
		}else if( v <= 180){
			if( v == 180){
				return "←";
			}
			return "↖";
		}else if( v <= 270){
			if( v == 270){
				return "↓";
			}
			return "↙";
		}else{
			if( v == 360){
				return "→";
			}
			return "↘";
		}
	}
	
	static List<int[]> toIntArrsX(List<PolyLine> polyLines, int max) {
		List<int[]> xs = new ArrayList<int[]>();
		for (int i = 0; i < polyLines.size(); i++) {
			PolyLine pl = polyLines.get(i);
			List<Integer> is = new ArrayList<Integer>();
			for (PointD d : pl.PointList) {
				int x = (int) Math.round(d.X);
				if (x >= max) {
					x = max - 1;
				}
				is.add(x);
			}
			xs.add(toIntArr(is));
		}
		return xs;
	}

	static List<int[]> toIntArrsY(List<PolyLine> polyLines, int max) {
		List<int[]> ys = new ArrayList<int[]>();
		for (int i = 0; i < polyLines.size(); i++) {
			PolyLine pl = polyLines.get(i);
			List<Integer> is = new ArrayList<Integer>();
			for (PointD d : pl.PointList) {
				int y = (int) Math.round(d.Y);
				y = max - 1 - y;
				if (y >= max) {
					y = max - 1;
				}
				if (y < 0) {
					y = 0;
				}
				is.add(y);
			}
			ys.add(toIntArr(is));
		}
		return ys;
	}

	static int[] toIntArr(List<Integer> iList) {
		int[] xs = new int[iList.size()];
		for (int i = 0; i < iList.size(); i++) {
			xs[i] = iList.get(i);
		}
		return xs;
	}

	static int getLocalRgb(int rgb) {
		DirectColorModel dcm = (DirectColorModel) ColorModel.getRGBdefault();
		// DirectColorModel类用来将ARGB值独立分解出来
		int red = dcm.getRed(rgb);
		int green = dcm.getGreen(rgb);
		int blue = dcm.getBlue(rgb);

		int alpha;
		if (red == 255 && blue == 255 && green == 255) {// 如果像素为白色,则让它透明
			alpha = 0;
		} else {
			alpha = 0;
		}

		return alpha << 24 | red << 16 | green << 8 | blue;
	}

	static BufferedImage buildImage(int xRes, int yRes, double[][] vals, double _undef) {

		BufferedImage image = new BufferedImage(yRes, xRes, BufferedImage.TYPE_4BYTE_ABGR);
		for (int x = 0; x < yRes; x++) {
			for (int y = 0; y < xRes; y++) {
				if (vals[y][x] == _undef) {
					int rgb = -123;
					rgb = getLocalRgb(rgb);
					image.setRGB(x, y, rgb);
				} else {
					image.setRGB(x, y, java.awt.Color.lightGray.getRGB());
				}
			}
		}
		return image;
	}

	static BufferedImage updateAlpha(int xRes, int yRes, double[][] vals, double _undef, BufferedImage img) {

		for (int x = 0; x < xRes; x++) {
			for (int y = 0; y < yRes; y++) {
				if (vals[y][x] == _undef || Double.isNaN(vals[y][x])) {
					int rgb = -16777088;
					rgb = getLocalRgb(rgb);
					img.setRGB(x, yRes - 1 - y, rgb);
				} else {

				}
			}
		}
		return img;
	}

	public static BufferedImage rotateImg(int xRes, int yRes, BufferedImage image) {
		BufferedImage imageRotate = new BufferedImage(yRes, xRes, BufferedImage.TYPE_4BYTE_ABGR);
		for (int x = 0; x < yRes; x++) {
			for (int y = 0; y < xRes; y++) {
				imageRotate.setRGB(x, y, image.getRGB(y, yRes - 1 - x));
			}
		}
		return imageRotate;
	}

	public static class CustomMapperContourPictureGenerator extends AbstractContourGenerator implements IContourPictureGenerator {

		public static int PIXEL_NEIGHBOUR_THRESHOLD = 2;
		public static float LINE_STRIP_WIDTH = 2.0F;
		public static int MERGE_STRIP_DIST = 1;
		protected Mapper mapper;
		protected Range xrange;
		protected Range yrange;

		public CustomMapperContourPictureGenerator(Mapper mapper, Range xrange, Range yrange) {
			this.mapper = mapper;
			this.xrange = xrange;
			this.yrange = yrange;
		}

		public double[][] getContourMatrix(int xRes, int yRes, int nLevels) {
			return computeContour(xRes, yRes, nLevels);
		}

		public BufferedImage getContourImage(IContourColoringPolicy policy, int xRes, int yRes, int nLevels) {
			double[][] contours = computeContour(xRes, yRes, nLevels);
			return buildImage(xRes, yRes, contours, policy);
		}

		public BufferedImage getContourImage(IContourColoringPolicy policy, int xRes, int yRes, double[] sortedLevels) {
			double[][] contours = computeContour(xRes, yRes, sortedLevels);
			return buildImage(xRes, yRes, contours, policy);
		}

		public BufferedImage getFilledContourImage(IContourColoringPolicy policy, int xRes, int yRes, int nLevels) {
			double[][] contours = computeFilledContour(xRes, yRes, nLevels);
			return buildImage(xRes, yRes, contours, policy);
		}

		public BufferedImage getFilledContourImage(IContourColoringPolicy policy, int xRes, int yRes, double[] sortedLevels) {
			double[][] contours = computeFilledContour(xRes, yRes, sortedLevels);
			return buildImage(xRes, yRes, contours, policy);
		}

		public BufferedImage getHeightMap(IContourColoringPolicy policy, int xRes, int yRes, int nLevels) {
			double[][] contours = computeXYColors(xRes, yRes, nLevels);
			return buildImage(xRes, yRes, contours, policy);
		}

		protected BufferedImage buildImage(int xRes, int yRes, double[][] contours, IContourColoringPolicy policy) {

			BufferedImage image = new BufferedImage(xRes, yRes, BufferedImage.TYPE_4BYTE_ABGR);
			for (int x = 0; x < xRes; x++) {
				for (int y = 0; y < yRes; y++) {
					image.setRGB(x, y, policy.getRGB(contours[x][y]));
				}
			}

			// rotate
			BufferedImage imageRotate = new BufferedImage(yRes, xRes, BufferedImage.TYPE_4BYTE_ABGR);
			for (int x = 0; x < yRes; x++) {
				for (int y = 0; y < xRes; y++) {
					imageRotate.setRGB(x, y, image.getRGB(xRes - 1 - y, yRes - 1 - x));
				}
			}
			return imageRotate;
		}

		protected double[][] computeFilledContour(int xRes, int yRes, double[] sortedLevels) {
			double[][] matrix = new double[xRes][yRes];
			computeHeightMatrix(matrix, xRes, yRes);
			quantizeMatrix(matrix, sortedLevels);
			return matrix;
		}

		protected void computeHeightMatrix(double[][] matrix, int xRes, int yRes) {
			this.minValue = Double.MAX_VALUE;
			this.maxValue = -1.7976931348623157E308D;

			double xstep = this.xrange.getRange() / (xRes - 1);
			double ystep = this.yrange.getRange() / (yRes - 1);
			for (int xi = 0; xi < xRes; xi++) {
				for (int yi = 0; yi < yRes; yi++) {
					double x = this.xrange.getMin() + xi * xstep;
					double y = this.yrange.getMin() + yi * ystep;

					double value = this.mapper.f(x, y);

					matrix[xi][(yRes - 1 - yi)] = value;
					if (value < this.minValue) {
						this.minValue = value;
					}
					if (value > this.maxValue) {
						this.maxValue = value;
					}
				}
			}
		}
	}



}

图片

两个不同的效果:


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值