3D terrain modelling program (dissertation help)

Hello.

This is my first time using a forum, so please bear with me and my ignorance.

I’m a 3rd year university student, and am currently tackling a dissertation project in a Visualisation of a 3D terrain using Java 3d.

I am currently trying to create a 3D Array to hold elevation data for my landscape. I am using the StringTokenizer to read in a elevation data set file, and store it in my array. The Data file contains [3] - colums [51] - rows and [51] sets of these data values. This has been taken from a map of a landscape, where i broke the map down into a grid of 51 * 51 squares. Each square has data pertaining to x, height, and y values - eg. (2, 11400, 12)
with an “a” separating each column of information, and a “b”

I am currently getting compiler errors which i cannot understand, ??? and was hoping someone could give me some advice on the section of code which i am about to show.

Any help would be much appreciated

thank you for your time

package terraingrid;

import java.io.;
import java.util.
;

/**
*

  • @author Owner
    */
    public class Reader {

    // instance made using empty constructor of reader1 class
    Reader reader = new Reader();
    int col;
    int row;
    int height;

    /** Creates a new instance of Reader */
    public Reader() {

    }

public void ReaderOfArray(){
// can access the array as follows

ArrayMaker myarray = new ArrayMaker();
  
int col = reader.ArrayMaker.myarray[0][0][0]; // = x of [0][0]
int row = reader.ArrayMaker.myarray[1][10][29]; // = y of [10][29] etc
int height = reader.ArrayMaker.myarray[10][30][1]; // = height of [][]
// and to run the Test1 Method

reader.Test1();    

}

//could be in a file Reader1.java and then public class Reader1{ //etc

//Test1 is created to read in the file containing all the elevation
//data for the 3D Polygon Model to be created to represent the
//landscape

class ReaderTokenizer {
//---------------FIELDS================================
//instance of the array class
//ArrayMaker myarray = new ArrayMaker();

//or with other constructor
ArrayMaker myarray = new ArrayMaker();

//--------CONSTRUCTORS-----------------------------------------------------------
//empty constructor
public ReaderTokenizer(){

int col[];
int row[];
int height[];

}
//------------------METHODS=============================
// don’t make static
public void Test1() throws FileNotFoundException, IOException{

    FileReader file = new FileReader
            ("H:\\University of Liverpool\\3rd Year\\COMP390 - Dissertation\\edited terrain data\\EDF.txt"); 
            //remember to change the pathname of the file
    BufferedReader fileInput = new BufferedReader(file);
    int col, row, height;
    ArrayMaker myarray = new ArrayMaker();
    String token;
    // Read file

    StringTokenizer Tokenizer = new StringTokenizer(fileInput.readLine(),"(),", true);

    while (Tokenizer.hasMoreTokens()) {


       for(col = 0; col < myarray.length; col++){
           for(row = 0; row < myarray[col].length; row++){

           // recognize the ( and go to next token
           token = Tokenizer.nextToken();
           System.out.println(token);
           col = Integer.parseInt(token = Tokenizer.nextToken());

           // recognize the , and go to next token
           token = Tokenizer.nextToken();
           System.out.println(token);
           row = Integer.parseInt(token = Tokenizer.nextToken());

           // recognize the , and go to next token
           token = Tokenizer.nextToken();
           System.out.println(token);
           height = Integer.parseInt(token = Tokenizer.nextToken());

           //recognize the ) and go to next token
           token = Tokenizer.nextToken();
           System.out.println(token);

           //access the instance of arraymaker made as a field to access the array and set values
           ArrayMaker.myarray[0][col][row] = col;
           ArrayMaker.myarray[1][col][row] = row;
           ArrayMaker.myarray[2][col][row] = height;

           //the For loops set [x,y,z][row][0 to 50](inner loop)
           //outer loops sets [x,y,z][0][0 to 50], [x,y,z][1][0 to 50], [x,y,z][2][0 to 50], etc


         }//end inner for loop

}//end outer for loop

      //need to put these inside loop, may need to play about with it
      //dataLine = new StringTokenizer(fileInput.readLine());
      if (Tokenizer.nextToken().compareTo("a")==0){
           token = Tokenizer.nextToken();
      }//space between brackets
      else {
      }

      if (Tokenizer.nextToken().compareTo("b")==0){
          break;
      }//space between brackets
      else {
      }

}// end Test1 method

}//end class
}

class ArrayMaker {

int[][][] myarray = new int[3][51][51]; // this is 51 by 51 with indices 0 to 50

//constructor to initialise my array as public, for use by all
//inner classes of class Reader
public ArrayMaker(){

ArrayMaker myarray = new ArrayMaker();

}

public ArrayMaker(int nocol,int norows, int noheight){
myarray = new int[nocol][norows][noheight];

}

//
//no methods for this class

}
}

