From ae3af2beafad68ace4227d8793cd3fc1610a9120 Mon Sep 17 00:00:00 2001 From: Radek Oslejsek <oslejsek@fi.muni.cz> Date: Sun, 4 Apr 2021 11:37:14 +0200 Subject: [PATCH] Curvature algorithms merged to a single class --- .../analyst/symmetry/SignificantPoints.java | 48 ++++- .../analyst/symmetry/SymmetryEstimator.java | 32 +-- .../analyst/tests/CurvatureTests.java | 53 ++++- .../analyst/tests/EfficiencyTests.java | 14 +- .../analyst/visitors/mesh/Curvature.java | 116 +++++++--- .../analyst/visitors/mesh/DeltaCurvature.java | 198 ------------------ .../visitors/mesh/GaussianCurvature.java | 89 -------- .../analyst/visitors/mesh/MeanCurvature.java | 45 ---- .../gui/ComparisonGLEventListener.java | 14 +- .../analyst/gui/GeneralGLEventListener.java | 3 +- .../fidentis/analyst/gui/SymmetryPanel.java | 3 +- .../fidentis/analyst/mesh/core/MeshModel.java | 9 + 12 files changed, 203 insertions(+), 421 deletions(-) delete mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java delete mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java delete mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java index 6bf6bc04..6169d48c 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SignificantPoints.java @@ -23,11 +23,20 @@ import javax.vecmath.Vector3d; * @author Natalia Bebjakova */ public class SignificantPoints extends MeshVisitor { - + + public enum CurvatureAlg { + MEAN, + GAUSSIAN, + MAX, + MIN + }; + private final int maxPoints; private final Curvature curvatureVisitor; + private final CurvatureAlg curvatureAlg; + private List<VertCurvature> significantPoints; private List<List<Vector3d>> normCosVecCache; @@ -39,19 +48,32 @@ public class SignificantPoints extends MeshVisitor { /** * Constructor. * - * @param curvatureVisitor Curvature computation strategy. If the object has + * @param cAlg Curvature strategy to be used for the selection of significant points. + * @param max Maximal number of significant points + * @throws IllegalArgumentException if the {@code curbatureVisitor} is missing + */ + public SignificantPoints(CurvatureAlg cAlg, int max) { + this(new Curvature(), cAlg, max); + } + + /** + * Constructor. + * + * @param curvatureVisitor Curvature. If the object has * pre-filled curvatures of meshes, then they are used also used for the computation * of significant points. In this way, it is possible to reuse already computed * curvatures and skip calling the {@link #visitMeshFacet} inspection method. + * @param cAlg Curvature strategy to be used for the selection of significant points. * @param max Maximal number of significant points * @throws IllegalArgumentException if the {@code curbatureVisitor} is missing */ - public SignificantPoints(Curvature curvatureVisitor, int max) { + public SignificantPoints(Curvature curvatureVisitor, CurvatureAlg cAlg, int max) { if (curvatureVisitor == null) { throw new IllegalArgumentException("curvatureVisitor"); } this.maxPoints = max; this.curvatureVisitor = curvatureVisitor; + this.curvatureAlg = cAlg; } @Override @@ -168,7 +190,25 @@ public class SignificantPoints extends MeshVisitor { // fill the priority queue final PriorityQueue<VertCurvature> priorityQueue = new PriorityQueue<>(); - Map<MeshFacet, List<Double>> curvMap = curvatureVisitor.getCurvatures(); + + Map<MeshFacet, List<Double>> curvMap = null; + switch (curvatureAlg) { + case MEAN: + curvMap = curvatureVisitor.getMeanCurvatures(); + break; + case GAUSSIAN: + curvMap = curvatureVisitor.getGaussianCurvatures(); + break; + case MAX: + curvMap = curvatureVisitor.getMaxPrincipalCurvatures(); + break; + case MIN: + curvMap = curvatureVisitor.getMinPrincipalCurvatures(); + break; + default: + throw new IllegalArgumentException("curvatureAlg"); + } + for (MeshFacet facet: curvMap.keySet()) { List<Double> curvs = curvMap.get(facet); for (int i = 0; i < curvs.size(); i++) { 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 8e3c82f4..cbfbfe35 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java @@ -5,12 +5,10 @@ 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 cz.fidentis.analyst.symmetry.SignificantPoints.CurvatureAlg; import cz.fidentis.analyst.visitors.mesh.BoundingBox; import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import cz.fidentis.analyst.visitors.mesh.Curvature; -import cz.fidentis.analyst.visitors.mesh.GaussianCurvature; -import cz.fidentis.analyst.visitors.mesh.DeltaCurvature; -import cz.fidentis.analyst.visitors.mesh.MeanCurvature; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; @@ -41,13 +39,6 @@ public class SymmetryEstimator extends MeshVisitor { private final SignificantPoints sigPointsVisitor; private final BoundingBox bbVisitor = new BoundingBox(); - public enum CurvatureAlg { - MEAN, - GAUSSIAN, - MAX, - MIN - }; - private CurvatureAlg curvatureAlg; private Plane symmetryPlane; @@ -65,26 +56,7 @@ public class SymmetryEstimator extends MeshVisitor { throw new IllegalArgumentException("config"); } this.config = config; - - // create the visitor of significant points with required curvate computation strategy - Curvature curvatureVisitor = null; - switch (curvatureAlg) { - case MEAN: - curvatureVisitor = new MeanCurvature(); - break; - case GAUSSIAN: - curvatureVisitor = new GaussianCurvature(); - break; - case MAX: - curvatureVisitor = new DeltaCurvature(true); - break; - case MIN: - curvatureVisitor = new DeltaCurvature(false); - break; - default: - throw new IllegalArgumentException("curvatureAlg"); - } - this.sigPointsVisitor = new SignificantPoints(curvatureVisitor, config.getSignificantPointCount()); + this.sigPointsVisitor = new SignificantPoints(curvatureAlg, config.getSignificantPointCount()); } @Override diff --git a/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java b/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java index 9fc85226..fc2d8cb6 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/tests/CurvatureTests.java @@ -2,14 +2,15 @@ package cz.fidentis.analyst.tests; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.mesh.core.MeshFacet; +import cz.fidentis.analyst.mesh.core.MeshPoint; import cz.fidentis.analyst.visitors.mesh.Curvature; -import cz.fidentis.analyst.visitors.mesh.DeltaCurvature; -import cz.fidentis.analyst.visitors.mesh.GaussianCurvature; -import cz.fidentis.analyst.visitors.mesh.MeanCurvature; import java.io.File; import java.io.IOException; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import javax.vecmath.Vector3d; /** * A class for testing curvature algorithms. @@ -19,6 +20,7 @@ import java.util.Map; public class CurvatureTests { private static File faceFile2 = new File("src/test/resources/cz/fidentis/analyst/00002_01_ECA.obj"); + private static File girlFile = new File("src/test/resources/cz/fidentis/analyst/average_girl_17-20.obj"); /** * Main method @@ -26,28 +28,57 @@ public class CurvatureTests { * @throws IOException on IO error */ public static void main(String[] args) throws IOException { + //HumanFace face = new HumanFace(girlFile); HumanFace face = new HumanFace(faceFile2); + System.out.println("MODEL: " + face.getMeshModel()); + + Set<MeshPoint> uniqueVerts = new HashSet<>(face.getMeshModel().getFacets().get(0).getVertices()); + System.out.println("UNIQUE VERTICES: " + uniqueVerts.size()); + Set<Vector3d> unique2 = new HashSet<>(); + for (MeshPoint p: face.getMeshModel().getFacets().get(0).getVertices()) { + unique2.add(p.getPosition()); + } + //System.out.println("UNIQUE VERTICES: " + unique2.size()); + //for (Vector3d v: unique2) { + // for (MeshPoint p: uniqueVerts) { + // if (v.equals(p.getPosition())) { + // System.out.println(p); + // } + // } + // System.out.println("----------------"); + //} + boolean print = false; System.out.println(); System.out.println("Curvature calculation:"); - System.out.println(measureCurvature(face, new GaussianCurvature(), print) + "\tmsec:\tGaussian curvature"); - System.out.println(measureCurvature(face, new MeanCurvature(), print) + "\tmsec:\tMean curvature"); - System.out.println(measureCurvature(face, new DeltaCurvature(true), print) + "\tmsec:\tMax curvature"); - System.out.println(measureCurvature(face, new DeltaCurvature(false), print) + "\tmsec:\tMin curvature"); + System.out.println(measureCurvature(face, print) + "\tmsec:\tCurvature"); System.out.println(); } - private static long measureCurvature(HumanFace face, Curvature vis, boolean printDetails) { + private static long measureCurvature(HumanFace face, boolean printDetails) { + Curvature vis = new Curvature(); long startTime = System.currentTimeMillis(); face.getMeshModel().compute(vis); long retTime = System.currentTimeMillis() - startTime; if (printDetails) { - Map<MeshFacet, List<Double>> results = vis.getCurvatures(); - for (MeshFacet facet: results.keySet()) { - System.out.println(results.get(facet)); + Map<MeshFacet, List<Double>> gaus = vis.getGaussianCurvatures(); + for (MeshFacet facet: gaus.keySet()) { + System.out.println(gaus.get(facet)); + } + Map<MeshFacet, List<Double>> mean = vis.getMeanCurvatures(); + for (MeshFacet facet: mean.keySet()) { + System.out.println(mean.get(facet)); + } + Map<MeshFacet, List<Double>> max = vis.getMaxPrincipalCurvatures(); + for (MeshFacet facet: max.keySet()) { + System.out.println(max.get(facet)); + } + Map<MeshFacet, List<Double>> min = vis.getMinPrincipalCurvatures(); + for (MeshFacet facet: min.keySet()) { + System.out.println(min.get(facet)); } } diff --git a/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java b/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java index 59bd6d0b..6ee0437f 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java @@ -5,13 +5,11 @@ import cz.fidentis.analyst.kdtree.KdTree; import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.symmetry.Config; import cz.fidentis.analyst.symmetry.Plane; +import cz.fidentis.analyst.symmetry.SignificantPoints; import cz.fidentis.analyst.symmetry.SymmetryEstimator; import cz.fidentis.analyst.visitors.mesh.Curvature; -import cz.fidentis.analyst.visitors.mesh.GaussianCurvature; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy; -import cz.fidentis.analyst.visitors.mesh.DeltaCurvature; -import cz.fidentis.analyst.visitors.mesh.MeanCurvature; import java.io.File; import java.io.IOException; import java.util.List; @@ -48,10 +46,10 @@ public class EfficiencyTests { //face1.getMeshModel().compute(new GaussianCurvature()); // initialize everything, then measure System.out.println("Symmetry plane calculation:"); - printSymmetryPlane(face1, true, SymmetryEstimator.CurvatureAlg.MEAN); - printSymmetryPlane(face1, true, SymmetryEstimator.CurvatureAlg.GAUSSIAN); - printSymmetryPlane(face1, false, SymmetryEstimator.CurvatureAlg.MEAN); - printSymmetryPlane(face1, false, SymmetryEstimator.CurvatureAlg.GAUSSIAN); + printSymmetryPlane(face1, true, SignificantPoints.CurvatureAlg.MEAN); + printSymmetryPlane(face1, true, SignificantPoints.CurvatureAlg.GAUSSIAN); + printSymmetryPlane(face1, false, SignificantPoints.CurvatureAlg.MEAN); + printSymmetryPlane(face1, false, SignificantPoints.CurvatureAlg.GAUSSIAN); System.out.println(); System.out.println(measureKdTreeCreation(face1) + "\tmsec:\tKd-tree creation of first face"); @@ -97,7 +95,7 @@ public class EfficiencyTests { return System.currentTimeMillis() - startTime; } - private static void printSymmetryPlane(HumanFace face, boolean concurrently, SymmetryEstimator.CurvatureAlg curvatureAlg) { + private static void printSymmetryPlane(HumanFace face, boolean concurrently, SignificantPoints.CurvatureAlg curvatureAlg) { long startTime = System.currentTimeMillis(); SymmetryEstimator est = new SymmetryEstimator(Config.getDefault(), curvatureAlg); face.getMeshModel().compute(est, false); diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java index 64e6853b..cfdf97b7 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/Curvature.java @@ -14,59 +14,123 @@ import javax.vecmath.Vector3d; /** * Abstract class for algorithms calculating curvatures of mesh vertices. * @see https://computergraphics.stackexchange.com/questions/1718/what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle + * @see http://rodolphe-vaillant.fr/?e=20 * <p> * <b>All curvature algorithms suppose that the triangle vertices are oriented clockwise!</b> * </p> * - * TODO: FeaturePoints/src/cz/fidentis/featurepoints/curvature/Curvature_jv.java - * TODO: http://rodolphe-vaillant.fr/?e=20 - * * @author Natalia Bebjakova * @author Radek Oslejsek */ -public abstract class Curvature extends MeshVisitor { +public class Curvature extends MeshVisitor { + + private final Map<MeshFacet, List<Double>> gaussian = new HashMap<>(); + private final Map<MeshFacet, List<Double>> mean = new HashMap<>(); + private final Map<MeshFacet, List<Double>> minPrincipal = new HashMap<>(); + private final Map<MeshFacet, List<Double>> maxPrincipal = new HashMap<>(); - private final Map<MeshFacet, List<Double>> curvatures = new HashMap<>(); + /** + * Returns Gaussian curvatures for all inspected mesh facets. The order corresponds to + * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex. + * + * @return Gaussian curvatures of inspected mesh facets. + */ + public Map<MeshFacet, List<Double>> getGaussianCurvatures() { + return Collections.unmodifiableMap(gaussian); + } + + /** + * Returns mean curvatures for all inspected mesh facets. The order corresponds to + * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex. + * + * @return Mean curvatures of inspected mesh facets. + */ + public Map<MeshFacet, List<Double>> getMeanCurvatures() { + return Collections.unmodifiableMap(mean); + } + + /** + * Returns minimum principal curvatures for all inspected mesh facets. The order corresponds to + * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex. + * + * @return Minimum principal curvatures of inspected mesh facets. + */ + public Map<MeshFacet, List<Double>> getMinPrincipalCurvatures() { + return Collections.unmodifiableMap(minPrincipal); + } /** - * Returns curvatures for all inspected mesh facets. The order corresponds to + * Returns maximu principal curvatures for all inspected mesh facets. The order corresponds to * the order of vertices, i.e., i-th value represents the curvature of i-th mesh vertex. * - * @return curvatures of inspected mesh facets. + * @return Maximum principal curvatures of inspected mesh facets. */ - public Map<MeshFacet, List<Double>> getCurvatures() { - return Collections.unmodifiableMap(curvatures); + public Map<MeshFacet, List<Double>> getMaxPrincipalCurvatures() { + return Collections.unmodifiableMap(maxPrincipal); } @Override public void visitMeshFacet(final MeshFacet facet) { synchronized (this) { - if (curvatures.containsKey(facet)) { + if (gaussian.containsKey(facet)) { return; // already visited facet } - curvatures.put(facet, new ArrayList<>()); - if (!facet.hasVertexNormals()) { - facet.calculateVertexNormals(); - } + gaussian.put(facet, new ArrayList<>()); + mean.put(facet, new ArrayList<>()); + minPrincipal.put(facet, new ArrayList<>()); + maxPrincipal.put(facet, new ArrayList<>()); + //if (!facet.hasVertexNormals()) { + // facet.calculateVertexNormals(); + //} //facet.calculateVoronoiPoints(); } //final List<MeshTriangle> triangles = facet.getTriangles(); final List<CurvTriangle> triangles = precomputeTriangles(facet); - for (int i = 0; i < facet.getNumberOfVertices(); i++) { - curvatures.get(facet).add(calculateCurvature(facet, triangles, i)); + for (int vertA = 0; vertA < facet.getNumberOfVertices(); vertA++) { + //curvatures.get(facet).add(calculateCurvature(facet, triangles, i)); + + List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA); + + if (neighbouringTriangles.isEmpty()) { + this.gaussian.get(facet).add(Double.NaN); + this.mean.get(facet).add(Double.NaN); + this.minPrincipal.get(facet).add(Double.NaN); + this.maxPrincipal.get(facet).add(Double.NaN); + continue; + } + + double sumArea = 0.0; + double sumAngles = 0.0; + Vector3d pointSum = new Vector3d(); + + // for all surrounding triangles: + for (int i = 0; i < neighbouringTriangles.size(); i++) { + CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i)); + CurvTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size())); + + sumArea += computeArea(ctri, facet.getVertex(vertA)); + sumAngles += ctri.alpha(facet.getVertex(vertA)); + + Vector3d aux = new Vector3d(ctri.vertC(facet.getVertex(vertA))); + aux.sub(ctri.vertA(facet.getVertex(vertA))); + aux.scale(ctri.betaCotan(facet.getVertex(vertA)) + tNext.gammaCotan(facet.getVertex(vertA))); + pointSum.add(aux); + } + + double gaussian = (2.0 * Math.PI - sumAngles) / sumArea; + double mean = 0.25 * sumArea * pointSum.length(); + double delta = Math.max(0, Math.pow(mean, 2) - gaussian); + double minPrincipal = mean - Math.sqrt(delta); + double maxPrincipal = mean + Math.sqrt(delta); + + this.gaussian.get(facet).add(gaussian); + this.mean.get(facet).add(mean); + this.minPrincipal.get(facet).add(minPrincipal); + this.maxPrincipal.get(facet).add(maxPrincipal); } } - /** - * - * @param facet - * @param triangles - * @param vertA The "central point" for the 1-ring neighborhood - * @return - */ - protected abstract double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA); - protected List<CurvTriangle> precomputeTriangles(MeshFacet facet) { List<CurvTriangle> ret = new ArrayList<>(facet.getNumTriangles()); for (MeshTriangle tri: facet) { @@ -93,7 +157,7 @@ public abstract class Curvature extends MeshVisitor { } /** - * Helper class that caches values used multiples times in triangle during the curvature computation. + * Helper class that caches triangle characteristics used multiples times during the curvature computation. * <ul> * <li>A = central point of the 1-ring neighborhood</li> * <li>B = point "on the left" (previous point in the clockwise orientation of the triangle</li> diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java deleted file mode 100644 index 22d07fa4..00000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/DeltaCurvature.java +++ /dev/null @@ -1,198 +0,0 @@ -package cz.fidentis.analyst.visitors.mesh; - -import cz.fidentis.analyst.mesh.core.MeshFacet; -import java.util.List; -import javax.vecmath.Vector3d; - -/** - * Calculates maximum or minimum curvatures of mesh vertices using the combination - * of Gaussian and mean curvatures. - * - * @author Natalia Bebjakova - * @author Radek Oslejsek - */ -public class DeltaCurvature extends GaussianCurvature { - - private boolean maxCurvature = true; - - /** - * Constructor. - * @param max If {@code true}, then maximum curvature is return. - * Otherwise, minimum curvature is computed. - */ - public DeltaCurvature(boolean max) { - this.maxCurvature = max; - } - - @Override - protected double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA) { - List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA); - - if (neighbouringTriangles.isEmpty()) { - return Double.NaN; - } - - double sumArea = 0.0; - double sumAngles = 0.0; - Vector3d pointSum = new Vector3d(); - - // for all surrounding triangles: - for (int i = 0; i < neighbouringTriangles.size(); i++) { - CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i)); - CurvTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size())); - - sumArea += computeArea(ctri, facet.getVertex(vertA)); - sumAngles += ctri.alpha(facet.getVertex(vertA)); - - Vector3d aux = new Vector3d(ctri.vertC(facet.getVertex(vertA))); - aux.sub(ctri.vertA(facet.getVertex(vertA))); - aux.scale(ctri.betaCotan(facet.getVertex(vertA)) + tNext.gammaCotan(facet.getVertex(vertA))); - pointSum.add(aux); - } - - double gaussian = (2.0 * Math.PI - sumAngles) / sumArea; - double mean = 0.25 * sumArea * pointSum.length(); - double delta = Math.max(0, Math.pow(mean, 2) - gaussian); - - return (maxCurvature) ? mean + Math.sqrt(delta) : mean - Math.sqrt(delta); - - - /* - double gaussianCurvature = super.calculateCurvature(facet, triangles, centerIndex); - if (Double.isNaN(gaussianCurvature)) { - return Double.NaN; - } - double meanCurvature = getMeanCurvature(facet, triangles, centerIndex); - double meanCurvatureSqr = meanCurvature * meanCurvature; - if (meanCurvatureSqr <= gaussianCurvature) { - return meanCurvature; - } - return meanCurvature + Math.sqrt(meanCurvatureSqr - gaussianCurvature); - */ - } - - /* - private Vector3d computeLaplaceBeltrami(MeshFacet facet, List<MeshTriangle> triangles, int centerIndex) { - List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(centerIndex); - - if (neighbouringTriangles.isEmpty()) { - return new Vector3d(); - } - - double areaSum = 0; - Vector3d pointSum = new Vector3d(); - List<Vector3d> voronoiPoints = facet.calculateVoronoiPoints(); - - for (int i = 0; i < neighbouringTriangles.size(); i++) { - MeshTriangle t = triangles.get(neighbouringTriangles.get(i)); - MeshTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size())); - double area = 0; - - MeshPoint centerPoint = facet.getVertices().get(centerIndex); - Vector3d voronoiPoint = voronoiPoints.get(neighbouringTriangles.get(i)); - - Vector3d aux = null; - if (t.vertex1 == facet.getVertex(centerIndex)) { - area = voronoiPoint.x; - aux = new Vector3d(t.vertex2.getPosition()); - } else if (t.vertex2 == facet.getVertex(centerIndex)) { - area = voronoiPoint.y; - aux = new Vector3d(t.vertex3.getPosition()); - } else if (t.vertex3 == facet.getVertex(centerIndex)) { - area = voronoiPoint.z; - aux = new Vector3d(t.vertex1.getPosition()); - } - aux.sub(centerPoint.getPosition()); - aux.scale(cotAlfa(centerPoint, t) + cotBeta(centerPoint, tNext)); - pointSum.add(aux); - areaSum += area; - } - pointSum.scale(1.0 / (2.0 * areaSum)); - return pointSum; - } - */ - - /** - * Calculates angle of the triangle according to center point - * TODO: optimize @see https://stackoverflow.com/questions/31159016/how-to-efficiently-calculate-cotangents-from-vectors - * - * @param centerPoint center point - * @param t triangle - * @return angle - */ - /* - private double cotAlfa(MeshPoint centerPoint, MeshTriangle t) { - double alfaCos = 0; - - if (t.vertex1 == centerPoint) { - MeshPoint e1 = t.vertex1.subtractPosition(t.vertex3); - e1 = e1.dividePosition(e1.abs()); - - MeshPoint e2 = t.vertex2.subtractPosition(t.vertex3); - e2 = e2.dividePosition(e2.abs()); - - alfaCos = e1.dotProduct(e2); - } else if (t.vertex2 == centerPoint) { - MeshPoint e1 = t.vertex2.subtractPosition(t.vertex1); - e1 = e1.dividePosition(e1.abs()); - - MeshPoint e2 = t.vertex3.subtractPosition(t.vertex1); - e2 = e2.dividePosition(e2.abs()); - - alfaCos = e1.dotProduct(e2); - } else if (t.vertex3 == centerPoint){ - MeshPoint e1 = t.vertex3.subtractPosition(t.vertex2); - e1 = e1.dividePosition(e1.abs()); - - MeshPoint e2 = t.vertex1.subtractPosition(t.vertex2); - e2 = e2.dividePosition(e2.abs()); - - alfaCos = e1.dotProduct(e2); - } - double alfa = Math.acos(alfaCos); - return 1 / Math.tan(alfa); // cotangent alpha - } - */ - - /** - * Calculates angle of the triangle according to center point - * TODO: optimize @see https://stackoverflow.com/questions/31159016/how-to-efficiently-calculate-cotangents-from-vectors - * - * @param centerPoint center point - * @param t triangle - * @return angle - */ - /* - private double cotBeta(MeshPoint centerPoint, MeshTriangle t) { - double betaCos = 0; - - if (t.vertex1 == centerPoint) { - MeshPoint e1 = t.vertex1.subtractPosition(t.vertex2); - e1 = e1.dividePosition(e1.abs()); - - MeshPoint e2 = t.vertex3.subtractPosition(t.vertex2); - e2 = e2.dividePosition(e2.abs()); - - betaCos = e1.dotProduct(e2); - } else if (t.vertex2 == centerPoint) { - MeshPoint e1 = t.vertex2.subtractPosition(t.vertex3); - e1 = e1.dividePosition(e1.abs()); - - MeshPoint e2 = t.vertex1.subtractPosition(t.vertex3); - e2 = e2.dividePosition(e2.abs()); - - betaCos = e1.dotProduct(e2); - } else if (t.vertex3 == centerPoint){ - MeshPoint e1 = t.vertex3.subtractPosition(t.vertex1); - e1 = e1.dividePosition(e1.abs()); - - MeshPoint e2 = t.vertex2.subtractPosition(t.vertex1); - e2 = e2.dividePosition(e2.abs()); - - betaCos = e1.dotProduct(e2); - } - double beta = Math.acos(betaCos); - return 1 / Math.tan(beta); // cotangent beta - } - */ -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java deleted file mode 100644 index 56999829..00000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/GaussianCurvature.java +++ /dev/null @@ -1,89 +0,0 @@ -package cz.fidentis.analyst.visitors.mesh; - -import cz.fidentis.analyst.mesh.core.MeshFacet; -import java.util.List; - -/** - * Gaussian curvatures. - * @see https://computergraphics.stackexchange.com/questions/1718/what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle - * - * @author Natalia Bebjakova - * @author Radek Oslejsek - */ -public class GaussianCurvature extends Curvature { - - @Override - protected double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA) { - List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA); - - if (neighbouringTriangles.isEmpty()) { - return Double.NaN; - } - - double sumArea = 0.0; - double sumAngles = 0.0; - - // for all surrounding triangles: - for (int i = 0; i < neighbouringTriangles.size(); i++) { - CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i)); - sumAngles += ctri.alpha(facet.getVertex(vertA)); - sumArea += computeArea(ctri, facet.getVertex(vertA)); - } - - return (2.0 * Math.PI - sumAngles) / sumArea; - } - - - /* - @Override - protected double calculateCurvature(MeshFacet facet, List<MeshTriangle> triangles, int centerIndex) { - List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(centerIndex); - - if (neighbouringTriangles.isEmpty()) { - return Double.NaN; - } - - double sum = 2 * Math.PI; - double areaSum = 0; - - // fro all surrounding triangles: - List<Vector3d> voronoiPoints = facet.calculateVoronoiPoints(); - for (int i = 0; i < neighbouringTriangles.size(); i++) { - Vector3d v1 = new Vector3d(); - Vector3d v2 = new Vector3d(); - MeshTriangle tri = triangles.get(neighbouringTriangles.get(i)); - Vector3d voronoiPoint = voronoiPoints.get(neighbouringTriangles.get(i)); - - double area = 0; - if (tri.vertex1 == facet.getVertex(centerIndex)) { - v1 = new Vector3d(tri.vertex2.getPosition()); - v2 = new Vector3d(tri.vertex3.getPosition()); - v1.sub(tri.vertex1.getPosition()); - v2.sub(tri.vertex1.getPosition()); - area = voronoiPoint.x; - } else if (tri.vertex2 == facet.getVertex(centerIndex)) { - v1 = new Vector3d(tri.vertex1.getPosition()); - v2 = new Vector3d(tri.vertex3.getPosition()); - v1.sub(tri.vertex2.getPosition()); - v2.sub(tri.vertex2.getPosition()); - area = voronoiPoint.y; - } else if (tri.vertex3 == facet.getVertex(centerIndex)) { - v1 = new Vector3d(tri.vertex2.getPosition()); - v2 = new Vector3d(tri.vertex1.getPosition()); - v1.sub(tri.vertex3.getPosition()); - v2.sub(tri.vertex3.getPosition()); - area = voronoiPoint.z; - } - - areaSum += area; - v1.normalize(); - v2.normalize(); - - sum -= Math.acos(v1.dot(v2)); - } - double value = sum * (1.0 / areaSum); - - return value; - } - */ -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java deleted file mode 100644 index f7ff3316..00000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/MeanCurvature.java +++ /dev/null @@ -1,45 +0,0 @@ -package cz.fidentis.analyst.visitors.mesh; - -import cz.fidentis.analyst.mesh.core.MeshFacet; -import java.util.List; -import javax.vecmath.Vector3d; - -/** - * Mean curvature based on solving Laplace-Beltrami mean operator by cotangent discretization. - * - * @see https://computergraphics.stackexchange.com/questions/1718/what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle - * @see http://rodolphe-vaillant.fr/?e=20 - * - * @author Natalia Bebjakova - * @author Radek Oslejsek - */ -public class MeanCurvature extends Curvature { - - @Override - protected double calculateCurvature(MeshFacet facet, List<CurvTriangle> triangles, int vertA) { - List<Integer> neighbouringTriangles = facet.getCornerTable().getTriangleIndexesByVertexIndex(vertA); - - if (neighbouringTriangles.isEmpty()) { - return Double.NaN; - } - - double sumArea = 0.0; - Vector3d pointSum = new Vector3d(); - - // for all surrounding triangles: - for (int i = 0; i < neighbouringTriangles.size(); i++) { - CurvTriangle ctri = triangles.get(neighbouringTriangles.get(i)); - CurvTriangle tNext = triangles.get(neighbouringTriangles.get((i + 1) % neighbouringTriangles.size())); - - sumArea += computeArea(ctri, facet.getVertex(vertA)); - - Vector3d aux = new Vector3d(ctri.vertC(facet.getVertex(vertA))); - aux.sub(ctri.vertA(facet.getVertex(vertA))); - aux.scale(ctri.betaCotan(facet.getVertex(vertA)) + tNext.gammaCotan(facet.getVertex(vertA))); - pointSum.add(aux); - } - - return 0.25 * sumArea * pointSum.length(); - - } -} diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java b/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java index 0864c3ad..2caa7052 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java +++ b/GUI/src/main/java/cz/fidentis/analyst/gui/ComparisonGLEventListener.java @@ -6,7 +6,6 @@ import com.jogamp.opengl.GLAutoDrawable; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshModel; -import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; import javax.vecmath.Vector3d; import java.awt.*; @@ -21,8 +20,7 @@ import static com.jogamp.opengl.GL2GL3.GL_LINE; import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX; import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX; import cz.fidentis.analyst.visitors.mesh.Curvature; -import cz.fidentis.analyst.visitors.mesh.GaussianCurvature; -import cz.fidentis.analyst.visitors.mesh.DeltaCurvature; +import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; /** * @@ -52,9 +50,9 @@ public class ComparisonGLEventListener extends GeneralGLEventListener { //HausdorffDistance hVisitor = new HausdorffDistance(getModel(), HausdorffDistance.Strategy.POINT_TO_POINT, false, false); //comparedFace.getMeshModel().compute(hVisitor); //distances = hVisitor.getDistances(); - Curvature visitor = new GaussianCurvature(); + Curvature visitor = new Curvature(); comparedFace.getMeshModel().compute(visitor); - distances = visitor.getCurvatures(); + distances = visitor.getGaussianCurvatures(); renderHeatmap = true; this.minColor = minColor; this.maxColor = maxColor; @@ -135,13 +133,13 @@ public class ComparisonGLEventListener extends GeneralGLEventListener { Color getColor(Double currentDistance, Double minDistance, Double maxDistance) { double currentParameter = ((currentDistance - minDistance) / (maxDistance - minDistance)); - //System.out.println("AAA " + currentParameter + " " + minDistance + " " + maxDistance); //return new Color((float)currentParameter, 0.5f, 0.5f); - //currentParameter *= 100; - //if (currentParameter > 1) { + //currentParameter *= 10; + //if (currentParameter > maxDistance) { // currentParameter = 1.0; //} + //System.out.println("AAA " + currentParameter + " " + minDistance + " " + maxDistance); float[] hsb1 = Color.RGBtoHSB(minColor.getRed(), minColor.getGreen(), minColor.getBlue(), null); double h1 = hsb1[0]; diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java index 28275cea..9354ceb7 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java +++ b/GUI/src/main/java/cz/fidentis/analyst/gui/GeneralGLEventListener.java @@ -15,6 +15,7 @@ import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX; import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX; import com.jogamp.opengl.glu.GLU; import cz.fidentis.analyst.symmetry.Config; +import cz.fidentis.analyst.symmetry.SignificantPoints; import cz.fidentis.analyst.symmetry.SymmetryEstimator; import javax.vecmath.Vector3d; @@ -241,7 +242,7 @@ public class GeneralGLEventListener implements GLEventListener { //Generate SymmetryPlane first time we request to see it if (symmetryPlane && symmetryPlaneFacet == null) { - SymmetryEstimator estimator = new SymmetryEstimator(Config.getDefault(), SymmetryEstimator.CurvatureAlg.GAUSSIAN); + SymmetryEstimator estimator = new SymmetryEstimator(Config.getDefault(), SignificantPoints.CurvatureAlg.GAUSSIAN); model.getFacets().get(0).accept(estimator); symmetryPlaneFacet = estimator.getSymmetryPlaneMesh(); diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java b/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java index 019378d9..af8c975b 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/gui/SymmetryPanel.java @@ -5,6 +5,7 @@ import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.symmetry.Config; import cz.fidentis.analyst.symmetry.Plane; +import cz.fidentis.analyst.symmetry.SignificantPoints; import cz.fidentis.analyst.symmetry.SymmetryEstimator; import java.util.logging.Level; import java.util.logging.Logger; @@ -153,7 +154,7 @@ public final class SymmetryPanel extends javax.swing.JPanel { private void computeSymmetryPlane() throws InterruptedException { MeshModel model = new MeshModel(); canvas.changeModel(canvas.getLoadedFace().getMeshModel()); - SymmetryEstimator est = new SymmetryEstimator(config, SymmetryEstimator.CurvatureAlg.GAUSSIAN); // MISTO TRUE MUSI BYT VYBER STRATEGIE VYPOCTU ZAKRIVENI!!! + SymmetryEstimator est = new SymmetryEstimator(config, SignificantPoints.CurvatureAlg.GAUSSIAN); // MISTO TRUE MUSI BYT VYBER STRATEGIE VYPOCTU ZAKRIVENI!!! canvas.getLoadedFace().getMeshModel().getFacets().get(0).accept(est); symmetryPlane = est.getSymmetryPlane(); MeshFacet facet = est.getSymmetryPlaneMesh(); 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 4d35e069..99e4f36f 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 @@ -134,4 +134,13 @@ public class MeshModel { public void unregisterListener(MeshListener listener) { eventBus.unregister(listener); } + + @Override + public String toString() { + int verts = 0; + for (MeshFacet f: facets) { + verts += f.getNumberOfVertices(); + } + return facets.size() + " facets with " + verts + " vertices"; + } } -- GitLab