add ColorTransferFunction class

This commit is contained in:
wyq 2022-04-24 11:40:03 +08:00
parent 0e4757e8fe
commit f2441b13a7
11 changed files with 383 additions and 10 deletions

View File

@ -1,8 +1,7 @@
package org.meteoinfo.chart.graphic;
import com.jogamp.common.nio.Buffers;
import org.meteoinfo.chart.jogl.Transform;
import org.meteoinfo.chart.render.TransferFunction;
import org.meteoinfo.geometry.colors.TransferFunction;
import org.meteoinfo.chart.render.jogl.RayCastingType;
import org.meteoinfo.common.Extent3D;
import org.meteoinfo.common.MIMath;
@ -12,10 +11,8 @@ import org.meteoinfo.geometry.colors.Normalize;
import org.meteoinfo.geometry.legend.LegendScheme;
import org.meteoinfo.geometry.shape.ShapeTypes;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.ndarray.math.ArrayMath;
import java.awt.*;
import java.nio.Buffer;
import java.util.List;
import static org.joml.Math.clamp;

View File

@ -19,7 +19,7 @@ import org.meteoinfo.chart.graphic.VolumeGraphics;
import org.meteoinfo.chart.jogl.mc.CallbackMC;
import org.meteoinfo.chart.jogl.mc.MarchingCubes;
import org.meteoinfo.chart.graphic.GraphicCollection3D;
import org.meteoinfo.chart.render.TransferFunction;
import org.meteoinfo.geometry.colors.TransferFunction;
import org.meteoinfo.chart.shape.TextureShape;
import org.meteoinfo.common.Extent;
import org.meteoinfo.common.Extent3D;
@ -47,7 +47,6 @@ import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

View File

@ -261,6 +261,39 @@ public class ColorUtil {
return ncts;
}
/**
* Get color maps
*
* @return Color maps
* @throws IOException
*/
public static ColorMap[] getColorMaps(String path) throws IOException {
File pathDir = new File(path);
if (!pathDir.isDirectory()) {
return null;
}
File[] files = pathDir.listFiles();
List<ColorMap> cts = new ArrayList<>();
for (File file : files) {
ColorMap ct = new ColorMap();
ct.readFromFile(file);
if (ct.getColorCount() > 0) {
String name = file.getName();
name = name.substring(0, name.lastIndexOf("."));
ct.setName(name);
cts.add(ct);
}
}
ColorMap[] ncts = new ColorMap[cts.size()];
for (int i = 0; i < cts.size(); i++) {
ncts[i] = cts.get(i);
}
return ncts;
}
/**
* Load color map from rgb file

View File

@ -223,6 +223,25 @@ public class DimArray {
return null;
}
/**
* Change all dimensions to be ascending
*/
public void asAscending() {
boolean changed = false;
int i = 0;
for (Dimension dimension : this.dimensions) {
if (dimension.isDescending()) {
dimension.reverse();
array = array.flip(i);
changed = true;
}
i += 1;
}
if (changed) {
array = array.copy();
}
}
/**
* Section
* @param origin Origin

View File

@ -658,12 +658,47 @@ public class Dimension {
return idx;
}
/**
* Get whether the dimension values are ascending
* @return Ascending or not
*/
public boolean isAscending() {
for (int i = 0; i < this.dimValue.getSize() - 1; i++) {
if (dimValue.getDouble(i) >= dimValue.getDouble(i + 1)) {
return false;
}
}
return true;
}
/**
* Get whether the dimension values are descending
* @return Descending or not
*/
public boolean isDescending() {
for (int i = 0; i < this.dimValue.getSize() - 1; i++) {
if (dimValue.getDouble(i) <= dimValue.getDouble(i + 1)) {
return false;
}
}
return true;
}
/**
* Get whether the dimension values are ordered
* @return Ordered or not
*/
public boolean isOrdered() {
return isAscending() || isDescending();
}
/**
* Reverse the dimension values
*/
public void reverse() {
this.dimValue = this.dimValue.flip(0);
//Collections.reverse(this.dimValue);
this.dimValue = this.dimValue.flip(0).copy();
}
@Override

View File

