org.fxyz3d.shapes.composites.ScatterPlotMesh Maven / Gradle / Ivy
The newest version!
/**
* ScatterPlotMesh.java
*
* Copyright (c) 2013-2016, F(X)yz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of F(X)yz, any associated website, nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL F(X)yz BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.fxyz3d.shapes.composites;
import java.util.ArrayList;
import javafx.scene.DepthTest;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.CullFace;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import org.fxyz3d.geometry.Point3D;
/**
*
* @author Sean
*/
public class ScatterPlotMesh extends Group {
private ArrayList xAxisData = new ArrayList<>();
private ArrayList yAxisData = new ArrayList<>();
private ArrayList zAxisData = new ArrayList<>();
public Group scatterDataGroup = new Group();
public double nodeRadius = 1;
private double axesSize = 1000;
private boolean normalized = false;
public boolean selfLightEnabled = true;
double plotSize = 1000;
double nodeSize = 1;
public enum NodeType {
SPHERE, CUBE, PYRAMID, STAR
};
protected NodeType defaultNodeType = NodeType.SPHERE;
public ScatterPlotMesh(boolean selfLit) {
selfLightEnabled = selfLit;
init();
}
public ScatterPlotMesh(double axesSize, double nodeRadius, boolean selfLit) {
this.nodeRadius = nodeRadius;
init();
}
private void init() {
setDepthTest(DepthTest.ENABLE);
}
public void setXYZData(ArrayList xData, ArrayList yData, ArrayList zData) {
xAxisData = xData;
yAxisData = yData;
zAxisData = zData;
getChildren().clear();
//for now we will always default to x axis
//later we could maybe dynamically determine the smallest axis and then
//uses 0's for the other axes that are larger.
ArrayList point3DList = new ArrayList<>();
for (int i = 0; i < xAxisData.size(); i++) {
//some safety checks for array sizes
double translateY = 0.0;
double translateZ = 0.0;
if (!yAxisData.isEmpty() && yAxisData.size() > i) {
translateY = yAxisData.get(i);
}
if (!zAxisData.isEmpty() && zAxisData.size() > i) {
translateZ = zAxisData.get(i);
}
setTranslateX(xAxisData.get(i));
//Convert to Floats and build list of adjusted points
point3DList.add(new Point3D(xAxisData.get(i).floatValue(), (float) translateY, (float) translateZ));
float width = 1;
final TriangleMesh mesh = new TriangleMesh();
//add each point. For each point add another point shifted on Z axis by width
//This extra point allows us to build triangles later
point3DList.stream().map((point) -> {
//Rear points
//top right rear point
mesh.getPoints().addAll(point.x + width, point.y + width, point.z + width);
return point;
}).map((point) -> {
//top left rear point
mesh.getPoints().addAll(point.x - width, point.y + width, point.z + width);
return point;
}).map((point) -> {
//bottom right rear point
mesh.getPoints().addAll(point.x + width, point.y - width, point.z + width);
return point;
}).map((point) -> {
//bottom left rear point
mesh.getPoints().addAll(point.x - width, point.y - width, point.z + width);
return point;
}).map((point) -> {
//Front points
//top right front point
mesh.getPoints().addAll(point.x + width, point.y + width, point.z - width);
return point;
}).map((point) -> {
//top left front point
mesh.getPoints().addAll(point.x - width, point.y + width, point.z - width);
return point;
}).map((point) -> {
//bottom right front point
mesh.getPoints().addAll(point.x + width, point.y - width, point.z - width);
return point;
}).forEach((point) -> {
//bottom left front point
mesh.getPoints().addAll(point.x - width, point.y - width, point.z - width);
});
//add dummy Texture Coordinate
mesh.getTexCoords().addAll(0, 0);
//Now generate nodes for each point
for (int p = 8; p < point3DList.size() * 7; p += 8) { //add each segment
//Wind the next 8 vertices as a cube. The cube itself will represent the data
//Vertices wound counter-clockwise which is the default front face of any Triangle
//Rear triangle faces should be wound clockwise to face away from center
mesh.getFaces().addAll(p, 0, p + 3, 0, p + 2, 0); //TRR,BLR,BRR
mesh.getFaces().addAll(p + 3, 0, p, 0, p + 1, 0); //BLR,TRR,TLR
//left side faces
mesh.getFaces().addAll(p + 1, 0, p + 5, 0, p + 3, 0); //TLR,TLF,BLR
mesh.getFaces().addAll(p + 5, 0, p + 7, 0, p + 3, 0); //TLF,BLR,BLF
//front side faces
mesh.getFaces().addAll(p + 5, 0, p + 7, 0, p + 4, 0); //TLF,BLF,TLR
mesh.getFaces().addAll(p + 4, 0, p + 7, 0, p + 6, 0); //TRF,BLF,BRF
//front side faces
mesh.getFaces().addAll(p + 4, 0, p + 6, 0, p + 2, 0); //TRF,BRF,BRR
mesh.getFaces().addAll(p + 4, 0, p + 2, 0, p, 0); //TRF,BRR,TRR
//Top faces
mesh.getFaces().addAll(p, 0, p + 1, 0, p + 3, 0); //TRR,TLR,TRF
mesh.getFaces().addAll(p + 1, 0, p + 5, 0, p + 3, 0); //TLR,TLF,TRF
//bottom faces
mesh.getFaces().addAll(p + 3, 0, p + 7, 0, p + 6, 0); //BLR,BLF,BRF
mesh.getFaces().addAll(p + 3, 0, p + 6, 0, p + 2, 0); //BLR,BRF,BRR
}
//Need to add the mesh to a MeshView before adding to our 3D scene
MeshView meshView = new MeshView(mesh);
meshView.setDrawMode(DrawMode.LINE); //Fill so that the line shows width
//Color hsb = Color.hsb(((double) i / 12) * 360, 1.0, 1.0, 0.5);
PhongMaterial material = new PhongMaterial(Color.ROYALBLUE);
//material.setDiffuseColor(hsb);
//material.setSpecularColor(hsb);
meshView.setMaterial(material);
//Make sure you Cull the Back so that no black shows through
meshView.setCullFace(CullFace.NONE);
getChildren().addAll(meshView);
}
}
}