diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java index 0d5cc0263693ef4f247b9d324736cec5239060ce..e30af5c6a5f36e108a803273501ebd48972dab74 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java @@ -2,7 +2,7 @@ package cz.fidentis.analyst.face; import com.google.common.eventbus.EventBus; import cz.fidentis.analyst.feature.FeaturePoint; -import cz.fidentis.analyst.feature.services.FeaturePointImportExportService; +import cz.fidentis.analyst.feature.services.FeaturePointImportService; import cz.fidentis.analyst.kdtree.KdTree; import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshModel; @@ -192,7 +192,7 @@ public class HumanFace implements MeshListener, Serializable { * @throws IOException on I/O failure */ public void loadFeaturePoints(String path, String fileName) throws IOException { - featurePoints = FeaturePointImportExportService.importFeaturePoints(path, fileName); + featurePoints = FeaturePointImportService.importFeaturePoints(path, fileName); } /** diff --git a/MeshModel/jshell.history b/MeshModel/jshell.history deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/MeshModel/pom.xml b/MeshModel/pom.xml index 30c08349b3c8de392e7d5d5a87ab5812566adc4d..a6a4b8901ec6842b63a02cb8f213c096d9a5ea09 100644 --- a/MeshModel/pom.xml +++ b/MeshModel/pom.xml @@ -126,6 +126,13 @@ <artifactId>opencsv</artifactId> <version>5.3</version> </dependency> + <!-- https://mvnrepository.com/artifact/javax.xml/jaxb-api --> + <dependency> + <groupId>javax.xml</groupId> + <artifactId>jaxb-api</artifactId> + <version>2.1</version> + </dependency> + </dependencies> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePoint.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePoint.java index 5de5f0f781d9b96e91f0c3dd8d023e4443c619a7..11fd16fb231fc3a268628d255db2aad1edc38f11 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePoint.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePoint.java @@ -1,34 +1,35 @@ package cz.fidentis.analyst.feature; import java.io.Serializable; +import java.util.Objects; import javax.vecmath.Point3d; /** * - * @author kubok + * @author Jakub Kolman */ public class FeaturePoint implements Serializable { private final Point3d position; - private final FeaturePointType FEATURE_POINT_TYPE; + private final FeaturePointType featurePointType; /** * Constructor. - * - * @param x Location x + * + * @param x Location x * @param y Location y * @param z Location z * @param featurePointType Original type */ public FeaturePoint(double x, double y, double z, FeaturePointType featurePointType) { this.position = new Point3d(x, y, z); - this.FEATURE_POINT_TYPE = featurePointType; + this.featurePointType = featurePointType; } - + public Point3d getPosition() { return position; } - + public double getX() { return position.x; } @@ -42,6 +43,44 @@ public class FeaturePoint implements Serializable { } public FeaturePointType getFeaturePointType() { - return FEATURE_POINT_TYPE; + return featurePointType; + } + + @Override + public boolean equals(Object o) { + // self check + if (this == o) { + return true; + } + // null check + if (o == null) { + return false; + } + // type check and cast + if (getClass() != o.getClass()) { + return false; + } + FeaturePoint fp = (FeaturePoint) o; + // field comparison + return Objects.equals(position.x, fp.position.x) + && Objects.equals(position.y, fp.position.y) + && Objects.equals(position.z, fp.position.z) + && Objects.equals(featurePointType.getCode(), fp.featurePointType.getCode()) + && Objects.equals(featurePointType.getInfo(), fp.featurePointType.getInfo()) + && Objects.equals(featurePointType.getName(), fp.featurePointType.getName()) + && Objects.equals(featurePointType.getType(), fp.featurePointType.getType()); + } + + /** + * generated hash code function + * + * @return + */ + @Override + public int hashCode() { + int hash = 5; + hash = 23 * hash + Objects.hashCode(this.position); + hash = 23 * hash + Objects.hashCode(this.featurePointType); + return hash; } } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePointType.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePointType.java index 0d4910be79e18499ae9200ea4f5ee86ab35eec35..9df62e4ef8a83aac24d5f003dca5c9db63261c79 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePointType.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/FeaturePointType.java @@ -2,13 +2,25 @@ package cz.fidentis.analyst.feature; import java.io.Serializable; +/** + * Class with basic structure of feature point + * + * @author Jakub Kolman + */ public class FeaturePointType implements Serializable { - private final int type; private final String name; private final String info; private final String code; + /** + * Constructor + * + * @param type + * @param name + * @param info + * @param code + */ public FeaturePointType(int type, String name, String info, String code) { this.type = type; this.name = name; diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/exception/FeaturePointException.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/exception/FeaturePointException.java new file mode 100644 index 0000000000000000000000000000000000000000..391081c5cd014b5ce20c53576fdb03943e485914 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/exception/FeaturePointException.java @@ -0,0 +1,22 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package cz.fidentis.analyst.feature.exception; + +/** + * + * @author Jakub Kolman + */ +public class FeaturePointException extends RuntimeException { + + /** + * Calls super method that throws exception with message parameter + * @param message + */ + public FeaturePointException(String message) { + super(message); + } + +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/provider/FeaturePointTypeProvider.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/provider/FeaturePointTypeProvider.java index 4b15f1fbbef1c136b9bc226b60d39de7423b44d7..f24d6935da1f8bca80b4d07029edffe56c1a93aa 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/feature/provider/FeaturePointTypeProvider.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/provider/FeaturePointTypeProvider.java @@ -1,30 +1,34 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package cz.fidentis.analyst.feature.provider; import cz.fidentis.analyst.feature.FeaturePointType; import cz.fidentis.analyst.feature.services.FeaturePointTypesService; + +import java.util.Collections; import java.util.HashMap; import java.util.Map; /** + * Feature point type provider class * - * @author kubok + * @author Jakub Kolman */ -public class FeaturePointTypeProvider { +public final class FeaturePointTypeProvider { private final Map<Integer, FeaturePointType> featurePointTypesById; private final Map<String, FeaturePointType> featurePointTypesByCode; - - // provide thread safe singleton - private static class InstanceHolder { - public static FeaturePointTypeProvider instance = new FeaturePointTypeProvider(); + /** + * provide thread safe singleton + * + * @author Jakub Kolman + */ + private static class InstanceHolder { + public static final FeaturePointTypeProvider INSTANCE = new FeaturePointTypeProvider(); } + /** + * + */ private FeaturePointTypeProvider() { FeaturePointTypesService service = new FeaturePointTypesService(); featurePointTypesById = service.readResources().orElse(new HashMap<>()); @@ -33,26 +37,48 @@ public class FeaturePointTypeProvider { /** * Access feature point types - * @return + * + * @return */ public static FeaturePointTypeProvider getInstance() { - return InstanceHolder.instance; + return InstanceHolder.INSTANCE; } + /** + * get feature points types by id + * + * @return + */ public Map<Integer, FeaturePointType> getFeaturePointTypesById() { - return featurePointTypesById; + return Collections.unmodifiableMap(featurePointTypesById); } + /** + * sorted feature point types by code + * + * @return + */ public Map<String, FeaturePointType> getFeaturePointTypesByCode() { - return featurePointTypesByCode; + return Collections.unmodifiableMap(featurePointTypesByCode); } /** - * Get feature point by code + * get single feature point type by its code + * * @param code - * @return + * @return */ public FeaturePointType getFeaturePointTypeByCode(String code) { return getFeaturePointTypesByCode().get(code); } + + /** + * get single feature point type by its id + * + * @param id + * @return + */ + public FeaturePointType getFeaturePointTypeById(int id) { + return getFeaturePointTypesById().get(id); + } } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointCsvExporter.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointCsvExporter.java new file mode 100644 index 0000000000000000000000000000000000000000..8e1086f765f9c84b5bb56fbf6f1f42a9b80b543f --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointCsvExporter.java @@ -0,0 +1,85 @@ +package cz.fidentis.analyst.feature.services; + +import cz.fidentis.analyst.feature.FeaturePoint; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Class used to export feature points to file of csv format + * + * @author Jakub Kolman + */ +public class FeaturePointCsvExporter { + + /** + * Exports a file to set location in csv format <br> + * File is located and named as {@param objectName}_landmarks.csv + * + * @param featurePointList + * @param objectName + * @throws IOException + */ + public static void exportFeaturePointsToCSV(List<FeaturePoint> featurePointList, String objectName) throws IOException { + File csvOutputFile = new File(String.format("%s_landmarks.csv", objectName)); + writeToFile(featurePointList, csvOutputFile, objectName); + } + +// /** +// * This method is only for testing purpose and saves the file only TEMPORARILY. <br> +// * <p> +// * Exports a file to set location for testing purpose. To permatently store feature points {@see exportFeaturePointsToCSV} +// * +// * @param featurePointList +// * @param objectName path + name of file +// * @throws IOException +// */ +// public static void testExportFeaturePointsToCSV(List<FeaturePoint> featurePointList, String objectName) throws IOException { +//// File csvOutputFile = new File(String.format("%s_test_landmarks.csv", objectName)); +// File csvOutputFile = File.createTempFile(String.format("%s_test_landmarks", objectName), "csv"); +// writeToFile(featurePointList, csvOutputFile, objectName); +// } + + /** + * Handles logic and format of exported csv file + * + * @param featurePointList + * @param csvOutputFile + * @param objectName + * @throws IOException + */ + public static void writeToFile(List<FeaturePoint> featurePointList, File csvOutputFile, String objectName) throws IOException { + // CSV is a normal text file, need a writer + try (BufferedWriter bw = new BufferedWriter(new FileWriter(csvOutputFile))) { + bw.write("Scan name"); + featurePointList.forEach(featurePoint -> { + try { + bw.write(String.format(",%s x", featurePoint.getFeaturePointType().getCode())); + bw.write(String.format(",%s y", featurePoint.getFeaturePointType().getCode())); + bw.write(String.format(",%s z", featurePoint.getFeaturePointType().getCode())); + } catch (IOException ex) { + Logger.getLogger(FeaturePointCsvExporter.class.getName()).log(Level.SEVERE, null, ex); + } + }); + bw.newLine(); + bw.write(String.format("%s", objectName)); + featurePointList.forEach(featurePoint -> { + try { + bw.write(","); + bw.write(Double.toString(featurePoint.getX())); + bw.write(","); + bw.write(Double.toString(featurePoint.getY())); + bw.write(","); + bw.write(Double.toString(featurePoint.getZ())); + } catch (IOException ex) { + Logger.getLogger(FeaturePointCsvExporter.class.getName()).log(Level.SEVERE, null, ex); + } + }); + } + } +} \ No newline at end of file diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointImportExportService.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointCsvLoader.java similarity index 51% rename from MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointImportExportService.java rename to MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointCsvLoader.java index 7fd77ee84e312651047ee1d2310a5639a3ac2757..326337084372cca5706c7ebf31f79fd908ec73eb 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointImportExportService.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointCsvLoader.java @@ -1,38 +1,37 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package cz.fidentis.analyst.feature.services; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.feature.provider.FeaturePointTypeProvider; import cz.fidentis.analyst.feature.utils.FileResourcesUtils; import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; import java.util.stream.Stream; /** - * - * @author kubok + * Class used to import feature points from file of csv format + * + * @author Jakub Kolman */ -public class FeaturePointImportExportService { - +public class FeaturePointCsvLoader { + private static final String COLUMN_DELIMETER = ","; private static final String CODE_PREFIX_DELIMETER = " "; - public static List<FeaturePoint> importFeaturePoints(String path, String fileName) throws FileNotFoundException, IOException { + /** + * Loads feature points from file of csv format + * @param path + * @param fileName + * @return + * @throws FileNotFoundException + * @throws IOException + */ + public static List<FeaturePoint> loadFeaturePoints(String path, String fileName) throws FileNotFoundException, IOException { FileResourcesUtils app = new FileResourcesUtils(); try (InputStreamReader streamReader = new InputStreamReader(app.getFileAsStream(path, fileName), StandardCharsets.UTF_8); @@ -72,36 +71,4 @@ public class FeaturePointImportExportService { private static String getCode(String str) { return str.substring(0, str.indexOf(CODE_PREFIX_DELIMETER)); } - - public static void exportFeaturePoints(List<FeaturePoint> featurePointList, String objectName) throws FileNotFoundException, IOException { - File csvOutputFile = new File(String.format("%s_landmarks.csv", objectName)); - // CSV is a normal text file, need a writer - try (BufferedWriter bw = new BufferedWriter(new FileWriter(csvOutputFile))) { - bw.write("Scan name"); - featurePointList.forEach(featurePoint -> { - try { - bw.write(String.format(",%s x", featurePoint.getFeaturePointType().getCode())); - bw.write(String.format(",%s y", featurePoint.getFeaturePointType().getCode())); - bw.write(String.format(",%s z", featurePoint.getFeaturePointType().getCode())); - } catch (IOException ex) { - Logger.getLogger(FeaturePointImportExportService.class.getName()).log(Level.SEVERE, null, ex); - } - }); - bw.newLine(); - bw.write(String.format("%s", objectName)); - featurePointList.forEach(featurePoint -> { - try { - bw.write(","); - bw.write(Double.toString(featurePoint.getX())); - bw.write(","); - bw.write(Double.toString(featurePoint.getY())); - bw.write(","); - bw.write(Double.toString(featurePoint.getZ())); - } catch (IOException ex) { - Logger.getLogger(FeaturePointImportExportService.class.getName()).log(Level.SEVERE, null, ex); - } - }); - } - } - } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointExportService.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointExportService.java new file mode 100644 index 0000000000000000000000000000000000000000..4caf625d30249dcb915c603f470e6b76c4e9ecd8 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointExportService.java @@ -0,0 +1,45 @@ +package cz.fidentis.analyst.feature.services; + +import cz.fidentis.analyst.feature.FeaturePoint; +import cz.fidentis.analyst.feature.utils.FeaturePointFileFormatTypes; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +/** + * Class used for exporting feature points from file + * + * for more details @see + * cz.fidentis.analyst.feature.services.FeaturePointCsvExporter or @see + * cz.fidentis.analyst.feature.services.FeaturePointFpExporter + * + * @author Jakub Kolman + */ +public class FeaturePointExportService { + + /** + * Method calls either @see FeaturePointCsvExporter or @see + * FeaturePointFpExporter based on the format given as parameter + * + * @param featurePointList + * @param objectName + * @param format + * @throws FileNotFoundException + * @throws IOException + */ + public void exportFeaturePoints(List<FeaturePoint> featurePointList, String objectName, String format) throws FileNotFoundException, IOException { + switch (format) { + case FeaturePointFileFormatTypes.FORMAT_TYPE_CSV: + FeaturePointCsvExporter.exportFeaturePointsToCSV(featurePointList, objectName); + break; + + case FeaturePointFileFormatTypes.FORMAT_TYPE_FP: + FeaturePointFpExporter.exportFeaturePointsToFP(featurePointList, objectName); + break; + + default: + break; + } + } + +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointFpExporter.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointFpExporter.java new file mode 100644 index 0000000000000000000000000000000000000000..31d1b4f6c454927ded9c5ebecf7a4e50f30f684d --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointFpExporter.java @@ -0,0 +1,56 @@ +package cz.fidentis.analyst.feature.services; + +import cz.fidentis.analyst.feature.FeaturePoint; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Class used to export feature points to file of fp format + * + * @author Jakub Kolman + */ +public class FeaturePointFpExporter { + + /** + * Exports feature points to file format fp at default location + * + * @param featurePointList + * @param objectName + * @throws FileNotFoundException + * @throws IOException + */ + public static void exportFeaturePointsToFP(List<FeaturePoint> featurePointList, String objectName) throws IOException { + File fpOutputFile = new File(String.format("%s_landmarks.fp", objectName)); + writeToFile(featurePointList, fpOutputFile, objectName); + } + + protected static void writeToFile(List<FeaturePoint> featurePointList, File fpOutputFile, String objectName) throws IOException { + // CSV is a normal text file, need a writer + try (BufferedWriter bw = new BufferedWriter(new FileWriter(fpOutputFile))) { + bw.write(String.format("<!--Saved by software Fidentis Analyst--><facialPoints model=\"%s\">", objectName)); + featurePointList.forEach(featurePoint -> { + try { + bw.newLine(); + bw.write(String.format("<facialPoint type=\"%s\">", featurePoint.getFeaturePointType().getType())); + bw.newLine(); + bw.write(String.format("<x>%f</x>", featurePoint.getX())); + bw.newLine(); + bw.write(String.format("<y>%f</y>", featurePoint.getY())); + bw.newLine(); + bw.write(String.format("<z>%f</z>", featurePoint.getZ())); + } catch (IOException ex) { + Logger.getLogger(FeaturePointFpExporter.class.getName()).log(Level.SEVERE, null, ex); + } + }); + bw.newLine(); + bw.write("</facialPoints>"); + } + } + +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointFpLoader.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointFpLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..992c2dde5be19a94af40aec2a93e7b59e6a22b5f --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointFpLoader.java @@ -0,0 +1,76 @@ +package cz.fidentis.analyst.feature.services; + +import cz.fidentis.analyst.feature.FeaturePoint; +import cz.fidentis.analyst.feature.exception.FeaturePointException; +import cz.fidentis.analyst.feature.provider.FeaturePointTypeProvider; +import cz.fidentis.analyst.feature.utils.FileResourcesUtils; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +/** + * Class used to import feature points from file of fp format + * + * @author Jakub Kolman + */ +public class FeaturePointFpLoader { + + private static final String GREATER_THAN_DELIMETER = ">"; + private static final String LESS_THAN_DELIMETER = "<"; + + /** + * Loads feature points form given file + * + * @param path + * @param fileName + * @return List of FeaturePoint + * @throws FileNotFoundException + */ + public static List<FeaturePoint> loadFeaturePoints(String path, String fileName) throws FileNotFoundException { + FileResourcesUtils app = new FileResourcesUtils(); + try (InputStreamReader streamReader + = new InputStreamReader(app.getFileAsStream(path, fileName), StandardCharsets.UTF_8); + BufferedReader reader = new BufferedReader(streamReader)) { + + Stream<String> lines = reader.lines(); + List<String> linesList = new ArrayList<>(); + + lines.forEach(line -> { + linesList.add(line); + }); + + if (linesList.isEmpty()) { + throw new FeaturePointException(String.format("Feature point import file '%s' has wrong format", fileName)); + } + + List<FeaturePoint> points = new ArrayList<>(); + for (int i = 1; i < linesList.size() - 6; i += 5) { + FeaturePoint point = new FeaturePoint( + Double.parseDouble(linesList.get(i + 1).substring( + linesList.get(i + 1).indexOf(GREATER_THAN_DELIMETER) + 1, + linesList.get(i + 1).indexOf(LESS_THAN_DELIMETER, linesList.get(i + 1).indexOf(GREATER_THAN_DELIMETER)))), + Double.parseDouble(linesList.get(i + 2).substring( + linesList.get(i + 2).indexOf(GREATER_THAN_DELIMETER) + 1, + linesList.get(i + 2).indexOf(LESS_THAN_DELIMETER, linesList.get(i + 2).indexOf(GREATER_THAN_DELIMETER)))), + Double.parseDouble(linesList.get(i + 3).substring( + linesList.get(i + 3).indexOf(GREATER_THAN_DELIMETER) + 1, + linesList.get(i + 3).indexOf(LESS_THAN_DELIMETER, linesList.get(i + 3).indexOf(GREATER_THAN_DELIMETER)))), + FeaturePointTypeProvider.getInstance().getFeaturePointTypeById( + Integer.parseInt(linesList.get(i).replaceAll("[^0-9]", ""))) + ); + points.add(point); + } + return points; + + } catch (IOException e) { + throw new FeaturePointException(String.format("Feature point service cannot open file", fileName)); + } catch (NumberFormatException e1) { + throw new FeaturePointException(e1.getMessage()); + } + } +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointImportService.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointImportService.java new file mode 100644 index 0000000000000000000000000000000000000000..2c6a8b398fc5584cc5afd23536c55cc06b6c77f9 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointImportService.java @@ -0,0 +1,39 @@ +package cz.fidentis.analyst.feature.services; + +import cz.fidentis.analyst.feature.FeaturePoint; +import cz.fidentis.analyst.feature.utils.FeaturePointFileFormatTypes; +import java.io.IOException; +import java.util.List; + +/** + * + * @author Jakub Kolman + */ +public class FeaturePointImportService { + + private static final String DELIMETER = "."; + + /** + * Method calls either @see FeaturePointCsvLoader or @see + FeaturePointFpLoader based on the format taken out of filename + * + * @param path + * @param fileName + * @return + * @throws IOException + */ + public static List<FeaturePoint> importFeaturePoints(String path, String fileName) throws IOException { + String format = fileName.substring(fileName.lastIndexOf(DELIMETER) + 1); + switch (format.toUpperCase()) { + case (FeaturePointFileFormatTypes.FORMAT_TYPE_CSV): + return FeaturePointCsvLoader.loadFeaturePoints(path, fileName); + + case (FeaturePointFileFormatTypes.FORMAT_TYPE_FP): + return FeaturePointFpLoader.loadFeaturePoints(path, fileName); + + default: + return null; + } + } + +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointTypesService.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointTypesService.java index 87dd5beb5b949972b62637af94c6f05a193a9295..d4d641a20e7e95a92a6701b176527ac459a1c468 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointTypesService.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/services/FeaturePointTypesService.java @@ -2,10 +2,11 @@ package cz.fidentis.analyst.feature.services; import cz.fidentis.analyst.feature.FeaturePointType; import cz.fidentis.analyst.feature.utils.FileResourcesUtils; - -import java.io.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Scanner; @@ -13,6 +14,10 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +/** + * + * @author Jakub Kolman + */ public class FeaturePointTypesService { private static final String FILE_NAME = "fp_text_default.csv"; @@ -48,6 +53,7 @@ public class FeaturePointTypesService { /** * Creates map of feature point types + * @param featurePointTypes * @return Optional map of feature point types mapped by code */ public Map<String, FeaturePointType> getFeaturepointTypesByCode(Map<Integer, FeaturePointType> featurePointTypes) { diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/utils/FeaturePointFileFormatTypes.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/utils/FeaturePointFileFormatTypes.java new file mode 100644 index 0000000000000000000000000000000000000000..ed25c3bacbc02d7221587c9941ebfa8c59274c4d --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/utils/FeaturePointFileFormatTypes.java @@ -0,0 +1,39 @@ +package cz.fidentis.analyst.feature.utils; + +/** + * Currently are available csv and fp formats. Rest can be added later. + * + * @author Jakub Kolman + */ +public class FeaturePointFileFormatTypes { + + public static final String FORMAT_TYPE_OBJ = "OBJ"; + public static final String FORMAT_TYPE_STL = "STL"; + public static final String FORMAT_TYPE_PLY = "PLY"; + public static final String FORMAT_TYPE_CSV = "CSV"; + public static final String FORMAT_TYPE_FP = "FP"; + public static final String FORMAT_TYPE_PP = "PP"; + public static final String FORMAT_TYPE_PTS = "PTS"; + public static final String FORMAT_TYPE_DTA = "DTA"; + public static final String FORMAT_TYPE_PNG = "PNG"; + public static final String FORMAT_TYPE_FID = "FID"; + public static final String FORMAT_TYPE_NONE = "NONE"; + + /** + * enum containing all possible file formats of feature points + * @author Jakub Kolman + */ + enum FormatType { + OBJ, + STL, + PLY, + CSV, + FP, + PP, + PTS, + DTA, + PNG, + FID, + NONE + } +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/utils/FileResourcesUtils.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/utils/FileResourcesUtils.java index 119a17225d3103c0dcd014d8147219961a6bccc3..e231d46f6718881d2ad01ce63f895a04c180e8f0 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/feature/utils/FileResourcesUtils.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/utils/FileResourcesUtils.java @@ -1,15 +1,32 @@ package cz.fidentis.analyst.feature.utils; -import java.io.*; -import java.net.URI; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.List; +/** + * Deprecated class + * + * @author Jakub Kolman + */ public class FileResourcesUtils { + /** + * main method + * + * @param args + * @throws IOException + * @throws URISyntaxException + */ public static void main(String[] args) throws IOException, URISyntaxException { FileResourcesUtils app = new FileResourcesUtils(); @@ -27,8 +44,13 @@ public class FileResourcesUtils { } - // get a file from the resources folder - // works everywhere, IDEA, unit test and JAR file. + /** + * get a file from the resources folder + * works everywhere, IDEA, unit test and JAR file. + * + * @param fileName + * @return + */ public InputStream getFileFromResourceAsStream(String fileName) { // The class loader that loaded the class @@ -44,12 +66,14 @@ public class FileResourcesUtils { } - /* - The resource URL is not working in the JAR - If we try to access a file that is inside a JAR, - It throws NoSuchFileException (linux), InvalidPathException (Windows) - - Resource URL Sample: file:java-io.jar!/json/file1.json + /** + * The resource URL is not working in the JAR If we try to access a file + * that is inside a JAR, It throws NoSuchFileException (linux), + * InvalidPathException (Windows) + * + * Resource URL Sample: file:java-io.jar!/json/file1.json + * + * @param fileName */ private File getFileFromResource(String fileName) throws URISyntaxException { @@ -66,17 +90,35 @@ public class FileResourcesUtils { } - // get a file from the resources folder - // works everywhere, IDEA, unit test and JAR file. + /** + * get a file from the resources folder works everywhere, IDEA, unit test + * and JAR file. + * + * @param path + * @param fileName + * @return + * @throws FileNotFoundException + */ public InputStream getFileAsStream(String path, String fileName) throws FileNotFoundException { return new FileInputStream(getFile(path, fileName)); } + /** + * get File from path, file name + * + * @param path + * @param fileName + * @return + */ private File getFile(String path, String fileName) { return new File(path, fileName); } - // print input stream + /** + * print input stream + * + * @param is + */ private static void printInputStream(InputStream is) { try (InputStreamReader streamReader = new InputStreamReader(is, StandardCharsets.UTF_8); diff --git a/MeshModel/src/main/resources/fp_text_default.csv b/MeshModel/src/main/resources/fp_text_default.csv index 1b86ec7acadaed9e263ec2651280618ffb63ffb4..5139b380f6d1bcb9e4757d4d1fe1478b8ac8e995 100644 --- a/MeshModel/src/main/resources/fp_text_default.csv +++ b/MeshModel/src/main/resources/fp_text_default.csv @@ -59,4 +59,4 @@ Type;Name;Info;Acronym 58;Supercilium Lateralis R;No information;SUL_R 59;Supercilium Lateralis L;No information;SUL_L 60;Supercilium Medialis R;No information;SUM_R -61;Supercilium Medialis L;No information;SUM_L +61;Supercilium Medialis L;No information;SUM_L \ No newline at end of file diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointExportServiceTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointExportServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f39b4d8c6b4852a948d71c2f216f7dde1e2a5e64 --- /dev/null +++ b/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointExportServiceTest.java @@ -0,0 +1,75 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package cz.fidentis.analyst.feature.services; + +import cz.fidentis.analyst.feature.FeaturePoint; +import cz.fidentis.analyst.feature.services.FeaturePointCsvLoader; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +/** + * @author Jakub Kolman + */ +public class FeaturePointExportServiceTest { + + private static final Path MODEL_TEST_FILE_DIRECTORY = Paths.get("src", "test", "resources", "cz", "fidentis", "analyst", "feature", "services"); + private static final String MODEL_FILE = "00007_01_landmarks.csv"; + + @DisplayName("Test writing a CSV file") + @Test + void exportFeaturePointsCSVTest() throws IOException { + // load model of feature points from file + FeaturePointCsvExporter service = new FeaturePointCsvExporter(); + List<FeaturePoint> featurePoints = loadCsvFeaturePoints(MODEL_TEST_FILE_DIRECTORY.toString(), MODEL_FILE); + // create tmp file to write in + File csvOutputFile = File.createTempFile(String.format("%s_test_file_csv_landmarks", MODEL_TEST_FILE_DIRECTORY.toString()), "csv"); + service.writeToFile(featurePoints, csvOutputFile, MODEL_TEST_FILE_DIRECTORY.toString() + "/" + "test_file_csv"); + // check if model file and created file generate lists with the same elements + List<FeaturePoint> loadedFeaturePoints = loadCsvFeaturePoints(MODEL_TEST_FILE_DIRECTORY.toString(), "test_file_csv_landmarks.csv"); + assertEquals(featurePoints.size(), loadedFeaturePoints.size()); + assertEquals(featurePoints, loadedFeaturePoints); + assertNotSame(featurePoints, loadedFeaturePoints); + } + + @DisplayName("Test writing a FP file") + @Test + void exportFeaturePointsFPTest() throws IOException { + // load model of feature points from file + FeaturePointFpExporter service = new FeaturePointFpExporter(); + List<FeaturePoint> featurePoints = loadCsvFeaturePoints(MODEL_TEST_FILE_DIRECTORY.toString(), MODEL_FILE); + // create tmp file to write in + File fpOutputFile = File.createTempFile(String.format("%s_test_file_fp_landmarks", MODEL_TEST_FILE_DIRECTORY.toString()), "fp"); + service.writeToFile(featurePoints, fpOutputFile, MODEL_TEST_FILE_DIRECTORY.toString() + "/" + "test_file_fp"); + // check if model file and created file generate lists with the same elements + List<FeaturePoint> loadedFeaturePoints = loadFpFeaturePoints(MODEL_TEST_FILE_DIRECTORY.toString(), "test_file_fp_landmarks.fp"); + assertEquals(featurePoints.size(), loadedFeaturePoints.size()); + assertEquals(featurePoints, loadedFeaturePoints); + assertNotSame(featurePoints, loadedFeaturePoints); + } + + private List<FeaturePoint> loadCsvFeaturePoints(String path, String fileName) throws IOException { + FeaturePointCsvLoader service = new FeaturePointCsvLoader(); + List<FeaturePoint> featurePoints = service.loadFeaturePoints(MODEL_TEST_FILE_DIRECTORY.toString(), MODEL_FILE); + return featurePoints; + } + + private List<FeaturePoint> loadFpFeaturePoints(String path, String fileName) throws IOException { + FeaturePointCsvLoader service = new FeaturePointCsvLoader(); + List<FeaturePoint> featurePoints = service.loadFeaturePoints(MODEL_TEST_FILE_DIRECTORY.toString(), MODEL_FILE); + return featurePoints; + } + +} diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointImportExportServiceTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointImportExportServiceTest.java deleted file mode 100644 index 7368ce54abad2f7f1e5a4444385a61bd5bcaa44b..0000000000000000000000000000000000000000 --- a/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointImportExportServiceTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package cz.fidentis.analyst.feature.services; - -import cz.fidentis.analyst.feature.FeaturePoint; -import cz.fidentis.analyst.feature.provider.FeaturePointTypeProvider; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.DisplayName; - -/** - * - * @author Jakub Kolman - */ -public class FeaturePointImportExportServiceTest { - - - private static final Path testFileDirectory = Paths.get("src", "test", "resources", "cz", "fidentis", "analyst", "feature", "services"); - private static final String TEST_CSV_FILE = "00007_01_landmarks.csv"; - - @Test() - void fileExistsTest() throws IOException { - File testCsv = new File(testFileDirectory.toFile(), TEST_CSV_FILE); - assertTrue(testCsv.canRead()); - } - - @DisplayName("Test loading a CSV file") - @Test - void importFeaturePointsTest() throws IOException { - List<FeaturePoint> featurePoints = loadFeaturePoints(); - assertTrue(featurePoints != null); - assertTrue(featurePoints.size() > 0); - assertTrue(featurePoints.get(0).getX() == -45.3298 - && featurePoints.get(0).getY() == 37.1466 - && featurePoints.get(0).getZ() == -40.5415 - && featurePoints.get(0).getFeaturePointType().equals( - FeaturePointTypeProvider.getInstance().getFeaturePointTypeByCode("EX_R")) - ); - } - - @DisplayName("Test writing a CSV file") - @Test - void exportFeaturePointsTest() throws IOException { - List<FeaturePoint> featurePoints = loadFeaturePoints(); - FeaturePointImportExportService.exportFeaturePoints(featurePoints, "test_file"); - } - - private List<FeaturePoint> loadFeaturePoints() throws IOException { - List<FeaturePoint> featurePoints = FeaturePointImportExportService.importFeaturePoints(testFileDirectory.toString(), TEST_CSV_FILE); - return featurePoints; - } -} diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointImportServiceTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointImportServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..22915793e82762faaf10374badb0320716dd575c --- /dev/null +++ b/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointImportServiceTest.java @@ -0,0 +1,88 @@ +package cz.fidentis.analyst.feature.services; + +import cz.fidentis.analyst.feature.FeaturePoint; +import cz.fidentis.analyst.feature.provider.FeaturePointTypeProvider; +import cz.fidentis.analyst.feature.services.FeaturePointCsvLoader; +import cz.fidentis.analyst.feature.services.FeaturePointFpLoader; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.DisplayName; + +/** + * + * @author Jakub Kolman + */ +public class FeaturePointImportServiceTest { + + private static final Path testFileDirectory = Paths.get("src", "test", "resources", "cz", "fidentis", "analyst", "feature", "services"); + private static final String TEST_CSV_FILE = "00007_01_landmarks.csv"; + private static final String TEST_FP_FILE = "fp_head1_test.fp"; + + @DisplayName("Test if CSV file can be read") + @Test() + void fileExistsTest() throws IOException { + File testCsv = new File(testFileDirectory.toFile(), TEST_CSV_FILE); + assertTrue(testCsv.canRead()); + } + + @DisplayName("Test loading a CSV file") + @Test + void importFeaturePointsCSVTest() throws IOException { + List<FeaturePoint> featurePoints = FeaturePointCsvLoader.loadFeaturePoints(testFileDirectory.toString(), TEST_CSV_FILE); + assertTrue(featurePoints != null); + assertTrue(featurePoints.size() > 0); + assertTrue(featurePoints.get(0).getX() == -45.3298 + && featurePoints.get(0).getY() == 37.1466 + && featurePoints.get(0).getZ() == -40.5415 + && featurePoints.get(0).getFeaturePointType().equals( + FeaturePointTypeProvider.getInstance().getFeaturePointTypeByCode("EX_R")) + ); + } + + @DisplayName("Test loading a FP file") + @Test + void importFeaturePointsTest() throws IOException { + List<FeaturePoint> featurePoints = FeaturePointFpLoader.loadFeaturePoints(testFileDirectory.toString(), TEST_FP_FILE); + assertTrue(featurePoints != null); + assertTrue(featurePoints.size() > 0); + assertTrue(featurePoints.get(0).getX() == -40.429775 + && featurePoints.get(0).getY() == 45.756405 + && featurePoints.get(0).getZ() == 37.12462 + && featurePoints.get(0).getFeaturePointType().equals( + FeaturePointTypeProvider.getInstance().getFeaturePointTypeByCode("EX_R")) + ); + } + + @DisplayName("Test loading a FP file from generic service") + @Test + void importFeaturePointsFpFromGenericServiceTest() throws IOException { + List<FeaturePoint> featurePoints = FeaturePointImportService.importFeaturePoints(testFileDirectory.toString(), TEST_FP_FILE); + assertTrue(featurePoints != null); + assertTrue(featurePoints.size() > 0); + assertTrue(featurePoints.get(0).getX() == -40.429775 + && featurePoints.get(0).getY() == 45.756405 + && featurePoints.get(0).getZ() == 37.12462 + && featurePoints.get(0).getFeaturePointType().equals( + FeaturePointTypeProvider.getInstance().getFeaturePointTypeByCode("EX_R")) + ); + } + + @DisplayName("Test loading a CSV file from generic service") + @Test + void importFeaturePointsCsvFromGenericServiceTest() throws IOException { + List<FeaturePoint> featurePoints = FeaturePointImportService.importFeaturePoints(testFileDirectory.toString(), TEST_CSV_FILE); + assertTrue(featurePoints != null); + assertTrue(featurePoints.size() > 0); + assertTrue(featurePoints.get(0).getX() == -45.3298 + && featurePoints.get(0).getY() == 37.1466 + && featurePoints.get(0).getZ() == -40.5415 + && featurePoints.get(0).getFeaturePointType().equals( + FeaturePointTypeProvider.getInstance().getFeaturePointTypeByCode("EX_R")) + ); + } +} diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointTypeTypesServiceTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointTypeTypesServiceTest.java index f0ff92a21ede396415679c54d4ff4cefdd9ce501..04ab3761c5080c44f14b35b079f0bb3f27beedf8 100644 --- a/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointTypeTypesServiceTest.java +++ b/MeshModel/src/test/java/cz/fidentis/analyst/feature/services/FeaturePointTypeTypesServiceTest.java @@ -16,7 +16,6 @@ class FeaturePointTypeTypesServiceTest { @DisplayName("Test loading a CSV file") @Test void readResourcesTest() { - FeaturePointTypesService service = new FeaturePointTypesService(); Optional<Map<Integer, FeaturePointType>> featurePointTypes = service.readResources(); assertTrue(featurePointTypes.isPresent()); @@ -26,4 +25,8 @@ class FeaturePointTypeTypesServiceTest { && featurePointTypes.get().get(1).getCode().equals("EX_R")); } + void aTest() { + FeaturePointTypesService service = new FeaturePointTypesService(); + } + } \ No newline at end of file diff --git a/MeshModel/src/test/resources/cz/fidentis/analyst/feature/services/fp_head1_test.fp b/MeshModel/src/test/resources/cz/fidentis/analyst/feature/services/fp_head1_test.fp new file mode 100644 index 0000000000000000000000000000000000000000..6a1414be7086356af13e6ec68b6c2a0cc7b7c991 --- /dev/null +++ b/MeshModel/src/test/resources/cz/fidentis/analyst/feature/services/fp_head1_test.fp @@ -0,0 +1,52 @@ +<!--Saved by software Fidentis Analyst--><facialPoints model="head01.obj"> +<facialPoint type="1"> +<x>-40.429775</x> +<y>45.756405</y> +<z>37.12462</z> +</facialPoint> +<facialPoint type="2"> +<x>-14.435408</x> +<y>47.491802</y> +<z>45.004395</z> +</facialPoint> +<facialPoint type="3"> +<x>16.292408</x> +<y>45.930874</y> +<z>43.787186</z> +</facialPoint> +<facialPoint type="4"> +<x>35.071796</x> +<y>44.352318</y> +<z>38.45862</z> +</facialPoint> +<facialPoint type="5"> +<x>8.0257435</x> +<y>31.204237</y> +<z>37.290848</z> +</facialPoint> +<facialPoint type="6"> +<x>-9.646407</x> +<y>28.970993</y> +<z>34.634415</z> +</facialPoint> +<facialPoint type="7"> +<x>-10.50379</x> +<y>-9.440336</y> +<z>41.965027</z> +</facialPoint> +<facialPoint type="8"> +<x>7.8041906</x> +<y>-9.892714</y> +<z>43.199005</z> +</facialPoint> +<facialPoint type="9"> +<x>-20.985464</x> +<y>-36.727818</y> +<z>31.406677</z> +</facialPoint> +<facialPoint type="10"> +<x>22.01368</x> +<y>-37.23364</y> +<z>30.561905</z> +</facialPoint> +</facialPoints> diff --git a/MeshModel/test_file_landmarks.csv b/MeshModel/test_file_landmarks.csv deleted file mode 100644 index e2d6288e77633889dd6f24afab8da4e892c0cc9b..0000000000000000000000000000000000000000 --- a/MeshModel/test_file_landmarks.csv +++ /dev/null @@ -1,2 +0,0 @@ -Scan name,EX_R x,EX_R y,EX_R z,EX_L x,EX_L y,EX_L z,EN_R x,EN_R y,EN_R z,EN_L x,EN_L y,EN_L z,PAS_R x,PAS_R y,PAS_R z,PAS_L x,PAS_L y,PAS_L z,PAI_R x,PAI_R y,PAI_R z,PAI_L x,PAI_L y,PAI_L z,G x,G y,G z,SN x,SN y,SN z,AL_R x,AL_R y,AL_R z,AL_L x,AL_L y,AL_L z,N x,N y,N z,PRN x,PRN y,PRN z,LS x,LS y,LS z,STO x,STO y,STO z,LI x,LI y,LI z,CH_R x,CH_R y,CH_R z,CH_L x,CH_L y,CH_L z,CP_R x,CP_R y,CP_R z,CP_L x,CP_L y,CP_L z,SL x,SL y,SL z,GN x,GN y,GN z,GOL_R x,GOL_R y,GOL_R z,GOL_L x,GOL_L y,GOL_L z,ZY_R x,ZY_R y,ZY_R z,ZY_L x,ZY_L y,ZY_L z,PG x,PG y,PG z,T_R x,T_R y,T_R z,T_L x,T_L y,T_L z,SA_R x,SA_R y,SA_R z,SA_L x,SA_L y,SA_L z,SBA_R x,SBA_R y,SBA_R z,SBA_L x,SBA_L y,SBA_L z,PA_R x,PA_R y,PA_R z,PA_L x,PA_L y,PA_L z,OBS_R x,OBS_R y,OBS_R z,OBS_L x,OBS_L y,OBS_L z,OBI_R x,OBI_R y,OBI_R z,OBI_L x,OBI_L y,OBI_L z,PRA_R x,PRA_R y,PRA_R z,PRA_L x,PRA_L y,PRA_L z -test_file,-45.3298,37.1466,-40.5415,44.3033,36.255,-42.623,-18.5134,33.2336,-36.7921,16.188,32.6379,-37.2197,-34.3363,41.5306,-33.6564,33.8288,39.5634,-34.2531,-34.4132,31.9017,-35.2642,33.5827,30.789,-36.755,0.12959,51.8853,-14.4235,-0.0356107,-13.0827,-16.9983,-16.6623,-4.05884,-19.1798,15.5038,-4.97323,-21.1836,0.044336,39.4236,-19.1853,-0.0291473,0.258132,-0.140334,-0.0901103,-29.1039,-16.7076,0.055705,-35.7511,-21.7819,0.0285089,-44.8791,-21.1852,-28.1537,-35.8802,-32.2677,24.4702,-34.6564,-34.317,-5.68164,-26.7827,-16.8184,5.63171,-26.3173,-17.4413,0.0403775,-52.2879,-27.0041,0.0981629,-80.2827,-43.5233,-57.0806,-39.8906,-118.469,50.4482,-38.958,-118.26,-63.254,40.8951,-53.951,59.7107,38.7682,-58.1024,0.0468024,-61.4376,-25.9881,-78.3702,26.048,-120.74,70.6534,28.1125,-122.519,-91.2689,55.5377,-137.688,87.5631,56.4117,-137.202,-75.6368,-4.45582,-120.828,70.4776,-1.8171,-120.704,-93.2421,34.1812,-155.155,90.0449,35.8349,-155.402,-82.7099,46.6375,-123.483,76.087,46.7891,-123.211,-72.0651,-5.47207,-119.272,64.1992,-3.95897,-118.937,-83.3521,40.1314,-121.805,75.3747,40.0263,-121.781 \ No newline at end of file