Skip to content
Snippets Groups Projects
Verified Commit 50665e88 authored by philippe.verley_ird.fr's avatar philippe.verley_ird.fr Committed by philippe.verley_ird.fr
Browse files

Updated the VoxToObj export function. Voxel size was (PAD/PADMax)^(1/3) and...

Updated the VoxToObj export function. Voxel size was (PAD/PADMax)^(1/3) and made it (PAD/PADMax)^alpha where alpha is set by user in the UI.
parent ac86caaa
No related branches found
No related tags found
No related merge requests found
...@@ -26,11 +26,10 @@ import java.util.Iterator; ...@@ -26,11 +26,10 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
...@@ -50,14 +49,14 @@ public class ObjExporterDialogController implements Initializable { ...@@ -50,14 +49,14 @@ public class ObjExporterDialogController implements Initializable {
private FileChooserContext fcVoxelFile = new FileChooserContext(); private FileChooserContext fcVoxelFile = new FileChooserContext();
private FileChooserContext fcOutputFile = new FileChooserContext(); private FileChooserContext fcOutputFile = new FileChooserContext();
private Stage stage; private Stage stage;
private List<Point3d> cubeVertices; private List<Point3d> cubeVertices;
private List<Point3i> faces; private List<Point3i> faces;
private Map<String, Point3f> materials; private Map<String, Point3f> materials;
private List<String> materialsKeys; private List<String> materialsKeys;
@FXML @FXML
private TextField textfieldInputVoxelFile; private TextField textfieldInputVoxelFile;
@FXML @FXML
...@@ -74,62 +73,72 @@ public class ObjExporterDialogController implements Initializable { ...@@ -74,62 +73,72 @@ public class ObjExporterDialogController implements Initializable {
private HBox hboxSizeFunctionOfPADParameters; private HBox hboxSizeFunctionOfPADParameters;
@FXML @FXML
private TextField textfieldPADMax; private TextField textfieldPADMax;
@FXML
private TextField textfieldAlpha;
//
private final String TITLE = "AMAPVox: VoxToObj export tool";
/** /**
* Initializes the controller class. * Initializes the controller class.
*/ */
@Override @Override
public void initialize(URL url, ResourceBundle rb) { public void initialize(URL url, ResourceBundle rb) {
fcVoxelFile = new FileChooserContext(); fcVoxelFile = new FileChooserContext();
comboboxGradient.getItems().addAll(Util.AVAILABLE_GRADIENT_COLOR_NAMES); comboboxGradient.getItems().addAll(Util.AVAILABLE_GRADIENT_COLOR_NAMES);
comboboxGradient.getSelectionModel().selectFirst(); comboboxGradient.getSelectionModel().selectFirst();
comboboxAttribute.getSelectionModel().selectFirst(); comboboxAttribute.getSelectionModel().selectFirst();
vboxMaterialParameters.disableProperty().bind(checkboxMaterial.selectedProperty().not()); vboxMaterialParameters.disableProperty().bind(checkboxMaterial.selectedProperty().not());
} }
@FXML @FXML
private void onActionButtonOpenVoxelFile(ActionEvent event) throws Exception { private void onActionButtonOpenVoxelFile(ActionEvent event) throws Exception {
File selectedFile = fcVoxelFile.showOpenDialog(stage); File selectedFile = fcVoxelFile.showOpenDialog(stage);
setVoxelFile(selectedFile); setVoxelFile(selectedFile);
} }
@FXML @FXML
private void onActionButtonExport(ActionEvent event) { private void onActionButtonExport(ActionEvent event) {
if (!textfieldInputVoxelFile.getText().isEmpty()) {
File voxFile = new File(textfieldInputVoxelFile.getText());
fcOutputFile.fc.setInitialDirectory(voxFile.getParentFile());
fcOutputFile.fc.setInitialFileName(replaceExtension(voxFile.getName(), "obj"));
}
File outputFile = fcOutputFile.showSaveDialog(stage); File outputFile = fcOutputFile.showSaveDialog(stage);
if(outputFile == null){
if (outputFile == null) {
return; return;
} }
cubeVertices = new ArrayList<>(); cubeVertices = new ArrayList<>();
faces = new ArrayList<>(); faces = new ArrayList<>();
VoxelFileRawReader reader; VoxelFileRawReader reader;
try { try {
reader = new VoxelFileRawReader(new File(textfieldInputVoxelFile.getText()), true); reader = new VoxelFileRawReader(new File(textfieldInputVoxelFile.getText()), true);
VoxelSpaceInfos infos = reader.getVoxelSpaceInfos(); VoxelSpaceInfos infos = reader.getVoxelSpaceInfos();
int padAttributeIndex = comboboxAttribute.getItems().indexOf("PadBVTotal")-3; int padAttributeIndex = comboboxAttribute.getItems().indexOf("PadBVTotal") - 3;
int selectedAttributeIndex = comboboxAttribute.getSelectionModel().getSelectedIndex()-3; int selectedAttributeIndex = comboboxAttribute.getSelectionModel().getSelectedIndex() - 3;
float padMax = Float.valueOf(textfieldPADMax.getText()); float padMax = Float.valueOf(textfieldPADMax.getText());
float alpha = Float.valueOf(textfieldAlpha.getText());
ColorGradient gradient = new ColorGradient(0, 0); ColorGradient gradient = new ColorGradient(0, 0);
if(checkboxMaterial.isSelected()){ if (checkboxMaterial.isSelected()) {
//find min and max //find min and max
Iterator<RawVoxel> iterator = reader.iterator(); Iterator<RawVoxel> iterator = reader.iterator();
Statistic attributeStat = new Statistic(); Statistic attributeStat = new Statistic();
while(iterator.hasNext()){ while (iterator.hasNext()) {
RawVoxel voxel = iterator.next(); RawVoxel voxel = iterator.next();
switch (selectedAttributeIndex) { switch (selectedAttributeIndex) {
case -3: case -3:
attributeStat.addValue(voxel.$i); attributeStat.addValue(voxel.$i);
...@@ -144,31 +153,30 @@ public class ObjExporterDialogController implements Initializable { ...@@ -144,31 +153,30 @@ public class ObjExporterDialogController implements Initializable {
attributeStat.addValue(voxel.attributs[selectedAttributeIndex]); attributeStat.addValue(voxel.attributs[selectedAttributeIndex]);
break; break;
} }
} }
gradient = new ColorGradient((float)attributeStat.getMinValue(), (float)attributeStat.getMaxValue()); gradient = new ColorGradient((float) attributeStat.getMinValue(), (float) attributeStat.getMaxValue());
gradient.setGradientColor(Util.AVAILABLE_GRADIENT_COLORS.get(comboboxGradient.getSelectionModel().getSelectedIndex())); gradient.setGradientColor(Util.AVAILABLE_GRADIENT_COLORS.get(comboboxGradient.getSelectionModel().getSelectedIndex()));
materials = new HashMap<>(); materials = new HashMap<>();
materialsKeys = new ArrayList<>(); materialsKeys = new ArrayList<>();
} }
Iterator<RawVoxel> iterator = reader.iterator(); Iterator<RawVoxel> iterator = reader.iterator();
while(iterator.hasNext()){ while (iterator.hasNext()) {
RawVoxel voxel = iterator.next(); RawVoxel voxel = iterator.next();
if(!Float.isNaN(voxel.attributs[padAttributeIndex]) && voxel.attributs[padAttributeIndex] != 0){ if (!Float.isNaN(voxel.attributs[padAttributeIndex]) && voxel.attributs[padAttributeIndex] != 0) {
Point3d position = getPosition(new Point3i(voxel.$i, voxel.$j, voxel.$k), infos); Point3d position = getPosition(new Point3i(voxel.$i, voxel.$j, voxel.$k), infos);
if (checkboxMaterial.isSelected()) {
if(checkboxMaterial.isSelected()){
Color c; Color c;
switch (selectedAttributeIndex) { switch (selectedAttributeIndex) {
case -3: case -3:
c = gradient.getColor(voxel.$i); c = gradient.getColor(voxel.$i);
...@@ -182,46 +190,45 @@ public class ObjExporterDialogController implements Initializable { ...@@ -182,46 +190,45 @@ public class ObjExporterDialogController implements Initializable {
default: default:
c = gradient.getColor(voxel.attributs[selectedAttributeIndex]); c = gradient.getColor(voxel.attributs[selectedAttributeIndex]);
break; break;
} }
float red = c.getRed() / 255.0f; float red = c.getRed() / 255.0f;
float green = c.getGreen() / 255.0f; float green = c.getGreen() / 255.0f;
float blue = c.getBlue() / 255.0f; float blue = c.getBlue() / 255.0f;
String key = String.valueOf(red)+"_"+String.valueOf(green)+"_"+String.valueOf(blue); String key = String.valueOf(red) + "_" + String.valueOf(green) + "_" + String.valueOf(blue);
materials.put(key, new Point3f(red, green, blue)); materials.put(key, new Point3f(red, green, blue));
materialsKeys.add(key); materialsKeys.add(key);
} }
float voxelSize; float voxelSize;
if(checkboxSizeFunctionOfPAD.isSelected()){ if (checkboxSizeFunctionOfPAD.isSelected()) {
float padValue = voxel.attributs[padAttributeIndex]; float padValue = voxel.attributs[padAttributeIndex];
voxelSize = (float) (infos.getResolution() * Math.pow(padValue/padMax, 1/3.0)); voxelSize = (float) (infos.getResolution() * Math.pow(padValue / padMax, alpha));
}else{ } else {
voxelSize = infos.getResolution(); voxelSize = infos.getResolution();
} }
createCube(voxelSize, position); createCube(voxelSize, position);
} }
} }
} catch (Exception ex) { } catch (Exception ex) {
DialogHelper.showErrorDialog(stage, ex); DialogHelper.showErrorDialog(stage, ex);
return; return;
} }
int extensionBeginIndex = outputFile.getAbsolutePath().lastIndexOf("."); File materialFile = new File(replaceExtension(outputFile.getAbsolutePath(), "mtl"));
File materialFile = new File(outputFile.getAbsolutePath().substring(0, extensionBeginIndex)+".mtl");
try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) { try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile))) {
if(checkboxMaterial.isSelected()){ if (checkboxMaterial.isSelected()) {
writer.write("mtllib "+materialFile.getName()+"\n"); writer.write("mtllib " + materialFile.getName() + "\n");
} }
for (Point3d point : cubeVertices) { for (Point3d point : cubeVertices) {
writer.write("v " + point.x + " " + point.y + " " + point.z + "\n"); writer.write("v " + point.x + " " + point.y + " " + point.z + "\n");
} }
...@@ -231,33 +238,32 @@ public class ObjExporterDialogController implements Initializable { ...@@ -231,33 +238,32 @@ public class ObjExporterDialogController implements Initializable {
for (Point3i face : faces) { for (Point3i face : faces) {
if(checkboxMaterial.isSelected()){ if (checkboxMaterial.isSelected()) {
if (count == 0) { if (count == 0) {
writer.write("usemtl Material." + getValueIndex(materialsKeys.get(matIndex)) + "\n"); writer.write("usemtl Material." + getValueIndex(materialsKeys.get(matIndex)) + "\n");
matIndex++; matIndex++;
count = 12; count = 12;
} }
count--; count--;
} }
writer.write("f " + face.x + " " + face.y + " " + face.z + "\n"); writer.write("f " + face.x + " " + face.y + " " + face.z + "\n");
} }
} catch (IOException ex) { } catch (IOException ex) {
DialogHelper.showErrorDialog(stage, new IOException("Cannot write obj file", ex)); DialogHelper.showErrorDialog(stage, new IOException("Cannot write obj file", ex));
return; return;
} }
if(checkboxMaterial.isSelected()){ if (checkboxMaterial.isSelected()) {
try{ try {
BufferedWriter materialWriter = new BufferedWriter(new FileWriter(materialFile)); BufferedWriter materialWriter = new BufferedWriter(new FileWriter(materialFile));
int count = 0; int count = 0;
Iterator<Map.Entry<String, Point3f>> iterator = materials.entrySet().iterator(); Iterator<Map.Entry<String, Point3f>> iterator = materials.entrySet().iterator();
while(iterator.hasNext()){ while (iterator.hasNext()) {
Map.Entry<String, Point3f> next = iterator.next(); Map.Entry<String, Point3f> next = iterator.next();
Point3f material = next.getValue(); Point3f material = next.getValue();
...@@ -273,81 +279,101 @@ public class ObjExporterDialogController implements Initializable { ...@@ -273,81 +279,101 @@ public class ObjExporterDialogController implements Initializable {
count++; count++;
} }
materialWriter.close(); materialWriter.close();
}catch(IOException ex){ } catch (IOException ex) {
DialogHelper.showErrorDialog(stage, new IOException("Cannot write material file", ex)); DialogHelper.showErrorDialog(stage, new IOException("Cannot write material file", ex));
} }
}
Alert success = new Alert(Alert.AlertType.INFORMATION);
success.setTitle(TITLE);
StringBuilder sb = new StringBuilder();
sb.append("Created file(s)\n");
sb.append('\t').append(outputFile);
if (checkboxMaterial.isSelected()) {
sb.append("\n\t").append(materialFile);
} }
success.setContentText(sb.toString());
success.setResizable(true);
success.getDialogPane().setPrefSize(500, 200);
success.initOwner(stage);
success.showAndWait();
}
private String replaceExtension(String file, String extension) {
int extensionBeginIndex = file.lastIndexOf(".");
return file.substring(0, extensionBeginIndex) + "." + extension;
} }
private void createCube(float size, Point3d translation){ private void createCube(float size, Point3d translation) {
cubeVertices.add(new Point3d(size/2.0f+translation.x, size/2.0f+translation.y, -size/2.0f+translation.z)); cubeVertices.add(new Point3d(size / 2.0f + translation.x, size / 2.0f + translation.y, -size / 2.0f + translation.z));
cubeVertices.add(new Point3d(size/2.0f+translation.x, -size/2.0f+translation.y, -size/2.0f+translation.z)); cubeVertices.add(new Point3d(size / 2.0f + translation.x, -size / 2.0f + translation.y, -size / 2.0f + translation.z));
cubeVertices.add(new Point3d(-size/2.0f+translation.x, -size/2.0f+translation.y, -size/2.0f+translation.z)); cubeVertices.add(new Point3d(-size / 2.0f + translation.x, -size / 2.0f + translation.y, -size / 2.0f + translation.z));
cubeVertices.add(new Point3d(-size/2.0f+translation.x, size/2.0f+translation.y, -size/2.0f+translation.z)); cubeVertices.add(new Point3d(-size / 2.0f + translation.x, size / 2.0f + translation.y, -size / 2.0f + translation.z));
cubeVertices.add(new Point3d(size/2.0f+translation.x, size/2.0f+translation.y, size/2.0f+translation.z)); cubeVertices.add(new Point3d(size / 2.0f + translation.x, size / 2.0f + translation.y, size / 2.0f + translation.z));
cubeVertices.add(new Point3d(size/2.0f+translation.x, -size/2.0f+translation.y, size/2.0f+translation.z)); cubeVertices.add(new Point3d(size / 2.0f + translation.x, -size / 2.0f + translation.y, size / 2.0f + translation.z));
cubeVertices.add(new Point3d(-size/2.0f+translation.x, -size/2.0f+translation.y, size/2.0f+translation.z)); cubeVertices.add(new Point3d(-size / 2.0f + translation.x, -size / 2.0f + translation.y, size / 2.0f + translation.z));
cubeVertices.add(new Point3d(-size/2.0f+translation.x, size/2.0f+translation.y, size/2.0f+translation.z)); cubeVertices.add(new Point3d(-size / 2.0f + translation.x, size / 2.0f + translation.y, size / 2.0f + translation.z));
int currentOffset = cubeVertices.size() - 7; int currentOffset = cubeVertices.size() - 7;
faces.add(new Point3i(currentOffset+0, currentOffset+1, currentOffset+2)); faces.add(new Point3i(currentOffset + 0, currentOffset + 1, currentOffset + 2));
faces.add(new Point3i(currentOffset+4, currentOffset+7, currentOffset+6)); faces.add(new Point3i(currentOffset + 4, currentOffset + 7, currentOffset + 6));
faces.add(new Point3i(currentOffset+0, currentOffset+4, currentOffset+5)); faces.add(new Point3i(currentOffset + 0, currentOffset + 4, currentOffset + 5));
faces.add(new Point3i(currentOffset+1, currentOffset+5, currentOffset+6)); faces.add(new Point3i(currentOffset + 1, currentOffset + 5, currentOffset + 6));
faces.add(new Point3i(currentOffset+2, currentOffset+6, currentOffset+7)); faces.add(new Point3i(currentOffset + 2, currentOffset + 6, currentOffset + 7));
faces.add(new Point3i(currentOffset+4, currentOffset+0, currentOffset+3)); faces.add(new Point3i(currentOffset + 4, currentOffset + 0, currentOffset + 3));
faces.add(new Point3i(currentOffset+3, currentOffset+0, currentOffset+2)); faces.add(new Point3i(currentOffset + 3, currentOffset + 0, currentOffset + 2));
faces.add(new Point3i(currentOffset+5, currentOffset+4, currentOffset+6)); faces.add(new Point3i(currentOffset + 5, currentOffset + 4, currentOffset + 6));
faces.add(new Point3i(currentOffset+1, currentOffset+0, currentOffset+5)); faces.add(new Point3i(currentOffset + 1, currentOffset + 0, currentOffset + 5));
faces.add(new Point3i(currentOffset+2, currentOffset+1, currentOffset+6)); faces.add(new Point3i(currentOffset + 2, currentOffset + 1, currentOffset + 6));
faces.add(new Point3i(currentOffset+3, currentOffset+2, currentOffset+7)); faces.add(new Point3i(currentOffset + 3, currentOffset + 2, currentOffset + 7));
faces.add(new Point3i(currentOffset+7, currentOffset+4, currentOffset+3)); faces.add(new Point3i(currentOffset + 7, currentOffset + 4, currentOffset + 3));
} }
private Point3d getPosition(Point3i indices, VoxelSpaceInfos infos) { private Point3d getPosition(Point3i indices, VoxelSpaceInfos infos) {
double posX = infos.getMinCorner().x + (infos.getResolution() / 2.0d) + (indices.x * infos.getResolution()); double posX = infos.getMinCorner().x + (infos.getResolution() / 2.0d) + (indices.x * infos.getResolution());
double posY = infos.getMinCorner().y + (infos.getResolution() / 2.0d) + (indices.y * infos.getResolution()); double posY = infos.getMinCorner().y + (infos.getResolution() / 2.0d) + (indices.y * infos.getResolution());
double posZ = infos.getMinCorner().z + (infos.getResolution() / 2.0d) + (indices.z * infos.getResolution()); double posZ = infos.getMinCorner().z + (infos.getResolution() / 2.0d) + (indices.z * infos.getResolution());
return new Point3d(posX, posY, posZ); return new Point3d(posX, posY, posZ);
} }
private int getValueIndex(String key){ private int getValueIndex(String key) {
Iterator<Map.Entry<String, Point3f>> iterator1 = materials.entrySet().iterator(); Iterator<Map.Entry<String, Point3f>> iterator1 = materials.entrySet().iterator();
int count = 0; int count = 0;
while(iterator1.hasNext()){ while (iterator1.hasNext()) {
Map.Entry<String, Point3f> next = iterator1.next(); Map.Entry<String, Point3f> next = iterator1.next();
if(next.getKey().equals(key)){ if (next.getKey().equals(key)) {
return count; return count;
} }
count++; count++;
} }
return -1; return -1;
} }
public void setStage(Stage stage){ public void setStage(Stage stage) {
this.stage =stage; this.stage = stage;
this.stage.setTitle(TITLE);
} }
public Stage getStage() { public Stage getStage() {
return stage; return stage;
} }
public void setVoxelFile(File voxelFile) throws Exception{ public void setVoxelFile(File voxelFile) throws Exception {
textfieldInputVoxelFile.setText(voxelFile.getAbsolutePath()); textfieldInputVoxelFile.setText(voxelFile.getAbsolutePath());
try { try {
VoxelFileReader reader = new VoxelFileReader(voxelFile); VoxelFileReader reader = new VoxelFileReader(voxelFile);
......
...@@ -8,9 +8,10 @@ ...@@ -8,9 +8,10 @@
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.geometry.Insets?>
<AnchorPane id="AnchorPane" prefHeight="253.0" prefWidth="437.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:controller="fr.amap.lidar.amapvox.gui.export.ObjExporterDialogController"> <AnchorPane id="AnchorPane" prefHeight="300.0" prefWidth="450.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:controller="fr.amap.lidar.amapvox.gui.export.ObjExporterDialogController">
<children> <children>
<VBox layoutX="14.0" layoutY="29.0" spacing="20.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0"> <VBox layoutX="14.0" layoutY="29.0" spacing="20.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0">
<children> <children>
...@@ -25,17 +26,22 @@ ...@@ -25,17 +26,22 @@
</HBox> </HBox>
</children> </children>
</VBox> </VBox>
<HBox alignment="CENTER_LEFT" spacing="15.0"> <VBox alignment="CENTER_LEFT" spacing="15.0">
<children> <children>
<CheckBox fx:id="checkboxSizeFunctionOfPAD" mnemonicParsing="false" text="Size function of PAD" /> <CheckBox fx:id="checkboxSizeFunctionOfPAD" mnemonicParsing="false" text="Size function of PAD (PAD/PADMax)^alpha" />
<HBox fx:id="hboxSizeFunctionOfPADParameters" alignment="CENTER_LEFT"> <HBox fx:id="hboxSizeFunctionOfPADParameters" alignment="CENTER_LEFT" spacing="10.0">
<children> <children>
<Label text="PAD max" /> <Label text="PAD max" />
<TextField fx:id="textfieldPADMax" prefHeight="26.0" prefWidth="54.0" text="5" /> <TextField fx:id="textfieldPADMax" prefHeight="26.0" prefWidth="54.0" text="5" />
<Label text="alpha" />
<TextField fx:id="textfieldAlpha" prefHeight="26.0" prefWidth="108.0" text="0.33333333" />
</children> </children>
<padding>
<Insets left="20.0" />
</padding>
</HBox> </HBox>
</children> </children>
</HBox> </VBox>
<HBox alignment="CENTER_LEFT" spacing="20.0"> <HBox alignment="CENTER_LEFT" spacing="20.0">
<children> <children>
<CheckBox fx:id="checkboxMaterial" mnemonicParsing="false" selected="true" text="Write material" /> <CheckBox fx:id="checkboxMaterial" mnemonicParsing="false" selected="true" text="Write material" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment