package org.jzy3d.contour;
/**
* The AbstractContourGenerator provides various utility fonctions
* to compute core contour matrices.
* A concrete generator should implement {@link computeHeightMatrix()}
* according to the input object on which one desire to compute a contour
* ({@link Mapper}s, {@link Shape}s, etc).
*
* @author Juan Barandiaran
*/
public abstract class AbstractContourGenerator {
protected static double NON_CONTOUR = -Double.MAX_VALUE;
protected double minValue;
protected double maxValue;
protected abstract void computeHeightMatrix(double matrix[][], int xRes, int yRes);
/**
* Calculates the points in the XY plane that belong to a contour
*
**/
protected double[][] computeContour(int xRes, int yRes, int nLevels) {
double matrix[][] = new double[xRes][yRes];
double contours[][] = new double[xRes][yRes];
// Calculates the Height of the surface for each point in the XY plane
computeHeightMatrix(matrix, xRes, yRes);
// Quantizes the heights in nLevels levels
quantizeMatrix(matrix, minValue, maxValue, nLevels);
// Leaves only the contours
// TODO: could be great to only modify "matrix" instead of copying into
// "contours"
extractCountours(contours, matrix, xRes, yRes);
return contours;
}
/**
* Calculates the points in the XY plane that belong to a contour whose
* height is defined by the user in an array
*
**/
protected double[][] computeContour(int xRes, int yRes, double sortedLevels[]) {
double matrix[][] = new double[xRes][yRes];
double contours[][] = new double[xRes][yRes];
// Calculates the Height of the surface for each point in the XY plane
computeHeightMatrix(matrix, xRes, yRes);
// Quantizes the heights in nLevels levels
quantizeMatrix(matrix, sortedLevels);
// Leaves only the contours
// TODO: could be great to only modify "matrix" instead of copying into
// "contours"
extractCountours(contours, matrix, xRes, yRes);
return contours;
}
/**
* To paint the contours in the XY plane filling with color between contour
* and contour
*
**/
protected double[][] computeFilledContour(int xRes, int yRes, int nLevels) {
double matrix[][] = new double[xRes][yRes];
// Calculates the Height of the surface for each point in the XY plane
computeHeightMatrix(matrix, xRes, yRes);
// Quantizes the heights in nLevels levels
quantizeMatrix(matrix, minValue, maxValue, nLevels);
return matrix;
}
/**
* Having the colors of the surface on the XY plane gives a lot of info in
* some surfaces
*
**/
protected double[][] computeXYColors(int xRes, int yRes, int nLevels) {
double matrix[][] = new double[xRes][yRes];
// Calculates the Height of the surface for each point in the XY plane
computeHeightMatrix(matrix, xRes, yRes);
return matrix;
}
/**
* Force the input matrix to have the minimum bigger value of the user
* provided sortedLevels list
**/
protected void quantizeMatrix(double matrix[][], double sortedLevels[]) {
double value;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
value = matrix[i][j];
matrix[i][j] = NON_CONTOUR;
for (int n = 0; n < sortedLevels.length; n++) {
if (value >= sortedLevels[n]) {
matrix[i][j] = sortedLevels[n];
} else
n = sortedLevels.length; // To speed it up a little bit
}
}
}
}
/**
* Force the input matrix to have values rounded to one of the N steps in
* the range [min;max].
**/
protected void quantizeMatrix(double matrix[][], double min, double max,
int n) {
double step = (max - min) / n;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
matrix[i][j] = step * (int) (matrix[i][j] / step);
}
}
}
/**
* A point belongs to the contour if it is bigger than anyone of the
* surrounding points of the Quantized matrix It is NOT part of the contour
* if it is equal (or smaller) to all the surrounding points
*/
protected void extractCountours(double contours[][], double matrix[][],
int xSpan, int ySpan) {
for (int x = 1; x < xSpan - 1; x++) {
for (int y = 1; y < ySpan - 1; y++) {
if ((matrix[x][y] > matrix[x - 1][y - 1])
|| (matrix[x][y] > matrix[x][y - 1])
|| (matrix[x][y] > matrix[x + 1][y - 1])
|| (matrix[x][y] > matrix[x - 1][y])
|| (matrix[x][y] > matrix[x + 1][y])
|| (matrix[x][y] > matrix[x - 1][y + 1])
|| (matrix[x][y] > matrix[x][y + 1])
|| (matrix[x][y] > matrix[x + 1][y + 1])) {
contours[x][y] = matrix[x][y];
} else {
contours[x][y] = NON_CONTOUR;
}
}
}
// Now fillup the borders to make it look a little better.
// Copy the pixel in the second row (or column) only if it is "alone",
// meaning that there is a contour line escaping the matrix
for (int x = 1; x < xSpan - 1; x++) {
if ((contours[x][1] != NON_CONTOUR)
&& (contours[x - 1][1] == NON_CONTOUR)
&& (contours[x + 1][1] == NON_CONTOUR)) {
contours[x][0] = contours[x][1];
} else
contours[x][0] = NON_CONTOUR;
if ((contours[x][ySpan - 2] != NON_CONTOUR)
&& (contours[x - 1][ySpan - 2] == NON_CONTOUR)
&& (contours[x + 1][ySpan - 2] == NON_CONTOUR)) {
contours[x][ySpan - 1] = contours[x][ySpan - 2];
} else
contours[x][ySpan - 1] = NON_CONTOUR;
}
for (int y = 1; y < ySpan - 1; y++) {
if ((contours[1][y] != NON_CONTOUR)
&& (contours[1][y - 1] == NON_CONTOUR)
&& (contours[1][y + 1] == NON_CONTOUR)) {
contours[0][y] = contours[1][y];
} else
contours[0][y] = NON_CONTOUR;
if ((contours[xSpan - 2][y] != NON_CONTOUR)
&& (contours[xSpan - 2][y - 1] == NON_CONTOUR)
&& (contours[xSpan - 2][y + 1] == NON_CONTOUR)) {
contours[xSpan - 1][y] = contours[xSpan - 2][y];
} else
contours[xSpan - 1][y] = NON_CONTOUR;
}
}
}
Ads help maintain this website.