diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/HumanFace.java b/Comparison/src/main/java/cz/fidentis/analyst/HumanFace.java similarity index 96% rename from MeshModel/src/main/java/cz/fidentis/analyst/mesh/HumanFace.java rename to Comparison/src/main/java/cz/fidentis/analyst/HumanFace.java index 044448d1edea8e513f0080ee75a8e185c0a9b1ce..e5ef7373be6a0c4732795ef40847621041ba5cb0 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/HumanFace.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/HumanFace.java @@ -1,4 +1,4 @@ -package cz.fidentis.analyst.mesh; +package cz.fidentis.analyst; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.io.MeshObjLoader; diff --git a/Comparison/src/main/java/cz/fidentis/analyst/comparison/ClosestVertices.java b/Comparison/src/main/java/cz/fidentis/analyst/comparison/ClosestVertices.java deleted file mode 100644 index 7c9cc087308ed3fa95d3ed7c16fc943a735b5b0d..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/comparison/ClosestVertices.java +++ /dev/null @@ -1,39 +0,0 @@ -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; - } -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/comparison/Comparison.java b/Comparison/src/main/java/cz/fidentis/analyst/comparison/Comparison.java deleted file mode 100644 index a7ce1c307db8f155356eb51bcae6efbae9070a13..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/comparison/Comparison.java +++ /dev/null @@ -1,95 +0,0 @@ -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(); - } -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/comparison/HausdorffDistance.java b/Comparison/src/main/java/cz/fidentis/analyst/comparison/HausdorffDistance.java deleted file mode 100644 index f63122bd1372f3a976781cc617d305a6ee651f58..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/comparison/HausdorffDistance.java +++ /dev/null @@ -1,359 +0,0 @@ -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; - } - } -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/comparison/Registration.java b/Comparison/src/main/java/cz/fidentis/analyst/comparison/Registration.java deleted file mode 100644 index dc681e550c9a874deb2cbff8adb7b4c89bea5b3c..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/comparison/Registration.java +++ /dev/null @@ -1,27 +0,0 @@ -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; - } - } -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/comparison/RegistrationMethod.java b/Comparison/src/main/java/cz/fidentis/analyst/comparison/RegistrationMethod.java deleted file mode 100644 index 730fcf274e47849e2ef3b8bd6b19d04ecc446201..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/comparison/RegistrationMethod.java +++ /dev/null @@ -1,8 +0,0 @@ -package cz.fidentis.analyst.comparison; - -/** - * @author Matej Lukes - */ -public enum RegistrationMethod { - NO_REGISTRATION -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java index 918c50881ef78e172b3a2e47f65f23ccc5b7e111..9b62883410673cff9658cd27dd383cae083c8d74 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java @@ -8,7 +8,6 @@ import cz.fidentis.analyst.mesh.core.MeshFacetImpl; import cz.fidentis.analyst.mesh.core.MeshPointImpl; import cz.fidentis.analyst.mesh.core.MeshTriangle; import cz.fidentis.analyst.mesh.visitors.BoundingBoxVisitor; -import cz.fidentis.analyst.mesh.visitors.TriangleListVisitor; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -49,13 +48,10 @@ public class SymmetryEstimator { this.facet = f; this.config = config; - TriangleListVisitor visitor = new TriangleListVisitor(); - f.accept(visitor); - this.triangles = visitor.getTriangles(); - - this.areas = new TriangleVertexAreas[triangles.size()]; - for (int i = 0; i < areas.length; i++) { - areas[i] = computeTriangleVertexAreas(triangles.get(i)); + this.areas = new TriangleVertexAreas[f.getNumTriangles()]; + int i = 0; + for (MeshTriangle tri: f) { + areas[i++] = computeTriangleVertexAreas(tri); } } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdNode.java b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdNode.java index 7156633509af9673c2361f202a89c187c898005e..47be30f520cfe01f86b13a307612c93112ef6742 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdNode.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdNode.java @@ -1,7 +1,6 @@ package cz.fidentis.analyst.kdtree; import cz.fidentis.analyst.mesh.core.MeshFacet; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -104,6 +103,10 @@ public class KdNode { return depth; } + /** + * Returns 3D location of vertices stored in this node + * @return 3D location of vertices stored in this node + */ public Vector3d get3dLocation() { Map.Entry<MeshFacet, Integer> entry = facets.entrySet().iterator().next(); return entry.getKey().getVertex(entry.getValue()).getPosition(); diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java index 1db7603be5d26ea5f17d69f5f5c6162bf3a0642a..35694362ac33ba6dccbb5adea38a48fdab159ad3 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java @@ -1,14 +1,14 @@ package cz.fidentis.analyst.mesh.core; -import cz.fidentis.analyst.mesh.visitors.Visitor; import java.util.List; +import cz.fidentis.analyst.mesh.visitors.MeshVisitor; /** * An ancapsulated mesh plate (with shared vertices). * * @author Matej Lukes */ -public interface MeshFacet { +public interface MeshFacet extends Iterable<MeshTriangle> { /** * returns vertex of specified index @@ -57,10 +57,17 @@ public interface MeshFacet { */ void calculateVertexNormals(); + /** + * Returns number of triangles. + * + * @return number of triangles + */ + int getNumTriangles(); + /** * Entry point for visitors. * * @param visitor Visitor */ - void accept(Visitor visitor); + void accept(MeshVisitor visitor); } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java index d50797953e3789ec245dd6c85a6bb0825c0ea6cd..2c9ce081e517abb57c97cbd4669888a11a227081 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java @@ -1,13 +1,14 @@ package cz.fidentis.analyst.mesh.core; -import cz.fidentis.analyst.mesh.visitors.TriangleListVisitor; -import cz.fidentis.analyst.mesh.visitors.Visitor; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.vecmath.Vector3d; +import cz.fidentis.analyst.mesh.visitors.MeshVisitor; +import java.util.Iterator; +import java.util.NoSuchElementException; /** * MashFacet @@ -37,7 +38,7 @@ public class MeshFacetImpl implements MeshFacet { } @Override - public void accept(Visitor visitor) { + public void accept(MeshVisitor visitor) { visitor.visitMeshFacet(this); } @@ -87,14 +88,12 @@ public class MeshFacetImpl implements MeshFacet { } // calculate normals from corresponding triangles - TriangleListVisitor visitor = new TriangleListVisitor(); - this.accept(visitor); - for (MeshTriangle t : visitor.getTriangles()) { + for (MeshTriangle t : this) { Vector3d triangleNormal = (t.vertex3.subtractPosition(t.vertex1)).crossProduct(t.vertex2.subtractPosition(t.vertex1)).getPosition(); - normalMap.get(t.vertex1).add(triangleNormal); - normalMap.get(t.vertex2).add(triangleNormal); - normalMap.get(t.vertex3).add(triangleNormal); + normalMap.get(t.vertex1.getPosition()).add(triangleNormal); + normalMap.get(t.vertex2.getPosition()).add(triangleNormal); + normalMap.get(t.vertex3.getPosition()).add(triangleNormal); } // normalize normals: @@ -102,6 +101,41 @@ public class MeshFacetImpl implements MeshFacet { normal.normalize(); } } + + public int getNumTriangles() { + return cornerTable.getSize(); + } + + @Override + public Iterator<MeshTriangle> iterator() { + return new Iterator<MeshTriangle>() { + private int index; + + /** + * + * @param facet Mesh facet to iterate + */ + @Override + public boolean hasNext() { + return index < cornerTable.getSize(); + } + + @Override + public MeshTriangle next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + + MeshTriangle tri = new MeshTriangle( + vertices.get(cornerTable.getRow(index + 0).getVertexIndex()), + vertices.get(cornerTable.getRow(index + 1).getVertexIndex()), + vertices.get(cornerTable.getRow(index + 2).getVertexIndex())); + + index += 3; + return tri; + } + }; + } } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java index eaa796cf2f24cf15d03a742f246b8fa432f5d7df..01b745ba6c1ffa414fc1822ba52330c414b6f9db 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java @@ -1,8 +1,8 @@ package cz.fidentis.analyst.mesh.core; -import cz.fidentis.analyst.mesh.visitors.Visitor; import java.util.ArrayList; import java.util.List; +import cz.fidentis.analyst.mesh.visitors.MeshVisitor; /** * MeshModel is a root node of the hierarchy @@ -53,7 +53,7 @@ public class MeshModel { * * @param visitor Visitor */ - public void accept(Visitor visitor) { + public void accept(MeshVisitor visitor) { visitor.visitMeshModel(this); } } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java index ce92a48824f25a7198a025dfd7773ab8077e93e2..234f9376b629837f8ef954c37b3db51b94c5b48d 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java @@ -1,5 +1,8 @@ package cz.fidentis.analyst.mesh.core; +import java.util.Iterator; +import java.util.NoSuchElementException; + /** * * @author Natália Bebjaková @@ -7,7 +10,7 @@ package cz.fidentis.analyst.mesh.core; * Adapter for the corner table representing a single triangle of the @code{MeshFacet}. */ -public class MeshTriangle { +public class MeshTriangle implements Iterable<MeshPoint> { public final MeshPoint vertex1; public final MeshPoint vertex2; @@ -25,6 +28,34 @@ public class MeshTriangle { this.vertex2 = v2; this.vertex3 = v3; } - + + @Override + public Iterator<MeshPoint> iterator() { + return new Iterator<MeshPoint>() { + private int counter = 0; + + @Override + public boolean hasNext() { + return counter < 3; + } + + @Override + public MeshPoint next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + switch (counter++) { + case 0: + return vertex1; + case 1: + return vertex2; + case 2: + return vertex3; + default: + return null; + } + } + }; + } } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitor.java index 4e138d069d3fed48b8f4ec78d21e4837e49d7536..fa3f8b791bdd6df31355170d53a66ede40e74bb2 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitor.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitor.java @@ -7,7 +7,7 @@ import cz.fidentis.analyst.mesh.core.MeshFacet; * * @author Radek Oslejsek */ -public class BoundingBoxVisitor implements Visitor { +public class BoundingBoxVisitor implements MeshVisitor { private BoundingBox bbox; diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshTriVisitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshTriVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..881a4bd72bae9c016e4620868da8404e4e27d108 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshTriVisitor.java @@ -0,0 +1,60 @@ +package cz.fidentis.analyst.mesh.visitors; + +import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshPoint; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Visitor for Hausdorff distance. + * This visitor is instantiated on a single mesh facet or multiple facets. + * When applied to other facets, it computes Huasdorff distance to them. + * + * Distances to triangles are computed, in constrast to the {@code HausdorffDistMeshTriVisitor} + * which calculated distances to mesh points. + * + * @author Matej Lukes + * @author Radek Oslejsek + */ +public class HausdorffDistMeshTriVisitor extends HausdorffDistMeshVisitor { + + /** + * @param mainFacets Facets whose distance to other facets is computed. Must not be {@code null} + * @param relativeDistance If true, then the visitor calculates the relative distances with respect + * to the normal vectors of source facets (normal vectors have to present), + * i.e., we can get negative distances. + * @throws IllegalArgumentException if some parametr is wrong + */ + public HausdorffDistMeshTriVisitor(Set<MeshFacet> mainFacets, boolean relativeDistance) { + super(mainFacets, relativeDistance); + } + + /** + * @param mainFacet Primary facet of which distance to others is to be computed. Must not be {@code null} + * @param relativeDistance If true, then the visitor calculates the relative distances with respect + * to the normal vectors of source facets (normal vectors have to present), + * i.e., we can get negative distances. + * @throws IllegalArgumentException if some parametr is wrong + */ + public HausdorffDistMeshTriVisitor(MeshFacet mainFacet, boolean relativeDistance) { + super(mainFacet, relativeDistance); + } + + @Override + public void visitMeshFacet(MeshFacet comparedFacet) { + for (Map.Entry<MeshFacet, List<Double>> entry: getDistMap().entrySet()) { + List<MeshPoint> vertices = entry.getKey().getVertices(); + List<Double> distList = entry.getValue(); + + boolean firstComparison = distList.isEmpty(); + + for (int i = 0; i < vertices.size(); i++) { + Point2MeshTriVisitor visitor = new Point2MeshTriVisitor(vertices.get(i), isRelativeDistance()); + comparedFacet.accept(visitor); + double dist = visitor.getDistance(); + updateDistances(distList, firstComparison, dist, i); + } + } + } +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshVisitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..10f26a75ffbe426a455f0d49d2eb4a524f49fe31 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshVisitor.java @@ -0,0 +1,110 @@ +package cz.fidentis.analyst.mesh.visitors; + +import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshPoint; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Visitor for Hausdorff distance. + * This visitor is instantiated on a single mesh facet or multiple facets. + * When applied to other facets, it computes Huasdorff distance to them. + * + * @author Matej Lukes + * @author Radek Oslejsek + */ +public class HausdorffDistMeshVisitor implements MeshVisitor { + + private boolean relativeDistance; + private Map<MeshFacet, List<Double>> distances = new HashMap<>(); + + /** + * @param mainFacets Facets whose distance to other facets is computed. Must not be {@code null} + * @param relativeDistance If true, then the visitor calculates the relative distances with respect + * to the normal vectors of source facets (normal vectors have to present), + * i.e., we can get negative distances. + * @throws IllegalArgumentException if some parametr is wrong + */ + public HausdorffDistMeshVisitor(Set<MeshFacet> mainFacets, boolean relativeDistance) { + if (mainFacets == null) { + throw new IllegalArgumentException("mainFacets"); + } + for (MeshFacet f: mainFacets) { + distances.put(f, new ArrayList<>()); + } + this.relativeDistance = relativeDistance; + } + + /** + * @param mainFacet Primary facet of which distance to others is to be computed. Must not be {@code null} + * @param relativeDistance If true, then the visitor calculates the relative distances with respect + * to the normal vectors of source facets (normal vectors have to present), + * i.e., we can get negative distances. + * @throws IllegalArgumentException if some parametr is wrong + */ + public HausdorffDistMeshVisitor(MeshFacet mainFacet, boolean relativeDistance) { + this(new HashSet<>(Collections.singleton(mainFacet)), relativeDistance); + if (mainFacet == null) { + throw new IllegalArgumentException("mainFacet"); + } + } + + @Override + public void visitMeshFacet(MeshFacet comparedFacet) { + for (Map.Entry<MeshFacet, List<Double>> entry: distances.entrySet()) { + List<MeshPoint> vertices = entry.getKey().getVertices(); + List<Double> distList = entry.getValue(); + + boolean firstComparison = distList.isEmpty(); + + for (int i = 0; i < vertices.size(); i++) { + Point2MeshVisitor visitor = new Point2MeshVisitor(vertices.get(i), relativeDistance); + comparedFacet.accept(visitor); + double dist = visitor.getDistance(); + updateDistances(distList, firstComparison, dist, i); + } + } + } + + /** + * Return Hausdorff distance for all points of the source mesh. + * A list of distances is returned for each mesh separaptely. Index of the + * list corresponds to the order of vertives in the mesh facet. + * Therefore, i-t number corresponds to the distance of i-th vertex of the + * source mesh. + * + * @return Hausdorff distance for all points of the source mesh + */ + public Map<MeshFacet, List<Double>> getDistances() { + return Collections.unmodifiableMap(distances); + } + + protected boolean isRelativeDistance() { + return relativeDistance; + } + + protected Map<MeshFacet, List<Double>> getDistMap() { + return distances; + } + + protected void updateDistances(List<Double> distList, boolean firstComparison, double dist, int index) { + if (firstComparison) { + distList.add(dist); + return; + } + + if (dist >= 0 && dist < distList.get(index)) { + distList.set(index, dist); + return; + } + + if (dist < 0 && dist > distList.get(index)) { // for relative dist only + distList.set(index, dist); + } + } +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitor.java index d703b91bfcc7f0f9ef45915fe9503fc36a03a76e..fe696ea2c1f6a6604ae15221c7b5f75186d9e1bf 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitor.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitor.java @@ -13,7 +13,7 @@ import java.util.List; * @author Maria Kocurekova */ -public class KdTreeBuildVisitor implements Visitor { +public class KdTreeBuildVisitor implements MeshVisitor { private List<MeshFacet> facets = new LinkedList<>(); @Override diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Visitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/MeshVisitor.java similarity index 52% rename from MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Visitor.java rename to MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/MeshVisitor.java index 1453f172dcbf4d4b691110916726840a1df1d9ba..850ffeba6ab98d7830c82e4f510ee25d8f73f55c 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Visitor.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/MeshVisitor.java @@ -4,15 +4,20 @@ import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshModel; /** - * Visitor for the traversal of @see cz.fidentis.analyst.mesh.core.MeshModel - * and @see cz.fidentis.analyst.mesh.core.MeshFacet. + * An object, when instatiated, can be applied to multiple meshes via + * @see cz.fidentis.analyst.mesh.core.MeshModel#accept() or + * @see cz.fidentis.analyst.mesh.core.MeshFacet#accept(). It inspects the state + * of these meshes one by one, and (cumulatevely) computes some results. + * + * Implement this interface whenever you want to define new algorithm over a mesh. * * @author Radek Oslejsek */ -public interface Visitor { +public interface MeshVisitor { /** - * Visits a mesh model. + * Visits a mesh model. Ba default, this method visits + * all facets of the model automatically. * * @param model Mesh model to be visited. */ diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Point2MeshTriVisitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Point2MeshTriVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..7c8ed4fa36c6e0ecffa68e1faa19d5582e8f9c75 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Point2MeshTriVisitor.java @@ -0,0 +1,175 @@ +package cz.fidentis.analyst.mesh.visitors; + +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 java.util.ArrayList; +import java.util.List; +import javax.vecmath.Vector3d; + +/** + * This visitor finds mesh points that are the closest to the given 3D point. + * In contrast to the {@code Point2MeshVisitor} visitor, + * which computes pont-to-point distance, this implementation measures + * the distance to the triangles. + * + * Because there can be multiple triangles with the same minimal distance, the visitor + * returns a list of mesh facets and a list of indices corresponding + * to the facets. + * + * Returned lists have the same size. + * {@code n = getIndices().get(i)} returns the index of the closest triangle on the i-th facet. + * Then iterate into the n-th triangle of facet {@code getClosestFacets().get(i)} to get + * the triangle instance. + * + * @author Matej Lukes + * @author Radek Oslejsek + */ +public class Point2MeshTriVisitor extends Point2MeshVisitor { + + public static final double EPS = 0.001; // tollerance for double computations + + /** + * @param point Mesh point of which distance is computed. Must not be {@code null} + * @param relativeDistance If true, the visitor calculates the distances with respect + * to the normals of the source point (the normal has to be present), + * i.e., we can get negative distance. + * @throws IllegalArgumentException if some parametr is wrong + */ + public Point2MeshTriVisitor(MeshPoint point, boolean relativeDistance) { + super(point, relativeDistance); + } + + /** + * @param point 3D point of which distance is computed. Must not be {@code null} + * @throws IllegalArgumentException if some parametr is wrong + */ + public Point2MeshTriVisitor(Vector3d point) { + this (new MeshPointImpl(point, null, null), true); + } + + @Override + public void visitMeshFacet(MeshFacet facet) { + Vector3d my = getMyPoint().getPosition(); + int i = 0; + for (MeshTriangle tri: facet) { + Vector3d projection = getProjectionToTrianglePlane(my, tri); + if (!isPointInTriangle(projection, tri)) { + projection = getProjectionToClosestEdge(projection, tri); + } + checkAndUpdateDistance(projection, facet, i); + } + } + + /** + * 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, MeshTriangle triangle) { + Vector3d ab = new Vector3d(triangle.vertex1.getPosition()); + ab.sub(triangle.vertex2.getPosition()); + Vector3d ac = new Vector3d(triangle.vertex1.getPosition()); + ac.sub(triangle.vertex3.getPosition()); + Vector3d normal = new Vector3d(); + normal.cross(ab, ac); + normal.normalize(); + + Vector3d projection = new Vector3d(vertex); + Vector3d helperVector = new Vector3d(vertex); + helperVector.sub(triangle.vertex1.getPosition()); + double dist = helperVector.dot(normal); + + projection.scaleAdd(-dist, normal, projection); + return projection; + } + + /** + * checks if a point in the 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, MeshTriangle triangle) { + List<Vector3d> pointToVertices = new ArrayList<>(); + for (MeshPoint p: triangle) { + Vector3d v = new Vector3d(p.getPosition()); + v.sub(point); + pointToVertices.add(v); + } + + double angleSum = 0; + for (int i = 0; i < 3; i++) { + angleSum += pointToVertices.get(i).angle(pointToVertices.get((i + 1) % 3)); + } + angleSum -= 2 * Math.PI; + return -EPS < angleSum && angleSum < EPS; + } + + /** + * returns projection to the nearest edge of the triangle + * + * @param point point in plane of triangle + * @param triangle triangle + * @return perpendicular projection to the nearest edge + */ + private Vector3d getProjectionToClosestEdge(Vector3d point, MeshTriangle triangle) { + Vector3d[] projections = new Vector3d[3]; + projections[0] = getProjectionToEdge(point, triangle.vertex1.getPosition(), triangle.vertex2.getPosition()); + projections[1] = getProjectionToEdge(point, triangle.vertex2.getPosition(), triangle.vertex3.getPosition()); + projections[2] = getProjectionToEdge(point, triangle.vertex3.getPosition(), triangle.vertex1.getPosition()); + + double minDistance = Double.MAX_VALUE; + Vector3d closestProjection = null; + Vector3d helperVector = new Vector3d(); + for (Vector3d projection: projections) { + helperVector.sub(point, projection); + double dist = helperVector.length(); + if (dist < minDistance) { + minDistance = dist; + 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(edgeVertex2, edgeVertex1); + Vector3d ap = new Vector3d(); + ap.sub(point, edgeVertex1); + double t = ab.dot(ap) / ab.lengthSquared(); + Vector3d projection = new Vector3d( + edgeVertex1.x + t * ab.x, + edgeVertex1.y + t * ab.y, + edgeVertex1.z + t * ab.z); + + Vector3d projectionToEdgeVertex1 = new Vector3d(); + projectionToEdgeVertex1.sub(edgeVertex1, projection); + Vector3d projectionToEdgeVertex2 = new Vector3d(); + projectionToEdgeVertex2.sub(edgeVertex2, projection); + + if (Math.abs((projectionToEdgeVertex1.length() + projectionToEdgeVertex2.length()) - ab.length()) < EPS) { + return projection; + } + + if (projectionToEdgeVertex1.length() < projectionToEdgeVertex2.length()) { + return edgeVertex1; + } + + return edgeVertex2; + } + +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Point2MeshVisitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Point2MeshVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..c0c718fa164e8f17fef55ac73bb9deb05f8b3945 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/Point2MeshVisitor.java @@ -0,0 +1,129 @@ +package cz.fidentis.analyst.mesh.visitors; + +import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshPoint; +import cz.fidentis.analyst.mesh.core.MeshPointImpl; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.vecmath.Vector3d; + +/** + * This visitor finds mesh points that are the closest to the given 3D point. + * Because there can be multiple points with the same minimal distance, the visitor + * returns a list of mesh facets and a list of indices corresponding + * to the facets. + * +* Returned lists have the same size. + * {@code n = getIndices().get(i)} returns the index of the closest point on the i-th facet. + * Then call {@code getClosestFacets().get(i).getVertex(n))} to get the closest point. + * + * @author Matej Lukes + * @author Radek Oslejsek + */ +public class Point2MeshVisitor implements MeshVisitor { + + private boolean relativeDist; + private MeshPoint myPoint; + private double distance = Double.POSITIVE_INFINITY; + private int sign = 1; + private final List<MeshFacet> closestFacets = new ArrayList<>(); + private final List<Integer> indices = new ArrayList<>(); + + /** + * @param point Mesh point of which distance is computed. Must not be {@code null} + * @param relativeDistance If true, the visitor calculates the distances with respect + * to the normals of the source point (the normal has to be present), + * i.e., we can get negative distance. + * @throws IllegalArgumentException if some parametr is wrong + */ + public Point2MeshVisitor(MeshPoint point, boolean relativeDistance) { + if (point == null) { + throw new IllegalArgumentException("point"); + } + if (point.getNormal() == null && relativeDistance) { + throw new IllegalArgumentException("normal required for relative distance"); + } + this.myPoint = point; + this.relativeDist = relativeDistance; + } + + /** + * @param point 3D point of which distance is computed. Must not be {@code null} + * @throws IllegalArgumentException if some parametr is wrong + */ + public Point2MeshVisitor(Vector3d point) { + this (new MeshPointImpl(point, null, null), true); + } + + @Override + public void visitMeshFacet(MeshFacet facet) { + List<MeshPoint> vertices = facet.getVertices(); + for (int i = 0; i < vertices.size(); i++) { + checkAndUpdateDistance(vertices.get(i).getPosition(), facet, i); + } + } + + /** + * Returns distance to the closest mesh point. + * + * @return distance to the closest mesh point, + * {@code Double.POSITIVE_INFINITY} if no distance has been calculated + */ + public double getDistance() { + return relativeDist ? sign * distance : distance; + } + + /** + * Returns indeces to the closest elements (points or triangles) of corresponding facet. + * + * @return indeces to the closest elements (points or triangles) of corresponding facet, + * {@code null} if no search has been performed + */ + public List<Integer> getIndices() { + return Collections.unmodifiableList(indices); + } + + /** + * Returns the closest mesh facets (containing the closest mesh points). + * + * @return the closest mesh facets + */ + public List<MeshFacet> getClosestFacets() { + return Collections.unmodifiableList(closestFacets); + } + + protected boolean isRelativeDist() { + return relativeDist; + } + + protected MeshPoint getMyPoint() { + return myPoint; + } + + protected int getSign() { + return sign; + } + + protected void checkAndUpdateDistance(Vector3d other, MeshFacet facet, int index) { + Vector3d aux = new Vector3d(other); + aux.sub(myPoint.getPosition()); + sign = relativeDist ? (int) Math.signum(aux.dot(myPoint.getNormal())): 1; + double dist = aux.length(); + + if (dist > distance) { + return; + } + + if (dist < distance) { // new closest point + distance = dist; + closestFacets.clear(); + indices.clear(); + closestFacets.add(facet); + indices.add(index); + } else { // the same distance + closestFacets.add(facet); + indices.add(index); + } + } +} diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitor.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitor.java index 8acb8c8bc098689cff9746bd20a7092adddabe9a..2608f7009ad76d883a1a99e40803287125172a09 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitor.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitor.java @@ -1,28 +1,26 @@ package cz.fidentis.analyst.mesh.visitors; -import cz.fidentis.analyst.mesh.core.CornerTable; import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshTriangle; import java.util.ArrayList; import java.util.List; /** - * Visitor that collects and returs list of triangles. + * A visitor that collects and returns a list of triangles. + * It is usefull for collecting triangles of multiple mesh facets. + * For iterating through triangles of a single facet, use the iterator instead. + * Or iterate through the facet in a for-each cycle. * * @author Radek Oslejsek */ -public class TriangleListVisitor implements Visitor { +public class TriangleListVisitor implements MeshVisitor { private List<MeshTriangle> triangles = new ArrayList<>(); @Override public void visitMeshFacet(MeshFacet facet) { - CornerTable ct = facet.getCornerTable(); - for (int i = 0; i < ct.getSize(); i += 3) { - triangles.add(new MeshTriangle( - facet.getVertex(ct.getRow(i + 0).getVertexIndex()), - facet.getVertex(ct.getRow(i + 1).getVertexIndex()), - facet.getVertex(ct.getRow(i + 2).getVertexIndex()))); + for (MeshTriangle tri : facet) { + triangles.add(tri); } } diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitorTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitorTest.java index 74a58e63c6bfa825e4102a9aef6f24ecf461557b..87abc48d9a549247a797e304b34c9af5f3710c90 100644 --- a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitorTest.java +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/BoundingBoxVisitorTest.java @@ -1,5 +1,6 @@ package cz.fidentis.analyst.mesh.visitors; +import cz.fidentis.analyst.mesh.visitors.BoundingBoxVisitor; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.io.MeshObjLoader; import java.io.File; diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshTriVisitorTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshTriVisitorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..73b6a884f3b9b6bde9f073c745a1ae134835d7f8 --- /dev/null +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshTriVisitorTest.java @@ -0,0 +1,88 @@ +package cz.fidentis.analyst.mesh.visitors; + +import cz.fidentis.analyst.mesh.core.CornerTableRow; +import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshFacetImpl; +import cz.fidentis.analyst.mesh.core.MeshPointImpl; +import java.util.List; +import java.util.Map; +import javax.vecmath.Vector3d; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; + +public class HausdorffDistMeshTriVisitorTest { + + private MeshFacet getTrivialFacet(double offset, double size) { + MeshFacet facet = new MeshFacetImpl(); + facet.addVertex(new MeshPointImpl(new Vector3d(0, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(size, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(0, size, offset), new Vector3d(0, 0, 1), new Vector3d())); + + facet.getCornerTable().addRow(new CornerTableRow(0, -1)); + facet.getCornerTable().addRow(new CornerTableRow(1, -1)); + facet.getCornerTable().addRow(new CornerTableRow(2, -1)); + + return facet; + } + + @Test + public void visitToVerticesTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(1.5, 1); + + HausdorffDistMeshTriVisitor hausdorffDistance = new HausdorffDistMeshTriVisitor(mainFacet, false); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(0.5, results.get(i)); + } + } + + @Test + public void visitToVerticesBehindMeshTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(-1.5, 1); + + HausdorffDistMeshTriVisitor hausdorffDistance = new HausdorffDistMeshTriVisitor(mainFacet, false); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(2.5, results.get(i)); + } + } + + @Test + public void visitToVerticesRelativeDistanceTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(1.5, 1); + + HausdorffDistMeshTriVisitor hausdorffDistance = new HausdorffDistMeshTriVisitor(mainFacet, true); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(0.5, results.get(i)); + } + } + + @Test + public void visitToVerticesBehindMeshRelativeDistanceTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(-1.5, 1); + + HausdorffDistMeshTriVisitor hausdorffDistance = new HausdorffDistMeshTriVisitor(mainFacet, true); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(-2.5, results.get(i)); + } + } + +} diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshVisitorTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshVisitorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c0e987fc88311855f963cf7f444a39c3644288ca --- /dev/null +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/HausdorffDistMeshVisitorTest.java @@ -0,0 +1,88 @@ +package cz.fidentis.analyst.mesh.visitors; + +import cz.fidentis.analyst.mesh.core.CornerTableRow; +import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshFacetImpl; +import cz.fidentis.analyst.mesh.core.MeshPointImpl; +import java.util.List; +import java.util.Map; +import javax.vecmath.Vector3d; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; + +public class HausdorffDistMeshVisitorTest { + + private MeshFacet getTrivialFacet(double offset, double size) { + MeshFacet facet = new MeshFacetImpl(); + facet.addVertex(new MeshPointImpl(new Vector3d(0, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(size, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(0, size, offset), new Vector3d(0, 0, 1), new Vector3d())); + + facet.getCornerTable().addRow(new CornerTableRow(0, -1)); + facet.getCornerTable().addRow(new CornerTableRow(1, -1)); + facet.getCornerTable().addRow(new CornerTableRow(2, -1)); + + return facet; + } + + @Test + public void visitToVerticesTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(1.5, 1); + + HausdorffDistMeshVisitor hausdorffDistance = new HausdorffDistMeshVisitor(mainFacet, false); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(0.5, results.get(i)); + } + } + + @Test + public void visitToVerticesBehindMeshTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(-1.5, 1); + + HausdorffDistMeshVisitor hausdorffDistance = new HausdorffDistMeshVisitor(mainFacet, false); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(2.5, results.get(i)); + } + } + + @Test + public void visitToVerticesRelativeDistanceTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(1.5, 1); + + HausdorffDistMeshVisitor hausdorffDistance = new HausdorffDistMeshVisitor(mainFacet, true); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(0.5, results.get(i)); + } + } + + @Test + public void visitToVerticesBehindMeshRelativeDistanceTest() { + MeshFacet mainFacet = getTrivialFacet(1, 1); + MeshFacet comparedFacet = getTrivialFacet(-1.5, 1); + + HausdorffDistMeshVisitor hausdorffDistance = new HausdorffDistMeshVisitor(mainFacet, true); + hausdorffDistance.visitMeshFacet(comparedFacet); + + Map<MeshFacet, List<Double>> map = hausdorffDistance.getDistances(); + List<Double> results = map.get(mainFacet); + for (int i = 0; i < mainFacet.getNumberOfVertices(); i++) { + assertEquals(-2.5, results.get(i)); + } + } + +} diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitorTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitorTest.java index 1fead8af2d734a556b7de83354a421562cbdd022..8de5cebe908230b1ec465fcf8e505cbd593e36e3 100644 --- a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitorTest.java +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/KdTreeBuildVisitorTest.java @@ -1,5 +1,6 @@ package cz.fidentis.analyst.mesh.visitors; +import cz.fidentis.analyst.mesh.visitors.KdTreeBuildVisitor; import cz.fidentis.analyst.kdtree.KdNode; import cz.fidentis.analyst.mesh.core.*; import cz.fidentis.analyst.mesh.io.MeshObjLoader; diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/Point2MeshTriVisitorTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/Point2MeshTriVisitorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9fbaae3b7e50458416c6dc8e7a81cb5d4983a9fb --- /dev/null +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/Point2MeshTriVisitorTest.java @@ -0,0 +1,320 @@ +package cz.fidentis.analyst.mesh.visitors; + +import cz.fidentis.analyst.mesh.core.CornerTableRow; +import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshFacetImpl; +import cz.fidentis.analyst.mesh.core.MeshPoint; +import cz.fidentis.analyst.mesh.core.MeshPointImpl; +import cz.fidentis.analyst.mesh.core.MeshTriangle; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import javax.vecmath.Vector3d; +import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.Test; + +/** + * + * @author oslejsek + */ +public class Point2MeshTriVisitorTest { + private MeshFacet getTrivialFacet(double offset, double size) { + MeshFacet facet = new MeshFacetImpl(); + facet.addVertex(new MeshPointImpl(new Vector3d(0, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(size, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(0, size, offset), new Vector3d(0, 0, 1), new Vector3d())); + + facet.getCornerTable().addRow(new CornerTableRow(0, -1)); + facet.getCornerTable().addRow(new CornerTableRow(1, -1)); + facet.getCornerTable().addRow(new CornerTableRow(2, -1)); + + return facet; + } + + @Test + public void absoluteDistTest() { + MeshFacet facet = getTrivialFacet(1.5, 1); + MeshPoint point = new MeshPointImpl(new Vector3d(0,0,0), new Vector3d(0,0,-1), new Vector3d()); + + Point2MeshVisitor vis = new Point2MeshTriVisitor(point, false); + facet.accept(vis); + assertEquals(1.5, vis.getDistance()); + + List<Integer> closestPoints = vis.getIndices(); + List<MeshFacet> closestMeshes = vis.getClosestFacets(); + assertNotNull(closestPoints); + assertNotNull(closestMeshes); + assertEquals(1, closestPoints.size()); + assertEquals(1, closestMeshes.size()); + assertEquals(facet, closestMeshes.get(0)); + assertEquals(0, closestPoints.get(0)); + } + + @Test + public void relativeDistTest() { + MeshFacet facet = getTrivialFacet(1.5, 1); + MeshPoint point = new MeshPointImpl(new Vector3d(0,0,0), new Vector3d(0,0,-1), new Vector3d()); + + Point2MeshVisitor vis = new Point2MeshTriVisitor(point, true); + facet.accept(vis); + assertEquals(-1.5, vis.getDistance()); + + List<Integer> closestPoints = vis.getIndices(); + List<MeshFacet> closestMeshes = vis.getClosestFacets(); + assertNotNull(closestPoints); + assertNotNull(closestMeshes); + assertEquals(1, closestPoints.size()); + assertEquals(1, closestMeshes.size()); + assertEquals(facet, closestMeshes.get(0)); + assertEquals(0, closestPoints.get(0)); + } + + @Test + public void exactMatchTest() { + MeshFacet facet = getTrivialFacet(1.5, 1); + MeshPoint point = new MeshPointImpl(new Vector3d(0, 0, 1.5), new Vector3d(0, 0, 1), new Vector3d()); + + System.out.println(facet.getVertices()); + + Point2MeshVisitor vis = new Point2MeshTriVisitor(point, false); + facet.accept(vis); + assertEquals(0, vis.getDistance()); + + System.out.println(facet.getVertices()); + + List<Integer> closestPoints = vis.getIndices(); + List<MeshFacet> closestMeshes = vis.getClosestFacets(); + assertNotNull(closestPoints); + assertNotNull(closestMeshes); + assertEquals(1, closestPoints.size()); + assertEquals(1, closestMeshes.size()); + assertEquals(facet, closestMeshes.get(0)); + assertEquals(0, closestPoints.get(0)); + } + + @Test + public void getProjectionToTrianglePlaneTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[2]; + argClasses[0] = Vector3d.class; + argClasses[1] = MeshTriangle.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("getProjectionToTrianglePlane", argClasses); + method.setAccessible(true); + Object[] args = new Object[2]; + + args[0] = new Vector3d(0, 0.5, 1); + MeshTriangle triangle = new MeshTriangle( + new MeshPointImpl(new Vector3d(1, 0, 0), null, null), + new MeshPointImpl(new Vector3d(1, 2, 0), null, null), + new MeshPointImpl(new Vector3d(2, 0, 0), null, null) + ); + args[1] = triangle; + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + Vector3d result = (Vector3d) method.invoke(hausdorffDistance, args); + + Assertions.assertEquals(0d, result.x); + Assertions.assertEquals(0.5d, result.y); + Assertions.assertEquals(0d, result.z); + } + + @Test + public void getProjectionToTrianglePlaneBelowPLaneTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[2]; + argClasses[0] = Vector3d.class; + argClasses[1] = MeshTriangle.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("getProjectionToTrianglePlane", argClasses); + method.setAccessible(true); + Object[] args = new Object[2]; + + args[0] = new Vector3d(0, 0.5, 1); + MeshTriangle triangle = new MeshTriangle( + new MeshPointImpl(new Vector3d(1, 0, 0), null, null), + new MeshPointImpl(new Vector3d(1, 2, 0), null, null), + new MeshPointImpl(new Vector3d(2, 0, 0), null, null) + ); + args[1] = triangle; + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + Vector3d result = (Vector3d) method.invoke(hausdorffDistance, args); + + Assertions.assertEquals(0d, result.x); + Assertions.assertEquals(0.5d, result.y); + Assertions.assertEquals(0d, result.z); + } + + @Test + public void isPointInTriangleInsideTriangleTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[2]; + argClasses[0] = Vector3d.class; + argClasses[1] = MeshTriangle.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("isPointInTriangle", argClasses); + method.setAccessible(true); + Object[] args = new Object[2]; + + args[0] = new Vector3d(1.2, 0.2, 0); + MeshTriangle triangle = new MeshTriangle( + new MeshPointImpl(new Vector3d(1, 0, 0), null, null), + new MeshPointImpl(new Vector3d(1, 2, 0), null, null), + new MeshPointImpl(new Vector3d(2, 0, 0), null, null) + ); + args[1] = triangle; + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + boolean result = (boolean) method.invoke(hausdorffDistance, args); + + Assertions.assertTrue(result); + } + + @Test + public void isPointInTriangleOutsideTriangleTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[2]; + argClasses[0] = Vector3d.class; + argClasses[1] = MeshTriangle.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("isPointInTriangle", argClasses); + method.setAccessible(true); + Object[] args = new Object[2]; + + args[0] = new Vector3d(0, 0.5, 0); + MeshTriangle triangle = new MeshTriangle( + new MeshPointImpl(new Vector3d(1, 0, 0), null, null), + new MeshPointImpl(new Vector3d(1, 2, 0), null, null), + new MeshPointImpl(new Vector3d(2, 0, 0), null, null) + ); + args[1] = triangle; + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + boolean result = (boolean) method.invoke(hausdorffDistance, args); + + Assertions.assertFalse(result); + } + + @Test + public void getProjectionToClosestEdgeTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[2]; + argClasses[0] = Vector3d.class; + argClasses[1] = MeshTriangle.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("getProjectionToClosestEdge", argClasses); + method.setAccessible(true); + Object[] args = new Object[2]; + + args[0] = new Vector3d(0, 0.5, 0); + MeshTriangle triangle = new MeshTriangle( + new MeshPointImpl(new Vector3d(1, 0, 0), null, null), + new MeshPointImpl(new Vector3d(1, 2, 0), null, null), + new MeshPointImpl(new Vector3d(2, 0, 0), null, null) + ); + args[1] = triangle; + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + Vector3d result = (Vector3d) method.invoke(hausdorffDistance, args); + + Assertions.assertEquals(1d, result.x); + Assertions.assertEquals(0.5d, result.y); + Assertions.assertEquals(0d, result.z); + } + + @Test + public void getProjectionToClosestEdgeNormalProjectionOutsideEdgeTestTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[2]; + argClasses[0] = Vector3d.class; + argClasses[1] = MeshTriangle.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("getProjectionToClosestEdge", argClasses); + method.setAccessible(true); + Object[] args = new Object[2]; + + args[0] = new Vector3d(0, -0.5, 0); + MeshTriangle triangle = new MeshTriangle( + new MeshPointImpl(new Vector3d(1, 0, 0), null, null), + new MeshPointImpl(new Vector3d(1, 2, 0), null, null), + new MeshPointImpl(new Vector3d(2, 0, 0), null, null) + ); + args[1] = triangle; + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + Vector3d result = (Vector3d) method.invoke(hausdorffDistance, args); + + Assertions.assertEquals(1d, result.x); + Assertions.assertEquals(0d, result.y); + Assertions.assertEquals(0d, result.z); + } + + @Test + public void getProjectionToEdgeTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[3]; + argClasses[0] = Vector3d.class; + argClasses[1] = Vector3d.class; + argClasses[2] = Vector3d.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("getProjectionToEdge", argClasses); + method.setAccessible(true); + Object[] args = new Object[3]; + + args[0] = new Vector3d(0, 0.5, 0); + args[1] = new Vector3d(1, 2, 0); + args[2] = new Vector3d(1, 0, 0); + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + Vector3d result = (Vector3d) method.invoke(hausdorffDistance, args); + + Assertions.assertEquals(1d, result.x); + Assertions.assertEquals(0.5d, result.y); + Assertions.assertEquals(0d, result.z); + } + + @Test + public void getProjectionToEdgeNormalProjectionOutsideEdgeTest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[3]; + argClasses[0] = Vector3d.class; + argClasses[1] = Vector3d.class; + argClasses[2] = Vector3d.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("getProjectionToEdge", argClasses); + method.setAccessible(true); + Object[] args = new Object[3]; + + args[0] = new Vector3d(0, -0.5, 0); + args[1] = new Vector3d(1, 2, 0); + args[2] = new Vector3d(1, 0, 0); + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + Vector3d result = (Vector3d) method.invoke(hausdorffDistance, args); + + Assertions.assertEquals(1d, result.x); + Assertions.assertEquals(0d, result.y); + Assertions.assertEquals(0d, result.z); + } + + @Test + public void getProjectionToEdgeNormalProjectionOutsideEdge2Test() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + Class<?>[] argClasses = new Class[3]; + argClasses[0] = Vector3d.class; + argClasses[1] = Vector3d.class; + argClasses[2] = Vector3d.class; + Method method = Point2MeshTriVisitor.class.getDeclaredMethod("getProjectionToEdge", argClasses); + method.setAccessible(true); + Object[] args = new Object[3]; + + args[0] = new Vector3d(0, 2.5, 0); + args[1] = new Vector3d(1, 2, 0); + args[2] = new Vector3d(1, 0, 0); + + Point2MeshTriVisitor hausdorffDistance = new Point2MeshTriVisitor(new MeshPointImpl(new Vector3d(), null, null), false); + Vector3d result = (Vector3d) method.invoke(hausdorffDistance, args); + + Assertions.assertEquals(1d, result.x); + Assertions.assertEquals(2d, result.y); + Assertions.assertEquals(0d, result.z); + } + +} diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/Point2MeshVisitorTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/Point2MeshVisitorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1a53154a39821e1c2539e7dbfaebbef733f038b1 --- /dev/null +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/Point2MeshVisitorTest.java @@ -0,0 +1,86 @@ +package cz.fidentis.analyst.mesh.visitors; + +import cz.fidentis.analyst.mesh.core.CornerTableRow; +import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshFacetImpl; +import cz.fidentis.analyst.mesh.core.MeshPoint; +import cz.fidentis.analyst.mesh.core.MeshPointImpl; +import java.util.List; +import javax.vecmath.Vector3d; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.Test; + +public class Point2MeshVisitorTest { + private MeshFacet getTrivialFacet(double offset, double size) { + MeshFacet facet = new MeshFacetImpl(); + facet.addVertex(new MeshPointImpl(new Vector3d(0, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(size, 0, offset), new Vector3d(0, 0, 1), new Vector3d())); + facet.addVertex(new MeshPointImpl(new Vector3d(0, size, offset), new Vector3d(0, 0, 1), new Vector3d())); + + facet.getCornerTable().addRow(new CornerTableRow(0, -1)); + facet.getCornerTable().addRow(new CornerTableRow(1, -1)); + facet.getCornerTable().addRow(new CornerTableRow(2, -1)); + + return facet; + } + + @Test + public void absoluteDistTest() { + MeshFacet facet = getTrivialFacet(1.5, 1); + MeshPoint point = new MeshPointImpl(new Vector3d(0,0,0), new Vector3d(0,0,-1), new Vector3d()); + + Point2MeshVisitor vis = new Point2MeshVisitor(point, false); + facet.accept(vis); + assertEquals(1.5, vis.getDistance()); + + List<Integer> closestPoints = vis.getIndices(); + List<MeshFacet> closestMeshes = vis.getClosestFacets(); + assertNotNull(closestPoints); + assertNotNull(closestMeshes); + assertEquals(1, closestPoints.size()); + assertEquals(1, closestMeshes.size()); + assertEquals(facet, closestMeshes.get(0)); + assertEquals(0, closestPoints.get(0)); + } + + @Test + public void relativeDistTest() { + MeshFacet facet = getTrivialFacet(1.5, 1); + MeshPoint point = new MeshPointImpl(new Vector3d(0,0,0), new Vector3d(0,0,-1), new Vector3d()); + + Point2MeshVisitor vis = new Point2MeshVisitor(point, true); + facet.accept(vis); + assertEquals(-1.5, vis.getDistance()); + + List<Integer> closestPoints = vis.getIndices(); + List<MeshFacet> closestMeshes = vis.getClosestFacets(); + assertNotNull(closestPoints); + assertNotNull(closestMeshes); + assertEquals(1, closestPoints.size()); + assertEquals(1, closestMeshes.size()); + assertEquals(facet, closestMeshes.get(0)); + assertEquals(0, closestPoints.get(0)); + } + + @Test + public void exactMatchTest() { + MeshFacet facet = getTrivialFacet(1.5, 1); + MeshPoint point = new MeshPointImpl(new Vector3d(0, 0, 1.5), new Vector3d(0, 0, 1), new Vector3d()); + + System.out.println(facet.getVertices()); + + Point2MeshVisitor vis = new Point2MeshVisitor(point, false); + facet.accept(vis); + assertEquals(0, vis.getDistance()); + + List<Integer> closestPoints = vis.getIndices(); + List<MeshFacet> closestMeshes = vis.getClosestFacets(); + assertNotNull(closestPoints); + assertNotNull(closestMeshes); + assertEquals(1, closestPoints.size()); + assertEquals(1, closestMeshes.size()); + assertEquals(facet, closestMeshes.get(0)); + assertEquals(0, closestPoints.get(0)); + } +} diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitorTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitorTest.java index 9221bd871ff70ce22d8ecd6fd4edd652a1a51090..6f3dd6d8665ccdc96b926753d052160e62f2d925 100644 --- a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitorTest.java +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/visitors/TriangleListVisitorTest.java @@ -1,6 +1,6 @@ package cz.fidentis.analyst.mesh.visitors; -import cz.fidentis.analyst.mesh.visitors.*; +import cz.fidentis.analyst.mesh.visitors.TriangleListVisitor; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.io.MeshObjLoader; import cz.fidentis.analyst.mesh.io.MeshObjLoader;