package org.jzy3d.contour;
import org.jzy3d.colors.Color;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.IntegerCoord2d;
import org.jzy3d.maths.Range;
import org.jzy3d.maths.Utils;
import org.jzy3d.plot3d.builder.Mapper;
import org.jzy3d.plot3d.primitives.LineStrip;
import org.jzy3d.plot3d.primitives.Point;
import org.jzy3d.plot3d.primitives.contour.ContourMesh;
/**
* Computes the contour matrix of a {@link Mapper}, and returns it
* as a {@link ContourMesh}.
*
* @author Juan Barandiaran
* @author Martin Pernollet
*/
public class MapperContourMeshGenerator extends AbstractContourGenerator implements IContourMeshGenerator {
public static int PIXEL_NEIGHBOUR_THRESHOLD = 2;
public static float LINE_STRIP_WIDTH = 2;
public static int MERGE_STRIP_DIST = 1;
public MapperContourMeshGenerator(Mapper mapper, Range xrange, Range yrange) {
this.mapper = mapper;
this.xrange = xrange;
this.yrange = yrange;
}
/**
* Extracts contour lines from the contour dots matrix of nLevels number of
* contours.
* Return a MeshContour that cleanly describes
*
**/
@Override
public ContourMesh getContourMesh(IContourColoringPolicy policy, int xRes, int yRes, int nLevels, float planeAxe, boolean writeText) {
double[][] contours = computeContour(xRes, yRes, nLevels);
return computeMesh(policy, xRes, yRes, contours, planeAxe);
}
/**
* Extracts contour lines from the contour dots matrix of contours at
* user-defined Heigths in sortedLevels
*
**/
@Override
public ContourMesh getContourMesh(IContourColoringPolicy policy, int xRes, int yRes, double sortedLevels[], float planeAxe, boolean writeText) {
for (int n = 1; n < sortedLevels.length; n++) {
if (sortedLevels[n] < sortedLevels[n - 1]) {
throw new RuntimeException("Levels sent to getContourStrips() are not in order from Min to Max");
}
}
double[][] contours = computeContour(xRes, yRes, sortedLevels);
return computeMesh(policy, xRes, yRes, contours, planeAxe);
}
@Override
public double[][] getContourMatrix(int xRes, int yRes, int nLevels) {
return computeContour(xRes, yRes, nLevels);
}
/**********************************************/
protected ContourMesh computeMesh(IContourColoringPolicy policy, int xRes, int yRes, double[][] contours, float planeAxe){
boolean[][] processed = new boolean[xRes][yRes];
// List strips = new ArrayList();
ContourMesh mesh = new ContourMesh();
for (int i = 0; i < contours.length; i++) {
for (int j = 0; j < contours[i].length; j++) {
if (!processed[i][j] && (contours[i][j] != NON_CONTOUR)) {
double level = contours[i][j];
// Compute a line part for this contour
LineStrip strip = followContourFrom(
(DefaultContourColoringPolicy) policy, i, j,
contours, processed, planeAxe);
strip.setWidth(LINE_STRIP_WIDTH);
// Setup mesh with
mesh.lines.appendLevelLine(level, strip);
mesh.setLevelLabel(level, Utils.num2str('f', level, 2));
}
}
}
return mesh;
}
protected LineStrip followContourFrom(DefaultContourColoringPolicy policy,
int i, int j, double[][] contours, boolean[][] processed,
float planeAxe) {
LineStrip strip = new LineStrip(100);
// add current
processed[i][j] = true;
strip.add(new Point(map(i, j, planeAxe, contours)));
int width = 1;
IntegerCoord2d next = findNext(i, j, width, contours, processed);
while (next != null) {
processed[next.x][next.y] = true;
Coord3d coord = map(next.x, next.y, planeAxe, contours);
Color color = policy.getColorMapper().getColor(
new Coord3d(0, 0, contours[next.x][next.y]));
strip.add(new Point(coord, color));
// follow path
next = findNext(next.x, next.y, width, contours, processed);
}
return strip;
}
protected IntegerCoord2d findNext(int i, int j, int width,
double[][] contours, boolean[][] processed) {
int iFrom = (i > (width - 1)) ? (i - width) : i;
int iTo = (i < contours.length - width) ? (i + width) : i;
int jFrom = (j > (width - 1)) ? (j - width) : j;
int jTo = (j < contours[0].length - width) ? (j + width) : j;
int n = 0;
for (int ii = iFrom; ii <= iTo; ii++) {
for (int jj = jFrom; jj <= jTo; jj++) {
n++;
if ((!processed[ii][jj]) && (contours[ii][jj] != NON_CONTOUR)) {
return new IntegerCoord2d(ii, jj);
}
}
}
if (width < PIXEL_NEIGHBOUR_THRESHOLD)
return findNext(i, j, width + 1, contours, processed);
return null;
}
protected Coord3d map(int i, int j, double[][] contours) {
return map(i, j, contours[i][j], contours);
}
// TODO: we flip back what was flipped during contour build
protected Coord3d map(int i, int j, double value, double[][] contours) {
double xrng = xrange.getRange();
double yrng = yrange.getRange();
double x = xrange.getMin() + xrng * ((i) / ((double) contours.length));
double y = yrange.getMin() + yrng
* ((contours[0].length - j) / ((double) contours[0].length));
return new Coord3d(x, y, value);
}
/***********************************/
/**
* Calculates the Height of the surface for each point in the XY plane
*
**/
@Override
protected void computeHeightMatrix(double matrix[][], int xRes, int yRes) {
double value;
minValue = Double.MAX_VALUE;
maxValue = -Double.MAX_VALUE;
// TODO: This matrix filling could be done at the same time the surface
// is computed to save time and avoid calling the mapper.f() two times
// for each point.
double xstep = xrange.getRange() / (double) (xRes - 1);
double ystep = yrange.getRange() / (double) (yRes - 1);
for (int xi = 0; xi < xRes; xi++) {
for (int yi = 0; yi < yRes; yi++) {
double x = xrange.getMin() + xi * xstep;
double y = yrange.getMin() + yi * ystep;
value = mapper.f(x, y);
// Y coordinate in the matrix is inverted because
// DrawableTexture
// is handled like this
matrix[xi][yRes - 1 - yi] = value;
if (value < minValue)
minValue = value;
if (value > maxValue)
maxValue = value;
}
}
}
protected Mapper mapper;
protected Range xrange;
protected Range yrange;
}
Ads help maintain this website.