Skip to content
Snippets Groups Projects
Commit b47a413c authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch 'issue22' into 'master'

The code of Matej re-entered

See merge request grp-fidentis/analyst2!23
parents 3f6767ba 0c830239
No related branches found
No related tags found
No related merge requests found
......@@ -59,6 +59,14 @@
<target>8</target>
</configuration>
</plugin>
<!-- <plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.4</version>
<configuration>
<mainClass>org.openjfx.App</mainClass>
</configuration>
</plugin> -->
</plugins>
</build>
<dependencies>
......@@ -77,6 +85,17 @@
<artifactId>vecmath</artifactId>
<version>${version.javax.vecmath}</version>
</dependency>
<!-- <dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11.0.2</version>
</dependency> -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
......
package cz.fidentis.analyst.comparison;
import cz.fidentis.analyst.mesh.core.MeshPoint;
/**
*
* @author Matej Lukes
*/
public class ClosestVertices {
private MeshPoint firstVertex;
private MeshPoint secondVertex;
private double distance;
/**
* Constructor.
*
* @param firstVertex Firt vertex of the pair
* @param secondVertex Second vertex of the pair
* @param distance Distance
*/
public ClosestVertices(MeshPoint firstVertex, MeshPoint secondVertex, double distance) {
this.firstVertex = firstVertex;
this.secondVertex = secondVertex;
this.distance = distance;
}
public MeshPoint getFirstVertex() {
return firstVertex;
}
public MeshPoint getSecondVertex() {
return secondVertex;
}
public double getDistance() {
return distance;
}
}
package cz.fidentis.analyst.comparison;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.io.MeshObjLoader;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* @author Matej Lukes
*/
public class Comparison {
private HausdorffDistance hausdorffDistance;
private MeshFacet mainFacet;
private MeshFacet comparedFacet;
/**
* Asynchronously loads main meshModel
*
* @param path path to meshModel file
* @return CompletableFuture
*/
public CompletableFuture loadMainModel(String path) {
return CompletableFuture.runAsync(() -> {
try {
mainFacet = MeshObjLoader.read(new File(path)).getFacets().get(1);
} catch (IOException e) {
e.printStackTrace();
}
});
}
/**
* Asynchronously loads compared meshModel
*
* @param path path to meshModel file
* @return CompletableFuture
*/
public CompletableFuture loadComparedModel(String path) {
return CompletableFuture.runAsync(() -> {
try {
comparedFacet = MeshObjLoader.read(new File(path)).getFacets().get(1);
} catch (IOException e) {
e.printStackTrace();
}
});
}
/**
* Asynchronously registers compared meshFacet to main meshFacet
*
* @param method registration method
* @return CompletableFuture
*/
public CompletableFuture register(RegistrationMethod method) {
return CompletableFuture.runAsync(() -> comparedFacet = Registration
.register(mainFacet, comparedFacet, method));
}
/**
* Asynchronously compares MeshFacets from vertices to vertices
*
* @return list containing vertex from first facet, closest vertex to it from second facet, distance
*/
public CompletableFuture<List<ClosestVertices>> compareHausdorffDistanceToVertices() {
hausdorffDistance = new HausdorffDistance(mainFacet, comparedFacet);
return CompletableFuture.supplyAsync(() -> hausdorffDistance.calculateHausdorffDistanceToVertices());
}
/**
* Asynchronously compares MeshFacets from vertices to any point on mesh
*
* @return list containing vertex from first facet, closest point to it from second facet, distance
*/
public CompletableFuture<List<ClosestVertices>> compareHausdorffDistanceToMesh() {
hausdorffDistance = new HausdorffDistance(mainFacet, comparedFacet);
return CompletableFuture.supplyAsync(() -> hausdorffDistance.calculateHausdorffDistanceToMesh());
}
/**
* returns progress percentage
*
* @return progress percentage
*/
public double getComparisonProgress() {
if (hausdorffDistance == null) {
return -1;
}
return hausdorffDistance.getProgressPercentage();
}
}
package cz.fidentis.analyst.comparison;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshPoint;
import cz.fidentis.analyst.mesh.core.MeshPointImpl;
import cz.fidentis.analyst.mesh.core.MeshTriangle;
import javax.vecmath.Vector3d;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* @author Matej Lukes
*/
public class HausdorffDistance {
private MeshFacet mainFacet;
private MeshFacet comparedFacet;
private AtomicInteger progress = new AtomicInteger();
private int numberOfVertices;
/**
* @param mainFacet main MeshFacet
* @param comparedFacet compared MeshFacet
*/
public HausdorffDistance(MeshFacet mainFacet, MeshFacet comparedFacet) {
this.mainFacet = mainFacet;
this.comparedFacet = comparedFacet;
this.numberOfVertices = mainFacet.getNumberOfVertices();
}
/**
* returns progress percentage
*
* @return progress
*/
public double getProgressPercentage() {
return ((double) progress.get() / numberOfVertices) * 100;
}
/**
* Finds the nearest vertex on the second facet.
*
* @param vertex vertex from
* @return vertex, nearest vertex from second facet, distance
*/
private ClosestVertices getNearestVertex(MeshPoint vertex) {
Optional<Pair<MeshPoint, Double>> closestVertexAndDistance = comparedFacet.getVertices().parallelStream()
.map((meshPoint) -> new Pair<>(meshPoint, getDistanceBetweenPoints(vertex, meshPoint.getPosition())))
.max((Comparator.comparingDouble(Pair::getValue)));
return closestVertexAndDistance.map(vector3dDoublePair -> new ClosestVertices(vertex,
vector3dDoublePair.getKey(),
vector3dDoublePair.getValue())).orElse(null);
}
/**
* returns distance between two points
*
* @param point1 first point
* @param point2 second point
* @return distance
*/
private double getDistanceBetweenPoints(MeshPoint point1, Vector3d point2) {
Vector3d helperVector = new Vector3d();
helperVector.sub(point1.getPosition(), point2);
return Math.signum(helperVector.dot(point1.getNormal())) * helperVector.length();
}
/**
* calculates Hausdorff Distance to the nearest vertex from second facet for each vertex in first facet
* this implementation uses executor
*
* @return list containing vertex from first facet, closest vertex to it from second facet, distance
*/
public List<ClosestVertices> calculateHausdorffDistanceToVertices() {
progress.set(0);
int numberOfVertices = mainFacet.getNumberOfVertices();
List<Future<ClosestVertices>> closestVerticesFutures = new ArrayList<>(numberOfVertices);
ExecutorService executor = Executors.newCachedThreadPool();
for (final MeshPoint vertex : mainFacet.getVertices()) {
closestVerticesFutures.add(executor.submit(() -> {
ClosestVertices result = getNearestVertex(vertex);
progress.addAndGet(1);
return result;
}));
}
List<ClosestVertices> closestVertices = new ArrayList<>(numberOfVertices);
for (Future<ClosestVertices> future :
closestVerticesFutures) {
executor.submit(() -> {
try {
ClosestVertices result = future.get();
synchronized (closestVertices) {
closestVertices.add(result);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
return closestVertices;
}
/**
* calculates Hausdorff Distance to the nearest vertex from second facet for each vertex in first facet
* this implementation uses parallel streams
*
* @return list containing vertex from first facet, closest vertex to it from second facet, distance
*/
public List<ClosestVertices> calculateHausdorffDistanceToVertices2() {
progress.set(0);
return mainFacet.getVertices().parallelStream()
.map((vertex) -> {
ClosestVertices result = getNearestVertex(vertex);
progress.addAndGet(1);
return result;
})
.collect(Collectors.toList());
}
/**
* calculates Hausdorff Distance to the nearest point on second facet for each vertex
* this implementation uses executor
*
* @return list containing vertex from first facet, closest point to it from second facet, distance
*/
public List<ClosestVertices> calculateHausdorffDistanceToMesh() {
progress.set(0);
int numberOfVertices = mainFacet.getNumberOfVertices();
List<Future<ClosestVertices>> closestPointsFutures = new ArrayList<>(numberOfVertices);
ExecutorService executor = Executors.newCachedThreadPool();
for (final MeshPoint vertex : mainFacet.getVertices()) {
closestPointsFutures.add(executor.submit(() -> {
ClosestVertices result = calculateNearestPointOnMesh(vertex,
comparedFacet.getCornerTable()
.getTriangleIndexesByVertexIndex(comparedFacet.getVertices()
.indexOf(getNearestVertex(vertex)
.getSecondVertex())));
progress.addAndGet(1);
return result;
}));
}
List<ClosestVertices> closestVertices = new ArrayList<>(numberOfVertices);
for (Future<ClosestVertices> future : closestPointsFutures) {
executor.submit(() -> {
try {
ClosestVertices result = future.get();
synchronized (closestVertices) {
closestVertices.add(result);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
return closestVertices;
}
/**
* calculates Hausdorff Distance to the nearest point on second facet for each vertex
* this implementation uses parallel streams
*
* @return list containing vertex from first facet, closest point to it from second facet, distance
*/
public List<ClosestVertices> calculateHausdorffDistanceToMesh2() {
progress.set(0);
return mainFacet.getVertices().parallelStream()
.map((meshPoint) -> {
ClosestVertices result = calculateNearestPointOnMesh(meshPoint,
comparedFacet.getCornerTable()
.getTriangleIndexesByVertexIndex(comparedFacet.getVertices()
.indexOf(getNearestVertex(meshPoint)
.getSecondVertex())));
progress.addAndGet(1);
return result;
}).collect(Collectors.toList());
}
/**
* calculates Hausdorff Distance to the nearest point on second facet for vertex
*
* @param vertex vertex from first facet
* @param indicesOfTrianglesOfVertex indices of triangles that contain the nearest vertex on second mesh
* @return vertex from first facet, closest point to it from second facet, distance
*/
private ClosestVertices calculateNearestPointOnMesh(MeshPoint vertex, List<Integer> indicesOfTrianglesOfVertex) {
Vector3d vertexPosition = vertex.getPosition();
List<Pair<Vector3d, Double>> projections = new ArrayList<>(indicesOfTrianglesOfVertex.size());
Vector3d helperVector = new Vector3d();
List<MeshTriangle> trList = comparedFacet.asTriangles();
for (int index : indicesOfTrianglesOfVertex) {
List<Vector3d> triangle = new ArrayList<>();
triangle.add(trList.get(index).vertex1.getPosition());
triangle.add(trList.get(index).vertex2.getPosition());
triangle.add(trList.get(index).vertex3.getPosition());
//List<Vector3d> triangle = comparedFacet.asTriangles()..getVerticesOfTriangle(index).stream()
// .map(MeshPoint::getPosition)
// .collect(Collectors.toList());
Vector3d projection = getProjectionToTrianglePlane(vertexPosition, triangle);
if (isPointInTriangle(projection, triangle)) {
helperVector.sub(vertexPosition, projection);
projections.add(new Pair<>(projection, helperVector.length()));
} else {
projection = getProjectionToClosestEdge(projection, triangle);
helperVector.sub(vertexPosition, projection);
projections.add(new Pair<>(projection, helperVector.length()));
}
}
Pair<Vector3d, Double> closestPosition = projections.stream()
.min(Comparator.comparingDouble(Pair::getValue)).orElseGet(() -> new Pair<>(null, Double.MAX_VALUE));
return new ClosestVertices(vertex,
new MeshPointImpl(closestPosition.getKey(), null, null),
closestPosition.getValue());
}
/**
* returns perpendicular projection from vertex to plane of triangle
*
* @param vertex vertex from which the projection is created
* @param triangle triangle that defines the plane
* @return projection to plane of triangle
*/
private Vector3d getProjectionToTrianglePlane(Vector3d vertex, List<Vector3d> triangle) {
Vector3d ab = new Vector3d();
ab.sub(triangle.get(0), triangle.get(1));
Vector3d ac = new Vector3d();
ac.sub(triangle.get(0), triangle.get(2));
Vector3d normal = new Vector3d();
normal.cross(ab, ac);
normal.normalize();
Vector3d helperVector = new Vector3d(vertex);
helperVector.sub(triangle.get(0));
double distance = helperVector.dot(normal);
helperVector.scaleAdd(-distance, normal, helperVector);
return helperVector;
}
/**
* checks if a point in plane of triangle lies within the triangle
*
* @param point checked point
* @param triangle triangle
* @return true if point is in triangle, false otherwise
*/
private boolean isPointInTriangle(Vector3d point, List<Vector3d> triangle) {
List<Vector3d> pointToVertices = triangle.stream()
.map((vertex) -> {
Vector3d v = new Vector3d(vertex);
v.sub(point);
return v;
}).collect(Collectors.toList());
double angleSum = 0;
for (int i = 0; i < 3; i++) {
angleSum += pointToVertices.get(i).angle(pointToVertices.get((i + 1) % 3));
}
angleSum -= Math.PI;
return -0.01 < angleSum && angleSum < 0.01;
}
/**
* returns projection to to the nearest edge of triangle
*
* @param point point in plane of triangle
* @param triangle triangle
* @return perpendicular projection to the nearest edge
*/
private Vector3d getProjectionToClosestEdge(Vector3d point, List<Vector3d> triangle) {
Vector3d[] projections = new Vector3d[3];
for (int i = 0; i < 3; i++) {
projections[i] = getProjectionToEdge(point, triangle.get(i), triangle.get((i + 1) % 3));
}
double minDistance = Double.MAX_VALUE;
Vector3d closestProjection = null;
Vector3d helperVector = new Vector3d();
for (Vector3d projection :
projections) {
helperVector.sub(point, projection);
double distance = helperVector.length();
if (distance < minDistance) {
minDistance = distance;
closestProjection = projection;
}
}
return closestProjection;
}
/**
* returns projection to edge
*
* @param point point in plane of triangle
* @param edgeVertex1 first vertex of edge
* @param edgeVertex2 second vertex of edge
* @return projection to edge
*/
private Vector3d getProjectionToEdge(Vector3d point, Vector3d edgeVertex1, Vector3d edgeVertex2) {
Vector3d ab = new Vector3d();
ab.sub(edgeVertex1, edgeVertex2);
Vector3d ap = new Vector3d();
ap.sub(edgeVertex1, point);
double t = ab.dot(ap) / ab.lengthSquared();
return new Vector3d(edgeVertex1.x + t * ab.x, edgeVertex1.y + t * ab.y, edgeVertex1.z + t * ab.z);
}
/**
* Helper class for pairs.
*
* @param <K> key
* @param <V> value
*/
private class Pair<K,V> {
private K key;
private V value;
/**
* Constructor.
* @param key key
* @param value value
*/
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
}
package cz.fidentis.analyst.comparison;
import cz.fidentis.analyst.mesh.core.MeshFacet;
/**
*
* @author Matej Lukes
*/
public class Registration {
/**
* Heler method - TO DO
*
* @param facet main facet
* @param registeredFacet refistered facet
* @param method registration method
* @return TO DO
*/
public static MeshFacet register(MeshFacet facet, MeshFacet registeredFacet, RegistrationMethod method) {
switch (method) {
case NO_REGISTRATION:
return registeredFacet;
default:
return null;
}
}
}
package cz.fidentis.analyst.comparison;
/**
* @author Matej Lukes
*/
public enum RegistrationMethod {
NO_REGISTRATION
}
package cz.fidentis.analyst.comparison;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class ComparisonTest {
}
\ No newline at end of file
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