2017-01-26 2 views
1

Looking this post、私は多くの困難を伴うjavaFXで実装しようとしました。散布図3Dはx、y、z軸です。私のポイント。3D散布図JavaFX:軸の近くで凡例と尺度を表示する方法

どのように凡例、軸ラベル、および範囲番号を軸に沿って配置できますか?私は外部ライブラリなしでjavaFXのみを使用できます。 私は絶望している..私は日中にしようとしている...結果なし してください:助けてください ありがとう。

コード

import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 
import javafx.application.Application; 
import javafx.event.EventHandler; 
import javafx.scene.Group; 
import javafx.scene.PerspectiveCamera; 
import javafx.scene.Scene; 
import javafx.scene.SceneAntialiasing; 
import javafx.scene.input.ScrollEvent; 
import javafx.scene.layout.Pane; 
import javafx.scene.layout.StackPane; 
import javafx.scene.paint.Color; 
import javafx.scene.paint.Paint; 
import javafx.scene.paint.PhongMaterial; 
import javafx.scene.shape.Line; 
import javafx.scene.shape.Rectangle; 
import javafx.scene.shape.Sphere; 
import javafx.scene.transform.Rotate; 
import javafx.stage.Stage; 

public class GraphingData extends Application { 

    private static Random rnd = new Random(); 

    // size of graph 
    int graphSize = 400; 

    // variables for mouse interaction 
    private double mousePosX, mousePosY; 
    private double mouseOldX, mouseOldY; 

    private final Rotate rotateX = new Rotate(150, Rotate.X_AXIS); 
    private final Rotate rotateY = new Rotate(120, Rotate.Y_AXIS); 

    @Override 
    public void start(Stage primaryStage) { 

     // create axis walls 
     Group grid = createGrid(graphSize); 

     // initial cube rotation 
     grid.getTransforms().addAll(rotateX, rotateY); 

     // add objects to scene 
     StackPane root = new StackPane(); 
     root.getChildren().add(grid); 

     root.setStyle("-fx-border-color: red;"); 
     // create bars 
     double gridSizeHalf = graphSize/2; 
     double size = 30; 

     //Drawing a Sphere 
     Sphere sphere = new Sphere(); 

     //Setting the properties of the Sphere 
     sphere.setRadius(10.0); 

     sphere.setTranslateX(-50); 
     sphere.setTranslateY(-50);  

     //Preparing the phong material of type specular color 
     PhongMaterial material6 = new PhongMaterial(); 

     //setting the specular color map to the material 
     material6.setDiffuseColor(Color.GREEN); 

     sphere.setMaterial(material6); 

     grid.getChildren().addAll(sphere); 

     // scene 
     Scene scene = new Scene(root, 1600, 900, true, SceneAntialiasing.BALANCED); 
     scene.setCamera(new PerspectiveCamera()); 

     scene.setOnMousePressed(me -> { 
      mouseOldX = me.getSceneX(); 
      mouseOldY = me.getSceneY(); 
     }); 
     scene.setOnMouseDragged(me -> { 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY)); 
      rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX)); 
      mouseOldX = mousePosX; 
      mouseOldY = mousePosY; 

     }); 

     makeZoomable(root); 

     primaryStage.setResizable(false); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

    } 

    /** 
    * Axis wall 
    */ 
    public static class Axis extends Pane { 

     Rectangle wall; 

     public Axis(double size) { 

      // wall 
      // first the wall, then the lines => overlapping of lines over walls 
      // works 
      wall = new Rectangle(size, size); 
      getChildren().add(wall); 

      // grid 
      double zTranslate = 0; 
      double lineWidth = 1.0; 
      Color gridColor = Color.RED; 

      for (int y = 0; y <= size; y += size/10) { 

       Line line = new Line(0, 0, size, 0); 
       line.setStroke(gridColor); 
       line.setFill(gridColor); 
       line.setTranslateY(y); 
       line.setTranslateZ(zTranslate); 
       line.setStrokeWidth(lineWidth); 

       getChildren().addAll(line); 

      } 

      for (int x = 0; x <= size; x += size/10) { 

       Line line = new Line(0, 0, 0, size); 
       line.setStroke(gridColor); 
       line.setFill(gridColor); 
       line.setTranslateX(x); 
       line.setTranslateZ(zTranslate); 
       line.setStrokeWidth(lineWidth); 

       getChildren().addAll(line); 

      } 

     } 

     public void setFill(Paint paint) { 
      wall.setFill(paint); 
     } 

    } 

    public void makeZoomable(StackPane control) { 

     final double MAX_SCALE = 20.0; 
     final double MIN_SCALE = 0.1; 

     control.addEventFilter(ScrollEvent.ANY, new EventHandler<ScrollEvent>() { 

      @Override 
      public void handle(ScrollEvent event) { 

       double delta = 1.2; 

       double scale = control.getScaleX(); 

       if (event.getDeltaY() < 0) { 
        scale /= delta; 
       } else { 
        scale *= delta; 
       } 

       scale = clamp(scale, MIN_SCALE, MAX_SCALE); 

       control.setScaleX(scale); 
       control.setScaleY(scale); 

       event.consume(); 

      } 

     }); 

    } 

    /** 
    * Create axis walls 
    * 
    * @param size 
    * @return 
    */ 
    private Group createGrid(int size) { 

     Group cube = new Group(); 

     // size of the cube 
     Color color = Color.LIGHTGRAY; 

     List<Axis> cubeFaces = new ArrayList<>(); 
     Axis r; 

     // back face 
     r = new Axis(size); 
     r.setFill(color.deriveColor(0.0, 1.0, (1 - 0.5 * 1), 1.0)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(-0.5 * size); 
     r.setTranslateZ(0.5 * size); 

     cubeFaces.add(r); 

     // bottom face 
     r = new Axis(size); 
     r.setFill(color.deriveColor(0.0, 1.0, (1 - 0.4 * 1), 1.0)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(0); 
     r.setRotationAxis(Rotate.X_AXIS); 
     r.setRotate(90); 

     cubeFaces.add(r); 

     // right face 
     r = new Axis(size); 
     r.setFill(color.deriveColor(0.0, 1.0, (1 - 0.3 * 1), 1.0)); 
     r.setTranslateX(-1 * size); 
     r.setTranslateY(-0.5 * size); 
     r.setRotationAxis(Rotate.Y_AXIS); 
     r.setRotate(90); 

     // cubeFaces.add(r); 

     // left face 
     r = new Axis(size); 
     r.setFill(color.deriveColor(0.0, 1.0, (1 - 0.2 * 1), 1.0)); 
     r.setTranslateX(0); 
     r.setTranslateY(-0.5 * size); 
     r.setRotationAxis(Rotate.Y_AXIS); 
     r.setRotate(90); 

     cubeFaces.add(r); 

     // top face 
     r = new Axis(size); 
     r.setFill(color.deriveColor(0.0, 1.0, (1 - 0.1 * 1), 1.0)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(-1 * size); 
     r.setRotationAxis(Rotate.X_AXIS); 
     r.setRotate(90); 

     // cubeFaces.add(r); 

     // front face 
     r = new Axis(size); 
     r.setFill(color.deriveColor(0.0, 1.0, (1 - 0.1 * 1), 1.0)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(-0.5 * size); 
     r.setTranslateZ(-0.5 * size); 

     // cubeFaces.add(r); 

     cube.getChildren().addAll(cubeFaces); 

     return cube; 
    } 

    public static double normalizeValue(double value, double min, double max, double newMin, double newMax) { 

     return (value - min) * (newMax - newMin)/(max - min) + newMin; 

    } 

    public static double clamp(double value, double min, double max) { 

     if (Double.compare(value, min) < 0) 
      return min; 

     if (Double.compare(value, max) > 0) 
      return max; 

     return value; 
    } 

    public static Color randomColor() { 
     return Color.rgb(rnd.nextInt(255), rnd.nextInt(255), rnd.nextInt(255)); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+1

http:// stackoverflowと同じです。com/questions/41873073/javafx-3d-how-to-put-a-legend-axis-labels-and-numbers-the-axis? –

+0

@James_D私たちは一緒にプロジェクトを行っています。質問は同じです –

+0

@James_Dあなたは私たちを助けることができますか? –

答えて

1

はここ軸上のいくつかの措置を作成するための基本的な考え方です。プロダクションの準備はできていませんが、始めるには十分なものを提供する必要があります。

private Group createGrid(int size) { 

    // existing code omitted... 

    cube.getChildren().addAll(cubeFaces); 


    double gridSizeHalf = size/2; 
    double labelOffset = 30 ; 
    double labelPos = gridSizeHalf - labelOffset ; 

    for (double coord = -gridSizeHalf ; coord < gridSizeHalf ; coord+=50) { 
     Text xLabel = new Text(coord, labelPos, String.format("%.0f", coord)); 
     xLabel.setTranslateZ(labelPos); 
     xLabel.setScaleX(-1); 
     Text yLabel = new Text(labelPos, coord, String.format("%.0f", coord)); 
     yLabel.setTranslateZ(labelPos); 
     yLabel.setScaleX(-1); 
     Text zLabel = new Text(labelPos, labelPos, String.format("%.0f", coord)); 
     zLabel.setTranslateZ(coord); 
     cube.getChildren().addAll(xLabel, yLabel, zLabel); 
     zLabel.setScaleX(-1); 
    } 

    return cube; 
} 

私はちょうど私がこの質問が古くなっているが、JavaFXの3Dシーンで2Dのラベルがある知っている...だけで回転していない2Dグリッドペインれるであろう、グラフの外

+0

ありがとうございました!とても便利でした。私は2Dの伝説を入れようとしました。[ディスカッションを読む](http://stackoverflow.com/questions/28628702/javafx-2d-part-in-3d-application)残念ながら、それは私の失敗のテストのリンクです。[リンク1](http://pastebin.com/vG16c4QV)と[インク2](http://pastebin.com/tU3UMhQX)です。どのように編集して修正できますか? –

+0

このようなラベルを翻訳すると、3D空間に2Dラベルが表示され、カメラを移動するまで正しく表示されます。移動または回転しない散布図が必要な場合は、これで問題ありません。他にも、カメラを動かすたびに2Dラベルを自動的に変換する必要があります。 (つまり...マウスハンドラ)。 – Birdasaur

+0

@Birdasaurええ、公正な点。私が正しく覚えていれば、以前のバージョンの 'Camera'は移動できませんでした(' Node'のサブクラスではなく、シーングラフに追加できませんでした)。シーンにカメラを設定するだけです。あなたが物事を相対的に動かしたければ、シーンのルート(またはその一部)に変換を適用します。 'SubScene'クラスもありませんでした。 JavaFXで3Dを使った私の実験の大半は、カメラを動かす前に行われていたので、シーングラフのさまざまな部分を独立して変える必要がありました。しかし、あなたのアプローチは現在のバージョンで正しいように見えます。 –

0

を凡例を置きますトピックがたくさん出てきて、「正しい方法」と答えたことは決してありません。

James_Dのようなラベルを翻訳すると、カメラを動かすまで正しいと思われる2Dラベルが3D空間に変換されます。移動または回転しない散布図が必要な場合は、これで問題ありません。他にも、カメラを動かすたびに2Dラベルを自動的に変換する必要があります。 (つまり...マウスハンドラ)。散布図を削除してその都度シーン全体に読み込むことができますが、それはヒープメモリを殺すことになり、実際の有用なサイズのデータ​​セットでは実現できません。

正しい方法は、各レンダリングループのパスでラベルを再描画するOpenGLまたはDirectDrawのテキストレンダリングを使用することですが、JavaFX 3Dはアクセス権を(現在)提供していません。したがって、「JavaFXの正しい方法」は、3Dラベルの上に2Dラベルを浮かべて、カメラが動くたびにそれらを翻訳することです。これには、ラベルを2Dスクリーンプロジェクションにする3D位置の3D座標投影を変換する必要があります。

ノードは、3Dサブシーンで、すでにいくつかの実際の3Dオブジェクトである
Point3D coordinates = node.localToScene(javafx.geometry.Point3D.ZERO); 
SubScene oldSubScene = NodeHelper.getSubScene(node); 
coordinates = SceneUtils.subSceneToScene(oldSubScene, coordinates); 
double x = coordinates.getX(); 
double y = coordinates.getY(); 
label.getTransforms().setAll(new Translate(x, y)); 

:一般的に次に沿って変換を実行する必要がありJavaFXの3DでたPoint3Dに接続された2Dのラベルを管理するために

。私のアプリケーションでは、非常に小さいサイズのSphereを使用するだけでは見えません。 James_Dの例に従うならば、元の軸ラベルを翻訳したのと同じ場所に球体を翻訳することができます。 ラベルは標準のJavaFX 2Dラベルで、シーンに追加します。通常は、StackPaneを通じてラベルが3Dサブセンダ上に浮かびます。

カメラが移動/回転するたびに、このトランスフォームが呼び出され、ラベルが2Dレイヤー上をスライドします。基礎となるGLまたはDD呼び出しに直接アクセスすることなく、これはJavaFX 3Dでこれを行う唯一の方法ですが、かなりうまく機能します。

ここにはvideo exampleが有効です。 浮動小数点ラベルの単純版を実装するopen source exampleがあります。 (警告、私はサンプルの寄稿者であり、図書館を宣伝しようとしていません)

関連する問題