All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fxyz3d.scene.CuboidViewer Maven / Gradle / Ivy

The newest version!
/**
 * CuboidViewer.java
 *
 * Copyright (c) 2018-2019, 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.scene;

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.transform.Rotate;
import javafx.scene.transform.Translate;
import org.fxyz3d.shapes.polygon.PolygonMesh;
import org.fxyz3d.shapes.polygon.PolygonMeshView;
import org.fxyz3d.utils.DataBox;

import java.util.logging.Logger;

/**
 *
 * @author JosePereda
 */
public class CuboidViewer extends Group {

    private static final Logger LOG = Logger.getLogger(CuboidViewer.class.getName());

    public static final double MARGIN_VALUE = 1.2;
    public static final double LOWER_VALUE = 0.4;

    private final PolygonMeshView backGridXY, frontGridXY;
    private final PolygonMeshView bottomGridXZ, topGridXZ;
    private final PolygonMeshView rightGridYZ, leftGridYZ;
    private final PolygonMeshView cuboidBox;

    private double delta;
    private double cameraRX, cameraRY, cameraRZ;

    public CuboidViewer() {
        backGridXY = new PolygonMeshView();
        frontGridXY = new PolygonMeshView();
        bottomGridXZ = new PolygonMeshView();
        topGridXZ = new PolygonMeshView();
        rightGridYZ = new PolygonMeshView();
        leftGridYZ = new PolygonMeshView();
        getChildren().addAll(backGridXY, frontGridXY, bottomGridXZ, topGridXZ, leftGridYZ, rightGridYZ);

        cuboidBox = new PolygonMeshView();
        getChildren().add(cuboidBox);

        getChildren().stream()
                .filter(PolygonMeshView.class::isInstance)
                .map(PolygonMeshView.class::cast)
                .forEach(m -> {
                    m.setDrawMode(DrawMode.LINE);
                    m.setCullFace(CullFace.NONE);
                    m.setDepthTest(DepthTest.ENABLE);
                    m.setMaterial(new PhongMaterial(Color.DARKGREY));
                    m.setOnMouseExited(t -> {
                        adjustPanelsByPos(cameraRX, cameraRY, cameraRZ);
                        t.consume();
                    });
                });
        setDepthTest(DepthTest.ENABLE);

        createCuboid(DataBox.getDefaultDataBox(), 10);
    }

    public final void createCuboid(DataBox dataBox, double delta) {
        this.delta = (delta < dataBox.getMaxSize() / 10d) ? dataBox.getMaxSize() / 10d : delta;
        double sizeX = dataBox.getSizeX() * MARGIN_VALUE;
        double cenX = dataBox.getCenterX();
        double sizeY = dataBox.getSizeY() * MARGIN_VALUE;
        double cenY = dataBox.getCenterY();
        double sizeZ = dataBox.getSizeZ() * MARGIN_VALUE;
        double cenZ = dataBox.getCenterZ();
        double min = LOWER_VALUE * dataBox.getMaxSize() * MARGIN_VALUE;
        if (sizeX < min) {
            sizeX = min;
        }
        if (sizeY < min) {
            sizeY = min;
        }
        if (sizeZ < min) {
            sizeZ = min;
        }

        final PolygonMesh planeXY = createQuadrilateralMesh((float) sizeX, (float) sizeY, (int) (sizeX / this.delta), (int) (sizeY / this.delta));

        backGridXY.setMesh(planeXY);
        backGridXY.getTransforms().setAll(new Translate(cenX, cenY, cenZ + sizeZ / 2d));

        frontGridXY.setMesh(planeXY);
        frontGridXY.getTransforms().setAll(new Translate(cenX, cenY, cenZ - sizeZ / 2d));

        final PolygonMesh planeXZ = createQuadrilateralMesh((float) sizeX, (float) sizeZ, (int) (sizeX / this.delta), (int) (sizeZ / this.delta));

        bottomGridXZ.setMesh(planeXZ);
        bottomGridXZ.getTransforms().setAll(new Translate(cenX, cenY + sizeY / 2d, cenZ));
        bottomGridXZ.getTransforms().add(new Rotate(90, 0, 0, 0, Rotate.X_AXIS));

        topGridXZ.setMesh(planeXZ);
        topGridXZ.getTransforms().setAll(new Translate(cenX, cenY - sizeY / 2d, cenZ));
        topGridXZ.getTransforms().add(new Rotate(90, 0, 0, 0, Rotate.X_AXIS));

        final PolygonMesh planeYZ = createQuadrilateralMesh((float) sizeZ, (float) sizeY, (int) (sizeZ / this.delta), (int) (sizeY / this.delta));

        rightGridYZ.setMesh(planeYZ);
        rightGridYZ.getTransforms().setAll(new Translate(cenX + sizeX / 2d, cenY, cenZ));
        rightGridYZ.getTransforms().add(new Rotate(90, Rotate.Y_AXIS));

        leftGridYZ.setMesh(planeYZ);
        leftGridYZ.getTransforms().setAll(new Translate(cenX - sizeX / 2d, cenY, cenZ));
        leftGridYZ.getTransforms().add(new Rotate(90, Rotate.Y_AXIS));

        final PolygonMesh cuboid = createCuboidMesh((float) sizeX, (float) sizeY, (float) sizeZ);
        cuboidBox.setMesh(cuboid);
        cuboidBox.getTransforms().setAll(new Translate(cenX, cenY, cenZ));

        adjustPanelsByPos(0, 0, 0);
    }

