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

Code cleaning

parent 6d587c5d
No related branches found
No related tags found
No related merge requests found
package cz.fidentis.analyst.comparison;
import cz.fidentis.analyst.mesh.core.MeshPoint;
/**
* The pair of closest vertices and their distance.
*
* @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 cz.fidentis.analyst.mesh.visitors.TriangleListVisitor;
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();
TriangleListVisitor visitor = new TriangleListVisitor();
comparedFacet.accept(visitor);
List<MeshTriangle> trList = visitor.getTriangles();
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
* @author Radek Oslejsek
*/
private final class Pair<K,V> {
private final K key;
private final V value;
/**
* Constructor.
* @param key key
* @param value value
*/
private 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
}
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