What error are you getting?

Thanks for the quick reply.

A few to be honest.

Mainly with the lines

int col = reader.ArrayMaker.myarray[0][0][0]; // = x of [0][0]

---- unexpected type: required: class, package
found : variable
&

— non-static variable myarray cannot be referenced from a static context (this is particularly confusing, as i havent specified any of the classes as static…)

( int row = reader.ArrayMaker.myarray[1][10][29]; // = y of [10][29] etc
int height = reader.ArrayMaker.myarray[10][30][1]; // = height of [][])

---- the same errors as above…

// and to run the Test1 Method

reader.Test1();    

— cannot find symbol
symbol : method Test1()
location: class terraingrid.Reader
reader.Test1();

these have been the main stumbling blocks.

I’ve also found that when trying to specify the array with any call such as

reader.ArrayMaker.myarray[][][]… it doesnt seem to be able to find the class ArrayMaker.

I made sure to make an instance of ArrayMaker in a public constructor of the class ArrayMaker, so as to make it visible by the other classes, but this doesnt seem to help either…

any ideas?

Just to let u know.

I’ll be away over the weekend. Will be leaving in the next few hrs.

Feel free to leave any hints tho.

Thanks

Before I get to the question, I can’t help but wonder why a 3 dimensional array is being used to describe a height map. Typically, a 2 dimensional array is used with the value of the array entry being the height.

This appears to be a fundamental Java concepts issue rather than a Java3D issue. The code: MyClass.aVariable is used to access a static variable aVariable in the class MyClass. For your particular situation ArrayMaker.myarray appears to the compiler as an attempt to access the static variable myarray in the class ArrayMaker. However, the myarray variable is not static so you get the error.

It appears to me that the myarray name is used far too much in the code to keep straight (for me anyway).

Thank you for your suggestion.

Unfortunately, i tried to specify the arrayMaker as static, and the compiler returned with the error that “inner classes cannot have static declarations”.

I’ve removed the unnecessary calls to arraymaker and my array from my source, but am still having some dificulty.

Basically, i’m not sure if the code i’ve posted will even begin to do what i need.
I have a txt file With a list of coordinate vertices in the form (0,11400,-12) and i want to read these into an array, so that i can create a TringleStrip(ARRAY maybe) of these vertices, to create the points required, to create the object of my landscape.

Any help would be most appreciated

Actually, I’ve just found that I can specify the class to be static.

Unfortunately, doing this causes the compiler error :non-static variable myarray cannot be referenced from a static context.

Wud i be correct in suggesting that it would be better not to have the array in an inner class, and just put it in the Reader or ReaderTokenizer class?

Finally, to comment on why i chose a 3D array. The values i have are 3 vertices (x,y,z) (one dimension). There is a column (the first set of values for the left hand side of the map i am modelling) of 51 of these values. And there are 51 columns in total.

Hence why i tried to create a 3D array [3][51][51], for a cube shape.

Is this a logical approach?

If you think about your classic object oriented programming stuff the terrain array sounds to me like a classic example of the type of thing that should have it’s own class. You could use this to contain the terrain data and any specifically relevant operations you might perform on it - finding the height at a given location and so on.

I’m not entirely sure I understand your arrays - It is quite common in terrain modelling to have a regular grid so that for example you are measuring the height every metre. If you’re doing that there is no point in recording the x and z co-ordinates because they will always be the same as your position in the array and the only irregular quantity will be the height.

That way rather than having


int[] point1 = {0, 3, 0};
int[] point1 = {1, 1, 0};
int[] point1 = {0, 4,1};
int[] point1 = {1, 2, 1};

You could have:


int[][] points = new int[2][2];
points[0][0]=3;
points[1][0]=1;
points[0][1]=4;
points[1][1]=2;

You know what your x and z values are at points[x][z] so you only need to find the y value.

If you’re in any doubt about your OO or any other java principles, these tutorials are outstanding.

Hello again,

I took on board the last comments posted about my project. Thank you for the advice given. Since then i have managed to get an File reader class working to read in the int values of my height map, into the created array, and working well.

I have now come accross a problem, in that i am not so sure how to read in the stored height values into a triangle strip array.

I have realised that in the timeframe i have left (until next thurs 21st april) i wont be able to complete the scope of my project.

However, it has been brought to my attention that creating a wire mesh for display, will get me sufficient marks to pass.

Unfortunately, as i said, i’m having trouble creating the triangle strip array, so that i can place this into my Canvas3D as a wireframe object.

I was wondering if anyone has any example code showing how this maybe done, or even any recommended tutorials which can explain the essentials of the process.

Any help would be much appreciated, as i am quickly running out of time.

Thanks
Andrew

Bet you wish you had prepared everything better now…

I spent the last few weeks of each term in my last year at uni staying awake approximately 24/7 and desperately wishing I’d planned ahead better, or that all our programming projects hadn’t been set in the last fortnight of the course…

This doesn’t do what you need but it is not a thousand miles away - this actually generates a Shape3D which you can display however you want- there are a few tutorials about this to be found around the place.

The method belongs to an object that extends Shape3D- hence the setGeometry() call at the end.

The ArrayList it expects is organised into squares, as far as I can recall (haven’t had much time for j3d for a few weeks) if your grid is like this:

A B C
D E F
G H I

Then vertList will contain { A, B, E, D, B, C, F, E, D, E, H, G, E, F, I, H}

I’m afraid the code is a bit scruffy and I have only just bodged it together so it’s probably not optimal, but it gives you some idea of what kind of thing you need to do.


public void generateGeometry(ArrayList verts)
{
    Point3d[] corners= new Point3d[verts.size()+(verts.size()/2)];
    Point3d[] cornerSet=new Point3d[verts.size()];
    verts.toArray(cornerSet);
    int pointCount= (int) corners.length/3;
    int cc=0;
    int step;
    for (int i=0;i<cornerSet.length;i=i+4)
        {
           step=0;
           corners[cc]=cornerSet[i];
           corners[++cc]=cornerSet[i+1];
           corners[++cc]=cornerSet[i+3];
           corners[++cc]=cornerSet[i+1];
           corners[++cc]=cornerSet[i+2];
           corners[++cc]=cornerSet[i+3];
           cc++;
        }
            
        TriangleArray shape= new TriangleArray(corners.length, GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_2 | GeometryArray.NORMALS);
        TexCoord2f[] texcors= new TexCoord2f[corners.length];
        for(int i=0; i <  texcors.length; i=i+3) 
        {
            texcors[i] = new TexCoord2f(0.0f, 0.0f); // for 1 point 
            texcors[i+1] = new TexCoord2f(1.0f, 0.0f);
            texcors[i+2] = new TexCoord2f(1.0f, 1.0f); 
        }

        GeometryInfo gi = new GeometryInfo(GeometryInfo.TRIANGLE_ARRAY); 
        gi.setCoordinates(corners); 

        
        gi.setTextureCoordinateParams(1, 2); // one set of 2D texels 
        gi.setTextureCoordinates(0, texcors);
        
        NormalGenerator ng = new NormalGenerator();
        ng.setCreaseAngle( (float) Math.toRadians(150));
        ng.generateNormals(gi);

        Stripifier st= new Stripifier();
        st.stripify(gi);
        setGeometry( gi.getGeometryArray() );
    }

Best of British…