/*
* Conrec.java
*
* Created on 5 August 2001, 15:03
*
* Copyright (c) 1996-1997 Nicholas Yue
*
* This software is copyrighted by Nicholas Yue. This code is base on the work of
* Paul D. Bourke CONREC.F routine
*
* The authors hereby grant permission to use, copy, and distribute this
* software and its documentation for any purpose, provided that existing
* copyright notices are retained in all copies and that this notice is included
* verbatim in any distributions. Additionally, the authors grant permission to
* modify this software and its documentation for any purpose, provided that
* such modifications are not distributed without the explicit consent of the
* authors and that existing copyright notices are retained in all copies. Some
* of the algorithms implemented by this software are patented, observe all
* applicable patent law.
*
* IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
* EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN
* "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
/**
* Conrec a straightforward method of contouring some surface represented a regular
* triangular mesh.
*
* Ported from the C++ code by Nicholas Yue (see above copyright notice).
* @see http://astronomy.swin.edu.au/pbourke/projection/conrec/ for full description
* of code and original C++ source.
*
* @author Bradley White
* @version 1.0
*/
public class Conrec {
private double [] h = new double [5];
private int [] sh = new int [5];
private double [] xh = new double [5];
private double [] yh = new double [5];
// Object that knows how to draw the contour
private Render render = null;
/** Creates new Conrec */
public Conrec(Render render) throws Exception {
if (render == null){
throw new Exception ("Render null");
}
this.render = render;
}
/**
* contour is a contouring subroutine for rectangularily spaced data
*
* It emits calls to a line drawing subroutine supplied by the user
* which draws a contour map corresponding to real*4data on a randomly
* spaced rectangular grid. The coordinates emitted are in the same
* units given in the x() and y() arrays.
*
* Any number of contour levels may be specified but they must be
* in order of increasing value.
*
*
* @param d - matrix of data to contour
* @param ilb,iub,jlb,jub - index bounds of data matrix
*
* The following two, one dimensional arrays (x and y) contain the horizontal and
* vertical coordinates of each sample points.
* @param x - data matrix column coordinates
* @param y - data matrix row coordinates
* @param nc - number of contour levels
* @param z - contour levels in increasing order.
*
*/
public void contour(double [][] d, int ilb, int iub, int jlb, int jub, double [] x, double [] y, int nc, double [] z) {
int m1;
int m2;
int m3;
int case_value;
double dmin;
double dmax;
double x1 = 0.0;
double x2 = 0.0;
double y1 = 0.0;
double y2 = 0.0;
int i,j,k,m;
// The indexing of im and jm should be noted as it has to start from zero
// unlike the fortran counter part
int [] im = {0,1,1,0};
int [] jm = {0,0,1,1};
// Note that castab is arranged differently from the FORTRAN code because
// Fortran and C/C++ arrays are transposed of each other, in this case
// it is more tricky as castab is in 3 dimension
int [][][] castab=
{
{
{0,0,8},{0,2,5},{7,6,9}
},
{
{0,3,4},{1,3,1},{4,3,0}
},
{
{9,6,7},{5,2,0},{8,0,0}
}
};
for (j=(jub-1);j>=jlb;j--) {
for (i=ilb;i<=iub-1;i++) {
double temp1,temp2;
temp1 = Math.min(d[i][j],d[i][j+1]);
temp2 = Math.min(d[i+1][j],d[i+1][j+1]);
dmin = Math.min(temp1,temp2);
temp1 = Math.max(d[i][j],d[i][j+1]);
temp2 = Math.max(d[i+1][j],d[i+1][j+1]);
dmax = Math.max(temp1,temp2);
if (dmax>=z[0]&&dmin<=z[nc-1]) {
for (k=0;k<nc;k++) {
if (z[k]>=dmin&&z[k]<=dmax) {
for (m=4;m>=0;m--) {
if (m>0) {
// The indexing of im and jm should be noted as it has to
// start from zero
h[m] = d[i+im[m-1]][j+jm[m-1]]-z[k];
xh[m] = x[i+im[m-1]];
yh[m] = y[j+jm[m-1]];
} else {
h[0] = 0.25*(h[1]+h[2]+h[3]+h[4]);
xh[0]=0.5*(x[i]+x[i+1]);
yh[0]=0.5*(y[j]+y[j+1]);
}
if (h[m]>0.0) {
sh[m] = 1;
} else if (h[m]<0.0) {
sh[m] = -1;
} else
sh[m] = 0;
}
//
// Note: at this stage the relative heights of the corners and the
// centre are in the h array, and the corresponding coordinates are
// in the xh and yh arrays. The centre of the box is indexed by 0
// and the 4 corners by 1 to 4 as shown below.
// Each triangle is then indexed by the parameter m, and the 3
// vertices of each triangle are indexed by parameters m1,m2,and
// m3.
// It is assumed that the centre of the box is always vertex 2
// though this isimportant only when all 3 vertices lie exactly on
// the same contour level, in which case only the side of the box
// is drawn.
//
//
// vertex 4 +-------------------+ vertex 3
// | \ / |
// | \ m-3 / |
// | \ / |
// | \ / |
// | m=2 X m=2 | the centre is vertex 0
// | / \ |
// | / \ |
// | / m=1 \ |
// | / \ |
// vertex 1 +-------------------+ vertex 2
//
//
//
// Scan each triangle in the box
//
for (m=1;m<=4;m++) {
m1 = m;
m2 = 0;
if (m!=4) {
m3 = m+1;
} else {
m3 = 1;
}
case_value = castab[sh[m1]+1][sh[m2]+1][sh[m3]+1];
if (case_value!=0) {
switch (case_value) {
case 1: // Line between vertices 1 and 2
x1=xh[m1];
y1=yh[m1];
x2=xh[m2];
y2=yh[m2];
break;
case 2: // Line between vertices 2 and 3
x1=xh[m2];
y1=yh[m2];
x2=xh[m3];
y2=yh[m3];
break;
case 3: // Line between vertices 3 and 1
x1=xh[m3];
y1=yh[m3];
x2=xh[m1];
y2=yh[m1];
break;
case 4: // Line between vertex 1 and side 2-3
x1=xh[m1];
y1=yh[m1];
x2=xsect(m2,m3);
y2=ysect(m2,m3);
break;
case 5: // Line between vertex 2 and side 3-1
x1=xh[m2];
y1=yh[m2];
x2=xsect(m3,m1);
y2=ysect(m3,m1);
break;
case 6: // Line between vertex 3 and side 1-2
x1=xh[m3];
y1=yh[m3];
x2=xsect(m1,m2);
y2=ysect(m1,m2);
break;
case 7: // Line between sides 1-2 and 2-3
x1=xsect(m1,m2);
y1=ysect(m1,m2);
x2=xsect(m2,m3);
y2=ysect(m2,m3);
break;
case 8: // Line between sides 2-3 and 3-1
x1=xsect(m2,m3);
y1=ysect(m2,m3);
x2=xsect(m3,m1);
y2=ysect(m3,m1);
break;
case 9: // Line between sides 3-1 and 1-2
x1=xsect(m3,m1);
y1=ysect(m3,m1);
x2=xsect(m1,m2);
y2=ysect(m1,m2);
break;
default:
break;
}
// Put your processing code here and comment out the printf
//printf("%f %f %f %f %f\n",x1,y1,x2,y2,z[k]);
render.drawContour(x1,y1,x2,y2,z[k]);
}
}
}
}
}
}
}
}
private double xsect(int p1, int p2){
return (h[p2]*xh[p1]-h[p1]*xh[p2])/(h[p2]-h[p1]);
}
private double ysect(int p1, int p2){
return (h[p2]*yh[p1]-h[p1]*yh[p2])/(h[p2]-h[p1]);
}
}
render.java的内容如下
/**
* A class implements the Render interface and drawContour method
* to draw contours.
*
* @author Bradley White
* @version 1.0
*/
public interface Render {
/**
* drawContour - interface for implementing the user supplied method to
* render the countours.
*
* Draws a line between the start and end coordinates.
*
* @param startX - start coordinate for X
* @param startY - start coordinate for Y
* @param endX - end coordinate for X
* @param endY - end coordinate for Y
* @param contourLevel - Contour level for line.
*/
public void drawContour(double startX, double startY, double endX, double endY, double contourLevel);
}