diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java index 449918875d4536aab0328752bfa9e4402b451dae..4ad68932a1073c8ac3c5490e7b35db98bb34e6f1 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java @@ -38,7 +38,7 @@ import java.util.Objects; * <p> * Changes in the human face and its data structures (e.g., mesh model, etc.) * can be monitored by listeners. Listeners have to implement the - * {@link cz.fidentis.analyst.face.HumanFaceListener} interface and they have to be + * {@link cz.fidentis.analyst.face.events.HumanFaceListener} interface and they have to be * registered using the {@link cz.fidentis.analyst.face.HumanFace#registerListener} method. * Then they are informed about changes in the human automatically via methods * prescribed by the interface. diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/CrossSectionCurve.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/CrossSectionCurve.java new file mode 100644 index 0000000000000000000000000000000000000000..dbc475e5e71a9d016618e81f7bc97f40485da289 --- /dev/null +++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/CrossSectionCurve.java @@ -0,0 +1,219 @@ +package cz.fidentis.analyst.symmetry; + +import cz.fidentis.analyst.mesh.core.MeshPoint; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.vecmath.Point3d; + +/** + * A 3D curve produced by a plane cutting a human face. + * + * @author Radek Oslejsek + */ +public class CrossSectionCurve { + + private final List<List<Point3d>> segments = new ArrayList<>(); + private final List<Point3d> fpProjections = new ArrayList<>(); + + /** + * Add a new point to the beginning of the curve segment. + * + * @param segment Index of the segment + * @param point A 3D point to be inserted + * @throws IllegalArgumentException if the segment does not exist or the point is {@code null} + */ + public void addPointToSegmentStart(int segment, Point3d point) { + if (segment < 0 || segment > segments.size() - 1) { + throw new IllegalArgumentException("segment"); + } + + if (point == null) { + throw new IllegalArgumentException("point"); + } + + segments.get(segment).add(0, point); + } + + /** + * Add a new point to the end of the curve segment. + * + * @param segment Index of the segment + * @param point A 3D point to be inserted + * @throws IllegalArgumentException if the segment does not exist or the point is {@code null} + */ + public void addPointToSegmentEnd(int segment, Point3d point) { + if (segment < 0 || segment > segments.size() - 1) { + throw new IllegalArgumentException("segment"); + } + + if (point == null) { + throw new IllegalArgumentException("point"); + } + + segments.get(segment).add(point); + } + + /** + * Adds a new segment to the curve. + * + * @return Index of the new segment + */ + public int addNewSegment() { + segments.add(new ArrayList<>()); + return segments.size() - 1; + } + + /** + * Returns number of segments. + * @return number of segments. + */ + public int getNumSegments() { + return segments.size(); + } + + /** + * Returns number of points in given segment. + * + * @param segment Index of the segment + * @return number of points in given segment. + * @throws IllegalArgumentException if the segment does not exist + */ + public int getSegmentSize(int segment) { + if (segment < 0 || segment > segments.size() - 1) { + throw new IllegalArgumentException("segment"); + } + return segments.get(segment).size(); + } + + /** + * Returns given segment. + * + * @param segment Index of the segment + * @return Points of the segment + * @throws IllegalArgumentException if the segment does not exist + */ + public List<Point3d> getSegment(int segment) { + if (segment < 0 || segment > segments.size() - 1) { + throw new IllegalArgumentException("segment"); + } + return Collections.unmodifiableList(segments.get(segment)); + } + + /** + * Returns all segments. + * @return Curve segments + */ + public List<List<Point3d>> getSegments() { + return Collections.unmodifiableList(segments); + } + + /** + * Returns given point of in given segment. + * + * @param segment Index of the segment + * @param point Index of the point in the segment + * @return Points of the curve + * @throws IndexOutOfBoundsException if the input arguments are out of range + */ + public Point3d getPoint(int segment, int point) { + return segments.get(segment).get(point); + } + + /** + * Find the closest point of the curve to the given point. + * Returned list contains two indexes. The first one is the index of + * curve segment, the second one is the index of the closest point in the segment. + * + * @param point A 3D point + * @return The closest point of the curve or {@code null} + * @throws NullPointerException if the input argument is {@code null} + */ + public Point3d getClosestPoint(Point3d point) { + Point3d ret = null; + double minDist = Double.POSITIVE_INFINITY; + + for (int i = 0; i < getNumSegments(); i++) { + for (int j = 0; j < getSegmentSize(i); j++) { + double dist = MeshPoint.distance(point, getPoint(i, j)); + if (dist < minDist) { + minDist = dist; + ret = getPoint(i, j); + } + } + } + + return ret; + } + + /** + * Finds points of the curve that are the closest the the given list of 3D points + * (locations of feature points) and returns them. + * + * @param candidatePoints (Feature) points to be projected to the curve + * @return projections, i.e., points of the curve that are the closest to the candidate points. + */ + public List<Point3d> projectFeaturePointsToCurve(List<Point3d> candidatePoints) { + this.fpProjections.clear(); + for (Point3d p: candidatePoints) { + this.fpProjections.add(getClosestPoint(p)); + } + return Collections.unmodifiableList(fpProjections); + } + + /** + * Returns projected feature points. + * @return projected feature points. + */ + public List<Point3d> getProjectedFeaturePoints() { + return Collections.unmodifiableList(fpProjections); + } + + /** + * Finds the closest point (see {@link #getClosestPoint(javax.vecmath.Point3d)}. + * If the point is inside of some segment, the segment is split. + * + * @param point A 3D point whose closeness is calculated + * @return The index of the original segment that has been split. -1 if no slitting has been made. + * @throws NullPointerException if the input argument is {@code null} + */ + /* + public int splitByClosestPoint(Point3d point) { + List<Integer> closest = getClosestPoint(point); + int clSegment = closest.get(0); + int clPoint = closest.get(1); + + if (closest == null) { + return -1; + } + + if (clPoint == 0 || clPoint == getSegmentSize(clSegment)-1) { // bordery points + return -1; + } + + List<Point3d> newSegment = new ArrayList<>(); + newSegment.add(new Point3d(getPoint(clSegment, clPoint))); + int i = clPoint + 1; + while (i < getSegmentSize(closest.get(0))) { + newSegment.add(segments.get(clSegment).remove(i)); + } + segments.add(clSegment+1, newSegment); + + return clSegment; + } + */ + + /** + * Joints neighboring segments. Independent segments (separated by a whole) + * remain separated. + */ + public void joinSegments() { + for (int i = 0; i < getNumSegments() -1 ; i++) { + if (getPoint(i, getSegmentSize(i)-1).equals(getPoint(i+1, 0))) { + segments.get(i+1).remove(0); + segments.get(i).addAll(segments.remove(i+1)); + i--; + } + } + } +} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java index c7951081c7ccc80c47ed8a76dc2db42e87eb8bc2..6a46bc19962b9e0f6ca30397b137eea8390978e7 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java @@ -128,6 +128,17 @@ public class Plane implements Serializable { protected void setDistance(double dist) { this.distance = dist; } + + /** + * Returns distance of the point from the plane. + * @param point Point whose distance is to be computed + * @return Point's distance. If the point is on the opposite side with + * the respect to the plane's normal, the negative distance is returned + */ + public double getPointDistance(Point3d point) { + return ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z) + distance) + / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z); + } /** * Calculates an intersection of a plane and a line given by two points @@ -137,12 +148,8 @@ public class Plane implements Serializable { * @return The point of intersection of null if no point found */ public Point3d getIntersectionWithLine(Point3d p1, Point3d p2) { - double distance1 = ((normal.x * p1.x) + (normal.y * p1.y) + (normal.z * p1.z) + distance) - / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z); - - double distance2 = ((normal.x * p2.x) + (normal.y * p2.y) + (normal.z * p2.z) + distance) - / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z); - + double distance1 = getPointDistance(p1); + double distance2 = getPointDistance(p2); double t = distance1 / (distance1 - distance2); if (distance1 * distance2 > 0) { 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 6b905a2fbea01c8cc8c88dd4d3ce5a21d77ecf0b..38b451c5436318b2a1710a227e31d5cd14bfccc5 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java @@ -1,10 +1,8 @@ package cz.fidentis.analyst.symmetry; import cz.fidentis.analyst.mesh.MeshVisitor; -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.mesh.core.MeshRectangleFacet; import cz.fidentis.analyst.visitors.mesh.BoundingBox; import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import java.util.ArrayList; @@ -141,7 +139,7 @@ public class SymmetryEstimator extends MeshVisitor { double scale = bbox.getMaxPoint().x - bbox.getMinPoint().x; - return createMeshFacet(midPointOnPlane, frontDir, upDir, symmetryPlane.getNormal(), scale); + return new MeshRectangleFacet(midPointOnPlane, frontDir, upDir, symmetryPlane.getNormal(), 2*scale, 2*scale); } /** @@ -230,49 +228,6 @@ public class SymmetryEstimator extends MeshVisitor { setSymmetryPlane(planes); } - protected static MeshFacet createMeshFacet(Point3d centroid, Vector3d frontDir, Vector3d upDir, Vector3d normal, double scale) { - - Point3d[] points = new Point3d[4]; - - Point3d aScaled = new Point3d(frontDir); - Point3d bScaled = new Point3d(upDir); - aScaled.scale(scale); - bScaled.scale(scale); - - points[0] = new Point3d(centroid); - points[0].sub(aScaled); - points[0].sub(bScaled); - - points[1] = new Point3d(centroid); - points[1].sub(aScaled); - points[1].add(bScaled); - - points[2] = new Point3d(centroid); - points[2].add(aScaled); - points[2].add(bScaled); - - points[3] = new Point3d(centroid); - points[3].add(aScaled); - points[3].sub(bScaled); - - MeshFacet facet = new MeshFacetImpl(); - for (Point3d point : points) { - facet.addVertex(new MeshPointImpl(point, normal, null)); - } - - //Create a simple square cornerTable - facet.getCornerTable().addRow(new CornerTableRow(0, 5)); - facet.getCornerTable().addRow(new CornerTableRow(1, -1)); - facet.getCornerTable().addRow(new CornerTableRow(3, -1)); - facet.getCornerTable().addRow(new CornerTableRow(3, -1)); - facet.getCornerTable().addRow(new CornerTableRow(1, -1)); - facet.getCornerTable().addRow(new CornerTableRow(2, 0)); - - //facet.calculateVertexNormals(); - - return facet; - } - protected int checkAndUpdatePlanes(List<Plane> planes, ApproxSymmetryPlane newPlane, int maxVotes) { if (newPlane.getVotes() > maxVotes) { planes.clear(); diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java index db7ec0c0ae3c338a8212ce4e71d5d46e65ea7a42..5b815eef88514684f645aa39d0456fec6b01ddee 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java @@ -1,14 +1,12 @@ package cz.fidentis.analyst.visitors.mesh; -import cz.fidentis.analyst.Logger; import cz.fidentis.analyst.mesh.MeshVisitor; import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshTriangle; +import cz.fidentis.analyst.symmetry.CrossSectionCurve; import cz.fidentis.analyst.symmetry.Plane; import javax.vecmath.Point3d; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -25,7 +23,7 @@ import java.util.stream.Collectors; * @author Radek Oslejsek */ public class CrossSectionZigZag extends MeshVisitor { - private List<List<Point3d>> segments; + private CrossSectionCurve curve; private Set<Point3d> usedPoints; private Set<MeshTriangle> visited; private Set<MeshTriangle> toVisit; @@ -40,7 +38,7 @@ public class CrossSectionZigZag extends MeshVisitor { public CrossSectionZigZag(Plane plane) { this.plane = plane; //this.points = new ArrayList<>(); - this.segments = new ArrayList<>(); + this.curve = new CrossSectionCurve(); this.usedPoints = new HashSet<>(); } @@ -49,9 +47,9 @@ public class CrossSectionZigZag extends MeshVisitor { usedPoints.add(p); if (direction) { - segments.get(segment).add(p); + curve.addPointToSegmentEnd(segment, p); } else { - segments.get(segment).add(0, p); + curve.addPointToSegmentStart(segment, p); } } } @@ -113,8 +111,7 @@ public class CrossSectionZigZag extends MeshVisitor { while (!toVisit.isEmpty()) { MeshTriangle tri = toVisit.iterator().next(); toVisit.remove(tri); - segments.add(new ArrayList<>()); - int segment = segments.size() - 1; + int segment = curve.addNewSegment(); // Figure out which lines are intersected Point3d intersection1 = plane.getIntersectionWithLine(tri.getVertex1(), tri.getVertex2()); @@ -156,7 +153,11 @@ public class CrossSectionZigZag extends MeshVisitor { //out.printDuration("Cross section with zigzag method"); } - public List<List<Point3d>> getSegments() { - return Collections.unmodifiableList(segments); + /** + * Returns computed cross section curve. + * @return cross section curve + */ + public CrossSectionCurve getCrossSectionCurve() { + return curve; } } diff --git a/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java b/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java index cc4bf5ed8eac8c73c7340690ffba5c17d5bddfad..217995700ed30ef5f8d6a3ea17a8459d8da82073 100644 --- a/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java +++ b/Comparison/src/test/java/cz/fidentis/analyst/visitors/mesh/CrossSectionTest.java @@ -8,6 +8,7 @@ import cz.fidentis.analyst.mesh.core.MeshFacet; import cz.fidentis.analyst.mesh.core.MeshFacetImpl; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.core.MeshPointImpl; +import cz.fidentis.analyst.symmetry.CrossSectionCurve; import cz.fidentis.analyst.symmetry.Plane; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -59,24 +60,24 @@ public class CrossSectionTest { CrossSectionZigZag cs = new CrossSectionZigZag(cuttingPlane); model.compute(cs); - List<List<Point3d>> points = cs.getSegments(); + CrossSectionCurve curve = cs.getCrossSectionCurve(); //They can be ordered two ways, check both - Assertions.assertEquals(points.get(0).size(), 6); - if (points.get(0).equals(new Point3d(0.5, 0, 0))) { - Assertions.assertEquals(points.get(0).get(0), new Point3d(0.5, 0, 0)); - Assertions.assertEquals(points.get(0).get(1), new Point3d(0.5, 0.5, 0)); - Assertions.assertEquals(points.get(0).get(2), new Point3d(0.5, 1, 0)); - Assertions.assertEquals(points.get(0).get(3), new Point3d(0.5, 1.5, 0)); - Assertions.assertEquals(points.get(0).get(4), new Point3d(0.5, 2, 0)); - Assertions.assertEquals(points.get(0).get(5), new Point3d(0.5, 2.5, 0)); - } else if (points.get(0).get(0).equals(new Point3d(0.5, 2.5, 0))) { - Assertions.assertEquals(points.get(0).get(0), new Point3d(0.5, 2.5, 0)); - Assertions.assertEquals(points.get(0).get(1), new Point3d(0.5, 2, 0)); - Assertions.assertEquals(points.get(0).get(2), new Point3d(0.5, 1.5, 0)); - Assertions.assertEquals(points.get(0).get(3), new Point3d(0.5, 1, 0)); - Assertions.assertEquals(points.get(0).get(4), new Point3d(0.5, 0.5, 0)); - Assertions.assertEquals(points.get(0).get(5), new Point3d(0.5, 0, 0)); + Assertions.assertEquals(curve.getSegmentSize(0), 6); + if (curve.getSegment(0).get(0).equals(new Point3d(0.5, 0, 0))) { + Assertions.assertEquals(curve.getSegment(0).get(0), new Point3d(0.5, 0, 0)); + Assertions.assertEquals(curve.getSegment(0).get(1), new Point3d(0.5, 0.5, 0)); + Assertions.assertEquals(curve.getSegment(0).get(2), new Point3d(0.5, 1, 0)); + Assertions.assertEquals(curve.getSegment(0).get(3), new Point3d(0.5, 1.5, 0)); + Assertions.assertEquals(curve.getSegment(0).get(4), new Point3d(0.5, 2, 0)); + Assertions.assertEquals(curve.getSegment(0).get(5), new Point3d(0.5, 2.5, 0)); + } else if (curve.getSegment(0).get(0).equals(new Point3d(0.5, 2.5, 0))) { + Assertions.assertEquals(curve.getSegment(0).get(0), new Point3d(0.5, 2.5, 0)); + Assertions.assertEquals(curve.getSegment(0).get(1), new Point3d(0.5, 2, 0)); + Assertions.assertEquals(curve.getSegment(0).get(2), new Point3d(0.5, 1.5, 0)); + Assertions.assertEquals(curve.getSegment(0).get(3), new Point3d(0.5, 1, 0)); + Assertions.assertEquals(curve.getSegment(0).get(4), new Point3d(0.5, 0.5, 0)); + Assertions.assertEquals(curve.getSegment(0).get(5), new Point3d(0.5, 0, 0)); } else { Assertions.fail(); } diff --git a/GUI/src/main/java/cz/fidentis/analyst/distance/FeaturePointsPanel.java b/GUI/src/main/java/cz/fidentis/analyst/distance/FeaturePointsPanel.java index 3c9c9583fa738ad549efd82f6d3f3f6e6c0db35b..605aa4c9e3b58e1b09379fa0b6a464ad15454708 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/distance/FeaturePointsPanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/distance/FeaturePointsPanel.java @@ -118,11 +118,11 @@ public class FeaturePointsPanel extends JPanel { /** * Creates and returns action listener that can be connected with a low-level - * GUI element (e.g., a button). Action event of the low-level element is then - * re-directed to the given {@code ControlPanelAction} as given command. + * GUI element (e.g., a button). Action event of triggered low-level element is + * redirected to the given {@code action}. * The listener may also carry additional data as a payload. * - * @param action An instance of the {@link ControlPanelAction} + * @param action Action listener * @param command Control panel command * @param data Payload data of the action listener * @return Action listener diff --git a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java index c6835ccc3859f6ffad670655a23d63369e916382..37aabc017b119a486992ebc92b1444de853f9c89 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java +++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java @@ -273,9 +273,9 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL * First it creates object of type ProcrusteAnalasys containing two face models converted * to ProcrustesAnalysisFaceModel objects which are required for next analysis step. * - * In analysis step faces are superimposed and rotated. + * In the analysis step, faces are superimposed and rotated. * - * If {@see this.procrustesScalingEnabled} is set to true then one of them is scaled as well. + * If the {@code procrustesScalingEnabled} attribute is set to true, then one of the faces is scaled as well. */ protected void applyProcrustes() { Logger out = Logger.measureTime(); diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java index 10e7d7b6b350f57c5cfcd8a993c3489accd407c6..3018786eef6d85c0396ff3282523be0aaa92b11c 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java @@ -57,7 +57,7 @@ public class DrawableFeaturePoints extends Drawable { * * @param featurePoints Feature points * @param defaultColor Default color - * @param defaultSize Default perimeter + * @param defaultPerimeter Default perimeter */ public DrawableFeaturePoints(List<FeaturePoint> featurePoints, Color defaultColor, double defaultPerimeter) { this.featurePoints = new ArrayList<>(featurePoints); diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFpWeights.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFpWeights.java index 3667c0fa2a64f3bbeabdd0d79e0558f8595169f4..4ce2b39dc1d209e79f00e50cbc579ed09c3762c6 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFpWeights.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFpWeights.java @@ -30,7 +30,7 @@ public class DrawableFpWeights extends DrawableFeaturePoints { * * @param featurePoints Feature points * @param defaultColor Default color - * @param defaultSize Default perimeter + * @param defaultPerimeter Default perimeter */ public DrawableFpWeights(List<FeaturePoint> featurePoints, Color defaultColor, double defaultPerimeter) { super(featurePoints, FPW_DEFAULT_COLOR, FPW_DEFAULT_SIZE); diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableMesh.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableMesh.java index 3963550706e1b7e2de69a519c05ac0d3a6283a42..e153b6277f4b490eff9ea271cb7e0a8120f62069 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableMesh.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableMesh.java @@ -23,7 +23,7 @@ public class DrawableMesh extends Drawable { /** * Copy constructor. * - * @param model Mesh to be copied + * @param mesh Mesh to be copied * @throws NullPointException if the input argument is {@code null} */ public DrawableMesh(DrawableMesh mesh) { diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java index 0ed46b150aca54541caab13c59941e70c40372c7..2c7aa70d56275da41e0428d266e2b018b3047506 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java @@ -66,10 +66,7 @@ public class DrawablePlane extends DrawableMesh { // Move Drawable plane Vector3d move = this.plane.getNormal(); - move.x *= value; - move.y *= value; - move.z *= value; - + move.scale(value); for (int i = 0; i < 4; ++i) { getFacets().get(0).getVertex(i).getPosition().sub(move); } diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java index b403593dcb41d649bbd857df4fb887cca04f638e..7c30646625bc75f9fd37e0ae5790657a09222799 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java @@ -7,7 +7,9 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Stroke; +import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; +import java.util.ArrayList; import java.util.List; import javax.swing.JPanel; import javax.vecmath.Point3d; @@ -21,6 +23,7 @@ import javax.vecmath.Point3d; */ public class CurveRenderingPanel extends JPanel { + private static final int SEGMENT_POINT_SIZE = 7; private static final int PREF_W = 400; private static final int PREF_H = 400; private static final int BORDER_GAP = 15; @@ -36,12 +39,11 @@ public class CurveRenderingPanel extends JPanel { */ private static final Stroke GRAPH_STROKE = new BasicStroke(3f); - private List<List<Point3d>> primarySegments; - private List<List<Point3d>> secondarySegments; - private List<List<Point3d>> primaryMirrorSegments; - private List<List<Point3d>> secondaryMirrorSegments; + private CrossSectionCurve primarySegments; + private CrossSectionCurve secondarySegments; + private CrossSectionCurve primaryMirrorSegments; + private CrossSectionCurve secondaryMirrorSegments; - private double primaryOffsetZ = 0; private boolean mirrorCuts = false; private double minZ = Double.POSITIVE_INFINITY; @@ -60,11 +62,11 @@ public class CurveRenderingPanel extends JPanel { /** * Sets primary points and draws them in the panel * - * @param segments primary points + * @param curve Points of the primary curve */ - public void setPrimarySegments(List<List<Point3d>> segments) { - this.primarySegments = segments; - updateMinMax(segments); + public void setPrimarySegments(CrossSectionCurve curve) { + this.primarySegments = curve; + updateMinMax(curve); repaint(); } @@ -72,22 +74,22 @@ public class CurveRenderingPanel extends JPanel { * Sets primary mirror points. * Only draws them if mirrorCuts is checked * - * @param segments primary mirror points + * @param curve Points of the primary mirror curve */ - public void setPrimaryMirrorSegments(List<List<Point3d>> segments) { - this.primaryMirrorSegments = segments; - updateMinMax(segments); + public void setPrimaryMirrorSegments(CrossSectionCurve curve) { + this.primaryMirrorSegments = curve; + updateMinMax(curve); repaint(); } /** * Sets secondary points and draws them in the panel * - * @param segments secondary points + * @param curve Points of the secondary curve */ - public void setSecondarySegments(List<List<Point3d>> segments) { - this.secondarySegments = segments; - updateMinMax(segments); + public void setSecondarySegments(CrossSectionCurve curve) { + this.secondarySegments = curve; + updateMinMax(curve); repaint(); } @@ -95,11 +97,11 @@ public class CurveRenderingPanel extends JPanel { * Sets secondary mirror points. * Only draws them if mirrorCuts is checked * - * @param segments secondary mirror points + * @param curve Points of the secondary mirror curve */ - public void setSecondaryMirrorSegments(List<List<Point3d>> segments) { - this.secondaryMirrorSegments = segments; - updateMinMax(segments); + public void setSecondaryMirrorSegments(CrossSectionCurve curve) { + this.secondaryMirrorSegments = curve; + updateMinMax(curve); repaint(); } @@ -122,85 +124,83 @@ public class CurveRenderingPanel extends JPanel { protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D)g; - - if (mirrorCuts) { - drawFace(g2, primarySegments, PRIMARY_COLOR, true); - drawFace(g2, primaryMirrorSegments, PRIMARY_MIRROR_COLOR, true); - - if (secondarySegments != null) { - drawFace(g2, secondarySegments, SECONDARY_COLOR, false); - drawFace(g2, secondaryMirrorSegments, SECONDARY_MIRROR_COLOR, false); - } - } else { - drawFace(g2, primarySegments, PRIMARY_COLOR, true); - - if (secondarySegments != null) { - drawFace(g2, secondarySegments, SECONDARY_COLOR, false); + + if (mirrorCuts && secondarySegments != null) { // two faces with mirror cutting planes => double view + double offsetZ = (PREF_W * 0.5) - (maxZ * scale); + drawFace(g2, primarySegments, PRIMARY_COLOR, offsetZ); + drawFace(g2, secondarySegments, SECONDARY_COLOR, offsetZ); + offsetZ = (PREF_W * 1.0) - (maxZ * scale); + drawFace(g2, primaryMirrorSegments, PRIMARY_COLOR, offsetZ); + drawFace(g2, secondaryMirrorSegments, SECONDARY_COLOR, offsetZ); + } else { // either a single face or two faces without mirror cutting planes => single view + double offsetZ = (PREF_W * 0.7) - (maxZ * scale); + drawFace(g2, primarySegments, PRIMARY_COLOR, offsetZ); + if (mirrorCuts) { // single face with mirror cutting plane + drawFace(g2, primaryMirrorSegments, PRIMARY_COLOR.darker(), offsetZ); + } else { // two faces without mirror cutting plane + drawFace(g2, secondarySegments, SECONDARY_COLOR, offsetZ); } } } - protected void drawFace(Graphics2D g2, List<List<Point3d>> curve, Color faceColor, boolean isPrimary) { + protected void drawFace(Graphics2D g2, CrossSectionCurve curve, Color faceColor, double offsetZ) { if (curve == null) { return; } - for (int i = 0; i < curve.size(); i++) { - drawCurveSegment(g2, curve.get(i), faceColor, isPrimary, maxY, maxZ); + for (int i = 0; i < curve.getNumSegments(); i++) { + drawCurveSegment(g2, curve.getSegment(i), faceColor, offsetZ); } + drawProjectedFeaturePoints(g2, curve.getProjectedFeaturePoints(), faceColor, offsetZ); } - protected void drawCurveSegment(Graphics2D g2, List<Point3d> curveSegment, Color faceColor, boolean isPrimary, double maxY, double maxZ) { - double offsetZ = 0; - - //Calculate the offsets - if (mirrorCuts) { - if (secondarySegments == null) { - //Mirror cuts with single face - center the face - this.primaryOffsetZ = (PREF_W * 0.7) - (maxZ * scale); - offsetZ = this.primaryOffsetZ; - } else { - //Mirror cuts with two faces - separate primary and secondary - offsetZ = isPrimary ? (PREF_W * 0.4) - (maxZ * scale) : (PREF_W * 0.9) - (maxZ * scale); - } - } else { - //No mirror cuts - center all faces - if (isPrimary) { - this.primaryOffsetZ = (PREF_W * 0.7) - (maxZ * scale); - } - //offsetZ = this.alignProfiles ? (PREF_W * 0.7) - (maxZ * scale) : this.primaryOffsetZ; - offsetZ = this.primaryOffsetZ; - } - + protected void drawCurveSegment(Graphics2D g2, List<Point3d> curveSegment, Color faceColor, double offsetZ) { //Draw lines + List<Ellipse2D.Double> points = new ArrayList<>(); g2.setColor(faceColor); g2.setStroke(GRAPH_STROKE); for (int i = 0; i < curveSegment.size() - 1; i++) { - double z1 = (curveSegment.get(i).z) * scale + BORDER_GAP + offsetZ; + double z1 = curveSegment.get(i).z * scale + BORDER_GAP + offsetZ; //double y1 = (maxY - curveSegment.get(i).y) * scale + BORDER_GAP; - double y1 = PREF_H / 2 - curveSegment.get(i).y * scale + 3 * BORDER_GAP; + double y1 = PREF_H / 2 - curveSegment.get(i).y * scale + 2 * BORDER_GAP; double z2 = (curveSegment.get(i + 1).z) * scale + BORDER_GAP + offsetZ; //double y2 = (maxY - curveSegment.get(i + 1).y) * scale + BORDER_GAP; - double y2 = PREF_H / 2 - curveSegment.get(i + 1).y * scale + 3 * BORDER_GAP; + double y2 = PREF_H / 2 - curveSegment.get(i + 1).y * scale + 2 * BORDER_GAP; g2.draw(new Line2D.Double(z1, y1, z2, y2)); } } + + protected void drawProjectedFeaturePoints(Graphics2D g2, List<Point3d> fps, Color faceColor, double offsetZ) { + g2.setColor(faceColor); + for (int i = 0; i < fps.size(); i++) { + double z = fps.get(i).z * scale + BORDER_GAP + offsetZ; + double y = PREF_H / 2 - fps.get(i).y * scale + 2 * BORDER_GAP; + Ellipse2D.Double point = new Ellipse2D.Double( + z - SEGMENT_POINT_SIZE / 2d, + y - SEGMENT_POINT_SIZE / 2d, + SEGMENT_POINT_SIZE, + SEGMENT_POINT_SIZE); + g2.fill(point); + g2.draw(point); + } + } - protected void updateMinMax(List<List<Point3d>> curve) { + protected void updateMinMax(CrossSectionCurve curve) { if (curve == null) { return; } - for (int i = 0; i < curve.size(); i++) { - for (int j = 0; j < curve.get(i).size(); j++) { - minZ = Math.min(minZ, curve.get(i).get(j).z); - maxZ = Math.max(maxZ, curve.get(i).get(j).z); - minY = Math.min(minY, curve.get(i).get(j).y); - maxY = Math.max(maxY, curve.get(i).get(j).y); + for (int i = 0; i < curve.getNumSegments(); i++) { + for (int j = 0; j < curve.getSegment(i).size(); j++) { + minZ = Math.min(minZ, curve.getSegment(i).get(j).z); + maxZ = Math.max(maxZ, curve.getSegment(i).get(j).z); + minY = Math.min(minY, curve.getSegment(i).get(j).y); + maxY = Math.max(maxY, curve.getSegment(i).get(j).y); } } scale = ((double) PREF_H - 2 * BORDER_GAP) / (maxY - minY); + scale *= 0.9; } } \ No newline at end of file diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java index 5403b36c7c80040f62019d47b44ed30cd5568fea..a611171c9e3a7b6cfe292cbe8e4a64ed8214ff96 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java +++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java @@ -3,12 +3,13 @@ package cz.fidentis.analyst.symmetry; import cz.fidentis.analyst.canvas.Canvas; import cz.fidentis.analyst.core.ComboSliderDouble; import cz.fidentis.analyst.core.ControlPanelAction; +import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.face.events.HumanFaceEvent; import cz.fidentis.analyst.face.events.HumanFaceListener; -import cz.fidentis.analyst.mesh.core.CornerTableRow; +import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent; 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.mesh.core.MeshRectangleFacet; import cz.fidentis.analyst.scene.DrawablePlane; import cz.fidentis.analyst.visitors.mesh.BoundingBox; import cz.fidentis.analyst.visitors.mesh.CrossSectionZigZag; @@ -22,6 +23,7 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.List; +import java.util.stream.Collectors; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JOptionPane; @@ -34,6 +36,8 @@ import javax.vecmath.Vector3d; * @author Radek Oslejsek */ public class ProfilesAction extends ControlPanelAction implements HumanFaceListener { + + public static final double FEATUE_POINTS_CLOSENESS = 1.5; /* * GUI elements @@ -44,12 +48,13 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe /* * Calculated profiles */ - private List<List<Point3d>> primarySegments; - private List<List<Point3d>> secondarySegments; - private List<List<Point3d>> primaryMirrorSegments; - private List<List<Point3d>> secondaryMirrorSegments; + private CrossSectionCurve primaryCurve; + private CrossSectionCurve secondaryCurve; + private CrossSectionCurve primaryMirrorCurve; + private CrossSectionCurve secondaryMirrorCurve; private double lastSliderValue = 0.5; + private boolean cuttingPlaneFromSymmetry; /** * Constructor. @@ -67,12 +72,12 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe if (getSecondaryDrawableFace() != null) { //recomputeSecondaryProfile(); - controlPanel = new ProfilesPanel(this, this.primarySegments, this.secondarySegments); - controlPanel.getProfileRenderingPanel().setSecondaryMirrorSegments(this.secondaryMirrorSegments); + controlPanel = new ProfilesPanel(this, this.primaryCurve, this.secondaryCurve); + controlPanel.getProfileRenderingPanel().setSecondaryMirrorSegments(this.secondaryMirrorCurve); } else { - controlPanel = new ProfilesPanel(this, this.primarySegments); + controlPanel = new ProfilesPanel(this, this.primaryCurve); } - controlPanel.getProfileRenderingPanel().setPrimaryMirrorSegments(this.primaryMirrorSegments); + controlPanel.getProfileRenderingPanel().setPrimaryMirrorSegments(this.primaryMirrorCurve); // Place control panel to the topControlPanel this.topControlPanel.addTab(controlPanel.getName(), controlPanel.getIcon(), controlPanel); @@ -107,15 +112,15 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe switch (action) { case ProfilesPanel.ACTION_COMMAND_EXPORT: - exportProfile(this.primarySegments, "Export primary face profile to file"); + exportProfile(this.primaryCurve, "Export primary face profile to file"); if (controlPanel.isMirrorCutsChecked()) { - exportProfile(this.primaryMirrorSegments, "Export primary face mirror profile to file"); + exportProfile(this.primaryMirrorCurve, "Export primary face mirror profile to file"); } if (getSecondaryDrawableFace() != null) { - exportProfile(this.secondarySegments, "Export secondary face profile to file"); + exportProfile(this.secondaryCurve, "Export secondary face profile to file"); if (controlPanel.isMirrorCutsChecked()) { - exportProfile(this.secondaryMirrorSegments, "Export secondary face mirror profile to file"); + exportProfile(this.secondaryMirrorCurve, "Export secondary face mirror profile to file"); } } break; @@ -172,9 +177,17 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe @Override public void acceptEvent(HumanFaceEvent event) { + if (event instanceof SymmetryPlaneChangedEvent && cuttingPlaneFromSymmetry) { + computeCuttingPlanesFromSymmetry(); // recompute cutting planes + if (controlPanel.isMirrorCutsChecked()) { + getCanvas().getScene().showMirrorPlanes(); + } else { + getCanvas().getScene().hideMirrorPlanes(); + } + } } - private void exportProfile(List<List<Point3d>> segments, String title) { + private void exportProfile(CrossSectionCurve curve, String title) { File file = new FileChooserBuilder(ProfilesAction.class) .setTitle(title) .setDefaultWorkingDirectory(new File(System.getProperty("user.home"))) @@ -200,9 +213,9 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe PrintWriter writer = new PrintWriter(file.getAbsoluteFile(), "UTF-8"); writer.println("N,X-Coordinate,Z-Coordinate"); - for (int i = 0; i < segments.size(); i++) { - for (int j = 0; j < segments.get(i).size(); ++j) { - writer.println(((i+1)*(j+1)) + "," + segments.get(i).get(j).x + "," + segments.get(i).get(j).z); + for (int i = 0; i < curve.getNumSegments(); i++) { + for (int j = 0; j < curve.getSegmentSize(i); ++j) { + writer.println(((i+1)*(j+1)) + "," + curve.getSegment(j).get(j).x + "," + curve.getSegment(i).get(j).z); } } @@ -216,35 +229,51 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe //Main profile CrossSectionZigZag cs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(0).getPlane()); getPrimaryDrawableFace().getModel().compute(cs); - this.primarySegments = cs.getSegments(); + this.primaryCurve = cs.getCrossSectionCurve(); //Mirror profile CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(0).getPlane()); getPrimaryDrawableFace().getModel().compute(mcs); - this.primaryMirrorSegments = mcs.getSegments(); + this.primaryMirrorCurve = mcs.getCrossSectionCurve(); } private void recomputeSecondaryProfile() { //Main profile CrossSectionZigZag cs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(1).getPlane()); getSecondaryDrawableFace().getModel().compute(cs); - this.secondarySegments = cs.getSegments(); + this.secondaryCurve = cs.getCrossSectionCurve(); //Mirror profile CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(1).getPlane()); getSecondaryDrawableFace().getModel().compute(mcs); - this.secondaryMirrorSegments = mcs.getSegments(); + this.secondaryMirrorCurve = mcs.getCrossSectionCurve(); } private void recomputeProfiles() { recomputePrimaryProfile(); - controlPanel.getProfileRenderingPanel().setPrimarySegments(this.primarySegments); - controlPanel.getProfileRenderingPanel().setPrimaryMirrorSegments(this.primaryMirrorSegments); + projectCloseFeaturePoints( + primaryCurve, + getCanvas().getScene().getHumanFace(0), + getScene().getDrawableCuttingPlane(0).getPlane()); + projectCloseFeaturePoints( + primaryMirrorCurve, + getCanvas().getScene().getHumanFace(0), + getScene().getDrawableCuttingPlane(0).getPlane()); + controlPanel.getProfileRenderingPanel().setPrimarySegments(this.primaryCurve); + controlPanel.getProfileRenderingPanel().setPrimaryMirrorSegments(this.primaryMirrorCurve); if (getSecondaryDrawableFace() != null) { recomputeSecondaryProfile(); - controlPanel.getProfileRenderingPanel().setSecondarySegments(this.secondarySegments); - controlPanel.getProfileRenderingPanel().setSecondaryMirrorSegments(this.secondaryMirrorSegments); + projectCloseFeaturePoints( + secondaryCurve, + getCanvas().getScene().getHumanFace(1), + getScene().getDrawableCuttingPlane(1).getPlane()); + projectCloseFeaturePoints( + secondaryMirrorCurve, + getCanvas().getScene().getHumanFace(1), + getScene().getDrawableCuttingPlane(1).getPlane()); + controlPanel.getProfileRenderingPanel().setSecondarySegments(this.secondaryCurve); + controlPanel.getProfileRenderingPanel().setSecondaryMirrorSegments(this.secondaryMirrorCurve); } } @@ -274,9 +303,10 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe getCanvas().getScene().setDrawableCuttingPlane(0, drPlane); getCanvas().getScene().setDrawableMirrorPlane(0, new DrawablePlane(drPlane)); if (getSecondaryDrawableFace() != null) { - getCanvas().getScene().setDrawableCuttingPlane(1, drPlane); + getCanvas().getScene().setDrawableCuttingPlane(1, new DrawablePlane(drPlane)); getCanvas().getScene().setDrawableMirrorPlane(1, new DrawablePlane(drPlane)); } + cuttingPlaneFromSymmetry = false; } protected DrawablePlane getDrawableOrthogonalPlane(boolean horizontal) { @@ -286,7 +316,7 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe getSecondaryDrawableFace().getModel().compute(bbox); } - Vector3d normal = (horizontal) ? new Vector3d(0,1,0) : new Vector3d(1,0,0); + Vector3d normal = (horizontal) ? new Vector3d(0,1,0) : new Vector3d(-1,0,0); Point3d midPoint = bbox.getBoundingBox().getMidPoint(); Point3d minPoint = bbox.getBoundingBox().getMinPoint(); Point3d maxPoint = bbox.getBoundingBox().getMaxPoint(); @@ -301,24 +331,24 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe Plane plane = new Plane(normal, (horizontal) ? midPoint.y : midPoint.x); - MeshFacet planeMesh = new MeshFacetImpl(); + MeshRectangleFacet planeMesh; if (horizontal) { - planeMesh.addVertex(new MeshPointImpl(new Point3d(minPoint.x, midPoint.y, maxPoint.z), normal, null)); - planeMesh.addVertex(new MeshPointImpl(new Point3d(minPoint.x, midPoint.y, minPoint.z), normal, null)); - planeMesh.addVertex(new MeshPointImpl(new Point3d(maxPoint.x, midPoint.y, minPoint.z), normal, null)); - planeMesh.addVertex(new MeshPointImpl(new Point3d(maxPoint.x, midPoint.y, maxPoint.z), normal, null)); + planeMesh = new MeshRectangleFacet( + midPoint, + new Vector3d(1, 0, 0), + new Vector3d(0, 0, 1), + maxPoint.x - minPoint.x, + maxPoint.z - minPoint.z + ); } else { - planeMesh.addVertex(new MeshPointImpl(new Point3d(midPoint.x, minPoint.y, minPoint.z), normal, null)); - planeMesh.addVertex(new MeshPointImpl(new Point3d(midPoint.x, maxPoint.y, minPoint.z), normal, null)); - planeMesh.addVertex(new MeshPointImpl(new Point3d(midPoint.x, maxPoint.y, maxPoint.z), normal, null)); - planeMesh.addVertex(new MeshPointImpl(new Point3d(midPoint.x, minPoint.y, maxPoint.z), normal, null)); + planeMesh = new MeshRectangleFacet( + midPoint, + new Vector3d(0, 0, 1), + new Vector3d(0, 1, 0), + maxPoint.z - minPoint.z, + maxPoint.y - minPoint.y + ); } - planeMesh.getCornerTable().addRow(new CornerTableRow(0, 5)); - planeMesh.getCornerTable().addRow(new CornerTableRow(1, -1)); - planeMesh.getCornerTable().addRow(new CornerTableRow(3, -1)); - planeMesh.getCornerTable().addRow(new CornerTableRow(3, -1)); - planeMesh.getCornerTable().addRow(new CornerTableRow(1, -1)); - planeMesh.getCornerTable().addRow(new CornerTableRow(2, 0)); DrawablePlane cuttingPlane = new DrawablePlane(planeMesh, plane); cuttingPlane.setTransparency(0.5f); @@ -354,6 +384,18 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe getCanvas().getScene().setDrawableMirrorPlane(1, new DrawablePlane(cuttingPlane)); recomputeSecondaryProfile(); } + cuttingPlaneFromSymmetry = true; } + protected void projectCloseFeaturePoints(CrossSectionCurve curve, HumanFace face, Plane cuttingPlane) { + if (!face.hasFeaturePoints()) { + return; + } + List<Point3d> close = face.getFeaturePoints() + .stream() + .filter(fp -> Math.abs(cuttingPlane.getPointDistance(fp.getPosition())) < FEATUE_POINTS_CLOSENESS) + .map(fp -> fp.getPosition()) + .collect(Collectors.toList()); + curve.projectFeaturePointsToCurve(close); + } } diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java index b3dd5b1b72f6ab0df8df7f986d6ce39bedca6b29..e9ac0b558c5e1574433758cc35be0720d0325f52 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java @@ -7,9 +7,7 @@ package cz.fidentis.analyst.symmetry; import cz.fidentis.analyst.core.ControlPanel; import java.awt.event.ActionListener; -import java.util.List; import javax.swing.ImageIcon; -import javax.vecmath.Point3d; /** * Control panel for face profiles. @@ -37,21 +35,28 @@ public class ProfilesPanel extends ControlPanel { public static final String NAME = "Profiles"; /** - * Constructor for one face + * Constructor for one face. + * + * @param action Action listener + * @param curve Cross section curve */ - public ProfilesPanel(ActionListener action, List<List<Point3d>> values) { - this(action, values, null); + public ProfilesPanel(ActionListener action, CrossSectionCurve curve) { + this(action, curve, null); } /** * Constructor for two faces + * + * @param action Action listener + * @param primaryCurve Primary cross section curve + * @param secondaryCurve Secondary cross section curve */ - public ProfilesPanel(ActionListener action, List<List<Point3d>> primary, List<List<Point3d>> secondary) { + public ProfilesPanel(ActionListener action, CrossSectionCurve primaryCurve, CrossSectionCurve secondaryCurve) { setName(NAME); initComponents(); - polylinePanel1.setPrimarySegments(primary); - polylinePanel1.setSecondarySegments(secondary); + polylinePanel1.setPrimarySegments(primaryCurve); + polylinePanel1.setSecondarySegments(secondaryCurve); comboSliderDouble1.setRange(0, 1, 2); comboSliderDouble1.setValue(0.5); 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 9d7047415f29a5785e50ed0da51b581f52ac9ef1..f046f5f948ffc74e693bd2f0b5de662298fdd059 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 @@ -58,8 +58,6 @@ public class MeshModel implements Serializable { /** * Adds a new mesh facet to the model. - * Fires {@link cz.fidentis.analyst.mesh.events.FacetAddedEvent} to - * registered listeners. * * @param facet new MeshFacet */ @@ -69,8 +67,6 @@ public class MeshModel implements Serializable { /** * Adds a new mesh facets to the model. - * Fires {@link cz.fidentis.analyst.mesh.events.FacetAddedEvent} to - * registered listeners. * * @param newFacets collection of new new facets */ diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshPoint.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshPoint.java index 67cd4703631ed78e2f667e6a3d5512b2c5827c95..ab67c9edef169daf9335fff21339c4f0315947f1 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshPoint.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshPoint.java @@ -21,7 +21,7 @@ public interface MeshPoint extends IPosition, Serializable { * @return distance * @throws NullPointerException if some input parameter is missing. */ - static double distance(Vector3d v1, Vector3d v2) { + static double distance(Point3d v1, Point3d v2) { return Math.sqrt(Math.pow(v1.x - v2.x, 2) + Math.pow(v1.y - v2.y, 2) + Math.pow(v1.z - v2.z, 2)); diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshRectangleFacet.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshRectangleFacet.java new file mode 100644 index 0000000000000000000000000000000000000000..6c54facb7d3580a09106e84b14bb044706bfdc58 --- /dev/null +++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshRectangleFacet.java @@ -0,0 +1,83 @@ +package cz.fidentis.analyst.mesh.core; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +/** + * A rectangular mesh facet consisted of two triangles. + * + * @author Radek Oslejsek + */ +public class MeshRectangleFacet extends MeshFacetImpl { + + /** + * Constructor. + * + * @param center Central point of the rectangle + * @param hDir Normalized horizontal direction of the rectangle + * @param vDir Normalized vertical direction of the rectangle + * @param w Width + * @param h Height + */ + public MeshRectangleFacet(Point3d center, Vector3d hDir, Vector3d vDir, double w, double h) { + this(center, hDir, vDir, null, w, h); + } + + /** + * Constructor. + * + * @param center Central point of the rectangle + * @param hDir Normalized horizontal direction of the rectangle + * @param vDir Normalized vertical direction of the rectangle + * @param normal Optional normalized normal direction perpendicular to {@code hDir} and {@code vDir}. Can be {@code null}. + * @param w Width + * @param h Height + */ + public MeshRectangleFacet(Point3d center, Vector3d hDir, Vector3d vDir, Vector3d normal, double w, double h) { + initRectangle(center, hDir, vDir, null, w, h); + } + + protected final void initRectangle(Point3d center, Vector3d hDir, Vector3d vDir, Vector3d normal, double w, double h) { + Vector3d myNormal; + + if (normal == null) { + myNormal = new Vector3d(); + myNormal.cross(hDir, vDir); + } else { + myNormal = new Vector3d(normal); + } + + Point3d corner = new Point3d(center); + Vector3d aScaled = new Vector3d(hDir); + Vector3d bScaled = new Vector3d(vDir); + aScaled.scale(w/2f); + bScaled.scale(h/2f); + corner.sub(aScaled); + corner.sub(bScaled); + + Point3d p = new Point3d(corner); + addVertex(new MeshPointImpl(p, myNormal, null)); + + Vector3d dir = new Vector3d(vDir); + dir.scale(h); + p = new Point3d(corner); + p.add(dir); + addVertex(new MeshPointImpl(p, myNormal, null)); + + dir = new Vector3d(hDir); + dir.scale(w); + p.add(dir); + addVertex(new MeshPointImpl(p, myNormal, null)); + + p = new Point3d(corner); + p.add(dir); + addVertex(new MeshPointImpl(p, myNormal, null)); + + getCornerTable().addRow(new CornerTableRow(0, 5)); + getCornerTable().addRow(new CornerTableRow(1, -1)); + getCornerTable().addRow(new CornerTableRow(3, -1)); + getCornerTable().addRow(new CornerTableRow(3, -1)); + getCornerTable().addRow(new CornerTableRow(1, -1)); + getCornerTable().addRow(new CornerTableRow(2, 0)); + } +}