SciChart Android 3D Charts API > 3D Chart Types > The Free Surface 3D Chart Type > The Custom Free Surface 3D Chart Type
The Custom Free Surface 3D Chart Type

Custom Free Surface 3D Charts are provided by the CustomSurfaceDataSeries3D type.

 

 

The shape of its surface is defined by a set of user-defined functions, injected in the constructor during the instantiation. This approach allows the surface to obtain any possible shape.

CustomSurfaceDataSeries3D Constructor
Copy Code
public CustomSurfaceDataSeries3D(Class<TX> xType, Class<TY> yType, Class<TZ> zType, int uSize, int vSize,
                                 UVFunc radialDistanceFunc, UVFunc azimuthalAngleFunc, UVFunc polarAngleFunc,
                                 ValueFunc<TX> xFunc, ValueFunc<TY> yFunc, ValueFunc<TZ> zFunc)
  • Radial Distance Function – is a user-defined function that determines how distance from the origin to the particular point on the surface differs.
  • Azimuthal Angle Function – is a user-defined function that determines the azimuthal angle between the particular point and the unit vector of the X-Axis, projected on the ZX plane.
  • Polar Angle Function – is a user-defined function that determines inclination (or polar angle) between the particular point and the unit vector of the Y-Axis (Zenith).

The U and V coordinates in intervals [uMin..uMax]  and [vMin..vMax] respectively are passed as the arguments to each of the three functions above.

  • X Function - is a user-defined function that determines the position of the particular point on the surface by the X-Axis.
  • Y Function - is a user-defined function that determines the position of the particular point on the surface by the Y-Axis.
  • Z Function - is a user-defined function that determines the position of the particular point on the surface by the Z-Axis.

The Radial Distance, Polar Angle, and Azimuthal Angle are passed as the arguments to each of the three functions above.

 

More information about the radial distance, azimuthal and polar angle can be found here: Spherical coordinate system.

 

The location of the CustomFreeSurfaceSeries3D is defined by following properties:

  • OffsetX – a location of the Custom Free Surface by the X-Axis
  • OffsetY – a location of the Custom Free Surface by the Y-Axis
  • OffsetZ – a location of the Custom Free Surface by the Z-Axis

Declaring the Custom Free Surface 3D Series that defines a free surface mesh

The following code will create the shape at the top of this article:

FreeSurfaceMesh Custom Mesh example

Custom Mesh
Copy Code
final Camera3D camera = sciChart3DBuilder.newCamera3D().build();
final NumericAxis3D xAxis = sciChart3DBuilder.newNumericAxis3D().withNegativeSideClipping(AxisSideClipping.None).withPositiveSideClipping(AxisSideClipping.None).build();
final NumericAxis3D yAxis = sciChart3DBuilder.newNumericAxis3D().build();
final NumericAxis3D zAxis = sciChart3DBuilder.newNumericAxis3D().withNegativeSideClipping(AxisSideClipping.None).withPositiveSideClipping(AxisSideClipping.None).build();
final CustomSurfaceDataSeries3D.UVFunc radialDistanceFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return 5d + Math.sin(5 * (u + v));
    }
};
final CustomSurfaceDataSeries3D.UVFunc azimuthalAngleFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return u;
    }
};
final CustomSurfaceDataSeries3D.UVFunc polarAngleFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return v;
    }
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> xFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return r * Math.sin(theta) * Math.cos(phi);
    }  
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> yFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return r * Math.cos(theta);
    }
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> zFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return r * Math.sin(theta) * Math.sin(phi);
    }
};
final CustomSurfaceDataSeries3D<Double, Double, Double> ds = new CustomSurfaceDataSeries3D<>(Double.class, Double.class, Double.class, 30, 30,
        radialDistanceFunc, azimuthalAngleFunc, polarAngleFunc,
        xFunc, yFunc, zFunc,  0d, Math.PI * 2, 0, Math.PI);
final int[] colors = {0xFF1D2C6B, Blue, Cyan, GreenYellow, Yellow, Red, DarkRed};
final float[] stops = {0, .1f, .3f, .5f, .7f, .9f, 1};
final FreeSurfaceRenderableSeries3D rs = sciChart3DBuilder.newFreeSurfaceSeries3D()
        .withDataSeries(ds)
        .withDrawMeshAs(DrawMeshAs.SolidWireframe)
        .withStroke(0x77228B22)
        .withContourInterval(0.1f)
        .withContourStroke(0x77228B22)
        .withStrokeThicknes(1f)
        .withLightingFactor(0.8f)
        .withMeshColorPalette(new GradientColorPalette(colors, stops))
        .build();

UpdateSuspender.using(surface3d, new Runnable() {
    @Override
    public void run() {
        surface3d.getWorldDimensions().assign(200, 200, 200);
        surface3d.setCamera(camera);
        surface3d.setXAxis(xAxis);
        surface3d.setYAxis(yAxis);
        surface3d.setZAxis(zAxis);
        surface3d.getRenderableSeries().add(rs);
        surface3d.getChartModifiers().add(sciChart3DBuilder.newModifierGroupWithDefaultModifiers().build());
    }
});

Declaring the Custom Free Surface 3D Series that defines the sphere with a radius of 10