    public void adjustPanelsByPos(double rx, double ry, double rz) {
        cameraRX = rx;
        cameraRY = ry;
        cameraRZ = rz;

        if ((Math.abs(rx) <= 90 && (-85 < ry && ry < 85)) ||
                (Math.abs(rx) > 90 && ((95 < ry && ry < 180) || (-180 < ry && ry < -95)))) {
            frontGridXY.setVisible(false);
        } else {
            frontGridXY.setVisible(true);
        }
        if ((Math.abs(rx) <= 90 && ((95 < ry && ry < 180) || (-180 < ry && ry < -95))) ||
                (Math.abs(rx) > 90 && (-85 < ry && ry < 85))) {
            backGridXY.setVisible(false);
        } else {
            backGridXY.setVisible(true);
        }

        leftGridYZ.setVisible(! (5 < ry && ry < 175));
        rightGridYZ.setVisible(! (-175 < ry && ry < -5));

        topGridXZ.setVisible(rx > 0);
        bottomGridXZ.setVisible(! topGridXZ.isVisible());
    }

    private PolygonMesh createQuadrilateralMesh(float width, float height, int subDivX, int subDivY) {
        final float minX = - width / 2f;
        final float minY = - height / 2f;
        final float maxX = width / 2f;
        final float maxY = height / 2f;

        final int pointSize = 3;
        final int texCoordSize = 2;
        // 4 point indices and 4 texCoord indices per face
        final int faceSize = 8;
        int numDivX = subDivX + 1;
        int numVerts = (subDivY + 1) * numDivX;
        float points[] = new float[numVerts * pointSize];
        float texCoords[] = new float[numVerts * texCoordSize];
        int faceCount = subDivX * subDivY;
        int faces[][] = new int[faceCount][faceSize];

        // Create points and texCoords
        for (int y = 0; y <= subDivY; y++) {
            float dy = (float) y / subDivY;
            double fy = (1 - dy) * minY + dy * maxY;

            for (int x = 0; x <= subDivX; x++) {
                float dx = (float) x / subDivX;
                double fx = (1 - dx) * minX + dx * maxX;

                int index = y * numDivX * pointSize + (x * pointSize);
                points[index] = (float) fx;
                points[index + 1] = (float) fy;
                points[index + 2] = 0.0f;

                index = y * numDivX * texCoordSize + (x * texCoordSize);
                texCoords[index] = dx;
                texCoords[index + 1] = dy;
            }
        }

        // Create faces
        int index = 0;
        for (int y = 0; y < subDivY; y++) {
            for (int x = 0; x < subDivX; x++) {
                int p00 = y * numDivX + x;
                int p01 = p00 + 1;
                int p10 = p00 + numDivX;
                int p11 = p10 + 1;
                int tc00 = y * numDivX + x;
                int tc01 = tc00 + 1;
                int tc10 = tc00 + numDivX;
                int tc11 = tc10 + 1;

                faces[index][0] = p00;
                faces[index][1] = tc00;
                faces[index][2] = p10;
                faces[index][3] = tc10;
                faces[index][4] = p11;
                faces[index][5] = tc11;
                faces[index][6] = p01;
                faces[index++][7] = tc01;
            }
        }

        int[] smooth = new int[faceCount];

        PolygonMesh mesh = new PolygonMesh(points, texCoords, faces);
        mesh.getFaceSmoothingGroups().addAll(smooth);
        return mesh;
    }

    private PolygonMesh createCuboidMesh(float width, float height, float depth) {
        float L = 2f * width + 2f * depth;
        float H = height + 2f * depth;
        float hw = width/2f, hh = height/2f, hd = depth/2f;

        float[] points = new float[] {
                hw, hh, hd,             hw, hh, -hd,
                hw, -hh, hd,            hw, -hh, -hd,
                -hw, hh, hd,            -hw, hh, -hd,
                -hw, -hh, hd,           -hw, -hh, -hd
        };

        float[] texCoords = new float[] {
                depth / L, 0f,                              (depth + width) / L, 0f,
                0f, depth / H,                              depth / L, depth / H,
                (depth + width) / L, depth / H,             (2f * depth + width) / L, depth/H,
                1f, depth / H,                              0f, (depth + height) / H,
                depth / L, (depth + height)/H,              (depth + width) / L, (depth + height) / H,
                (2f * depth + width) / L, (depth + height) / H,  1f, (depth + height) / H,
                depth / L, 1f,                              (depth + width) / L, 1f
        };

        int[][] faces = new int[][] {
                {0, 8, 2, 3, 3, 2, 1, 7},
                {4, 9, 5, 10, 7, 5, 6, 4},
                {0, 8, 1, 12, 5, 13, 4, 9},
                {2, 3, 6, 4, 7, 1, 3, 0},
                {0, 8, 4, 9, 6, 4, 2, 3},
                {1, 11, 3, 6, 7, 5, 5, 10}
        };

        int[] smooth = new int[] {
                1, 2, 3, 4, 5, 6
        };

        PolygonMesh mesh = new PolygonMesh(points, texCoords, faces);
        mesh.getFaceSmoothingGroups().addAll(smooth);
        return mesh;
    }

    public double getDelta() {
        return delta;
    }

    public double getCameraRX() {
        return cameraRX;
    }

    public double getCameraRY() {
        return cameraRY;
    }

    public double getCameraRZ() {
        return cameraRZ;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy