Commit 2b8957aa authored by Ivan Dages's avatar Ivan Dages
Browse files

editor specific code imported from the common repository

parent 2bf5dda5
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
target/
nomad-3d-editor.log
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>nomad-3d-editor</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.ill.ics</groupId>
<artifactId>nomad-3d-editor</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Nomad 3D Editor</name>
<distributionManagement>
<repository>
<id>ill-repo</id>
<name>The ILL Maven Repository</name>
<url>https://maven.ill.fr/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>ill-repo</id>
<name>The ILL Maven Repository</name>
<url>https://maven.ill.fr/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<repositories>
<repository>
<id>ill-repo-thirdparty</id>
<url>https://maven.ill.fr/content/repositories/thirdparty</url>
</repository>
<repository>
<id>ill-repo-releases</id>
<url>https://maven.ill.fr/content/repositories/releases</url>
</repository>
<repository>
<id>ill-repo-snapshots</id>
<url>https://maven.ill.fr/content/repositories/snapshots</url>
</repository>
<repository>
<id>ill-repo-eclipse</id>
<url>https://maven.ill.fr/content/repositories/eclipse</url>
</repository>
</repositories>
<profiles>
<profile>
<id>jzmq</id>
<properties>
<zmq.implementation>jzmq</zmq.implementation>
</properties>
<dependencies>
<dependency>
<groupId>org.zeromq</groupId>
<artifactId>jzmq</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>jeromq</id>
<properties>
<zmq.implementation>jeromq</zmq.implementation>
</properties>
<dependencies>
<dependency>
<groupId>org.zeromq</groupId>
<artifactId>jeromq</artifactId>
<version>0.3.6</version>
</dependency>
</dependencies>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>fr.ill.ics</groupId>
<artifactId>nomadcommandsystem</artifactId>
<version>3.1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>fr.ill.ics</groupId>
<artifactId>nomad-3d-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Force the compilation with 1.8 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Assemble a single jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fr.ill.ics.n3d.Nomad3DEditor</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Build-Timestamp>${maven.build.timestamp}</Build-Timestamp>
<Implementation-Version>${project.version}</Implementation-Version>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>nomad-3d-editor-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package fr.ill.ics.n3d;
import java.io.File;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import fr.ill.ics.n3d.gui.AxisBuilder;
import fr.ill.ics.n3d.gui.CameraControls;
import fr.ill.ics.n3d.gui.EditorMenuBar;
import fr.ill.ics.n3d.gui.HierarchyCell;
import fr.ill.ics.n3d.io.Nomad3DImporter;
import fr.ill.ics.n3d.model.Component;
import fr.ill.ics.n3d.model.Model;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.AmbientLight;
import javafx.scene.Camera;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.ImageCursor;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.control.MenuBar;
import javafx.scene.control.TreeView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import fr.ill.ics.cameo.*;
/**
* Main class of the Nomad 3D Editor.
* @author dages
*/
public class Nomad3DEditor extends Application {
/** Stage of the application. */
public Stage stage = null;
/** Scene of the stage, managing the gui. The 3D scene is a descendant of this scene, inserted as a SubScene. */
public Scene scene = null;
/** Root of the scene (gui). */
public BorderPane pane = null;
/** Current Nomad 3D model. */
public Model model = null;
/** Camera used for 3D rendering. */
public Camera camera = null;
/** Controls managing the camera. */
public CameraControls controls = null;
/** Path to an eventual initial model to load, null otherwise. */
public String initialModelPath = null;
/** Axis builder. */
public AxisBuilder axisBuilder = new AxisBuilder();
/** Root of the 3D scene. */
public Group root = null;
/** 3D scene. */
public SubScene subScene = null;
/**
* Reference to the logger, used to prevent the garbage collector to destroy it.
* It happens when the editor is launched by the converter.
*/
@SuppressWarnings("unused")
private final Logger logger = Logger.getLogger("nomad-3d");
/** Mouse position, used when dragging the mouse. */
private Point2D mousePos = null;
/** Mouse old position, used when dragging the mouse. */
private Point2D mouseOldPos = null;
/** Mouse previous cursor. */
private Cursor mouseOldCursor = null;
/** Title of the editor's window. */
public final static String TITLE = "Nomad 3D editor";
/** Legth of the axes of the coordinate system (XYZ). */
private final static double AXIS_LENGTH = 50;
/**
* Main method.
* @param args Program arguments
*/
public static void main(String[] args) {
// fr.ill.ics.cameo.Application.This.init(args);
try {
launch(args);
} catch (Exception e) {
e.printStackTrace();
} finally {
// fr.ill.ics.cameo.Application.This.terminate();
}
}
@Override
public void start(Stage stage) throws Exception {
try {
Logger logger = Logger.getLogger("nomad-3d");
String logPath = System.getProperty("user.dir") + File.separator + "nomad-3d-editor.log";
FileHandler handler = new FileHandler(logPath);
handler.setFormatter(new SimpleFormatter());
logger.addHandler(handler);
logger.info("Logging into " + logPath + "\n");
} catch (Exception e) {
e.printStackTrace();
}
Logger.getLogger("nomad-3d").info("Starting " + TITLE + "... \n");
model = null;
this.scene = null;
if (initialModelPath == null) {
// -----------------
// --- 3D scene ---
// -----------------
this.root = new Group();
this.subScene = new SubScene(root, 1280, 720, true, SceneAntialiasing.BALANCED);
subScene.setFill(Color.color(0.5, 0.55, 0.65));
buildCamera();
// ---------------
// --- 2D gui ---
// ---------------
StackPane subScenePane = new StackPane(subScene);
subScenePane.setPrefSize(subScene.getWidth(), subScene.getHeight());
subScene.widthProperty().bind(subScenePane.widthProperty());
subScene.heightProperty().bind(subScenePane.heightProperty());
TreeView<Component> hierarchyView = buildHierarchyView();
pane = new BorderPane();
pane.setCenter(subScenePane);
pane.setTop(buildMenuBar());
pane.setLeft(hierarchyView);
scene = new Scene(pane);
scene.setFill(Color.WHITE);
buildEventHandlers(null);
} else {
scene = loadScene(initialModelPath);
}
this.stage = stage;
stage.setTitle(TITLE);
stage.setScene(scene);
stage.getIcons().add(Nomad3DImporter.createImage("img/nomadIcon.png"));
stage.show();
}
/**
* Loads a scene. The model is chosen by the user.
* @return The created scene
*/
public Scene loadScene() {
return loadScene(null);
}
/**
* Loads a scene.
* @param modelPath Path of the XML file of the model
* @return The created scene
*/
public Scene loadScene(String modelPath) {
Nomad3DImporter n3dImporter = new Nomad3DImporter();
if (modelPath != null) {
n3dImporter.read(modelPath);
} else {
n3dImporter.read();
}
if (n3dImporter.getModel().getRoot() != null) {
this.model = n3dImporter.getModel();
} else {
// No model loaded
return null;
}
this.root = new Group();
this.subScene = new SubScene(root, 1280, 720, true, SceneAntialiasing.BALANCED);
subScene.setFill(Color.color(0.5, 0.55, 0.65));
StackPane subScenePane = new StackPane(subScene);
subScenePane.setPrefSize(subScene.getWidth(), subScene.getHeight());
subScene.widthProperty().bind(subScenePane.widthProperty());
subScene.heightProperty().bind(subScenePane.heightProperty());
root.getChildren().add(model.getRoot().getSceneNode());
Group axesGroup = buildAxes();
root.getChildren().add(axesGroup);
buildLights();
buildCamera();
TreeView<Component> hierarchyView = buildHierarchyView();
this.pane = new BorderPane();
pane.setTop(buildMenuBar());
pane.setCenter(subScenePane);
pane.setLeft(hierarchyView);
this.scene = new Scene(pane);
scene.setFill(Color.WHITE);
buildEventHandlers(axesGroup);
return scene;
}
/**
* Builds the menu bar.
* @return The menu bar
*/
private MenuBar buildMenuBar() {
MenuBar menuBar = new EditorMenuBar(this);
return menuBar;
}
/**
* Builds the hierarchy view.
* @return The trre view.
*/
private TreeView<Component> buildHierarchyView() {
TreeView<Component> hierarchyView = (model != null && model.getRoot() != null) ? new TreeView<Component>(model.getRoot().getTreeItem()) : new TreeView<Component>();
hierarchyView.setEditable(true);
hierarchyView.setMinWidth(100);
hierarchyView.setPrefWidth(300);
hierarchyView.setMaxWidth(1000);
hierarchyView.setCellFactory(HierarchyCell.FACTORY);
return hierarchyView;
}
/**
* Builds the group for visualizing the coordinate system's axes (XYZ).
* @return The group of the axes
*/
private Group buildAxes() {
PhongMaterial redMaterial = new PhongMaterial();
redMaterial.setDiffuseColor(Color.RED);
redMaterial.setSpecularColor(Color.RED);
PhongMaterial greenMaterial = new PhongMaterial();
greenMaterial.setDiffuseColor(Color.GREEN);
greenMaterial.setSpecularColor(Color.GREEN);
PhongMaterial blueMaterial = new PhongMaterial();
blueMaterial.setDiffuseColor(Color.BLUE);
blueMaterial.setSpecularColor(Color.BLUE);
Box xAxis = new Box(AXIS_LENGTH, 1, 1);
xAxis.getTransforms().add(new Translate(AXIS_LENGTH/2, 0, 0));
Box yAxis = new Box(1, AXIS_LENGTH, 1);
yAxis.getTransforms().add(new Translate(0, AXIS_LENGTH/2, 0));
Box zAxis = new Box(1, 1, AXIS_LENGTH);
zAxis.getTransforms().add(new Translate(0, 0, AXIS_LENGTH/2));
xAxis.setMaterial(redMaterial);
yAxis.setMaterial(greenMaterial);
zAxis.setMaterial(blueMaterial);
Group axisGroup = new Group();
axisGroup.getChildren().addAll(xAxis, yAxis, zAxis);
axisGroup.setVisible(true);
// root.getChildren().add(axisGroup);
return axisGroup;
}
/**
* Builds the lights and adds them to the scene.
*/
private void buildLights() {
Bounds sceneBox = root.getBoundsInLocal();
root.getChildren().add(new AmbientLight(Color.color(0.3, 0.3, 0.3)));
Color pointColor = Color.color(0.5, 0.5, 0.5);
PointLight light = null;
double lightHeight = sceneBox.getMinY() + 1.1 * sceneBox.getHeight();
light = new PointLight(pointColor);
light.setTranslateX(sceneBox.getMinX());
light.setTranslateY(lightHeight);
light.setTranslateZ(sceneBox.getMinZ());
root.getChildren().add(light);
light = new PointLight(pointColor);
light.setTranslateX(sceneBox.getMaxX());
light.setTranslateY(lightHeight);
light.setTranslateZ(sceneBox.getMaxZ());
root.getChildren().add(light);
}
/**
* Builds the camera and attaches it to the scene.
*/
public void buildCamera() {
camera = new PerspectiveCamera();
camera.setNearClip(0.1);
camera.setFarClip(Double.MAX_VALUE);
subScene.setCamera(camera);
}
/**
* Sets up the events handlers of the gui scene and the 3D scene.
* @param axesGroup Coordinate system's axes' group
*/
private void buildEventHandlers(Group axesGroup) {
controls = new CameraControls();
controls.setTarget(camera);
controls.setCenterNode(axesGroup);
controls.update();
subScene.setOnMousePressed(me -> {
mousePos = new Point2D(me.getSceneX(), me.getSceneY());
mouseOldPos = new Point2D(me.getSceneX(), me.getSceneY());
mouseOldCursor = subScene.getCursor();
if (me.isMiddleButtonDown()) {
subScene.setCursor(new ImageCursor(Nomad3DImporter.createImage("img/rotate_cursor.png")));
} else if (me.isSecondaryButtonDown()) {
subScene.setCursor(new ImageCursor(Nomad3DImporter.createImage("img/translate_cursor.png")));
}
});
this.scene.setOnKeyPressed(event -> {
if (event.isShiftDown() || event.isControlDown() || event.isAltDown()) {
return;
}
if (event.getCode() == KeyCode.S) {
Component.selectOn = !Component.selectOn;
if (Component.selectOn && Component.unselectOn) {
Component.unselectOn = false;
}
}
if (event.getCode() == KeyCode.D) {
Component.unselectOn = !Component.unselectOn;
if (Component.selectOn && Component.unselectOn) {
Component.selectOn = false;
}
}
if (Component.selectOn) {
Cursor cursor = new ImageCursor(Nomad3DImporter.createImage("img/select_cursor.png"));
subScene.setCursor(cursor);
} else if (Component.unselectOn) {
Cursor cursor = new ImageCursor(Nomad3DImporter.createImage("img/unselect_cursor.png"));
subScene.setCursor(cursor);
} else {
subScene.setCursor(Cursor.DEFAULT);
}
});
subScene.setOnMouseReleased(me -> {
subScene.setCursor(mouseOldCursor);
});
subScene.setOnMouseDragged(me -> {
mouseOldPos = mousePos;
mousePos = new Point2D(me.getSceneX(), me.getSceneY());
Point2D delta = mousePos.subtract(mouseOldPos);
if (me.isMiddleButtonDown()) {
controls.rotate(delta, me.isControlDown(), me.isShiftDown());
} else if (me.isSecondaryButtonDown()) {
controls.translate(delta, me.isControlDown(), me.isShiftDown(), me.isAltDown());
axisBuilder.translate(controls.getCenter());
}
});
subScene.setOnScroll(se -> {
controls.zoom(se.getDeltaY(), se.isControlDown(), se.isShiftDown());
});
subScene.widthProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
controls.setResolution(new Point2D(newValue.doubleValue(), controls.getResolution().getY()));
controls.update();
}
});
subScene.heightProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
controls.setResolution(new Point2D(controls.getResolution().getX(), newValue.doubleValue()));
controls.update();
}
});
}
}