@ -0,0 +1,110 @@
package org.meteoinfo.geometry.colors;
import org.meteoinfo.common.colors.ColorMap;
import java.awt.*;
public class ColorTransferFunction {
private TransferFunction transferFunction;
private ColorMap colorMap;
private Normalize normalize;
/**
* Constructor
* @param transferFunction Transfer function
* @param colorMap Color map
* @param normalize Normalize
*/
public ColorTransferFunction(TransferFunction transferFunction, ColorMap colorMap, Normalize normalize) {
this.transferFunction = transferFunction;
this.colorMap = colorMap;
this.normalize = normalize;
}
/**
* Constructor
* @param transferFunction Transfer function
* @param colorMap Color map
*/
public ColorTransferFunction(TransferFunction transferFunction, ColorMap colorMap) {
this(transferFunction, colorMap, new Normalize());
}
/**
* Constructor
* @param colorMap Color map
* @param normalize Normalize
*/
public ColorTransferFunction(ColorMap colorMap, Normalize normalize) {
this(new TransferFunction(), colorMap, normalize);
}
/**
* Constructor
* @param colorMap Color map
*/
public ColorTransferFunction(ColorMap colorMap) {
this(colorMap, new Normalize());
}
/**
* Get transfer function
* @return Transfer function
*/
public TransferFunction getTransferFunction() {
return this.transferFunction;
}
/**
* Set transfer function
* @param value Transfer function
*/
public void setTransferFunction(TransferFunction value) {
this.transferFunction = value;
}
/**
* Get color map
* @return Color map
*/
public ColorMap getColorMap() {
return this.colorMap;
}
/**
* Set color map
* @param value Color map
*/
public void setColorMap(ColorMap value) {
this.colorMap = value;
}
/**
* Get normalize
* @return Normalize
*/
public Normalize getNormalize() {
return this.normalize;
}
/**
* Set normalize
* @param value Normalize
*/
public void setNormalize(Normalize value) {
this.normalize = value;
}
/**
* Get color with a data value
* @param v The data value
* @return The color
*/
public Color getColor(double v) {
float ratio = this.normalize.apply(v).floatValue();
Color c = this.colorMap.getColor(ratio);
float alpha = this.transferFunction.getOpacity(ratio);
return new Color(c.getRed(), c.getGreen(), c.getBlue(), (int) alpha * 255);
}
}

View File

@ -1,4 +1,4 @@
package org.meteoinfo.chart.render;
package org.meteoinfo.geometry.colors;
import org.meteoinfo.geometry.colors.Normalize;

View File

@ -34,5 +34,5 @@
</Font>
<LookFeel DockWindowDecorated="true" LafDecorated="true" Name="FlatDarkLaf"/>
<Figure DoubleBuffering="true"/>
<Startup MainFormLocation="-7,-7" MainFormSize="1293,685"/>
<Startup MainFormLocation="-7,0" MainFormSize="1391,812"/>
</MeteoInfo>

View File

@ -0,0 +1,18 @@
package org.meteoinfo.math;
public class Constants {
public static double P0 = 1000.; //reference pressure for potential temperature (hPa)
public static double R = 8.3144598; //molar gas constant (J / K / mol)
public static double Mw = 18.01528; //Molecular weight of water (g / mol)
public static double Md = 28.9644; //Nominal molecular weight of dry air at the surface of th Earth (g / mol)
public static double Rd = R / Md; //Gas constant for dry air at the surface of the Earth (J (K kg)^-1)
public static double Lv = 2.501e6; //Latent heat of vaporization for liquid water at 0C (J kg^-1)
public static double Cp_d = 1005; //Specific heat at constant pressure for dry air (J kg^-1)
public static double epsilon = Mw / Md;
public static double kappa = 0.286;
public static double degCtoK = 273.15; //Temperature offset between K and C (deg C)
public static double g = 9.8; //Gravitational acceleration (m / s^2)
public static double sat_pressure_0c = 6.112; //Saturation pressure at 0 degree (hPa)
public static double T_BASE = 300.;
public static double omega = 7292115e-11; //Avg. angular velocity of Earth (rad / s)
}

View File

