For this demo I'm going to use the Java3D builder created for previous posts.

The TriangleArray class will be used to create the grid to plot the function . Two triangles will be create for each set of 4 points. For future posts I'm going to try to change this to support TriangleStripArray or QuadArray.

In order to create each coordinate of the plane, a function that maps between the iteration number and the real coordinate to be plotted is required. In order to do this the createMapFunc was created, this function returns a function that maps between two coordinates.

Closure createMapFunc(int x1,int x2,double y1,double y2) {

double m = (y2 - y1)/(x2 - x1);

double b = y1 - m*x1;

return { x -> m*x + b}

}

Closure createFloatMapFunc(int x1,int x2,double y1,double y2) {

Closure f = createMapFunc(x1,x2,y1,y2);

return { (float)f(it)};

}

Given this we can now create the TriangleArray data required to plot the function:

Geometry createGeometry(Closure f,double min,double max,int gridSize) {

Closure fInter = createFloatMapFunc(0,gridSize-1,min,max);

TriangleArray ta = new TriangleArray(((gridSize-1)**2)*6,

TriangleArray.COORDINATES

|TriangleArray.NORMALS

);

int idx = 0;

float x,y,z;

for ( iY in (0..(gridSize-2))) {

for( iX in (0..(gridSize-2))) {

// First triangle

x = fInter(iX);

y = fInter(iY);

z = (float) f(x,y);

ta.setCoordinate(idx,new Point3f(x,y,z));

x = fInter(iX+1);

y = fInter(iY);

z = (float) f(x,y);

ta.setCoordinate(idx+1,new Point3f(x,y,z));

x = fInter(iX);

y = fInter(iY+1);

z = (float) f(x,y);

ta.setCoordinate(idx+2,new Point3f(x,y,z));

idx += 3;

// Second triangle

x = fInter(iX+1);

y = fInter(iY);

z = (float) f(x,y);

ta.setCoordinate(idx,new Point3f(x,y,z));

x = fInter(iX+1);

y = fInter(iY+1);

z = (float) f(x,y);

ta.setCoordinate(idx+1,new Point3f(x,y,z));

x = fInter(iX);

y = fInter(iY+1);

z = (float) f(x,y);

ta.setCoordinate(idx+2,new Point3f(x,y,z));

idx += 3;

}

}

return ta;

}

The function to be plotted is a parameter to the createGeometry function.

For this example the following function will be used:

def f = { x,y -> Math.cos(x+y)*Math.sin(x-y)}

Now that we have the code to generate the 3D function geometry we can create the Java3D/Swing required elements by using the Swing, Java3D and SimpleUniverse builders.

SwingBuilder sb = new SwingBuilder();

SimpleUniverseBuilder sub = new SimpleUniverseBuilder();

Java3dBuilder jb = new Java3dBuilder();

JFrame aFrame = sb.frame(title:"Function",size:[500,500]){

panel(layout: new FlowLayout()) {

thePanel = panel(preferredSize:[500,500],

layout:new BorderLayout())

}

}

SimpleUniverse univ =

sub.simpleUniverse() {

viewingPlatform(nominalViewingTransform:true) {

orbitBehavior(

flags:OrbitBehavior.REVERSE_ALL,

bounds:new BoundingSphere(

new Point3d(0.0,0.0,0.0),

100.0))

}

viewer() {

view(minFrameCycleTime:5)

}

}

thePanel.add(univ.getCanvas(),BorderLayout.CENTER);

BranchGroup bg =

jb.branchGroup() {

transformGroup(

capability:

TransformGroup.ALLOW_TRANSFORM_WRITE) {

shape3d(geometry:createGeometry(f,-2.5,2.5,20),

appearance:polyAppearance())

}

}

bg.compile();

univ.addBranchGraph(bg);

aFrame.show()

The result of running the program looks like this:

As a last detail, the appearance of the surface is created with the createPolyAppearance function:

Appearance polyAppearance() {

Appearance app = new Appearance();

PolygonAttributes pa = new PolygonAttributes();

pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);

app.setPolygonAttributes(pa);

return app;

}

Code for this experiment can be found here.

In future posts I'm going to try to add more features, like materials applied to the surface geometry, axis lines, etc.