/*
* Copyright (C) 2013-2015 F(X)yz,
* Sean Phillips, Jason Pollastrini and Jose Pereda
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fxyz.shapes.primitives;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.DepthTest;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.shape.CullFace;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.TriangleMesh;
import org.fxyz.geometry.Point3D;
import org.fxyz.shapes.primitives.helper.MeshHelper;
import org.fxyz.shapes.primitives.helper.TextureMode;
import org.fxyz.utils.Palette.ColorPalette;
import org.fxyz.utils.Patterns;
/**
*
* @author José Pereda
*/
public class ScatterMesh extends Group implements TextureMode {
private final static List<Point3D> DEFAULT_SCATTER_DATA = Arrays.asList(new Point3D(0f,0f,0f),
new Point3D(1f,1f,1f), new Point3D(2f,2f,2f));
private final static double DEFAULT_HEIGHT = 0.1d;
private final static int DEFAULT_LEVEL = 0;
private final static boolean DEFAULT_JOIN_SEGMENTS = true;
private ObservableList<TexturedMesh> meshes=null;
public ScatterMesh(){
this(DEFAULT_SCATTER_DATA,DEFAULT_JOIN_SEGMENTS,DEFAULT_HEIGHT,DEFAULT_LEVEL);
}
public ScatterMesh(List<Point3D> scatterData){
this(scatterData,DEFAULT_JOIN_SEGMENTS,DEFAULT_HEIGHT,DEFAULT_LEVEL);
}
public ScatterMesh(List<Point3D> scatterData, double height){
this(scatterData,DEFAULT_JOIN_SEGMENTS,height,DEFAULT_LEVEL);
}
public ScatterMesh(List<Point3D> scatterData, boolean joinSegments, double height, int level){
setScatterData(scatterData);
setJoinSegments(joinSegments);
setHeight(height);
setLevel(level);
updateMesh();
}
private final ObjectProperty<List<Point3D>> scatterData = new SimpleObjectProperty<List<Point3D>>(DEFAULT_SCATTER_DATA){
@Override
protected void invalidated() {
if(meshes!=null){
updateMesh();
}
}
};
public List<Point3D> getScatterData() {
return scatterData.get();
}
public final void setScatterData(List<Point3D> value) {
scatterData.set(value);
}
public ObjectProperty<List<Point3D>> scatterDataProperty() {
return scatterData;
}
private final ObjectProperty<List<Number>> functionData = new SimpleObjectProperty<List<Number>>(){
@Override
protected void invalidated() {
if(meshes!=null){
updateF(get());
}
}
};
public List<Number> getFunctionData() {
return functionData.get();
}
public void setFunctionData(List<Number> value) {
functionData.set(value);
}
public ObjectProperty<List<Number>> functionDataProperty() {
return functionData;
}
private final DoubleProperty height = new SimpleDoubleProperty(DEFAULT_HEIGHT){
@Override
protected void invalidated() {
if(meshes!=null){
updateMesh();
}
}
};
public double getHeight() {
return height.get();
}
public final void setHeight(double value) {
height.set(value);
}
public DoubleProperty heightProperty() {
return height;
}
private final IntegerProperty level = new SimpleIntegerProperty(DEFAULT_LEVEL){
@Override
protected void invalidated() {
if(meshes!=null){
updateMesh();
}
}
};
public final int getLevel() {
return level.get();
}
public final void setLevel(int value) {
level.set(value);
}
public final IntegerProperty levelProperty() {
return level;
}
private final BooleanProperty joinSegments = new SimpleBooleanProperty(DEFAULT_JOIN_SEGMENTS){
@Override
protected void invalidated() {
if(meshes!=null){
updateMesh();
}
}
};
public boolean isJoinSegments() {
return joinSegments.get();
}
public final void setJoinSegments(boolean value) {
joinSegments.set(value);
}
public BooleanProperty joinSegmentsProperty() {
return joinSegments;
}
protected final void updateMesh() {
meshes=FXCollections.<TexturedMesh>observableArrayList();
createDots();
if(joinSegments.get()){
// System.out.println("Single mesh created");
}
getChildren().setAll(meshes);
updateTransforms();
}
private AtomicInteger index;
private void createDots() {
if(!joinSegments.get()){
List<TexturedMesh> dots=new ArrayList<>();
index=new AtomicInteger();
scatterData.get().forEach(point3d->{
// TexturedMesh dot = new CuboidMesh(height.get(), height.get(), height.get(), level.get(), point3d);
TexturedMesh dot = new TetrahedraMesh(height.get(), level.get(), point3d);
dot.setCullFace(CullFace.BACK);
dot.setDrawMode(DrawMode.FILL);
dot.setDepthTest(DepthTest.ENABLE);
dot.setId(""+index.getAndIncrement());
dots.add(dot);
});
meshes.addAll(dots);
} else {
// TexturedMesh dot = new CuboidMesh(height.get(), height.get(), height.get(), level.get(), scatterData.get().get(0));
TexturedMesh dot = new TetrahedraMesh(height.get(), level.get(), scatterData.get().get(0));
dot.setCullFace(CullFace.BACK);
dot.setDrawMode(DrawMode.FILL);
dot.setDepthTest(DepthTest.ENABLE);
dot.setId("0");
/*
Combine new polyMesh with previous polyMesh into one single polyMesh
*/
MeshHelper mh = new MeshHelper((TriangleMesh)dot.getMesh());
// TexturedMesh dot1 = new CuboidMesh(height.get(), height.get(), height.get(), level.get(), null);
TexturedMesh dot1 = new TetrahedraMesh(height.get(), level.get(), null);
MeshHelper mh1 = new MeshHelper((TriangleMesh)dot1.getMesh());
mh.addMesh(mh1,scatterData.get().stream().skip(1).collect(Collectors.toList()));
dot.updateMesh(mh);
meshes.add(dot);
}
}
@Override
public void setTextureModeNone() {
meshes.stream().forEach(m->m.setTextureModeNone());
}
@Override
public void setTextureModeNone(Color color) {
meshes.stream().forEach(m->m.setTextureModeNone(color));
}
@Override
public void setTextureModeNone(Color color, String image) {
meshes.stream().forEach(m->m.setTextureModeNone(color,image));
}
@Override
public void setTextureModeImage(String image) {
meshes.stream().forEach(m->m.setTextureModeImage(image));
}
@Override
public void setTextureModePattern(Patterns.CarbonPatterns pattern, double scale) {
meshes.stream().forEach(m->m.setTextureModePattern(pattern, scale));
}
@Override
public void setTextureModeVertices3D(int colors, Function<Point3D, Number> dens) {
meshes.stream().forEach(m->m.setTextureModeVertices3D(colors, dens));
}
@Override
public void setTextureModeVertices3D(ColorPalette palette, int colors, Function<Point3D, Number> dens) {
meshes.stream().forEach(m->m.setTextureModeVertices3D(palette, colors, dens));
}
@Override
public void setTextureModeVertices3D(int colors, Function<Point3D, Number> dens, double min, double max) {
meshes.stream().forEach(m->m.setTextureModeVertices3D(colors, dens, min, max));
}
@Override
public void setTextureModeVertices1D(int colors, Function<Number, Number> function) {
meshes.stream().forEach(m->m.setTextureModeVertices1D(colors, function));
}
@Override
public void setTextureModeVertices1D(ColorPalette palette, int colors, Function<Number, Number> function) {
meshes.stream().forEach(m->m.setTextureModeVertices1D(palette, colors, function));
}
@Override
public void setTextureModeVertices1D(int colors, Function<Number, Number> function, double min, double max) {
meshes.stream().forEach(m->m.setTextureModeVertices1D(colors, function, min, max));
}
@Override
public void setTextureModeFaces(int colors) {
meshes.stream().forEach(m->m.setTextureModeFaces(colors));
}
@Override
public void setTextureModeFaces(ColorPalette palette, int colors) {
meshes.stream().forEach(m->m.setTextureModeFaces(palette, colors));
}
@Override
public void updateF(List<Number> values) {
meshes.stream().forEach(m->m.updateF(values));
}
public void setDrawMode(DrawMode mode) {
meshes.stream().forEach(m->m.setDrawMode(mode));
}
private void updateTransforms() {
meshes.stream().forEach(m->m.updateTransforms());
}
public TexturedMesh getMeshFromId(String id){
return meshes.stream().filter(p->p.getId().equals(id)).findFirst().orElse(meshes.get(0));
}
}