Sphere Mesh
Copy Code
final Camera3D camera = sciChart3DBuilder.newCamera3D().build();
final NumericAxis3D xAxis = sciChart3DBuilder.newNumericAxis3D().withNegativeSideClipping(AxisSideClipping.None).withPositiveSideClipping(AxisSideClipping.None).build();
final NumericAxis3D yAxis = sciChart3DBuilder.newNumericAxis3D().build();
final NumericAxis3D zAxis = sciChart3DBuilder.newNumericAxis3D().withNegativeSideClipping(AxisSideClipping.None).withPositiveSideClipping(AxisSideClipping.None).build();
final CustomSurfaceDataSeries3D.UVFunc radialDistanceFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return 10d;
    }
};
final CustomSurfaceDataSeries3D.UVFunc azimuthalAngleFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return u;
    }
};
final CustomSurfaceDataSeries3D.UVFunc polarAngleFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return v;
    }
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> xFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return r * Math.sin(theta) * Math.cos(phi);
    }  
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> yFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return r * Math.cos(theta);
    }
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> zFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return r * Math.sin(theta) * Math.sin(phi);
    }
};
final CustomSurfaceDataSeries3D<Double, Double, Double> ds = new CustomSurfaceDataSeries3D<>(Double.class, Double.class, Double.class, 30, 30,
        radialDistanceFunc, azimuthalAngleFunc, polarAngleFunc,
        xFunc, yFunc, zFunc,  0d, Math.PI * 2, 0, Math.PI);
final int[] colors = {0xFF1D2C6B, Blue, Cyan, GreenYellow, Yellow, Red, DarkRed};
final float[] stops = {0, .1f, .3f, .5f, .7f, .9f, 1};
final FreeSurfaceRenderableSeries3D rs = sciChart3DBuilder.newFreeSurfaceSeries3D()
        .withDataSeries(ds)
        .withDrawMeshAs(DrawMeshAs.SolidWireframe)
        .withStroke(0x77228B22)
        .withContourInterval(0.1f)
        .withContourStroke(0x77228B22)
        .withStrokeThicknes(1f)
        .withLightingFactor(0.8f)
        .withMeshColorPalette(new GradientColorPalette(colors, stops))
        .build();

UpdateSuspender.using(surface3d, new Runnable() {
    @Override
    public void run() {
        surface3d.getWorldDimensions().assign(200, 200, 200);
        surface3d.setCamera(camera);
        surface3d.setXAxis(xAxis);
        surface3d.setYAxis(yAxis);
        surface3d.setZAxis(zAxis);
        surface3d.getRenderableSeries().add(rs);
        surface3d.getChartModifiers().add(sciChart3DBuilder.newModifierGroupWithDefaultModifiers().build());
    }
});

Declaring the Custom Free Surface 3D Series that defines the cylinder with a radius of 10 and a height of 40

Cylinder Mesh
Copy Code
final Camera3D camera = sciChart3DBuilder.newCamera3D().build();
final NumericAxis3D xAxis = sciChart3DBuilder.newNumericAxis3D().withNegativeSideClipping(AxisSideClipping.None).withPositiveSideClipping(AxisSideClipping.None).build();
final NumericAxis3D yAxis = sciChart3DBuilder.newNumericAxis3D().build();
final NumericAxis3D zAxis = sciChart3DBuilder.newNumericAxis3D().withNegativeSideClipping(AxisSideClipping.None).withPositiveSideClipping(AxisSideClipping.None).build();
final CustomSurfaceDataSeries3D.UVFunc radialDistanceFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return 0d;
    }
};
final CustomSurfaceDataSeries3D.UVFunc azimuthalAngleFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return u;
    }
};
final CustomSurfaceDataSeries3D.UVFunc polarAngleFunc = new CustomSurfaceDataSeries3D.UVFunc() {
    @Override
    public double getValueFor(double u, double v) {
        return v;
    }
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> xFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return 10 * Math.sin(Math.PI / 2) * Math.cos(phi);
    }  
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> yFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return 20 * Math.cos(theta);
    }
};
final CustomSurfaceDataSeries3D.ValueFunc<Double> zFunc = new CustomSurfaceDataSeries3D.ValueFunc<Double>() {
    @Override
    public Double getValueFor(double r, double theta, double phi) {
        return 10 * Math.sin(Math.PI / 2) * Math.sin(phi);
    }
};
final CustomSurfaceDataSeries3D<Double, Double, Double> ds = new CustomSurfaceDataSeries3D<>(Double.class, Double.class, Double.class, 30, 30,
        radialDistanceFunc, azimuthalAngleFunc, polarAngleFunc,
        xFunc, yFunc, zFunc,  0d, Math.PI * 2, 0, Math.PI);
final int[] colors = {0xFF1D2C6B, Blue, Cyan, GreenYellow, Yellow, Red, DarkRed};
final float[] stops = {0, .1f, .3f, .5f, .7f, .9f, 1};
final FreeSurfaceRenderableSeries3D rs = sciChart3DBuilder.newFreeSurfaceSeries3D()
        .withDataSeries(ds)
        .withDrawMeshAs(DrawMeshAs.SolidWireframe)
        .withStroke(0x77228B22)
        .withContourInterval(0.1f)
        .withContourStroke(0x77228B22)
        .withStrokeThicknes(1f)
        .withLightingFactor(0.8f)
        .withMeshColorPalette(new GradientColorPalette(colors, stops))
        .withDrawBackSize(true)
        .build();

UpdateSuspender.using(surface3d, new Runnable() {
    @Override
    public void run() {
        surface3d.getWorldDimensions().assign(200, 200, 200);
        surface3d.setCamera(camera);
        surface3d.setXAxis(xAxis);
        surface3d.setYAxis(yAxis);
        surface3d.setZAxis(zAxis);
        surface3d.getRenderableSeries().add(rs);
        surface3d.getChartModifiers().add(sciChart3DBuilder.newModifierGroupWithDefaultModifiers().build());
    }
});