@ -5,6 +5,7 @@
*/
package org.meteoinfo.math.meteo;
import org.meteoinfo.math.Constants;
import org.meteoinfo.ndarray.math.ArrayMath;
import org.meteoinfo.ndarray.Array;
import org.meteoinfo.ndarray.DataType;
@ -238,6 +239,38 @@ public class MeteoMath {
return (rh * es) / 100;
}
/**
* Convert pressure data to heights using the U.S. standard atmosphere.
*
* @param p Pressure - hPa
* @return Height - meter
*/
public static double pressure2Height(double p) {
double t0 = 288.;
double gamma = 6.5;
double p0 = 1013.25;
double h = (t0 / gamma) * (1 - Math.pow(p / p0, Constants.Rd * gamma / Constants.g)) * 1000;
return h;
}
/**
* Convert pressure data to heights using the U.S. standard atmosphere.
*
* @param p Pressure - hPa
* @return Height - meter
*/
public static Array pressure2Height(Array press) {
Array r = Array.factory(DataType.DOUBLE, press.getShape());
IndexIterator iter = press.getIndexIterator();
IndexIterator iterR = r.getIndexIterator();
while (iter.hasNext()) {
iterR.setDoubleNext(pressure2Height(iter.getDoubleNext()));
}
return r;
}
/**
* Calculate height from pressure
*

View File

@ -457,6 +457,135 @@ public class Reproject {
return r;
}
/**
* Reproject
*
* @param data Data array
* @param x X array
* @param y Y array
* @param rx Result x array
* @param ry Result y array
* @param fromProj From projection
* @param toProj To projection
* @param resampleMethod Resample method
* @return Result arrays
* @throws InvalidRangeException
*/
public static Array reproject(Array data, Array x, Array y, Array rx, Array ry,
ProjectionInfo fromProj, ProjectionInfo toProj, ResampleMethods resampleMethod) throws InvalidRangeException {
int n = (int) rx.getSize();
int[] dshape = data.getShape();
int[] shape;
if (rx.getRank() == 1) {
shape = new int[1];
shape[0] = rx.getShape()[0];
} else {
shape = new int[data.getRank()];
for (int i = 0; i < shape.length; i++) {
if (i == shape.length - 2) {
shape[i] = rx.getShape()[0];
} else if (i == shape.length - 1) {
shape[i] = rx.getShape()[1];
} else {
shape[i] = data.getShape()[i];
}
}
}
Array r = Array.factory(data.getDataType(), shape);
double[][] points = new double[n][];
for (int i = 0; i < n; i++) {
points[i] = new double[]{rx.getDouble(i), ry.getDouble(i)};
}
if (!fromProj.equals(toProj)) {
Reproject.reprojectPoints(points, toProj, fromProj, 0, points.length);
}
double xx, yy;
if (resampleMethod == ResampleMethods.Bilinear) {
if (shape.length <= 2) {
for (int i = 0; i < n; i++) {
xx = points[i][0];
yy = points[i][1];
r.setObject(i, ArrayUtil.toStation(data, x, y, xx, yy));
}
} else {
Index indexr = r.getIndex();
int[] current, cc = null;
boolean isNew;
Array ndata = null;
int k;
for (int i = 0; i < r.getSize(); i++) {
current = indexr.getCurrentCounter();
isNew = true;
if (i > 0) {
for (int j = 0; j < shape.length - 2; j++) {
if (cc[j] != current[j]) {
isNew = false;
break;
}
}
}
cc = Arrays.copyOf(current, current.length);
if (isNew) {
List<Range> ranges = new ArrayList<>();
for (int j = 0; j < shape.length - 2; j++) {
ranges.add(new Range(current[j], current[j], 1));
}
ranges.add(new Range(0, dshape[dshape.length - 2] - 1, 1));
ranges.add(new Range(0, dshape[dshape.length - 1] - 1, 1));
ndata = data.section(ranges).reduce();
}
k = current[shape.length - 2] * shape[shape.length - 1] + current[shape.length - 1];
xx = points[k][0];
yy = points[k][1];
r.setObject(i, ArrayUtil.toStation(ndata, x, y, xx, yy));
indexr.incr();
}
}
} else if (shape.length == 2) {
for (int i = 0; i < n; i++) {
xx = points[i][0];
yy = points[i][1];
r.setObject(i, ArrayUtil.toStation_Neighbor(data, x, y, xx, yy));
}
} else {
Index indexr = r.getIndex();
int[] current, cc = null;
boolean isNew;
Array ndata = null;
int k;
for (int i = 0; i < r.getSize(); i++) {
current = indexr.getCurrentCounter();
isNew = true;
if (i > 0) {
for (int j = 0; j < shape.length - 2; j++) {
if (cc[j] != current[j]) {
isNew = false;
break;
}
}
}
cc = Arrays.copyOf(current, current.length);
if (isNew) {
List<Range> ranges = new ArrayList<>();
for (int j = 0; j < shape.length - 2; j++) {
ranges.add(new Range(current[j], current[j], 1));
}
ranges.add(new Range(0, dshape[dshape.length - 2] - 1, 1));
ranges.add(new Range(0, dshape[dshape.length - 1] - 1, 1));
ndata = data.section(ranges).reduce();
}
k = current[shape.length - 2] * shape[shape.length - 1] + current[shape.length - 1];
xx = points[k][0];
yy = points[k][1];
r.setObject(i, ArrayUtil.toStation_Neighbor(ndata, x, y, xx, yy));
indexr.incr();
}
}
return r;
}
/**
* Reproject
*