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 15cafbc9995852a0bfa1091a36009ba5010d808f..8e089d9c2bcdb5f46a88ef66aea2b5f34a7d5f2e 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java @@ -7,12 +7,7 @@ import cz.fidentis.analyst.face.events.HumanFaceEvent; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.feature.services.FeaturePointImportService; import cz.fidentis.analyst.kdtree.KdTree; -import cz.fidentis.analyst.face.events.KdTreeCreated; -import cz.fidentis.analyst.face.events.KdTreeDestroyed; -import cz.fidentis.analyst.face.events.MeshChangedEvent; -import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent; import cz.fidentis.analyst.mesh.core.MeshModel; -import cz.fidentis.analyst.mesh.core.MeshRectangleFacet; import cz.fidentis.analyst.mesh.io.MeshObjLoader; import cz.fidentis.analyst.symmetry.Plane; import cz.fidentis.analyst.visitors.face.HumanFaceVisitor; @@ -92,10 +87,7 @@ public class HumanFace implements Serializable { meshModel.simplifyModel(); this.id = file.getCanonicalPath(); - BoundingBox visitor = new BoundingBox(); - meshModel.compute(visitor); - bbox = visitor.getBoundingBox(); - + updateBoundingBox(); eventBus = new EventBus(); if (loadLandmarks) { @@ -138,13 +130,8 @@ public class HumanFace implements Serializable { throw new IllegalArgumentException("id"); } this.meshModel = model; - - BoundingBox visitor = new BoundingBox(); - meshModel.compute(visitor); - bbox = visitor.getBoundingBox(); - + updateBoundingBox(); this.id = id; - eventBus = new EventBus(); } @@ -159,7 +146,6 @@ public class HumanFace implements Serializable { /** * Sets the mesh model. - * Triggers {@link cz.fidentis.analyst.face.events.MeshChangedEvent}. * * @param meshModel new mesh model, must not be {@code null} * @throws IllegalArgumentException if new model is missing @@ -169,12 +155,8 @@ public class HumanFace implements Serializable { throw new IllegalArgumentException("meshModel"); } this.meshModel = meshModel; - - BoundingBox visitor = new BoundingBox(); - meshModel.compute(visitor); - bbox = visitor.getBoundingBox(); - - announceEvent(new MeshChangedEvent(this, getShortName(), this)); + updateBoundingBox(); + //announceEvent(new MeshChangedEvent(this, getShortName(), this)); } /** @@ -210,16 +192,26 @@ public class HumanFace implements Serializable { eventBus.post(evt); } } + + /** + * Computes and return bounding box. + * + * @return bounding box + */ + public final BBox updateBoundingBox() { + BoundingBox visitor = new BoundingBox(); + this.meshModel.compute(visitor); + this.bbox = visitor.getBoundingBox(); + return bbox; + } /** * Sets the symmetry plane. If the input argument is {@code null}, then removes the plane. - * Triggers {@link cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent}. * * @param plane The new symmetry plane; Must not be {@code null} */ public void setSymmetryPlane(Plane plane) { this.symmetryPlane = plane; - this.announceEvent(new SymmetryPlaneChangedEvent(this, getShortName(), this)); } /** @@ -234,8 +226,17 @@ public class HumanFace implements Serializable { * Returns rectangular mesh facet of the symmetry plane, if exists. * @return a rectangular mesh facet of the symmetry plane or {@code null} */ - public MeshRectangleFacet getSymmetryPlaneFacet() { - return (symmetryPlane == null) ? null : symmetryPlane.getMesh(bbox); + //@Deprecated + //public MeshRectangleFacet getSymmetryPlaneFacet() { + // return (symmetryPlane == null) ? null : symmetryPlane.getMesh(bbox); + //} + + /** + * Returns {@code true} if the face has the symmetry plane computed. + * @return {@code true} if the face has the symmetry plane computed. + */ + public boolean hasSymmetryPlane() { + return (symmetryPlane != null); } /** @@ -250,6 +251,7 @@ public class HumanFace implements Serializable { * * @param points List of feature points */ + @Deprecated public void setFeaturePoints(List<FeaturePoint> points) { featurePoints = points; } @@ -273,7 +275,8 @@ public class HumanFace implements Serializable { if (featurePoints == null) { return Collections.emptyList(); } - return Collections.unmodifiableList(featurePoints); + //return Collections.unmodifiableList(featurePoints); + return featurePoints; } /** @@ -337,9 +340,6 @@ public class HumanFace implements Serializable { public KdTree computeKdTree(boolean recompute) { if (kdTree == null || recompute) { kdTree = new KdTree(new ArrayList<>(meshModel.getFacets())); - if (eventBus != null) { // eventBus is null when the class is deserialized! - eventBus.post(new KdTreeCreated(this, this.getShortName(), this)); - } } return kdTree; } @@ -351,9 +351,6 @@ public class HumanFace implements Serializable { public KdTree removeKdTree() { KdTree ret = this.kdTree; this.kdTree = null; - if (eventBus != null) { // eventBus is null when the class is deserialized! - eventBus.post(new KdTreeDestroyed(this, this.getShortName(), this)); - } return ret; } diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..27d4396722094d37c5a4fcfce3ca00863b7789ac --- /dev/null +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceUtils.java @@ -0,0 +1,355 @@ +package cz.fidentis.analyst.face; + +import cz.fidentis.analyst.feature.FeaturePoint; +import cz.fidentis.analyst.icp.EigenvalueDecomposition; +import cz.fidentis.analyst.icp.IcpTransformer; +import cz.fidentis.analyst.icp.NoUndersampling; +import cz.fidentis.analyst.icp.Quaternion; +import cz.fidentis.analyst.icp.RandomStrategy; +import cz.fidentis.analyst.symmetry.Plane; +import javax.vecmath.Matrix3d; +import javax.vecmath.Matrix4d; +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +/** + * A utility class for operations (visitors) applied onto the whole human faces. + * Currently, transformation operations that affect multiple parts of the human + * face consistently (mesh, symmetry plane, feature points, etc.) are provided. + * + * @author Radek Oslejsek + */ +public class HumanFaceUtils { + + /** + * Superimpose two faces using ICP applied on their triangular meshes. + * + * @param staticFace A face that remains unchanged. + * @param transformedFace A face to be transformed. + * @param maxIterations Maximal number of ICP iterations, bigger than zero. + * Reasonable number seems to be 10. + * @param scale Whether to scale face as well + * @param error Acceptable error (a number bigger than or equal to zero). + * @param undersampling 100 = no undersampling, 10 = undersampling into 10% of vertices. + * @param recomputeKdTree If {@code true} and the k-d tree of the {@code transformedFace} exists, + * the it automatically re-computed. Otherwise, it is simply removed. + * @return ICP visitor that holds the transformations performed on the {@code transformedFace}. + */ + public static IcpTransformer alignMeshes( + HumanFace staticFace, HumanFace transformedFace, + int maxIterations, boolean scale, double error, int undersampling, + boolean recomputeKdTree) { + + // transform mesh: + IcpTransformer icp = new IcpTransformer( + staticFace.getMeshModel(), + maxIterations, + scale, + error, + (undersampling == 100) ? new NoUndersampling() : new RandomStrategy(undersampling) + ); + transformedFace.getMeshModel().compute(icp, true); // superimpose face towards the static face + + // update k-d of transformed face: + if (transformedFace.hasKdTree()) { + if (recomputeKdTree) { + transformedFace.computeKdTree(true); + } else { + transformedFace.removeKdTree(); + } + } + + // update bounding box, which is always present: + transformedFace.updateBoundingBox(); + + // transform feature points: + if (transformedFace.hasFeaturePoints()) { + icp.getTransformations().values().forEach(trList -> { // List<IcpTransformation> + trList.forEach(tr -> { // IcpTransformation + for (int i = 0; i < transformedFace.getFeaturePoints().size(); i++) { + FeaturePoint fp = transformedFace.getFeaturePoints().get(i); + Point3d trPoint = tr.transformPoint(fp.getPosition(), scale); + transformedFace.getFeaturePoints().set(i, + new FeaturePoint(trPoint.x, trPoint.y, trPoint.z, fp.getFeaturePointType()) + ); + } + }); + }); + } + + // transform symmetry plane: + if (transformedFace.hasSymmetryPlane()) { + icp.getTransformations().values().forEach(trList -> { // List<IcpTransformation> + trList.forEach(tr -> { // IcpTransformation + transformedFace.setSymmetryPlane(transformPlane( + transformedFace.getSymmetryPlane(), + tr.getRotation(), + tr.getTranslation(), + tr.getScaleFactor())); + }); + }); + } + + return icp; + } + + /** + * Transform the face. + * + * @param face Face to be transformed. + * @param rotation Rotation vector denoting the rotation angle around axes X, Y, and Z. + * @param translation Translation vector denoting the translation in the X, Y, and Z direction. + * @param scale Scale factor (1 = no scale). + * @param recomputeKdTree If {@code true} and the k-d tree of the {@code transformedFace} exists, + * the it automatically re-computed. Otherwise, it is simply removed. + */ + public static void transformFace(HumanFace face, Vector3d rotation, Vector3d translation, double scale, boolean recomputeKdTree) { + Quaternion rot = new Quaternion(rotation.x, rotation.y, rotation.z, 1.0); + + face.getMeshModel().getFacets().stream() + .map(facet -> facet.getVertices()) + .flatMap(meshPoint -> meshPoint.parallelStream()) + .forEach(meshPoint -> { + transformPoint(meshPoint.getPosition(), rot, translation, scale); + }); + + + // update k-d of transformed face: + if (face.hasKdTree()) { + if (recomputeKdTree) { + face.computeKdTree(true); + } else { + face.removeKdTree(); + } + } + + // update bounding box, which is always present: + face.updateBoundingBox(); + + // transform feature points: + if (face.hasFeaturePoints()) { + face.getFeaturePoints().parallelStream().forEach(fp -> { + transformPoint(fp.getPosition(), rot, translation, scale); + }); + } + + // transform symmetry plane: + if (face.hasSymmetryPlane()) { + face.setSymmetryPlane(transformPlane(face.getSymmetryPlane(), rot, translation, scale)); + } + } + + /** + * Transforms one face so that its symmetry plane fits the symmetry plane of the other face. + * + * @param staticFace a human face that remains unchanged + * @param transformedFace a human face that will be transformed + * @param recomputeKdTree If {@code true} and the k-d tree of the {@code transformedFace} exists, + * the it automatically re-computed. Otherwise, it is simply removed. + */ + public static void alignSymmetryPlanes(HumanFace staticFace, HumanFace transformedFace, boolean recomputeKdTree) { + Plane statPlane = staticFace.getSymmetryPlane(); + Plane tranPlane = transformedFace.getSymmetryPlane(); + + // Get "centroids" of the planes + Point3d statCentroid = statPlane.projectToPlane(staticFace.getBoundingBox().getMidPoint()); + Point3d tranCentroid = tranPlane.projectToPlane(transformedFace.getBoundingBox().getMidPoint()); + + // Compute a 3D transformation of planes. + // However, this transforation rotates the face around the plane axis arbitrarily + Vector3d translation = new Vector3d( + statCentroid.x - tranCentroid.x, + statCentroid.y - tranCentroid.y, + statCentroid.z - tranCentroid.z + ); + Quaternion rotation = computeRotation(tranPlane.getNormal(), statPlane.getNormal()); + + // Compute rotation around plane's normal so that the face is oriented as before + + // Get a vector perpendicular to the transformed plane nornal (and then laying at the plane) + Point3d pp = getPerpendicularPoint(tranPlane); // point at the original plane + Vector3d pv = new Vector3d(pp); + pv.sub(tranCentroid); + pv.normalize(); + + // transform the point so that it lays at the target plane + transformPoint(pp, rotation, translation, 1.0); // point at the transformed plane + transformPoint(tranCentroid, rotation, translation, 1.0); // point at the transformed plane + Vector3d trPV = new Vector3d(pp); + trPV.sub(tranCentroid); + trPV.normalize(); + + // compute angle of rotation around the plane normal so that the face is oriented as before + double cosRot = pv.dot(trPV); + pv.cross(pv, trPV); + double sinRot = pv.length(); + Vector3d axis = (statPlane.getNormal().dot(tranPlane.getNormal()) < 0) + ? statPlane.getNormal() + : new Vector3d(-statPlane.getNormal().x, -statPlane.getNormal().y, -statPlane.getNormal().z); + + // get rotation matrix around the plane's normal + Matrix3d rotMat = rotMatAroundAxis(axis, sinRot, cosRot); + + // Transform mesh vertices: + transformedFace.getMeshModel().getFacets().forEach(f -> { + f.getVertices().stream().forEach(p -> { + transformPoint(p.getPosition(), rotation, translation, 1.0); + rotMat.transform(p.getPosition()); // rotate around the plane's normal + }); + }); + + // update k-d of transformed face: + if (transformedFace.hasKdTree()) { + if (recomputeKdTree) { + transformedFace.computeKdTree(true); + } else { + transformedFace.removeKdTree(); + } + } + + // update bounding box, which is always present: + transformedFace.updateBoundingBox(); + + // Transform feature points: + if (transformedFace.hasFeaturePoints()) { + transformedFace.getFeaturePoints().parallelStream().forEach(fp -> { + transformPoint(fp.getPosition(), rotation, translation, 1.0); + rotMat.transform(fp.getPosition()); // rotate around the plane's normal + }); + } + + // Transform the symmetry plane: + if (transformedFace.hasSymmetryPlane()) { + transformedFace.setSymmetryPlane(transformPlane( + transformedFace.getSymmetryPlane(), rotation, translation, 1.0) + ); + } + } + + /** + * Create rotation matrix from rotation axis and the angle + * + * @param axis rotation axis + * @param sinAngle cosine of the angle + * @param cosAngle sin of the angle + * @return rotation matrix + */ + protected static Matrix3d rotMatAroundAxis(Vector3d axis, double sinAngle, double cosAngle) { + Matrix3d matC = new Matrix3d( + 0, -axis.z, axis.y, + axis.z, 0, -axis.x, + -axis.y, axis.x, 0 + ); + + Matrix3d matCC = new Matrix3d(matC); + matCC.mul(matCC); + matCC.mul(1.0 - cosAngle); + + matC.mul(sinAngle); + + Matrix3d rotMat = new Matrix3d(); + rotMat.setIdentity(); + rotMat.add(matC); + rotMat.add(matCC); + + return rotMat; + } + + /** + * Computes a "random" point at the plan, i.e. a point, which is + * perpendicular to the plane's normal and lays at the plane. + * + * @param plane the plane + * @return point at the plane + */ + protected static Point3d getPerpendicularPoint(Plane plane) { + Point3d p; + if (plane.getNormal().x >= Math.max(plane.getNormal().y, plane.getNormal().z)) { + p = new Point3d(0, 1000, 0); + } else if (plane.getNormal().y >= Math.max(plane.getNormal().x, plane.getNormal().y)) { + p = new Point3d(1000, 0, 0); + } else { + p = new Point3d(0, 1000, 0); + } + return plane.projectToPlane(p); + } + + /** + * Computed 3D rotation matrix that transforms one vector onto another. + * @param trDir vector to be transformed + * @param targetDir target vector + * @return rotation + */ + protected static Quaternion computeRotation(Vector3d trDir, Vector3d targetDir) { + Matrix4d multipleMatrix = new Matrix4d(); + Matrix4d sumMatrixComp = new Matrix4d( + 0, -trDir.x, -trDir.y, -trDir.z, + trDir.x, 0, trDir.z, -trDir.y, + trDir.y, -trDir.z, 0, trDir.x, + trDir.z, trDir.y, -trDir.x, 0 + ); + Matrix4d sumMatrixMain = new Matrix4d( + 0, -targetDir.x, -targetDir.y, -targetDir.z, + targetDir.x, 0, -targetDir.z, targetDir.y, + targetDir.y, targetDir.z, 0, -targetDir.x, + targetDir.z, -targetDir.y, targetDir.x, 0 + ); + + multipleMatrix.mulTransposeLeft(sumMatrixComp, sumMatrixMain); + Quaternion rotation = new Quaternion(new EigenvalueDecomposition(multipleMatrix)); + rotation.normalize(); + return rotation; + } + + + /** + * Transform a single 3d point. + * + * @param point point to be transformed + * @param rotation rotation, can be {@code null} + * @param translation translation + * @param scale scale + */ + protected static void transformPoint(Point3d point, Quaternion rotation, Vector3d translation, double scale) { + Quaternion rotQuat = new Quaternion(point.x, point.y, point.z, 1); + + if (rotation != null) { + Quaternion rotationCopy = Quaternion.multiply(rotQuat, rotation.getConjugate()); + rotQuat = Quaternion.multiply(rotation, rotationCopy); + } + + point.set( + (rotQuat.x + translation.x) * scale, + (rotQuat.y + translation.y) * scale, + (rotQuat.z + translation.z) * scale + ); + } + + /** + * Transforms the whole plane, i.e., its normal and position. + * + * @param plane plane to be transformed + * @param rot rotation + * @param translation translation + * @param scale scale + * @return transformed plane + */ + protected static Plane transformPlane(Plane plane, Quaternion rot, Vector3d translation, double scale) { + Point3d point = new Point3d(plane.getNormal()); + transformPoint(point, rot, new Vector3d(0, 0, 0), 1.0); // rotate only + Plane retPlane = new Plane(point, plane.getDistance()); + + // ... then translate and scale a point projected on the rotate plane: + point.scale(retPlane.getDistance()); // point laying on the rotated plane + transformPoint(point, null, translation, scale); // translate and scale only + Vector3d normal = retPlane.getNormal(); + double dist = ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z)) + / Math.sqrt(normal.dot(normal)); // distance of tranformed surface point in the plane's mormal direction + + return new Plane(retPlane.getNormal(), dist); + } + + + + +} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/HumanFaceTransformedEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/HumanFaceTransformedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..960862ef40ddd6d697f3759ff2dad16f35a214bb --- /dev/null +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/events/HumanFaceTransformedEvent.java @@ -0,0 +1,46 @@ +package cz.fidentis.analyst.face.events; + +import cz.fidentis.analyst.face.HumanFace; + +/** + * A human face all its components (mesh, symmetry plane, feature points, etc.) + * have been transformed in scape. + * + * @author Radek Oslejsek + */ +public class HumanFaceTransformedEvent extends HumanFaceEvent { + + private final boolean isFinished; + + /** + * Constructor of finished transformation. + * + * @param face Human face related to the event + * @param name Event name provided by issuer + * @param issuer The issuer + */ + public HumanFaceTransformedEvent(HumanFace face, String name, Object issuer) { + this(face, name, issuer, true); + } + + /** + * Constructor. + * @param face Human face related to the event + * @param name Event name provided by issuer + * @param issuer The issuer + * @param isFinished if {@code true}, then it is supposed that the transformation will continue + * (is in the progress). + */ + public HumanFaceTransformedEvent(HumanFace face, String name, Object issuer, boolean isFinished) { + super(face, name, issuer); + this.isFinished = isFinished; + } + + /** + * Returns {@code true} it the transformation is finished (is not under progress) + * @return {@code true} it the transformation is finished + */ + public boolean isFinished() { + return this.isFinished; + } +} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeCreated.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeCreated.java deleted file mode 100644 index 52d62d033e3197dab56c82f90449285a11f8f743..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeCreated.java +++ /dev/null @@ -1,29 +0,0 @@ - -package cz.fidentis.analyst.face.events; - -import cz.fidentis.analyst.face.HumanFace; - -/** - * An event fired when a new KdTree is calculated - - * @author Matej Kovar - */ -public class KdTreeCreated extends KdTreeEvent { - - /** - * Constructor. - * @param face Human face related to the event - * @param name Event name provided by issuer - * @param issuer The issuer - */ - public KdTreeCreated(HumanFace face, String name, Object issuer) { - super(face, name, issuer); - } - - @Override - public boolean isCalculated() { - return true; - } - - -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeDestroyed.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeDestroyed.java deleted file mode 100644 index 30d3ffd832a4a1a46ebcee62428f2bdb58743683..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/KdTreeDestroyed.java +++ /dev/null @@ -1,24 +0,0 @@ - -package cz.fidentis.analyst.face.events; - -import cz.fidentis.analyst.face.HumanFace; - -/** - * An event fired when a KD-tree is destroyed - - * @author Matej Kovar - */ - -public class KdTreeDestroyed extends KdTreeEvent { - - /** - * Constructor. - * @param face Human face related to the event - * @param name Event name provided by issuer - * @param issuer The issuer - */ - public KdTreeDestroyed(HumanFace face, String name, Object issuer) { - super(face, name, issuer); - } - -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshChangedEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshChangedEvent.java deleted file mode 100644 index daa6bc3d7c22a59dec1ca1febf2e8cce274f23ea..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshChangedEvent.java +++ /dev/null @@ -1,22 +0,0 @@ -package cz.fidentis.analyst.face.events; - -import cz.fidentis.analyst.face.HumanFace; - -/** - * An event fired when the topology or position has changed. - - * @author Radek Oslejsek - */ -public class MeshChangedEvent extends MeshEvent { - - /** - * Constructor. - * @param face Human face related to the event - * @param name Event name provided by issuer - * @param issuer The issuer - */ - public MeshChangedEvent(HumanFace face, String name, Object issuer) { - super(face, name, issuer); - } - -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshEvent.java deleted file mode 100644 index b4f0df4f470d64f2f2dc0941927f044b93512ada..0000000000000000000000000000000000000000 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/MeshEvent.java +++ /dev/null @@ -1,22 +0,0 @@ -package cz.fidentis.analyst.face.events; - -import cz.fidentis.analyst.face.HumanFace; - -/** - * The root type for events related to changes in the triangular mesh. - * - * @author Radek Oslejsek - */ -public class MeshEvent extends HumanFaceEvent { - - /** - * Constructor. - * @param face Human face related to the event - * @param name Event name provided by issuer - * @param issuer The issuer - */ - public MeshEvent(HumanFace face, String name, Object issuer) { - super(face, name, issuer); - } - -} diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java index f171633aceccb3b150c38fca80be6f7a43362e47..04f52440f578647b86a11d361989afbba74263df 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/face/events/SymmetryPlaneChangedEvent.java @@ -3,7 +3,11 @@ package cz.fidentis.analyst.face.events; import cz.fidentis.analyst.face.HumanFace; /** - * New symmetry plane has been added or changed (transformed). + * A new symmetry plane has been added or the previous one has been recomputed. + * If the plane is transformed separately (without the transformation of mesh or + * other parts of the human face), use this event as well. + * On the contrary, if symmetry plane is transformed together with + * the mesh transformation, use the {@link HausdorffDistanceComputed} event instead. * * @author Radek Oslejsek */ @@ -11,6 +15,7 @@ public class SymmetryPlaneChangedEvent extends HumanFaceEvent { /** * Constructor. + * * @param face Human face related to the event * @param name Event name provided by issuer * @param issuer The issuer diff --git a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java index fcf0fda9110e5afdc8e8d007220d3d088bfb09c2..363ee1e8b7666b1fffcd1cf8def6965f391d20f7 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformation.java @@ -22,7 +22,7 @@ public class IcpTransformation { * @param rotation Rotation is represented by Quaternion * (x, y, z coordinate and scalar component). * @param scaleFactor ScaleFactor represents scale between two objects. - * In case there is no scale the value is 0. + * In case there is no scale the value is 1. * @param meanD MeanD represents mean distance between objects. */ public IcpTransformation(Vector3d translation, Quaternion rotation, double scaleFactor, double meanD) { @@ -82,9 +82,9 @@ public class IcpTransformation { if(scale && !Double.isNaN(getScaleFactor())) { return new Point3d( - rotQuat.x * getScaleFactor() + getTranslation().x, - rotQuat.y * getScaleFactor() + getTranslation().y, - rotQuat.z * getScaleFactor() + getTranslation().z + (rotQuat.x + getTranslation().x) * getScaleFactor(), + (rotQuat.y + getTranslation().y) * getScaleFactor(), + (rotQuat.z + getTranslation().z) * getScaleFactor() ); } else { return new Point3d( diff --git a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java index 5f9d1a51ad9f754ff36c77949ebf5abcfd478309..5c47b7e9700ba9317bcb13a7e5bc8dbd81a1dbbc 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/icp/IcpTransformer.java @@ -76,7 +76,7 @@ public class IcpTransformer extends MeshVisitor { * new transformation and applying it). A number bigger than zero. * Reasonable number seems to be 10. * @param scale If {@code true}, then the scale factor is also computed. - * @param error Acceptable error. A number bugger than or equal to zero. + * @param error Acceptable error. A number bigger than or equal to zero. * When reached, then the ICP stops. Reasonable number seems to be 0.05. * @param strategy One of the reduction strategies. If {@code null}, then {@link NoUndersampling} is used. * @throws IllegalArgumentException if some parameter is wrong @@ -295,7 +295,7 @@ public class IcpTransformer extends MeshVisitor { List<Point3d>centers = computeCenterBothFacets(nearestPoints, comparedPoints); Point3d mainCenter = centers.get(0); Point3d comparedCenter = centers.get(1); - + Matrix4d sumMatrix = new Matrix4d(); Matrix4d multipleMatrix = new Matrix4d(); @@ -330,7 +330,7 @@ public class IcpTransformer extends MeshVisitor { // END computing rotation parameter //computing SCALE parameter - double scaleFactor = 0; + double scaleFactor = 1.0; if (scale) { double sxUp = 0; double sxDown = 0; @@ -341,7 +341,7 @@ public class IcpTransformer extends MeshVisitor { } Matrix4d matrixPoint = pointToMatrix(relativeCoordinate(nearestPoints.get(i), mainCenter)); - Matrix4d matrixPointCompare = pointToMatrix(relativeCoordinate(comparedPoints.get(i).getPosition(),comparedCenter)); + Matrix4d matrixPointCompare = pointToMatrix(relativeCoordinate(comparedPoints.get(i).getPosition(), comparedCenter)); matrixPointCompare.mul(rotationMatrix); @@ -383,38 +383,28 @@ public class IcpTransformer extends MeshVisitor { * and the second one represents center of compared facet. */ private List<Point3d> computeCenterBothFacets(List<Point3d> nearestPoints, List<MeshPoint> comparedPoints) { - double xN = 0; - double yN = 0; - double zN = 0; - - double xC = 0; - double yC = 0; - double zC = 0; - + //assert(nearestPoints.size() == comparedPoints.size()); + Point3d n = new Point3d(0, 0, 0); + Point3d c = new Point3d(0, 0, 0); int countOfNotNullPoints = 0; List<Point3d> result = new ArrayList<>(2); for (int i = 0; i < nearestPoints.size(); i++) { - - if(nearestPoints.get(i) == null){ + if (nearestPoints.get(i) == null) { continue; } - - xN += nearestPoints.get(i).x; - yN += nearestPoints.get(i).y; - zN += nearestPoints.get(i).z; - - xC += comparedPoints.get(i).getPosition().x; - yC += comparedPoints.get(i).getPosition().y; - zC += comparedPoints.get(i).getPosition().z; - + n.add(nearestPoints.get(i)); + c.add(comparedPoints.get(i).getPosition()); countOfNotNullPoints ++; } - result.add(new Point3d(xN/countOfNotNullPoints, yN/countOfNotNullPoints, zN/countOfNotNullPoints)); - result.add(new Point3d(xC/countOfNotNullPoints, yC/countOfNotNullPoints, zC/countOfNotNullPoints)); + + n.scale(1.0/countOfNotNullPoints); + c.scale(1.0/countOfNotNullPoints); + result.add(n); + result.add(c); return result; } - + /** * Compute relative coordinate of given point according to given center. * Relative coordinates represents distance from the center of the mesh to vertex. 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 80737435ff3459dbd291c509b212babfd5f0fa8f..2b9489bf6f2f0eebf8424608e5084294c29d2b45 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java @@ -5,10 +5,11 @@ import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import java.io.Serializable; import java.util.List; import javax.vecmath.Point3d; +import javax.vecmath.Tuple3d; import javax.vecmath.Vector3d; /** - * Symmetry plane. + * Immutable symmetry plane. * * @author Natalia Bebjakova * @author Dominik Racek @@ -26,8 +27,8 @@ public class Plane implements Serializable { * @param dist distance * @throws IllegalArgumentException if the @code{plane} argument is null */ - public Plane(Vector3d normal, double dist) { - setNormal(new Vector3d(normal)); + public Plane(Tuple3d normal, double dist) { + setNormal(normal); setDistance(dist); } @@ -54,7 +55,7 @@ public class Plane implements Serializable { Vector3d n = new Vector3d(); double d = 0; Vector3d refDir = planes.get(0).getNormal(); - for (int i = 0; i < planes.size(); i++) { + for (int i = 1; i < planes.size(); i++) { Vector3d normDir = planes.get(i).getNormal(); if (normDir.dot(refDir) < 0) { n.sub(normDir); @@ -66,7 +67,7 @@ public class Plane implements Serializable { } setNormal(n); - setDistance(d); + setDistance(-d); normalize(); } @@ -90,11 +91,7 @@ public class Plane implements Serializable { */ @Override public String toString(){ - return "APPROXIMATE PLANE:" + System.lineSeparator() + - normal.x + System.lineSeparator() + - normal.y + System.lineSeparator() + - normal.z + System.lineSeparator() + - distance + System.lineSeparator(); + return normal + " dist " + distance; } public Vector3d getNormal() { @@ -104,14 +101,47 @@ public class Plane implements Serializable { public double getDistance() { return distance; } + + /** + * Returns a point laying at the plane + * @return a point laying at the plane + */ + public Point3d getPlanePoint() { + Point3d ret = new Point3d(normal); + ret.scale(distance); + return ret; + } /** * Translate the plane along its normal * * @param value */ - public void translate(double value) { - this.distance += value; + //public void shift(double value) { + // this.distance += value; + //} + + /** + * Translate the plane along its normal + * + * @param value a value to be added to the current plane's distance value + * @return shifted plane + */ + public Plane shift(double value) { + Plane ret = new Plane(this); + ret.distance += value; + return ret; + } + + /** + * Returns a plane with flipped direction + * @return a plane with flipped direction + */ + public Plane flip() { + Plane ret = new Plane(this); + ret.normal.scale(-1.0); + ret.distance *= -1.0; + return ret; } /** @@ -122,39 +152,50 @@ public class Plane implements Serializable { * @throws NullPointerException if the {@code point} is {@code null} */ public Point3d projectToPlane(Point3d point) { + Point3d ret = new Point3d(normal); + ret.scale(-getPointDistance(point)); + ret.add(point); + return ret; + + /* double shiftDist = ((normal.x * point.x) + (normal.y * point.y) + - (normal.z * point.z) + - distance) / normSquare; + (normal.z * point.z)) / normSquare; + shiftDist -= distance; Point3d ret = new Point3d(normal); ret.scale(-shiftDist); ret.add(point); return ret; + */ } /** * Returns a point laying on the opposite side of the plane ("mirrors" the point). - * This method implements equation (1) of - * <a href="https://link.springer.com/content/pdf/10.1007/s00371-020-02034-w.pdf">Hruda et al: Robust, fast and flexible symmetry plane detection based -on differentiable symmetry measure</a> * * @param point A 3D point to be reflected * @return a point on the opposite side of the plane. * @throws NullPointerException if the {@code point} is {@code null} */ public Point3d reflectOverPlane(Point3d point) { + Point3d ret = new Point3d(normal); + ret.scale(-2.0 * getPointDistance(point)); + ret.add(point); + return ret; + + /* double shiftDist = ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z) + distance) / normSquare; - + //System.out.println("HHH "+ shiftDist); Point3d ret = new Point3d(normal); ret.scale(-2.0 * shiftDist); ret.add(point); return ret; + */ } /** @@ -181,7 +222,7 @@ on differentiable symmetry measure</a> * @throws IllegalArgumentException if {@code size} is <= 0 */ public MeshRectangleFacet getMesh(Point3d point, double size) { - return Plane.this.getMesh(point, size, size); + return getMesh(point, size, size); } /** @@ -193,14 +234,27 @@ on differentiable symmetry measure</a> * @throws NullPointerException if the {@code midPoint} or {@code bbox} are {@code null} */ public MeshRectangleFacet getMesh(BBox bbox) { - return Plane.this.getMesh(bbox.getMidPoint(), bbox.getDiagonalLength(), bbox.getDiagonalLength()); + return getMesh(bbox.getMidPoint(), bbox.getDiagonalLength(), bbox.getDiagonalLength()); } - protected final void setNormal(Vector3d normal) { - this.normal = normal; - this.normSquare = normal.dot(normal); + /** + * Changes the normal vector. + * @param normal new normalized normal vector + * @throw IllegalArgumentExcpetion if the normal is {@code null} + * or if length is not one. + */ + protected final void setNormal(Tuple3d normal) { + if (normal == null) { + throw new IllegalArgumentException("noraml"); + } + this.normal = new Vector3d(normal); + this.normSquare = this.normal.dot(this.normal); } + /** + * Changes the distance. + * @param dist new distance + */ protected final void setDistance(double dist) { this.distance = dist; } @@ -212,8 +266,10 @@ on differentiable symmetry measure</a> * 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(normSquare); + Point3d v = new Point3d(point); + v.sub(this.getPlanePoint()); + return (normal.x * v.x) + (normal.y * v.y) + (normal.z * v.z); + //return ((normal.x * point.x) + (normal.y * point.y) + (normal.z * point.z) + distance) / Math.sqrt(normSquare); } /** @@ -226,12 +282,14 @@ on differentiable symmetry measure</a> public Point3d getIntersectionWithLine(Point3d p1, Point3d p2) { double distance1 = getPointDistance(p1); double distance2 = getPointDistance(p2); - double t = distance1 / (distance1 - distance2); - - if (distance1 * distance2 > 0) { + + if (distance1 * distance2 > 0) { // both are positive or negative return null; } + double t = distance1 / (distance1 - distance2); + + //Logger.print("EEE "+p1+ " "+getPointDistance(p1)); Point3d output = new Point3d(p2); output.sub(p1); output.scale(t); diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java index 7e1f96886f692fd60b3f299f753ce50ee78309bb..ca0484675ec400f1d788067597e1a247cd243f5f 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/HausdorffDistance.java @@ -356,7 +356,7 @@ import javax.vecmath.Point3d; updateResults(visitor, vertices.get(i), comparedFacet); } } - + if (inParallel()) { // process asynchronous computation of distance executor.shutdown(); while (!executor.isTerminated()){} diff --git a/Comparison/src/test/java/cz/fidentis/analyst/symmetry/PlaneTest.java b/Comparison/src/test/java/cz/fidentis/analyst/symmetry/PlaneTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1e053ae74c4002d23b66100de000a94c4c1a4256 --- /dev/null +++ b/Comparison/src/test/java/cz/fidentis/analyst/symmetry/PlaneTest.java @@ -0,0 +1,129 @@ +package cz.fidentis.analyst.symmetry; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + + +/** + * + * @author Radek Oslejsek + */ +public class PlaneTest { + + @Test + public void construction() { + Vector3d norm = new Vector3d(-1, -1, -1); + norm.normalize(); + + Plane p = new Plane(norm, -3); + Assertions.assertEquals(norm, p.getNormal()); + Assertions.assertEquals(-3, p.getDistance()); + + p = new Plane(p); + Assertions.assertEquals(norm, p.getNormal()); + Assertions.assertEquals(-3, p.getDistance()); + } + + @Test + public void modification() { + Vector3d norm = new Vector3d(-1, -1, -1); + norm.normalize(); + Plane p = new Plane(norm, -3); + + Assertions.assertTrue(p.getPlanePoint() + .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001)); + Assertions.assertTrue(p.shift(1) + .getPlanePoint().epsilonEquals(new Vector3d(1.1547005383792517, 1.1547005383792517, 1.1547005383792517), 0.001)); + Assertions.assertTrue(p.shift(-1) + .getPlanePoint().epsilonEquals(new Vector3d(2.3094010767585034, 2.3094010767585034, 2.3094010767585034), 0.001)); + + Vector3d n2 = new Vector3d(norm); + n2.scale(-1); + Assertions.assertEquals(n2, p.flip().getNormal()); + Assertions.assertEquals(3, p.flip().getDistance()); + } + + @Test + public void projectToPlane() { + Plane p = new Plane(new Vector3d(-1, 0, 0), -3); + Assertions.assertTrue(p.projectToPlane(new Point3d(9,9,9)) + .epsilonEquals(new Vector3d(3, 9, 9), 0.001)); + Assertions.assertTrue(p.projectToPlane(new Point3d(-9,-9,-9)) + .epsilonEquals(new Vector3d(3, -9, -9), 0.001)); + Assertions.assertTrue(p.projectToPlane(new Point3d(0,0,0)) + .epsilonEquals(new Vector3d(3, 0, 0), 0.001)); + + p = new Plane(new Vector3d(-1, 0, 0), 3); + Assertions.assertTrue(p.projectToPlane(new Point3d(9,9,9)) + .epsilonEquals(new Vector3d(-3, 9, 9), 0.001)); + Assertions.assertTrue(p.projectToPlane(new Point3d(-9,-9,-9)) + .epsilonEquals(new Vector3d(-3, -9, -9), 0.001)); + Assertions.assertTrue(p.projectToPlane(new Point3d(0,0,0)) + .epsilonEquals(new Vector3d(-3, 0, 0), 0.001)); + + Vector3d norm = new Vector3d(-1, -1, -1); + norm.normalize(); + p = new Plane(norm, -3); + Assertions.assertTrue(p.projectToPlane(new Point3d(9,9,9)) + .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001)); + Assertions.assertTrue(p.projectToPlane(new Point3d(-9,-9,-9)) + .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001)); + Assertions.assertTrue(p.projectToPlane(new Point3d(0,0,0)) + .epsilonEquals(new Vector3d(1.7320508075688776, 1.7320508075688776, 1.7320508075688776), 0.001)); + } + + @Test + public void reflectOverPlane() { + Plane p = new Plane(new Vector3d(-1, 0, 0), -3); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(9,9,9)) + .epsilonEquals(new Vector3d(-3, 9, 9), 0.001)); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(-9,-9,-9)) + .epsilonEquals(new Vector3d(15, -9, -9), 0.001)); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(0,0,0)) + .epsilonEquals(new Vector3d(6, 0, 0), 0.001)); + + p = new Plane(new Vector3d(-1, 0, 0), 3); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(9,9,9)) + .epsilonEquals(new Vector3d(-15, 9, 9), 0.001)); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(-9,-9,-9)) + .epsilonEquals(new Vector3d(3, -9, -9), 0.001)); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(0,0,0)) + .epsilonEquals(new Vector3d(-6, 0, 0), 0.001)); + + Vector3d norm = new Vector3d(-1, -1, -1); + norm.normalize(); + p = new Plane(norm, -3); + + Assertions.assertTrue(p.reflectOverPlane(new Point3d(9,9,9)) + .epsilonEquals(new Vector3d(-5.535898384862248, -5.535898384862248, -5.535898384862248), 0.001)); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(-9,-9,-9)) + .epsilonEquals(new Vector3d(12.464101615137768, 12.464101615137768, 12.464101615137768), 0.001)); + Assertions.assertTrue(p.reflectOverPlane(new Point3d(0,0,0)) + .epsilonEquals(new Vector3d(3.464101615137756, 3.464101615137756, 3.464101615137756), 0.001)); + } + + @Test + public void getPointDistance() { + Plane p = new Plane(new Vector3d(-1, 0, 0), -3); + Assertions.assertEquals(-6, p.getPointDistance(new Point3d(9, 9, 9))); + Assertions.assertEquals(12, p.getPointDistance(new Point3d(-9, -9, -9))); + Assertions.assertEquals(3, p.getPointDistance(new Point3d(0, 0, 0))); + + p = new Plane(new Vector3d(-1, 0, 0), 3); + Assertions.assertEquals(-12, p.getPointDistance(new Point3d(9, 9, 9))); + Assertions.assertEquals(6, p.getPointDistance(new Point3d(-9, -9, -9))); + Assertions.assertEquals(-3, p.getPointDistance(new Point3d(0, 0, 0))); + + p = new Plane(new Vector3d(1, 0, 0), 3); + Assertions.assertEquals(6, p.getPointDistance(new Point3d(9, 9, 9))); + Assertions.assertEquals(-12, p.getPointDistance(new Point3d(-9, -9, -9))); + Assertions.assertEquals(-3, p.getPointDistance(new Point3d(0, 0, 0))); + + p = new Plane(new Vector3d(1, 0, 0), -3); + Assertions.assertEquals(12, p.getPointDistance(new Point3d(9, 9, 9))); + Assertions.assertEquals(-6, p.getPointDistance(new Point3d(-9, -9, -9))); + Assertions.assertEquals(3, p.getPointDistance(new Point3d(0, 0, 0))); + } +} 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 217995700ed30ef5f8d6a3ea17a8459d8da82073..29d32ff33feaf376aa7bec416c95fdc14e2a2915 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 @@ -55,7 +55,7 @@ public class CrossSectionTest { */ @Test public void CrossSectionZigZag() { - Plane cuttingPlane = new Plane(new Vector3d(1, 0, 0), -0.5); + Plane cuttingPlane = new Plane(new Vector3d(-1, 0, 0), -0.5); MeshModel model = createModel(); CrossSectionZigZag cs = new CrossSectionZigZag(cuttingPlane); @@ -63,7 +63,7 @@ public class CrossSectionTest { CrossSectionCurve curve = cs.getCrossSectionCurve(); //They can be ordered two ways, check both - Assertions.assertEquals(curve.getSegmentSize(0), 6); + Assertions.assertEquals(6, curve.getSegmentSize(0)); 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)); @@ -88,7 +88,7 @@ public class CrossSectionTest { */ @Test public void CrossSection() { - Plane cuttingPlane = new Plane(new Vector3d(1, 0, 0), -0.5); + Plane cuttingPlane = new Plane(new Vector3d(-1, 0, 0), -0.5); MeshModel model = createModel(); CrossSection cs = new CrossSection(cuttingPlane); @@ -98,7 +98,7 @@ public class CrossSectionTest { //They can be ordered two ways, check both //Flaw of the non-zigzag design: it can't detect first and last intersection, //since it only controls edges between two triangles. - Assertions.assertEquals(points.size(), 4); + Assertions.assertEquals(4, points.size()); if (points.get(0).equals(new Point3d(0.5, 0.5, 0))) { Assertions.assertEquals(points.get(0), new Point3d(0.5, 0.5, 0)); Assertions.assertEquals(points.get(1), new Point3d(0.5, 1, 0)); diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java index 0a18717db2f118eaa3d099f45b2b53d6b38f0654..f7666fbfa8e3a8a3ffa4635e28284f2596a6be8d 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java +++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java @@ -94,21 +94,16 @@ public class ApproxHausdorffDistTask extends SimilarityTask { HausdorffDistance hd = new HausdorffDistance( face.getKdTree(), HausdorffDistance.Strategy.POINT_TO_POINT, - true, // relative + true, // relative distance true, // parallel true // crop ); - templateFace.getMeshModel().compute(hd, true); - - // Store relative distances of individual vertices to the cache - distCache.add(hd.getDistances() - .values() - .stream() - .flatMap(List::stream) - .collect(Collectors.toList())); - face.removeKdTree(); // k-d tree construction is fast, and the memory is more valuable - + templateFace.getMeshModel().compute(hd); + distCache.add(hd.getDistances().values().stream() // Store relative distances of vertices to the cache + .flatMap(List::stream).collect(Collectors.toList())); hdComputationTime.stop(); + + face.removeKdTree(); // k-d tree construction is fast, and the memory is more valuable } else { distCache.add(DoubleStream.generate(() -> 0.0d) .limit(templateFace.getMeshModel().getNumVertices()) diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java index b95faa4a1b271da3f4214e40fb2bad86bb115d3b..f6879d116407f6ecf699406d6450119f394f4b72 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java +++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java @@ -150,11 +150,11 @@ public class ApproxHausdorffDistTaskGPU extends SimilarityTask { HausdorffDistance hd = new HausdorffDistance( face.getKdTree(), HausdorffDistance.Strategy.POINT_TO_POINT, - true, // relative + true, // relative distance true, // parallel true // crop ); - templateFace.getMeshModel().compute(hd, true); + templateFace.getMeshModel().compute(hd); // Copy commputed distances into the GPU memory: float[] auxDist = new float[numVertices]; @@ -168,9 +168,9 @@ public class ApproxHausdorffDistTaskGPU extends SimilarityTask { CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR, Sizeof.cl_float * numVertices, arrayP, null); - face.removeKdTree(); // TO BE TESTED - hdComputationTime.stop(); + + face.removeKdTree(); } else { // distance to template face itself is zero float[] auxDist = new float[numVertices]; // filled by zeros by default Pointer arrayP = Pointer.to(auxDist); diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java index ea7eec93a4bd0b919116521f70f219f0b9515af7..c01d5330a272ef6107fceb029aeda47f6f1205c0 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java +++ b/GUI/src/main/java/cz/fidentis/analyst/batch/CompleteHausdorffDistTask.java @@ -60,28 +60,26 @@ public class CompleteHausdorffDistTask extends SimilarityTask { //Logger.print(priFace.getShortName() + " - " + secFace.getShortName()); - // compute Huasdorff distance in both ways + // compute Huasdorff distance in both directions hdComputationTime.start(); - //priFace.computeKdTree(true); HausdorffDistance hd = new HausdorffDistance( - priFace.getMeshModel(), - HausdorffDistance.Strategy.POINT_TO_POINT, - false, // relative + priFace.getKdTree(), + HausdorffDistance.Strategy.POINT_TO_POINT, + false, // relative distance true, // parallel - true // crop + true // crop ); - secFace.getMeshModel().compute(hd, true); + secFace.getMeshModel().compute(hd); setDistSimilarity(j, i, hd.getStats().getAverage()); - //secFace.computeKdTree(true); hd = new HausdorffDistance( - secFace.getMeshModel(), - HausdorffDistance.Strategy.POINT_TO_POINT, - false, // relative + secFace.getKdTree(), + HausdorffDistance.Strategy.POINT_TO_POINT, + false, // relative distance true, // parallel - false // crop - ); - priFace.getMeshModel().compute(hd, true); + true // crop + ); + priFace.getMeshModel().compute(hd); setDistSimilarity(i, j, hd.getStats().getAverage()); hdComputationTime.stop(); diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java index a6b375c9bcb43e21c0734ef76cc2c714a1b5f24f..d82266ed172fbc583cc3917a52872c4ea0b79cad 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java +++ b/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java @@ -5,9 +5,7 @@ import cz.fidentis.analyst.canvas.Canvas; import cz.fidentis.analyst.core.ProgressDialog; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.face.HumanFaceFactory; -import cz.fidentis.analyst.icp.IcpTransformer; -import cz.fidentis.analyst.icp.NoUndersampling; -import cz.fidentis.analyst.icp.RandomStrategy; +import cz.fidentis.analyst.face.HumanFaceUtils; import cz.fidentis.analyst.mesh.core.MeshModel; import cz.fidentis.analyst.mesh.io.MeshObjExporter; import cz.fidentis.analyst.scene.DrawableFace; @@ -103,13 +101,15 @@ public class IcpTask extends SwingWorker<MeshModel, HumanFace> { if (computeICP) { // ICP registration - face is transformed! icpComputationTime.start(); - IcpTransformer icp = new IcpTransformer( - initFace.getMeshModel(), - 100, - controlPanel.scaleIcp(), - 0.3, - (undersampling == 100) ? new NoUndersampling() : new RandomStrategy(undersampling)); - face.getMeshModel().compute(icp, true); // superimpose face towards the initFace + HumanFaceUtils.alignMeshes( + initFace, + face, // is transformed + 100, // max iterations + controlPanel.scaleIcp(), + 0.3, // error + undersampling, + false // drop k-d tree, if exists + ); icpComputationTime.stop(); } diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java index 29feb0575f1688aab17e92ed1de04179501da65f..053f750f4a12ea28922e26108cad818f32054828 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java +++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java @@ -8,7 +8,12 @@ import cz.fidentis.analyst.scene.Camera; import cz.fidentis.analyst.scene.Scene; import cz.fidentis.analyst.scene.SceneRenderer; import cz.fidentis.analyst.canvas.toolbar.RenderingModeToolbox; +import cz.fidentis.analyst.face.events.HumanFaceEvent; +import cz.fidentis.analyst.face.events.HumanFaceListener; +import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent; +import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent; import cz.fidentis.analyst.scene.Drawable; +import cz.fidentis.analyst.scene.DrawableFace; import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.ActionEvent; @@ -39,7 +44,7 @@ import org.openide.util.NbBundle; * @author Natalia Bebjakova * @author Radek Oslejsek */ -public class Canvas extends JPanel { +public class Canvas extends JPanel implements HumanFaceListener { private static final String RENDERING_MODE_TOOLBOX_ICON = "wireframe28x28.png"; private static final String BACKGROUND_BUTTON_ICON = "background28x28.png"; @@ -87,6 +92,7 @@ public class Canvas extends JPanel { int index = scene.getFreeSlot(); scene.setHumanFace(index, face); scene.setFaceAsPrimary(index); + face.registerListener(this); return index; } return -1; @@ -104,6 +110,7 @@ public class Canvas extends JPanel { int index = scene.getFreeSlot(); scene.setHumanFace(index, face); scene.setFaceAsSecondary(index); + face.registerListener(this); return index; } return -1; @@ -226,6 +233,24 @@ public class Canvas extends JPanel { } } + @Override + public void acceptEvent(HumanFaceEvent event) { + // The symmtery plane is replaced with new nstance during the transformation + // of a human face. Therefore, the drawable plane has to be updated. + // It is not necesary for meshes and feature points because their vertices + // are directly modified and then do not affect their drawable wrappers + if (event instanceof HumanFaceTransformedEvent || event instanceof SymmetryPlaneChangedEvent) { + final HumanFace face = event.getFace(); + final List<DrawableFace> drFaces = getScene().getDrawableFaces(); + for (int i = 0; i < drFaces.size(); i++) { + if (drFaces.get(i).getHumanFace().equals(face)) { // recomputes and replaces i-th symmetry plane + getScene().setDrawableSymmetryPlane(i, face); + break; + } + } + } + } + private ControlButtons getButtonsPanel(Canvas canvas) { diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java index 984f9ac28cd4eb8e7f7b01a52de31aba6f6ffd75..3ec0db480d37e02d252f769f725452c1a1f95f8f 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java +++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java @@ -1,8 +1,12 @@ package cz.fidentis.analyst.canvas.toolbar; import cz.fidentis.analyst.canvas.Canvas; +import cz.fidentis.analyst.face.HumanFace; +import cz.fidentis.analyst.face.events.HumanFaceEvent; +import cz.fidentis.analyst.face.events.HumanFaceListener; +import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent; import cz.fidentis.analyst.scene.DrawableFace; -import cz.fidentis.analyst.scene.DrawableFeaturePoints; +import cz.fidentis.analyst.scene.DrawablePlane; import java.awt.Color; import java.awt.FlowLayout; import java.awt.event.ActionEvent; @@ -23,8 +27,9 @@ import org.openide.util.NbBundle; * @author Richard Pajersky * @author Radek Oslejsek */ -public class SceneToolboxFaceToFace extends JPanel { +public class SceneToolboxFaceToFace extends JPanel implements HumanFaceListener { + private static final String SYMMETRY_BUTTON_ICON = "symmetry28x28.png"; private static final String PRIMARY_FACE_ICON = "primaryFace28x28.png"; private static final String SECONDARY_FACE_ICON = "secondaryFace28x28.png"; private static final String FEATURE_POINTS_ICON = "fps28x28.png"; @@ -32,10 +37,12 @@ public class SceneToolboxFaceToFace extends JPanel { private static final int TRANSPARENCY_RANGE = 50; - private JToggleButton primLandButton; + private JToggleButton priLandButton; private JToggleButton secLandButton; - private JToggleButton primFaceButton; + private JToggleButton priFaceButton; private JToggleButton secFaceButton; + private JToggleButton priSymmetryButton; + private JToggleButton secSymmetryButton; private JSlider slider; private JToggleButton secDistButton; @@ -47,50 +54,106 @@ public class SceneToolboxFaceToFace extends JPanel { */ public SceneToolboxFaceToFace(Canvas canvas) { this.canvas = canvas; - initComponents(); + initComponents(); // buttons are turned on by default + + // be informed if something changes in the faces -- see acceptEvent() + canvas.getPrimaryFace().registerListener(this); + canvas.getSecondaryFace().registerListener(this); // Change inital state: - primLandButton.setSelected(false); - DrawableFeaturePoints fp0 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()); - if (fp0 != null) { - fp0.show(false); - } + + // show the symmetry planes automatically, but only after they are computed + priSymmetryButton.setSelected(true); + priSymmetryButton.setEnabled(false); + secSymmetryButton.setSelected(true); + secSymmetryButton.setEnabled(false); + // currently, FPs (landmarks) are either presented or not + priLandButton.setSelected(false); + if (canvas.getPrimaryFace().hasFeaturePoints()) { + canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()).show(false); + } else { + priLandButton.setEnabled(false); + } secLandButton.setSelected(false); - DrawableFeaturePoints fp1 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceSlot()); - if (fp1 != null) { - fp1.show(false); + if (canvas.getSecondaryFace().hasFeaturePoints()) { + canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceSlot()).show(false); + } else { + secLandButton.setEnabled(false); } - secDistButton.setSelected(true); - canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(true); + secDistButton.setSelected(false); + canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(false); slider.setValue(30); canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceSlot()).setTransparency(30/(float)TRANSPARENCY_RANGE); canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setTransparency(1); } + + + @Override + public void acceptEvent(HumanFaceEvent event) { + if (event instanceof SymmetryPlaneChangedEvent) { + DrawablePlane dp = null; + JToggleButton button = null; + HumanFace face = event.getFace(); + + if (face.equals(canvas.getPrimaryFace())) { + dp = canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot()); + button = priSymmetryButton; + } else if (face.equals(canvas.getSecondaryFace())) { + dp = canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getSecondaryFaceSlot()); + button = secSymmetryButton; + } + + if (dp != null) { // the symmetry plane is included in the scene + button.setEnabled(true); + dp.show(button.isSelected()); + } else { + button.setEnabled(false); + } + } + } + + private JToggleButton initButton(Color color, String icon, String tooltip) { + JToggleButton button = new JToggleButton(); + button.setBorder(Canvas.BUTTONS_BORDER); + if (color != null) { + button.setBackground(null); // default color + button.setUI(new MetalToggleButtonUI() { + @Override + protected Color getSelectColor() { + return color; + } + }); + } + button.setIcon(new ImageIcon(getClass().getResource("/" + icon))); + button.setFocusable(false); + button.setSelected(true); + button.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, tooltip)); + + return button; + } private void initComponents() { JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); add(panel); - primLandButton = new JToggleButton(); - primLandButton.setBorder(Canvas.BUTTONS_BORDER); - primLandButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY); - primLandButton.setUI(new MetalToggleButtonUI() { + priSymmetryButton = initButton(null, SYMMETRY_BUTTON_ICON, "SceneToolboxFaceToFace.symmetryButton.tooltip"); + panel.add(priSymmetryButton); + priSymmetryButton.addActionListener(new AbstractAction() { @Override - protected Color getSelectColor() { - return DrawableFace.SKIN_COLOR_PRIMARY.darker(); + public void actionPerformed(ActionEvent e) { + boolean onOff = ((JToggleButton) e.getSource()).isSelected(); + canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot()).show(onOff); + canvas.renderScene(); } }); - primLandButton.setIcon(new ImageIcon(getClass().getResource("/" + FEATURE_POINTS_ICON))); - primLandButton.setFocusable(false); - primLandButton.setSelected(true); - primLandButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.landButton.tooltip")); - panel.add(primLandButton); - - primLandButton.addActionListener(new AbstractAction() { + + priLandButton = initButton(null, FEATURE_POINTS_ICON, "SceneToolboxFaceToFace.landButton.tooltip"); + panel.add(priLandButton); + priLandButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { boolean onOff = ((JToggleButton) e.getSource()).isSelected(); @@ -99,23 +162,9 @@ public class SceneToolboxFaceToFace extends JPanel { } }); - ///////////////////////// - primFaceButton = new JToggleButton(); - primFaceButton.setBorder(Canvas.BUTTONS_BORDER); - primFaceButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY); - primFaceButton.setUI(new MetalToggleButtonUI() { - @Override - protected Color getSelectColor() { - return DrawableFace.SKIN_COLOR_PRIMARY.darker(); - } - }); - primFaceButton.setIcon(new ImageIcon(getClass().getResource("/" + PRIMARY_FACE_ICON))); - primFaceButton.setFocusable(false); - primFaceButton.setSelected(true); - primFaceButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.faceButton.tooltip")); - panel.add(primFaceButton); - - primFaceButton.addActionListener(new AbstractAction() { + priFaceButton = initButton(DrawableFace.SKIN_COLOR_PRIMARY, PRIMARY_FACE_ICON, "SceneToolboxFaceToFace.faceButton.tooltip"); + panel.add(priFaceButton); + priFaceButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { boolean onOff = ((JToggleButton) e.getSource()).isSelected(); @@ -150,21 +199,8 @@ public class SceneToolboxFaceToFace extends JPanel { }); ///////////////////////// - secFaceButton = new JToggleButton(); - secFaceButton.setBorder(Canvas.BUTTONS_BORDER); - secFaceButton.setBackground(DrawableFace.SKIN_COLOR_SECONDARY); - secFaceButton.setUI(new MetalToggleButtonUI() { - @Override - protected Color getSelectColor() { - return DrawableFace.SKIN_COLOR_SECONDARY.darker(); - } - }); - secFaceButton.setIcon(new ImageIcon(getClass().getResource("/" + SECONDARY_FACE_ICON))); - secFaceButton.setFocusable(false); - secFaceButton.setSelected(true); - secFaceButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.faceButton.tooltip")); + secFaceButton = initButton(DrawableFace.SKIN_COLOR_SECONDARY, SECONDARY_FACE_ICON, "SceneToolboxFaceToFace.faceButton.tooltip"); panel.add(secFaceButton); - secFaceButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -174,23 +210,8 @@ public class SceneToolboxFaceToFace extends JPanel { } }); - - ///////////////////////// - secLandButton = new JToggleButton(); - secLandButton.setBorder(Canvas.BUTTONS_BORDER); - secLandButton.setBackground(DrawableFace.SKIN_COLOR_SECONDARY); - secLandButton.setUI(new MetalToggleButtonUI() { - @Override - protected Color getSelectColor() { - return DrawableFace.SKIN_COLOR_SECONDARY.darker(); - } - }); - secLandButton.setIcon(new ImageIcon(getClass().getResource("/" + FEATURE_POINTS_ICON))); - secLandButton.setFocusable(false); - secLandButton.setSelected(true); - secLandButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.landButton.tooltip")); + secLandButton = initButton(null, FEATURE_POINTS_ICON, "SceneToolboxFaceToFace.landButton.tooltip"); panel.add(secLandButton); - secLandButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -199,38 +220,27 @@ public class SceneToolboxFaceToFace extends JPanel { canvas.renderScene(); } }); - - ///////////////////// - secDistButton = new JToggleButton(); - secDistButton.setBorder(Canvas.BUTTONS_BORDER); - secDistButton.setBackground(DrawableFace.SKIN_COLOR_SECONDARY); - secDistButton.setUI(new MetalToggleButtonUI() { + + secSymmetryButton = initButton(null, SYMMETRY_BUTTON_ICON, "SceneToolboxFaceToFace.symmetryButton.tooltip"); + panel.add(secSymmetryButton); + secSymmetryButton.addActionListener(new AbstractAction() { @Override - protected Color getSelectColor() { - return DrawableFace.SKIN_COLOR_SECONDARY.darker(); + public void actionPerformed(ActionEvent e) { + boolean onOff = ((JToggleButton) e.getSource()).isSelected(); + canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getSecondaryFaceSlot()).show(onOff); + canvas.renderScene(); } }); - secDistButton.setIcon(new ImageIcon(getClass().getResource("/" + DISTANCE_BUTTON_ICON))); - secDistButton.setFocusable(false); - secDistButton.setSelected(true); - secDistButton.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, "SceneToolboxFaceToFace.distButton.tooltip")); + + secDistButton = initButton(null, DISTANCE_BUTTON_ICON, "SceneToolboxFaceToFace.distButton.tooltip"); panel.add(secDistButton); - secDistButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - if (((JToggleButton) e.getSource()).isSelected()) { - canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(true); - } else { - canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(false); - } - // Switch: - //canvas.getScene().getDrawableFace(secIndex).setRenderHeatmap( - // !canvas.getScene().getDrawableFace(secIndex).isHeatmapRendered() - //); + boolean onOff = ((JToggleButton) e.getSource()).isSelected(); + canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(onOff); canvas.renderScene(); } }); } - } diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java index b5078bcb9453b228bb8c85f201d0248231e64fa0..c27fee4866ba12a91574ebd158b79c6b45dd13e6 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java +++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java @@ -1,7 +1,11 @@ package cz.fidentis.analyst.canvas.toolbar; import cz.fidentis.analyst.canvas.Canvas; +import cz.fidentis.analyst.face.events.HumanFaceEvent; +import cz.fidentis.analyst.face.events.HumanFaceListener; +import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent; import cz.fidentis.analyst.scene.DrawableFace; +import cz.fidentis.analyst.scene.DrawablePlane; import java.awt.Color; import java.awt.FlowLayout; import java.awt.event.ActionEvent; @@ -22,15 +26,17 @@ import org.openide.util.NbBundle; * @author Richard Pajersky * @author Radek Oslejsek */ -public class SceneToolboxSingleFace extends JPanel { +public class SceneToolboxSingleFace extends JPanel implements HumanFaceListener { + private static final String SYMMETRY_BUTTON_ICON = "symmetry28x28.png"; private static final String FACE_ICON = "head28x28.png"; private static final String FEATURE_POINTS_ICON = "fps28x28.png"; private static final int TRANSPARENCY_RANGE = 100; - private JToggleButton primLandButton; - private JToggleButton primFaceButton; + private JToggleButton priLandButton; + private JToggleButton priFaceButton; + private JToggleButton priSymmetryButton; private JSlider slider; private final Canvas canvas; @@ -42,6 +48,56 @@ public class SceneToolboxSingleFace extends JPanel { public SceneToolboxSingleFace(Canvas canvas) { this.canvas = canvas; initComponents(); + + // show the symmetry planes automatically, but only after they are computed + priSymmetryButton.setSelected(true); + priSymmetryButton.setEnabled(false); + + // currently, FPs (landmarks) are either presented or not + priLandButton.setSelected(false); + if (canvas.getPrimaryFace() != null) { + if (canvas.getPrimaryFace().hasFeaturePoints()) { + canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()).show(false); + } else { + priLandButton.setEnabled(false); + } + + // be informed if something changes in the faces -- see acceptEvent() + canvas.getPrimaryFace().registerListener(this); + } + } + + @Override + public void acceptEvent(HumanFaceEvent event) { + if (event instanceof SymmetryPlaneChangedEvent) { + DrawablePlane dp = canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot()); + if (dp != null) { // the symmetry plane is included in the scene + priSymmetryButton.setEnabled(true); + dp.show(priSymmetryButton.isSelected()); + } else { + priSymmetryButton.setEnabled(false); + } + } + } + + private JToggleButton initButton(Color color, String icon, String tooltip) { + JToggleButton button = new JToggleButton(); + button.setBorder(Canvas.BUTTONS_BORDER); + if (color != null) { + button.setBackground(null); // default color + button.setUI(new MetalToggleButtonUI() { + @Override + protected Color getSelectColor() { + return color; + } + }); + } + button.setIcon(new ImageIcon(getClass().getResource("/" + icon))); + button.setFocusable(false); + button.setSelected(true); + button.setToolTipText(NbBundle.getMessage(SceneToolboxFaceToFace.class, tooltip)); + + return button; } private void initComponents() { @@ -49,22 +105,20 @@ public class SceneToolboxSingleFace extends JPanel { panel.setLayout(new FlowLayout()); add(panel); - primLandButton = new JToggleButton(); - primLandButton.setBorder(Canvas.BUTTONS_BORDER); - primLandButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY); - primLandButton.setUI(new MetalToggleButtonUI() { + priSymmetryButton = initButton(null, SYMMETRY_BUTTON_ICON, "SceneToolboxFaceToFace.symmetryButton.tooltip"); + panel.add(priSymmetryButton); + priSymmetryButton.addActionListener(new AbstractAction() { @Override - protected Color getSelectColor() { - return DrawableFace.SKIN_COLOR_PRIMARY.darker(); + public void actionPerformed(ActionEvent e) { + boolean onOff = ((JToggleButton) e.getSource()).isSelected(); + canvas.getScene().getDrawableSymmetryPlane(canvas.getScene().getPrimaryFaceSlot()).show(onOff); + canvas.renderScene(); } }); - primLandButton.setIcon(new ImageIcon(getClass().getResource("/" + FEATURE_POINTS_ICON))); - primLandButton.setFocusable(false); - primLandButton.setSelected(true); - primLandButton.setToolTipText(NbBundle.getMessage(SceneToolboxSingleFace.class, "SceneToolboxSingleFace.landButton.tooltip")); - panel.add(primLandButton); - primLandButton.addActionListener(new AbstractAction() { + priLandButton = initButton(null, FEATURE_POINTS_ICON, "SceneToolboxFaceToFace.landButton.tooltip"); + panel.add(priLandButton); + priLandButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { boolean onOff = ((JToggleButton) e.getSource()).isSelected(); @@ -72,24 +126,10 @@ public class SceneToolboxSingleFace extends JPanel { canvas.renderScene(); } }); - - ///////////////////////// - primFaceButton = new JToggleButton(); - primFaceButton.setBorder(Canvas.BUTTONS_BORDER); - primFaceButton.setBackground(DrawableFace.SKIN_COLOR_PRIMARY); - primFaceButton.setUI(new MetalToggleButtonUI() { - @Override - protected Color getSelectColor() { - return DrawableFace.SKIN_COLOR_PRIMARY.darker(); - } - }); - primFaceButton.setIcon(new ImageIcon(getClass().getResource("/" + FACE_ICON))); - primFaceButton.setFocusable(false); - primFaceButton.setSelected(true); - primFaceButton.setToolTipText(NbBundle.getMessage(SceneToolboxSingleFace.class, "SceneToolboxSingleFace.faceButton.tooltip")); - panel.add(primFaceButton); - primFaceButton.addActionListener(new AbstractAction() { + priFaceButton = initButton(DrawableFace.SKIN_COLOR_PRIMARY, FACE_ICON, "SceneToolboxFaceToFace.faceButton.tooltip"); + panel.add(priFaceButton); + priFaceButton.addActionListener(new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { boolean onOff = ((JToggleButton) e.getSource()).isSelected(); @@ -98,6 +138,7 @@ public class SceneToolboxSingleFace extends JPanel { } }); + ///////////////////////// slider = new JSlider(); //slider.setMajorTickSpacing(TRANSPARENCY_RANGE/2); diff --git a/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java b/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java index 455ab3f81433672de8fa0485cfd459496e73390e..28798ab389df4daee6ae1fef6d76c0c000980706 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java +++ b/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java @@ -8,7 +8,7 @@ import cz.fidentis.analyst.core.ControlPanelAction; import cz.fidentis.analyst.face.events.HausdorffDistanceComputed; import cz.fidentis.analyst.face.events.HumanFaceEvent; import cz.fidentis.analyst.face.events.HumanFaceListener; -import cz.fidentis.analyst.face.events.MeshChangedEvent; +import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.feature.FeaturePointType; import cz.fidentis.analyst.scene.DrawableFpWeights; @@ -203,15 +203,18 @@ public class DistanceAction extends ControlPanelAction implements HumanFaceListe @Override public void acceptEvent(HumanFaceEvent event) { - if (event instanceof MeshChangedEvent && event.getIssuer() != this) { // recompte (W)HD - hdVisitor = null; - whdVisitor = null; - computeAndUpdateHausdorffDistance(true); - // Relocate weight speheres: - final List<FeaturePoint> secondaryFPs = getSecondaryFeaturePoints().getFeaturePoints(); - final List<FeaturePoint> weightedFPs = fpSpheres.getFeaturePoints(); - for (int i = 0; i < secondaryFPs.size(); i++) { - weightedFPs.get(i).getPosition().set(secondaryFPs.get(i).getPosition()); + if (event instanceof HumanFaceTransformedEvent && event.getIssuer() != this) { // recompte (W)HD + HumanFaceTransformedEvent ftEvent = (HumanFaceTransformedEvent) event; + if (ftEvent.isFinished()) { + hdVisitor = null; + whdVisitor = null; + computeAndUpdateHausdorffDistance(true); + // Relocate weight speheres: + final List<FeaturePoint> secondaryFPs = getSecondaryFeaturePoints().getFeaturePoints(); + final List<FeaturePoint> weightedFPs = fpSpheres.getFeaturePoints(); + for (int i = 0; i < secondaryFPs.size(); i++) { + weightedFPs.get(i).getPosition().set(secondaryFPs.get(i).getPosition()); + } } } else if (event instanceof HausdorffDistanceComputed) { // update stats HausdorffDistanceComputed hdEvent = (HausdorffDistanceComputed) event; @@ -281,14 +284,16 @@ public class DistanceAction extends ControlPanelAction implements HumanFaceListe getPrimaryDrawableFace().getHumanFace().getKdTree(), useStrategy, relativeDist, - true, + true, // parallel crop ); } whdVisitor = new HausdorffDistancePrioritized(hdVisitor, featurePoints); Logger out = Logger.measureTime(); + getSecondaryDrawableFace().getHumanFace().accept(whdVisitor); + out.printDuration("Weighted Hausdorff distance for models with " + getPrimaryDrawableFace().getHumanFace().getMeshModel().getNumVertices() + "/" @@ -304,7 +309,7 @@ public class DistanceAction extends ControlPanelAction implements HumanFaceListe getSecondaryDrawableFace().getHumanFace().getShortName(), this )); - } + } /** * Updates the GUI elements of {@link DistancePanel} that display 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 63982c2364a89d3033dfd943fcae1114492b0523..a18d4d5e6dad070bcb24673b9da4b8658193ddae 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java +++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java @@ -4,29 +4,19 @@ import cz.fidentis.analyst.Logger; import cz.fidentis.analyst.canvas.Canvas; import cz.fidentis.analyst.core.ControlPanelAction; import cz.fidentis.analyst.face.HumanFace; +import cz.fidentis.analyst.face.HumanFaceUtils; import cz.fidentis.analyst.face.events.HausdorffDistanceComputed; import cz.fidentis.analyst.face.events.HumanFaceEvent; import cz.fidentis.analyst.face.events.HumanFaceListener; -import cz.fidentis.analyst.face.events.MeshChangedEvent; -import cz.fidentis.analyst.feature.FeaturePoint; -import cz.fidentis.analyst.icp.IcpTransformation; -import cz.fidentis.analyst.icp.IcpTransformer; -import cz.fidentis.analyst.icp.NoUndersampling; -import cz.fidentis.analyst.icp.RandomStrategy; -import cz.fidentis.analyst.icp.UndersamplingStrategy; -import cz.fidentis.analyst.mesh.core.MeshFacet; -import cz.fidentis.analyst.mesh.core.MeshPoint; +import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent; import cz.fidentis.analyst.procrustes.ProcrustesAnalysis; -import cz.fidentis.analyst.scene.DrawableFace; import java.awt.Color; import java.awt.event.ActionEvent; -import java.util.List; import java.util.zip.DataFormatException; import javax.swing.JCheckBox; -import javax.swing.JComboBox; import javax.swing.JFormattedTextField; +import javax.swing.JOptionPane; import javax.swing.JTabbedPane; -import javax.vecmath.Point3d; import javax.vecmath.Vector3d; /** @@ -61,13 +51,11 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL private boolean scale = true; private int maxIterations = 10; private double error = 0.3; - private UndersamplingStrategy undersampling = new RandomStrategy(200); private String strategy = RegistrationPanel.STRATEGY_POINT_TO_POINT; private boolean relativeDist = false; private boolean heatmapRender = false; private boolean procrustesScalingEnabled = false; - /* * Coloring threshold and statistical values of feature point distances: */ @@ -115,100 +103,29 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL case RegistrationPanel.ACTION_COMMAND_APPLY_ICP: applyICP(); highlightCloseFeaturePoints(); - announceMeshChange(getSecondaryDrawableFace()); - break; - case RegistrationPanel.ACTION_COMMAND_SHIFT_X: - value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); - getSecondaryDrawableFace().getTranslation().x = value; - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().getTranslation().x = value; - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_SHIFT_Y: - value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); - getSecondaryDrawableFace().getTranslation().y = value; - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().getTranslation().y = value; - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_SHIFT_Z: - value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); - getSecondaryDrawableFace().getTranslation().z = value; - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().getTranslation().z = value; - } - highlightCloseFeaturePoints(); + //announceMeshChange(getSecondaryDrawableFace()); + getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent( + getCanvas().getSecondaryFace(), "", this) + ); break; - case RegistrationPanel.ACTION_COMMAND_ROTATE_X: - value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); - getSecondaryDrawableFace().getRotation().x = value; - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().getRotation().x = value; - } + case RegistrationPanel.ACTION_COMMAND_MANUAL_TRANSFORMATION_IN_PROGRESS: + HumanFaceUtils.transformFace( + getSecondaryDrawableFace().getHumanFace(), + controlPanel.getAndClearManualRotation(), + controlPanel.getAndClearManualTranslation(), + controlPanel.getAndClearManualScale(), + false + ); highlightCloseFeaturePoints(); + getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent( + getCanvas().getSecondaryFace(), "", this, false) // transformation under progress + ); break; - case RegistrationPanel.ACTION_COMMAND_ROTATE_Y: - value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); - getSecondaryDrawableFace().getRotation().y = value; - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().getRotation().y = value; - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_ROTATE_Z: - value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); - getSecondaryDrawableFace().getRotation().z = value; - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().getRotation().z = value; - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_SCALE: - value = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); - getSecondaryDrawableFace().getScale().x = value; - getSecondaryDrawableFace().getScale().y = value; - getSecondaryDrawableFace().getScale().z = value; - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().getScale().x = value; - getSecondaryFeaturePoints().getScale().y = value; - getSecondaryFeaturePoints().getScale().z = value; - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_RESET_TRANSLATION: - getSecondaryDrawableFace().setTranslation(new Vector3d(0, 0, 0)); - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().setTranslation(new Vector3d(0, 0, 0)); - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_RESET_ROTATION: - getSecondaryDrawableFace().setRotation(new Vector3d(0, 0, 0)); - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().setRotation(new Vector3d(0, 0, 0)); - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_RESET_SCALE: - getSecondaryDrawableFace().setScale(new Vector3d(0, 0, 0)); - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().setScale(new Vector3d(0, 0, 0)); - } - highlightCloseFeaturePoints(); - break; - case RegistrationPanel.ACTION_COMMAND_APPLY_TRANSFORMATIONS: - transformFace(); - getSecondaryDrawableFace().setTranslation(new Vector3d(0, 0, 0)); - getSecondaryDrawableFace().setRotation(new Vector3d(0, 0, 0)); - getSecondaryDrawableFace().setScale(new Vector3d(0, 0, 0)); - if (getSecondaryFeaturePoints() != null) { - getSecondaryFeaturePoints().setTranslation(new Vector3d(0, 0, 0)); - getSecondaryFeaturePoints().setRotation(new Vector3d(0, 0, 0)); - getSecondaryFeaturePoints().setScale(new Vector3d(0, 0, 0)); - } - announceMeshChange(getSecondaryDrawableFace()); + case RegistrationPanel.ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED: + getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent( + getCanvas().getSecondaryFace(), "", this, true) // finished transformation + ); + //announceMeshChange(getSecondaryDrawableFace()); break; case RegistrationPanel.ACTION_COMMAND_FP_CLOSENESS_THRESHOLD: fpThreshold = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); @@ -223,27 +140,28 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL case RegistrationPanel.ACTION_COMMAND_ICP_ERROR: error = ((Number) (((JFormattedTextField) ae.getSource()).getValue())).doubleValue(); break; - case RegistrationPanel.ACTION_COMMAND_ICP_UNDERSAMPLING: - String item = (String) ((JComboBox) ae.getSource()).getSelectedItem(); - switch (item) { - case "None": - this.undersampling = new NoUndersampling(); - break; - case "Random 200": - this.undersampling = new RandomStrategy(200); - break; - default: - throw new UnsupportedOperationException(item); - } - break; case RegistrationPanel.ACTION_COMMAND_PROCRUSTES_SCALE: this.procrustesScalingEnabled = ((JCheckBox) ae.getSource()).isSelected(); break; case RegistrationPanel.ACTION_COMMAND_PROCRUSTES_APPLY: applyProcrustes(); highlightCloseFeaturePoints(); - announceMeshChange(getPrimaryDrawableFace()); - announceMeshChange(getSecondaryDrawableFace()); + getCanvas().getPrimaryFace().announceEvent(new HumanFaceTransformedEvent( + getCanvas().getPrimaryFace(), "", this) + ); + getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent( + getCanvas().getSecondaryFace(), "", this) + ); + //announceMeshChange(getPrimaryDrawableFace()); + //announceMeshChange(getSecondaryDrawableFace()); + break; + case RegistrationPanel.ACTION_COMMAND_ALIGN_SYMMETRY_PLANES: + alignSymmetryPlanes(); + highlightCloseFeaturePoints(); + getCanvas().getSecondaryFace().announceEvent(new HumanFaceTransformedEvent( + getCanvas().getSecondaryFace(), "", this) + ); + //announceMeshChange(getSecondaryDrawableFace()); break; default: // do nothing @@ -305,20 +223,17 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL protected void applyICP() { Logger out = Logger.measureTime(); - - IcpTransformer visitor = new IcpTransformer(getPrimaryDrawableFace().getModel(), maxIterations, scale, error, undersampling); - getSecondaryDrawableFace().getModel().compute(visitor); // NOTE: the secondary face is physically transformed - getSecondaryDrawableFace().getHumanFace().removeKdTree(); // invalidate k-d tree, if exists - for (List<IcpTransformation> trList : visitor.getTransformations().values()) { // transform feature points - for (IcpTransformation tr : trList) { - for (int i = 0; i < getSecondaryFeaturePoints().getFeaturePoints().size(); i++) { - FeaturePoint fp = getSecondaryFeaturePoints().getFeaturePoints().get(i); - Point3d trPoint = tr.transformPoint(fp.getPosition(), scale); - getSecondaryFeaturePoints().getFeaturePoints().set(i, new FeaturePoint(trPoint.x, trPoint.y, trPoint.z, fp.getFeaturePointType())); - } - } - } - + + HumanFaceUtils.alignMeshes( + getPrimaryDrawableFace().getHumanFace(), + getSecondaryDrawableFace().getHumanFace(), // is transformed + maxIterations, + scale, + error, + controlPanel.getIcpUndersampling(), + false // drop k-d tree, if exists + ); + out.printDuration("ICP for models with " + getPrimaryDrawableFace().getHumanFace().getMeshModel().getNumVertices() + "/" @@ -346,14 +261,9 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL double fpMinDist = Double.POSITIVE_INFINITY; double distSum = 0.0; for (int i = 0; i < getPrimaryFeaturePoints().getFeaturePoints().size(); i++) { - FeaturePoint primary = getPrimaryFeaturePoints().getFeaturePoints().get(i); - FeaturePoint secondary = getSecondaryFeaturePoints().getFeaturePoints().get(i); - Point3d transformed = new Point3d(secondary.getX(), secondary.getY(), secondary.getZ()); - transformPoint(transformed); - double distance = Math.sqrt( - Math.pow(transformed.x - primary.getX(), 2) + - Math.pow(transformed.y - primary.getY(), 2) + - Math.pow(transformed.z - primary.getZ(), 2)); + Vector3d v = new Vector3d(getPrimaryFeaturePoints().getFeaturePoints().get(i).getPosition()); + v.sub(getSecondaryFeaturePoints().getFeaturePoints().get(i).getPosition()); + double distance = v.length(); if (distance > fpThreshold) { getPrimaryFeaturePoints().resetColorToDefault(i); getSecondaryFeaturePoints().resetColorToDefault(i); @@ -369,88 +279,27 @@ public class RegistrationAction extends ControlPanelAction implements HumanFaceL // to do: show ACF dist } - /** - * Applies carried out transformations first on - * {@link #getSecondaryDrawableFace} and then on - * {@link #getSecondaryDrawableFace} feature points - */ - private void transformFace() { - for (MeshFacet transformedFacet : getSecondaryDrawableFace().getFacets()) { - for (MeshPoint comparedPoint : transformedFacet.getVertices()) { - transformPoint(comparedPoint.getPosition()); - } - } - for (int i = 0; i < getSecondaryFeaturePoints().getFeaturePoints().size(); i++) { - FeaturePoint point = getSecondaryFeaturePoints().getFeaturePoints().get(i); - Point3d transformed = new Point3d(point.getX(), point.getY(), point.getZ()); - transformPoint(transformed); - point = new FeaturePoint(transformed.x, transformed.y, transformed.z, point.getFeaturePointType()); - getSecondaryFeaturePoints().getFeaturePoints().set(i, point); - } - getSecondaryDrawableFace().getHumanFace().removeKdTree(); // invalidate k-d tree, if exists - } - - /** - * Transforms point based on transformation info from - * {@link #getSecondaryDrawableFace} - * - * @param point Point to transform - */ - private void transformPoint(Point3d point) { - if (point == null) { - throw new IllegalArgumentException("point is null"); - } - - Point3d newPoint = new Point3d(0, 0, 0); - double quotient; - - // rotate around X - quotient = Math.toRadians(getSecondaryDrawableFace().getRotation().x); - if (!Double.isNaN(quotient)) { - double cos = Math.cos(quotient); - double sin = Math.sin(quotient); - newPoint.y = point.y * cos - point.z * sin; - newPoint.z = point.z * cos + point.y * sin; - point.y = newPoint.y; - point.z = newPoint.z; - } - - // rotate around Y - quotient = Math.toRadians(getSecondaryDrawableFace().getRotation().y); - if (!Double.isNaN(quotient)) { - double cos = Math.cos(quotient); - double sin = Math.sin(quotient); - newPoint.x = point.x * cos + point.z * sin; - newPoint.z = point.z * cos - point.x * sin; - point.x = newPoint.x; - point.z = newPoint.z; - } - - // rotate around Z - quotient = Math.toRadians(getSecondaryDrawableFace().getRotation().z); - if (!Double.isNaN(quotient)) { - double cos = Math.cos(quotient); - double sin = Math.sin(quotient); - newPoint.x = point.x * cos - point.y * sin; - newPoint.y = point.y * cos + point.x * sin; - point.x = newPoint.x; - point.y = newPoint.y; - } + //protected void announceMeshChange(DrawableFace face) { + // if (face != null) { + // face.getHumanFace().announceEvent(new MeshChangedEvent(face.getHumanFace(), face.getHumanFace().getShortName(), this)); + // } + //} - // translate - point.x += getSecondaryDrawableFace().getTranslation().x; - point.y += getSecondaryDrawableFace().getTranslation().y; - point.z += getSecondaryDrawableFace().getTranslation().z; - - // scale - point.x *= 1 + getSecondaryDrawableFace().getScale().x; - point.y *= 1 + getSecondaryDrawableFace().getScale().y; - point.z *= 1 + getSecondaryDrawableFace().getScale().z; - } - - protected void announceMeshChange(DrawableFace face) { - if (face != null) { - face.getHumanFace().announceEvent(new MeshChangedEvent(face.getHumanFace(), face.getHumanFace().getShortName(), this)); + private void alignSymmetryPlanes() { + if (!getPrimaryDrawableFace().getHumanFace().hasSymmetryPlane() + || !getSecondaryDrawableFace().getHumanFace().hasSymmetryPlane()) { + + JOptionPane.showMessageDialog(controlPanel, + "Compute symmetry planes first", + "No symmerty planes", + JOptionPane.INFORMATION_MESSAGE); + return; } + + HumanFaceUtils.alignSymmetryPlanes( + getPrimaryDrawableFace().getHumanFace(), + getSecondaryDrawableFace().getHumanFace(), // is transformed + false // drops k-d tree, if exists + ); } } diff --git a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form index 146a2f5abf312602f0057d3c65ad94b603a82d75..754e92b26aadcb71ca82f2aaea191c0dc879981c 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form +++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.form @@ -44,15 +44,18 @@ <Group type="102" alignment="0" attributes="0"> <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="1" max="-2" attributes="0"> - <Component id="jPanel2" alignment="0" max="32767" attributes="0"/> + <Component id="jPanel1" alignment="0" max="32767" attributes="0"/> <Component id="jPanel4" alignment="0" max="32767" attributes="0"/> - <Component id="jPanel7" alignment="0" max="32767" attributes="0"/> <Component id="transformationPanel" alignment="0" min="-2" pref="585" max="-2" attributes="0"/> - <Component id="jPanel1" alignment="0" max="32767" attributes="0"/> + <Component id="jPanel7" max="32767" attributes="0"/> </Group> - <EmptySpace min="-2" pref="153" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> <Component id="jSeparator7" min="-2" pref="50" max="-2" attributes="0"/> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jPanel2" min="-2" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> @@ -72,12 +75,12 @@ <EmptySpace max="-2" attributes="0"/> <Component id="jPanel1" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> - <Component id="transformationPanel" min="-2" pref="209" max="-2" attributes="0"/> + <Component id="transformationPanel" min="-2" pref="176" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="jPanel4" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="jPanel2" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="232" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="328" max="-2" attributes="0"/> <Component id="jSeparator11" min="-2" pref="10" max="-2" attributes="0"/> <EmptySpace min="-2" pref="221" max="-2" attributes="0"/> <Component id="jSeparator2" min="-2" pref="10" max="-2" attributes="0"/> @@ -93,7 +96,7 @@ <Properties> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder title="Fine-tuning the mutual position:"> + <TitledBorder title="Manual alignment:"> <ResourceString PropertyName="titleX" bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.transformationPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> <Font PropertyName="font" name="Dialog" size="14" style="1"/> </TitledBorder> @@ -117,36 +120,16 @@ <EmptySpace min="-2" pref="580" max="-2" attributes="0"/> <Component id="shiftPanel" min="-2" max="-2" attributes="0"/> </Group> - <Group type="102" attributes="0"> - <EmptySpace min="-2" pref="349" max="-2" attributes="0"/> - <Component id="jSeparator10" min="-2" pref="15" max="-2" attributes="0"/> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace max="-2" attributes="0"/> + <Component id="jButton3" min="-2" max="-2" attributes="0"/> </Group> <Group type="102" alignment="0" attributes="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <EmptySpace min="-2" pref="24" max="-2" attributes="0"/> - <Component id="shiftLabel" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="lowShiftRB" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="highShiftRB" min="-2" max="-2" attributes="0"/> - </Group> - <Component id="translationPanel" alignment="0" min="-2" pref="227" max="-2" attributes="0"/> - </Group> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="24" max="-2" attributes="0"/> - <Component id="resetAllButton" min="-2" pref="128" max="-2" attributes="0"/> - <EmptySpace type="unrelated" max="-2" attributes="0"/> - <Component id="applyButton" min="-2" pref="128" max="-2" attributes="0"/> - </Group> - <Group type="102" alignment="0" attributes="0"> - <EmptySpace max="-2" attributes="0"/> - <Component id="rotationPanel" min="-2" pref="224" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="scalePanel" min="-2" pref="102" max="-2" attributes="0"/> - </Group> - </Group> + <Component id="translationPanel" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rotationPanel" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="scalePanel" min="-2" max="-2" attributes="0"/> </Group> </Group> <EmptySpace min="0" pref="0" max="32767" attributes="0"/> @@ -157,24 +140,14 @@ <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" attributes="0"> <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> + <Group type="103" groupAlignment="0" max="-2" attributes="0"> <Component id="scalePanel" max="32767" attributes="0"/> - <Component id="rotationPanel" max="32767" attributes="0"/> - <Component id="translationPanel" max="32767" attributes="0"/> + <Component id="rotationPanel" alignment="0" max="32767" attributes="0"/> + <Component id="translationPanel" alignment="0" max="32767" attributes="0"/> </Group> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="applyButton" alignment="0" min="-2" pref="26" max="-2" attributes="0"/> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="shiftLabel" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="lowShiftRB" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="highShiftRB" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="resetAllButton" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - </Group> - <EmptySpace min="-2" pref="39" max="-2" attributes="0"/> - <Component id="jSeparator10" min="-2" pref="62" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="25" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> + <Component id="jButton3" min="-2" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="59" max="-2" attributes="0"/> <Component id="shiftPanel" min="-2" max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/> <Component id="jSeparator5" min="-2" pref="10" max="-2" attributes="0"/> @@ -198,36 +171,21 @@ <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> - <Group type="103" groupAlignment="1" max="-2" attributes="0"> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace min="-2" pref="31" max="-2" attributes="0"/> - <Component id="translXLabel" min="-2" max="-2" attributes="0"/> - </Group> + <EmptySpace max="-2" attributes="0"/> + <Group type="103" groupAlignment="1" attributes="0"> + <Component id="translXLabel" alignment="1" min="-2" max="-2" attributes="0"/> <Group type="102" alignment="1" attributes="0"> - <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> - <Component id="translationButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="32767" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="translationXFTF" alignment="0" min="-2" pref="54" max="-2" attributes="0"/> - <Group type="102" alignment="0" attributes="0"> - <Component id="leftTranslationXButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="rightTranslationXButton" min="-2" max="-2" attributes="0"/> - </Group> - </Group> + <Component id="leftTranslationXButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rightTranslationXButton" min="-2" max="-2" attributes="0"/> </Group> </Group> <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> + <Group type="102" alignment="0" attributes="0"> <EmptySpace min="-2" pref="7" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <Component id="leftTranslationYButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="rightTranslationYButton" min="-2" max="-2" attributes="0"/> - </Group> - <Component id="translationYFTF" min="-2" pref="54" max="-2" attributes="0"/> - </Group> + <Component id="leftTranslationYButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rightTranslationYButton" min="-2" max="-2" attributes="0"/> </Group> <Group type="102" alignment="0" attributes="0"> <EmptySpace min="-2" pref="15" max="-2" attributes="0"/> @@ -238,14 +196,9 @@ <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> <EmptySpace min="-2" pref="1" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <Component id="leftTranslationZButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="rightTranslationZButton" min="-2" max="-2" attributes="0"/> - </Group> - <Component id="translationZFTF" min="-2" pref="54" max="-2" attributes="0"/> - </Group> + <Component id="leftTranslationZButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rightTranslationZButton" min="-2" max="-2" attributes="0"/> <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> </Group> <Component id="translZLabel" alignment="1" min="-2" max="-2" attributes="0"/> @@ -265,75 +218,21 @@ </Group> <EmptySpace min="-2" pref="9" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="0" attributes="0"> - <Group type="103" groupAlignment="1" attributes="0"> - <Component id="rightTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/> - <Component id="leftTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="translationXFTF" max="-2" attributes="0"/> - <Group type="102" alignment="1" attributes="0"> - <Component id="translationButton" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="6" max="-2" attributes="0"/> - </Group> - </Group> - </Group> - <Group type="102" alignment="0" attributes="0"> - <Group type="103" groupAlignment="1" attributes="0"> - <Component id="rightTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/> - <Component id="leftTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="-2" attributes="0"/> - <Component id="translationYFTF" min="-2" max="-2" attributes="0"/> - </Group> - <Group type="102" alignment="0" attributes="0"> - <Group type="103" groupAlignment="1" attributes="0"> - <Group type="102" alignment="1" attributes="0"> - <Component id="rightTranslationZButton" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="6" max="-2" attributes="0"/> - </Group> - <Group type="102" alignment="0" attributes="0"> - <Component id="leftTranslationZButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - </Group> - </Group> - <Component id="translationZFTF" min="-2" max="-2" attributes="0"/> + <Group type="103" alignment="0" groupAlignment="1" attributes="0"> + <Component id="rightTranslationZButton" alignment="1" min="-2" max="-2" attributes="0"/> + <Component id="leftTranslationZButton" alignment="0" min="-2" max="-2" attributes="0"/> </Group> + <Component id="rightTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/> + <Component id="leftTranslationXButton" alignment="0" min="-2" max="-2" attributes="0"/> + <Component id="rightTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/> + <Component id="leftTranslationYButton" alignment="0" min="-2" max="-2" attributes="0"/> </Group> - <EmptySpace min="10" pref="10" max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> </Layout> <SubComponents> - <Component class="javax.swing.JButton" name="translationButton"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/restart-line.png"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.translationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.translationButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder/> - </Border> - </Property> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Default Cursor"/> - </Property> - <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor"> - <Insets value="[2, 2, 2, 2]"/> - </Property> - </Properties> - <Events> - <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="translationButtonMousePressed"/> - </Events> - </Component> <Component class="javax.swing.JButton" name="rightTranslationXButton"> <Properties> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> @@ -368,19 +267,6 @@ <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="rightTranslationXButtonMouseReleased"/> </Events> </Component> - <Component class="javax.swing.JFormattedTextField" name="translationXFTF"> - <Properties> - <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> - <Format subtype="0" type="0"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.translationXFTF.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Text Cursor"/> - </Property> - </Properties> - </Component> <Component class="javax.swing.JButton" name="leftTranslationYButton"> <Properties> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> @@ -409,13 +295,6 @@ <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="leftTranslationYButtonMouseReleased"/> </Events> </Component> - <Component class="javax.swing.JFormattedTextField" name="translationYFTF"> - <Properties> - <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> - <Format subtype="0" type="0"/> - </Property> - </Properties> - </Component> <Component class="javax.swing.JButton" name="rightTranslationYButton"> <Properties> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> @@ -454,13 +333,6 @@ </Property> </Properties> </Component> - <Component class="javax.swing.JFormattedTextField" name="translationZFTF"> - <Properties> - <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> - <Format subtype="0" type="0"/> - </Property> - </Properties> - </Component> <Component class="javax.swing.JLabel" name="translZLabel"> <Properties> <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> @@ -588,36 +460,24 @@ <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> - <Component id="rotationButton" min="-2" max="-2" attributes="0"/> + <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="rotationXFTF" min="-2" pref="54" max="-2" attributes="0"/> - <Group type="102" alignment="0" attributes="0"> - <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/> - </Group> - </Group> + <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/> </Group> <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="55" max="-2" attributes="0"/> + <EmptySpace min="-2" pref="23" max="-2" attributes="0"/> <Component id="rotatXLabel" min="-2" pref="20" max="-2" attributes="0"/> </Group> </Group> <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> + <Group type="102" alignment="0" attributes="0"> <EmptySpace min="-2" pref="6" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/> - </Group> - <Component id="rotationYFTF" min="-2" pref="54" max="-2" attributes="0"/> - </Group> + <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/> </Group> <Group type="102" alignment="0" attributes="0"> <EmptySpace min="-2" pref="29" max="-2" attributes="0"/> @@ -631,14 +491,9 @@ </Group> <Group type="102" alignment="0" attributes="0"> <EmptySpace min="-2" pref="6" max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" max="-2" attributes="0"> - <Component id="rotationZFTF" min="-2" pref="54" max="-2" attributes="0"/> - <Group type="102" attributes="0"> - <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="rightRotationZButton" max="32767" attributes="0"/> - </Group> - </Group> + <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="rightRotationZButton" min="-2" max="-2" attributes="0"/> </Group> </Group> <EmptySpace max="32767" attributes="0"/> @@ -661,31 +516,12 @@ </Group> <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" attributes="0"> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/> - <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/> - <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/> - <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/> - <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/> - </Group> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="rotationXFTF" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="rotationYFTF" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="rotationZFTF" alignment="3" min="-2" max="-2" attributes="0"/> - </Group> - <Group type="102" alignment="1" attributes="0"> - <Component id="rotationButton" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="5" max="-2" attributes="0"/> - </Group> - </Group> - </Group> - <Group type="102" attributes="0"> - <Component id="rightRotationZButton" min="-2" pref="24" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="41" max="-2" attributes="0"/> - </Group> + <Component id="rightRotationZButton" min="-2" pref="24" max="-2" attributes="0"/> + <Component id="leftRotationXButton" min="-2" max="-2" attributes="0"/> + <Component id="rightRotationXButton" min="-2" max="-2" attributes="0"/> + <Component id="leftRotationYButton" min="-2" max="-2" attributes="0"/> + <Component id="rightRotationYButton" min="-2" max="-2" attributes="0"/> + <Component id="leftRotationZButton" min="-2" max="-2" attributes="0"/> </Group> <EmptySpace max="32767" attributes="0"/> </Group> @@ -785,47 +621,6 @@ </Property> </Properties> </Component> - <Component class="javax.swing.JButton" name="rotationButton"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/restart-line.png"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.rotationButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.rotationButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder/> - </Border> - </Property> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Default Cursor"/> - </Property> - <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor"> - <Insets value="[2, 2, 2, 2]"/> - </Property> - </Properties> - <Events> - <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="rotationButtonMousePressed"/> - </Events> - </Component> - <Component class="javax.swing.JFormattedTextField" name="rotationZFTF"> - <Properties> - <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> - <Format subtype="0" type="0"/> - </Property> - </Properties> - </Component> - <Component class="javax.swing.JFormattedTextField" name="rotationYFTF"> - <Properties> - <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> - <Format subtype="0" type="0"/> - </Property> - </Properties> - </Component> <Component class="javax.swing.JButton" name="rightRotationZButton"> <Properties> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> @@ -962,16 +757,6 @@ <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="rightRotationXButtonMouseReleased"/> </Events> </Component> - <Component class="javax.swing.JFormattedTextField" name="rotationXFTF"> - <Properties> - <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> - <Format subtype="0" type="0"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.rotationXFTF.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - </Properties> - </Component> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="scalePanel"> @@ -989,38 +774,23 @@ <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> - <EmptySpace min="-2" pref="32" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> <Component id="scalePlusButton" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="scaleMinusButton" min="-2" max="-2" attributes="0"/> - <EmptySpace min="0" pref="0" max="32767" attributes="0"/> - </Group> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace min="-2" pref="2" max="-2" attributes="0"/> - <Component id="scaleButton" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="7" max="-2" attributes="0"/> - <Component id="scaleFTF" min="-2" pref="54" max="-2" attributes="0"/> - <EmptySpace max="32767" attributes="0"/> + <EmptySpace pref="15" max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> - <Group type="102" alignment="1" attributes="0"> - <EmptySpace max="32767" attributes="0"/> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="26" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> <Component id="scalePlusButton" min="-2" max="-2" attributes="0"/> <Component id="scaleMinusButton" min="-2" max="-2" attributes="0"/> </Group> - <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" attributes="0"> - <Component id="scaleFTF" min="-2" max="-2" attributes="0"/> - <Group type="102" alignment="1" attributes="0"> - <Component id="scaleButton" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="5" max="-2" attributes="0"/> - </Group> - </Group> - <EmptySpace max="-2" attributes="0"/> + <EmptySpace max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> @@ -1060,46 +830,6 @@ <EventHandler event="mouseReleased" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="scalePlusButtonMouseReleased"/> </Events> </Component> - <Component class="javax.swing.JFormattedTextField" name="scaleFTF"> - <Properties> - <Property name="formatterFactory" type="javax.swing.JFormattedTextField$AbstractFormatterFactory" editor="org.netbeans.modules.form.editors.AbstractFormatterFactoryEditor"> - <Format subtype="0" type="0"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.scaleFTF.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="scaleFTFActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JButton" name="scaleButton"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/restart-line.png"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.scaleButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.scaleButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder/> - </Border> - </Property> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Default Cursor"/> - </Property> - <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor"> - <Insets value="[2, 2, 2, 2]"/> - </Property> - </Properties> - <Events> - <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="scaleButtonMousePressed"/> - </Events> - </Component> <Component class="javax.swing.JButton" name="scaleMinusButton"> <Properties> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> @@ -1136,28 +866,6 @@ </Component> </SubComponents> </Container> - <Component class="javax.swing.JButton" name="resetAllButton"> - <Properties> - <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> - <Image iconType="3" name="/refresh-line.png"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.resetAllButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.resetAllButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder/> - </Border> - </Property> - <Property name="focusPainted" type="boolean" value="false"/> - </Properties> - <Events> - <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="resetAllButtonMousePressed"/> - </Events> - </Component> <Container class="javax.swing.JPanel" name="shiftPanel"> <Layout> @@ -1173,79 +881,14 @@ </DimensionLayout> </Layout> </Container> - <Component class="javax.swing.JSeparator" name="jSeparator10"> - <Properties> - <Property name="orientation" type="int" value="1"/> - </Properties> - </Component> - <Component class="javax.swing.JButton" name="applyButton"> - <Properties> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.applyButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.applyButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> - <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> - <TitledBorder/> - </Border> - </Property> - <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor"> - <Color id="Hand Cursor"/> - </Property> - <Property name="focusPainted" type="boolean" value="false"/> - </Properties> - <Events> - <EventHandler event="mousePressed" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="applyButtonMousePressed"/> - </Events> - </Component> <Component class="javax.swing.JSeparator" name="jSeparator5"> </Component> - <Component class="javax.swing.JLabel" name="shiftLabel"> - <Properties> - <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> - <Font name="Ubuntu" size="15" style="1"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.shiftLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.shiftLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - </Properties> - </Component> - <Component class="javax.swing.JRadioButton" name="lowShiftRB"> - <Properties> - <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> - <ComponentRef name="precisionGroup"/> - </Property> - <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.lowShiftRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.lowShiftRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="lowShiftRBActionPerformed"/> - </Events> - </Component> - <Component class="javax.swing.JRadioButton" name="highShiftRB"> + <Component class="javax.swing.JButton" name="jButton3"> <Properties> - <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> - <ComponentRef name="precisionGroup"/> - </Property> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.highShiftRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> - </Property> - <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> - <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.highShiftRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> + <ResourceString bundle="cz/fidentis/analyst/registration/Bundle.properties" key="RegistrationPanel.jButton3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> </Property> </Properties> - <Events> - <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="highShiftRBActionPerformed"/> - </Events> </Component> </SubComponents> </Container> @@ -1271,27 +914,31 @@ <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" attributes="0"> <EmptySpace max="-2" attributes="0"/> - <Group type="103" groupAlignment="0" max="-2" attributes="0"> - <Group type="102" attributes="0"> - <Component id="jLabel8" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jComboBox1" min="-2" pref="166" max="-2" attributes="0"/> - <EmptySpace max="32767" attributes="0"/> - <Component id="jButton1" min="-2" max="-2" attributes="0"/> - </Group> + <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" attributes="0"> - <Component id="jLabel7" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jCheckBox1" min="-2" max="-2" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> - <Component id="jLabel5" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jFormattedTextField1" min="-2" pref="49" max="-2" attributes="0"/> - <EmptySpace type="separate" max="-2" attributes="0"/> - <Component id="jLabel6" min="-2" max="-2" attributes="0"/> - <EmptySpace max="-2" attributes="0"/> - <Component id="jFormattedTextField2" min="-2" pref="53" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" alignment="0" attributes="0"> + <Component id="jLabel7" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="jCheckBox1" min="-2" max="-2" attributes="0"/> + <EmptySpace type="separate" max="-2" attributes="0"/> + <Component id="jLabel5" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="jFormattedTextField1" min="-2" pref="49" max="-2" attributes="0"/> + </Group> + <Component id="comboSliderInteger1" alignment="0" min="-2" max="-2" attributes="0"/> + </Group> + <EmptySpace min="-2" pref="12" max="-2" attributes="0"/> + <Group type="103" groupAlignment="0" attributes="0"> + <Group type="102" attributes="0"> + <Component id="jLabel6" min="-2" max="-2" attributes="0"/> + <EmptySpace max="-2" attributes="0"/> + <Component id="jFormattedTextField2" min="-2" pref="53" max="-2" attributes="0"/> + </Group> + <Component id="jLabel8" min="-2" max="-2" attributes="0"/> + </Group> </Group> + <Component id="jButton1" alignment="0" min="-2" max="-2" attributes="0"/> </Group> <EmptySpace max="32767" attributes="0"/> </Group> @@ -1311,14 +958,18 @@ <Component id="jFormattedTextField2" alignment="3" min="-2" pref="20" max="-2" attributes="0"/> </Group> </Group> - <EmptySpace type="separate" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0"> - <Group type="103" groupAlignment="3" attributes="0"> - <Component id="jLabel8" alignment="3" min="-2" max="-2" attributes="0"/> - <Component id="jComboBox1" alignment="3" min="-2" pref="27" max="-2" attributes="0"/> + <Group type="102" attributes="0"> + <EmptySpace min="-2" pref="5" max="-2" attributes="0"/> + <Component id="comboSliderInteger1" min="-2" max="-2" attributes="0"/> + </Group> + <Group type="102" alignment="0" attributes="0"> + <EmptySpace min="-2" pref="26" max="-2" attributes="0"/> + <Component id="jLabel8" min="-2" max="-2" attributes="0"/> </Group> - <Component id="jButton1" alignment="0" min="-2" max="-2" attributes="0"/> </Group> + <EmptySpace max="-2" attributes="0"/> + <Component id="jButton1" min="-2" max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/> </Group> </Group> @@ -1384,19 +1035,6 @@ </Property> </Properties> </Component> - <Component class="javax.swing.JComboBox" name="jComboBox1"> - <Properties> - <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> - <StringArray count="2"> - <StringItem index="0" value="None"/> - <StringItem index="1" value="Random 200"/> - </StringArray> - </Property> - </Properties> - <AuxValues> - <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/> - </AuxValues> - </Component> <Component class="javax.swing.JButton" name="jButton1"> <Properties> <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> @@ -1413,6 +1051,8 @@ <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/> </Events> </Component> + <Component class="cz.fidentis.analyst.core.ComboSliderInteger" name="comboSliderInteger1"> + </Component> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="jPanel4"> @@ -1563,12 +1203,12 @@ <Group type="103" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0"> <EmptySpace max="-2" attributes="0"/> + <Component id="jButton2" min="-2" max="-2" attributes="0"/> + <EmptySpace type="separate" max="-2" attributes="0"/> <Component id="jLabel4" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="jCheckBox2" min="-2" max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/> - <Component id="jButton2" min="-2" max="-2" attributes="0"/> - <EmptySpace min="-2" pref="190" max="-2" attributes="0"/> </Group> </Group> </DimensionLayout> @@ -1577,9 +1217,11 @@ <Group type="102" alignment="0" attributes="0"> <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="0" max="-2" attributes="0"> - <Component id="jButton2" min="-2" max="-2" attributes="0"/> <Component id="jCheckBox2" alignment="1" max="32767" attributes="0"/> - <Component id="jLabel4" alignment="1" max="32767" attributes="0"/> + <Group type="103" alignment="1" groupAlignment="3" attributes="0"> + <Component id="jLabel4" alignment="3" max="32767" attributes="0"/> + <Component id="jButton2" alignment="3" min="-2" max="-2" attributes="0"/> + </Group> </Group> <EmptySpace max="32767" attributes="0"/> </Group> @@ -1650,7 +1292,7 @@ <Component id="jLabel2" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/> <Component id="jTextField2" min="-2" pref="60" max="-2" attributes="0"/> - <EmptySpace max="32767" attributes="0"/> + <EmptySpace pref="30" max="32767" attributes="0"/> </Group> </Group> </DimensionLayout> diff --git a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java index d2d56b969909d736f3f9d99f7e226d75710dbce8..d3eaa22f72b69ddaeb602a843566a5527c75a4a4 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationPanel.java @@ -2,10 +2,11 @@ package cz.fidentis.analyst.registration; import cz.fidentis.analyst.canvas.Direction; import cz.fidentis.analyst.core.ControlPanel; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.DoubleSummaryStatistics; import javax.swing.ImageIcon; -import javax.swing.JFormattedTextField; +import javax.vecmath.Vector3d; /** * Panel used to interactively visualize two face and adjust their registration. @@ -26,53 +27,44 @@ public class RegistrationPanel extends ControlPanel { */ public static final String ACTION_COMMAND_APPLY_ICP = "apply ICP"; - public static final String ACTION_COMMAND_SHIFT_X = "shift x"; - public static final String ACTION_COMMAND_SHIFT_Y = "shift y"; - public static final String ACTION_COMMAND_SHIFT_Z = "shift z"; - public static final String ACTION_COMMAND_ROTATE_X = "rotate x"; - public static final String ACTION_COMMAND_ROTATE_Y = "rotate y"; - public static final String ACTION_COMMAND_ROTATE_Z = "rotate z"; - public static final String ACTION_COMMAND_SCALE = "scale"; - public static final String ACTION_COMMAND_RESET_ROTATION = "reset translation"; - public static final String ACTION_COMMAND_RESET_TRANSLATION = "reset rotation"; - public static final String ACTION_COMMAND_RESET_SCALE = "reset scale"; - public static final String ACTION_COMMAND_APPLY_TRANSFORMATIONS = "apply transformations"; + public static final String ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED = "manual transformation"; + public static final String ACTION_COMMAND_MANUAL_TRANSFORMATION_IN_PROGRESS = "manual transformation in progress"; public static final String ACTION_COMMAND_FP_CLOSENESS_THRESHOLD = "fp closeness treshold"; public static final String ACTION_COMMAND_ICP_SCALE = "ICP scale"; public static final String ACTION_COMMAND_ICP_MAX_ITERATIONS = "ICP iterations"; public static final String ACTION_COMMAND_ICP_ERROR = "ICP error"; - public static final String ACTION_COMMAND_ICP_UNDERSAMPLING = "ICP undersampling"; public static final String ACTION_COMMAND_PROCRUSTES_APPLY = "Procrustes apply"; public static final String ACTION_COMMAND_PROCRUSTES_SCALE = "Procrustes scale"; + public static final String ACTION_COMMAND_ALIGN_SYMMETRY_PLANES = "align symmetry planes"; + /* * Configuration of panel-specific GUI elements */ public static final String STRATEGY_POINT_TO_POINT = "Point to point"; public static final String STRATEGY_POINT_TO_TRIANGLE = "Point to triangle"; - public static final double TRANSFORMATION_FINESS = 1.0; - /** - * Transformation shift is higher + * Animator which animates transformations */ - public static final double HIGH_SHIFT_QUOTIENT = 1.0; + private final ModelRotationAnimator animator = new ModelRotationAnimator(); - /** - * Transformation shift is lower - */ - public static final double LOW_SHIFT_QUOTIENT = 0.1; + private static final double MOVE_MODIFIER = 0.2; /** - * Animator which animates transformations + * ICP undersampling. 100 = none */ - private final ModelRotationAnimator animator = new ModelRotationAnimator(); + private int undersampling = 100; - private double moveModifier = LOW_SHIFT_QUOTIENT; + private Vector3d manualRotation = new Vector3d(); + private Vector3d manualTranslation = new Vector3d(); + private double manualScale = 1.0; + private final ActionListener action; + /** * Constructor. * @param action Action listener @@ -80,36 +72,67 @@ public class RegistrationPanel extends ControlPanel { public RegistrationPanel(ActionListener action) { this.setName(NAME); initComponents(); - setDefaults(); + this.action = action; // connect GUI element with RegistrationAction listener: jButton1.addActionListener(createListener(action, ACTION_COMMAND_APPLY_ICP)); - translationXFTF.addActionListener(createListener(action, ACTION_COMMAND_SHIFT_X)); - translationYFTF.addActionListener(createListener(action, ACTION_COMMAND_SHIFT_Y)); - translationZFTF.addActionListener(createListener(action, ACTION_COMMAND_SHIFT_Z)); - rotationXFTF.addActionListener(createListener(action, ACTION_COMMAND_ROTATE_X)); - rotationYFTF.addActionListener(createListener(action, ACTION_COMMAND_ROTATE_Y)); - rotationZFTF.addActionListener(createListener(action, ACTION_COMMAND_ROTATE_Z)); - scaleFTF.addActionListener(createListener(action, ACTION_COMMAND_SCALE)); - translationButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_TRANSLATION)); - rotationButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_ROTATION)); - scaleButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_SCALE)); - jButton2.addActionListener(createListener(action, ACTION_COMMAND_PROCRUSTES_APPLY)); - scaleFTF.addActionListener(createListener(action, ACTION_COMMAND_PROCRUSTES_SCALE)); - - resetAllButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_TRANSLATION)); - resetAllButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_SCALE)); - resetAllButton.addActionListener(createListener(action, ACTION_COMMAND_RESET_ROTATION)); + jButton3.addActionListener(createListener(action, ACTION_COMMAND_ALIGN_SYMMETRY_PLANES)); - applyButton.addActionListener(createListener(action, ACTION_COMMAND_APPLY_TRANSFORMATIONS)); + thersholdFTF.setValue(5.0); thersholdFTF.addActionListener(createListener(action, ACTION_COMMAND_FP_CLOSENESS_THRESHOLD)); + jCheckBox1.addActionListener(createListener(action, ACTION_COMMAND_ICP_SCALE)); jFormattedTextField1.addActionListener(createListener(action, ACTION_COMMAND_ICP_ERROR)); jFormattedTextField2.addActionListener(createListener(action, ACTION_COMMAND_ICP_MAX_ITERATIONS)); - jComboBox1.addActionListener(createListener(action, ACTION_COMMAND_ICP_UNDERSAMPLING)); + + //comboSliderInteger1.setSliderEast(); + comboSliderInteger1.setRange(10, 100); + comboSliderInteger1.setValue(this.undersampling); + comboSliderInteger1.addInputFieldListener((ActionEvent ae) -> { // update slider when the input field changed + this.undersampling = comboSliderInteger1.getValue(); + }); + } + + /** + * Returns the manual rotation info and resents it + * @return rotation info + */ + public Vector3d getAndClearManualRotation() { + Vector3d ret = this.manualRotation; + this.manualRotation = new Vector3d(0, 0, 0); + return ret; + } + + /** + * Returns the manual translation info and resents it + * @return translation info + */ + public Vector3d getAndClearManualTranslation() { + Vector3d ret = this.manualTranslation; + this.manualTranslation = new Vector3d(0, 0, 0); + return ret; } + /** + * Returns the manual scale info and resents it + * @return scale info + */ + public double getAndClearManualScale() { + double ret = this.manualScale; + this.manualScale = 1.0; + return ret; + } + + /** + * Returns ICP undersampling parameter + * @return ICP undersampling parameter + */ + public int getIcpUndersampling() { + return undersampling; + } + + /** * Updates GUI elements that display statistical data about the calculated Hausdorff distance. * @@ -131,50 +154,56 @@ public class RegistrationPanel extends ControlPanel { public void transform(Direction dir) { switch (dir) { case TRANSLATE_LEFT: - decreaseInputField(translationXFTF); + this.manualTranslation.x -= this.MOVE_MODIFIER; break; case TRANSLATE_RIGHT: - increaseInputField(translationXFTF); + this.manualTranslation.x += this.MOVE_MODIFIER; break; case TRANSLATE_UP: - decreaseInputField(translationYFTF); + this.manualTranslation.y -= this.MOVE_MODIFIER; break; case TRANSLATE_DOWN: - increaseInputField(translationYFTF); + this.manualTranslation.y += this.MOVE_MODIFIER; break; case TRANSLATE_IN: - decreaseInputField(translationZFTF); + this.manualTranslation.z -= this.MOVE_MODIFIER; break; case TRANSLATE_OUT: - increaseInputField(translationZFTF); + this.manualTranslation.z += this.MOVE_MODIFIER; break; case ROTATE_LEFT: - decreaseInputField(rotationXFTF); + this.manualRotation.x -= this.MOVE_MODIFIER / 180.0; break; case ROTATE_RIGHT: - increaseInputField(rotationXFTF); + this.manualRotation.x += this.MOVE_MODIFIER / 180.0; break; case ROTATE_UP: - increaseInputField(rotationYFTF); + this.manualRotation.y -= this.MOVE_MODIFIER / 180.0; break; case ROTATE_DOWN: - decreaseInputField(rotationYFTF); + this.manualRotation.y += this.MOVE_MODIFIER / 180.0; break; case ROTATE_IN: - increaseInputField(rotationZFTF); + this.manualRotation.z += this.MOVE_MODIFIER / 180.0; break; case ROTATE_OUT: - decreaseInputField(rotationZFTF); + this.manualRotation.z -= this.MOVE_MODIFIER / 180.0; break; case ZOOM_OUT: - decreaseInputField(scaleFTF); + this.manualScale /= 1.005; break; case ZOOM_IN: - increaseInputField(scaleFTF); + this.manualScale *= 1.005; break; default: throw new UnsupportedOperationException(); } + + action.actionPerformed(new ActionEvent( + this, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_IN_PROGRESS) + ); } @Override @@ -191,37 +220,6 @@ public class RegistrationPanel extends ControlPanel { return new ImageIcon(RegistrationPanel.class.getClassLoader().getResource("/" + ICON)); } - /** - * Additional initialization of panel - */ - private void setDefaults() { - lowShiftRB.setSelected(true); - thersholdFTF.setValue(5.0); - //resetAllButtonActionPerformed(null); - - rotationXFTF.setValue(0.0); - rotationYFTF.setValue(0.0); - rotationZFTF.setValue(0.0); - translationXFTF.setValue(0.0); - translationYFTF.setValue(0.0); - translationZFTF.setValue(0.0); - scaleFTF.setValue(0.0); - } - - private void increaseInputField(JFormattedTextField textField) { - double newValue = ((Number)textField.getValue()).doubleValue() + moveModifier; - newValue *= TRANSFORMATION_FINESS; - textField.setValue(newValue); - textField.postActionEvent(); - } - - private void decreaseInputField(JFormattedTextField textField) { - double newValue = ((Number)textField.getValue()).doubleValue() - moveModifier; - newValue *= TRANSFORMATION_FINESS; - textField.setValue(newValue); - textField.postActionEvent(); - } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -237,14 +235,10 @@ public class RegistrationPanel extends ControlPanel { jSeparator11 = new javax.swing.JSeparator(); transformationPanel = new javax.swing.JPanel(); translationPanel = new javax.swing.JPanel(); - translationButton = new javax.swing.JButton(); rightTranslationXButton = new javax.swing.JButton(); - translationXFTF = new javax.swing.JFormattedTextField(); leftTranslationYButton = new javax.swing.JButton(); - translationYFTF = new javax.swing.JFormattedTextField(); rightTranslationYButton = new javax.swing.JButton(); translXLabel = new javax.swing.JLabel(); - translationZFTF = new javax.swing.JFormattedTextField(); translZLabel = new javax.swing.JLabel(); translYLabel = new javax.swing.JLabel(); rightTranslationZButton = new javax.swing.JButton(); @@ -256,27 +250,16 @@ public class RegistrationPanel extends ControlPanel { rotatZLabel = new javax.swing.JLabel(); rotatYLabel = new javax.swing.JLabel(); rotatXLabel = new javax.swing.JLabel(); - rotationButton = new javax.swing.JButton(); - rotationZFTF = new javax.swing.JFormattedTextField(); - rotationYFTF = new javax.swing.JFormattedTextField(); rightRotationZButton = new javax.swing.JButton(); rightRotationYButton = new javax.swing.JButton(); leftRotationZButton = new javax.swing.JButton(); rightRotationXButton = new javax.swing.JButton(); - rotationXFTF = new javax.swing.JFormattedTextField(); scalePanel = new javax.swing.JPanel(); scalePlusButton = new javax.swing.JButton(); - scaleFTF = new javax.swing.JFormattedTextField(); - scaleButton = new javax.swing.JButton(); scaleMinusButton = new javax.swing.JButton(); - resetAllButton = new javax.swing.JButton(); shiftPanel = new javax.swing.JPanel(); - jSeparator10 = new javax.swing.JSeparator(); - applyButton = new javax.swing.JButton(); jSeparator5 = new javax.swing.JSeparator(); - shiftLabel = new javax.swing.JLabel(); - lowShiftRB = new javax.swing.JRadioButton(); - highShiftRB = new javax.swing.JRadioButton(); + jButton3 = new javax.swing.JButton(); jSeparator2 = new javax.swing.JSeparator(); jPanel1 = new javax.swing.JPanel(); jLabel7 = new javax.swing.JLabel(); @@ -286,8 +269,8 @@ public class RegistrationPanel extends ControlPanel { jLabel6 = new javax.swing.JLabel(); jFormattedTextField2 = new javax.swing.JFormattedTextField(); jLabel8 = new javax.swing.JLabel(); - jComboBox1 = new javax.swing.JComboBox<>(); jButton1 = new javax.swing.JButton(); + comboSliderInteger1 = new cz.fidentis.analyst.core.ComboSliderInteger(); jPanel4 = new javax.swing.JPanel(); featurePointsLabel = new javax.swing.JLabel(); thersholdFTF = new javax.swing.JFormattedTextField(); @@ -312,18 +295,6 @@ public class RegistrationPanel extends ControlPanel { translationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationPanel.border.title"))); // NOI18N - translationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/restart-line.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(translationButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationButton.text")); // NOI18N - translationButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationButton.toolTipText")); // NOI18N - translationButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); - translationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - translationButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); - translationButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mousePressed(java.awt.event.MouseEvent evt) { - translationButtonMousePressed(evt); - } - }); - rightTranslationXButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-right-s-line.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(rightTranslationXButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rightTranslationXButton.text")); // NOI18N rightTranslationXButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); @@ -341,10 +312,6 @@ public class RegistrationPanel extends ControlPanel { } }); - translationXFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter())); - translationXFTF.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translationXFTF.toolTipText")); // NOI18N - translationXFTF.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR)); - leftTranslationYButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-left-s-line.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(leftTranslationYButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.leftTranslationYButton.text")); // NOI18N leftTranslationYButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); @@ -360,8 +327,6 @@ public class RegistrationPanel extends ControlPanel { } }); - translationYFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter())); - rightTranslationYButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-right-s-line.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(rightTranslationYButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rightTranslationYButton.text")); // NOI18N rightTranslationYButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); @@ -380,8 +345,6 @@ public class RegistrationPanel extends ControlPanel { translXLabel.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(translXLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translXLabel.text")); // NOI18N - translationZFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter())); - translZLabel.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(translZLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.translZLabel.text")); // NOI18N @@ -440,29 +403,19 @@ public class RegistrationPanel extends ControlPanel { translationPanelLayout.setHorizontalGroup( translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(translationPanelLayout.createSequentialGroup() - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(translationPanelLayout.createSequentialGroup() - .addGap(31, 31, 31) - .addComponent(translXLabel)) + .addContainerGap() + .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(translXLabel) .addGroup(translationPanelLayout.createSequentialGroup() - .addGap(2, 2, 2) - .addComponent(translationButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(translationXFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(translationPanelLayout.createSequentialGroup() - .addComponent(leftTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rightTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addComponent(leftTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rightTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(translationPanelLayout.createSequentialGroup() .addGap(7, 7, 7) - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(translationPanelLayout.createSequentialGroup() - .addComponent(leftTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rightTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(translationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(leftTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rightTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(translationPanelLayout.createSequentialGroup() .addGap(15, 15, 15) .addComponent(translYLabel))) @@ -470,12 +423,9 @@ public class RegistrationPanel extends ControlPanel { .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(translationPanelLayout.createSequentialGroup() .addGap(1, 1, 1) - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(translationPanelLayout.createSequentialGroup() - .addComponent(leftTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(translationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(leftTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(2, 2, 2)) .addComponent(translZLabel, javax.swing.GroupLayout.Alignment.TRAILING)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) @@ -490,32 +440,14 @@ public class RegistrationPanel extends ControlPanel { .addComponent(translZLabel)) .addGap(9, 9, 9) .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(translationPanelLayout.createSequentialGroup() - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(rightTranslationXButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(leftTranslationXButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(translationXFTF, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, translationPanelLayout.createSequentialGroup() - .addComponent(translationButton) - .addGap(6, 6, 6)))) - .addGroup(translationPanelLayout.createSequentialGroup() - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(rightTranslationYButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(leftTranslationYButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(translationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(translationPanelLayout.createSequentialGroup() - .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(translationPanelLayout.createSequentialGroup() - .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(6, 6, 6)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, translationPanelLayout.createSequentialGroup() - .addComponent(leftTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))) - .addComponent(translationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(10, 10, 10)) + .addGroup(translationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(rightTranslationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(leftTranslationZButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(rightTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(leftTranslationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(rightTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(leftTranslationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); rotationPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationPanel.border.title"))); // NOI18N @@ -561,22 +493,6 @@ public class RegistrationPanel extends ControlPanel { rotatXLabel.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(rotatXLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotatXLabel.text")); // NOI18N - rotationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/restart-line.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rotationButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationButton.text")); // NOI18N - rotationButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationButton.toolTipText")); // NOI18N - rotationButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); - rotationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - rotationButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); - rotationButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mousePressed(java.awt.event.MouseEvent evt) { - rotationButtonMousePressed(evt); - } - }); - - rotationZFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter())); - - rotationYFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter())); - rightRotationZButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/arrow-right-s-line.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(rightRotationZButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rightRotationZButton.text")); // NOI18N rightRotationZButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); @@ -645,37 +561,26 @@ public class RegistrationPanel extends ControlPanel { } }); - rotationXFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter())); - rotationXFTF.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.rotationXFTF.toolTipText")); // NOI18N - javax.swing.GroupLayout rotationPanelLayout = new javax.swing.GroupLayout(rotationPanel); rotationPanel.setLayout(rotationPanelLayout); rotationPanelLayout.setHorizontalGroup( rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(rotationPanelLayout.createSequentialGroup() - .addGap(2, 2, 2) + .addContainerGap() .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(rotationPanelLayout.createSequentialGroup() - .addComponent(rotationButton) + .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(rotationXFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(rotationPanelLayout.createSequentialGroup() - .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(rotationPanelLayout.createSequentialGroup() - .addGap(55, 55, 55) + .addGap(23, 23, 23) .addComponent(rotatXLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(rotationPanelLayout.createSequentialGroup() .addGap(6, 6, 6) - .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(rotationPanelLayout.createSequentialGroup() - .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(rotationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(rotationPanelLayout.createSequentialGroup() .addGap(29, 29, 29) .addComponent(rotatYLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE))) @@ -685,12 +590,9 @@ public class RegistrationPanel extends ControlPanel { .addComponent(rotatZLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(rotationPanelLayout.createSequentialGroup() .addGap(6, 6, 6) - .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(rotationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(rotationPanelLayout.createSequentialGroup() - .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rightRotationZButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) + .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rightRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); rotationPanelLayout.setVerticalGroup( @@ -706,25 +608,12 @@ public class RegistrationPanel extends ControlPanel { .addComponent(rotatYLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(rotationPanelLayout.createSequentialGroup() - .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(rotationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(rotationXFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(rotationYFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(rotationZFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rotationPanelLayout.createSequentialGroup() - .addComponent(rotationButton) - .addGap(5, 5, 5)))) - .addGroup(rotationPanelLayout.createSequentialGroup() - .addComponent(rightRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(41, 41, 41))) + .addComponent(rightRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(leftRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(rightRotationXButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(leftRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(rightRotationYButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(leftRotationZButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -747,26 +636,6 @@ public class RegistrationPanel extends ControlPanel { } }); - scaleFTF.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter())); - scaleFTF.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleFTF.toolTipText")); // NOI18N - scaleFTF.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - scaleFTFActionPerformed(evt); - } - }); - - scaleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/restart-line.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(scaleButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleButton.text")); // NOI18N - scaleButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleButton.toolTipText")); // NOI18N - scaleButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); - scaleButton.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - scaleButton.setMargin(new java.awt.Insets(2, 2, 2, 2)); - scaleButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mousePressed(java.awt.event.MouseEvent evt) { - scaleButtonMousePressed(evt); - } - }); - scaleMinusButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/subtract-line.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(scaleMinusButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.scaleMinusButton.text")); // NOI18N scaleMinusButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); @@ -789,45 +658,22 @@ public class RegistrationPanel extends ControlPanel { scalePanelLayout.setHorizontalGroup( scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(scalePanelLayout.createSequentialGroup() - .addGap(32, 32, 32) + .addContainerGap() .addComponent(scalePlusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(scaleMinusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, scalePanelLayout.createSequentialGroup() - .addGap(2, 2, 2) - .addComponent(scaleButton) - .addGap(7, 7, 7) - .addComponent(scaleFTF, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(15, Short.MAX_VALUE)) ); scalePanelLayout.setVerticalGroup( scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, scalePanelLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(scalePanelLayout.createSequentialGroup() + .addGap(26, 26, 26) .addGroup(scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(scalePlusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(scaleMinusButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(scalePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scaleFTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, scalePanelLayout.createSequentialGroup() - .addComponent(scaleButton) - .addGap(5, 5, 5))) - .addContainerGap()) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); - resetAllButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/refresh-line.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(resetAllButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.resetAllButton.text")); // NOI18N - resetAllButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.resetAllButton.toolTipText")); // NOI18N - resetAllButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); - resetAllButton.setFocusPainted(false); - resetAllButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mousePressed(java.awt.event.MouseEvent evt) { - resetAllButtonMousePressed(evt); - } - }); - javax.swing.GroupLayout shiftPanelLayout = new javax.swing.GroupLayout(shiftPanel); shiftPanel.setLayout(shiftPanelLayout); shiftPanelLayout.setHorizontalGroup( @@ -839,40 +685,7 @@ public class RegistrationPanel extends ControlPanel { .addGap(0, 84, Short.MAX_VALUE) ); - jSeparator10.setOrientation(javax.swing.SwingConstants.VERTICAL); - - org.openide.awt.Mnemonics.setLocalizedText(applyButton, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.applyButton.text")); // NOI18N - applyButton.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.applyButton.toolTipText")); // NOI18N - applyButton.setBorder(javax.swing.BorderFactory.createTitledBorder("")); - applyButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); - applyButton.setFocusPainted(false); - applyButton.addMouseListener(new java.awt.event.MouseAdapter() { - public void mousePressed(java.awt.event.MouseEvent evt) { - applyButtonMousePressed(evt); - } - }); - - shiftLabel.setFont(new java.awt.Font("Ubuntu", 1, 15)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(shiftLabel, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.shiftLabel.text")); // NOI18N - shiftLabel.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.shiftLabel.toolTipText")); // NOI18N - - precisionGroup.add(lowShiftRB); - org.openide.awt.Mnemonics.setLocalizedText(lowShiftRB, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.lowShiftRB.text")); // NOI18N - lowShiftRB.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.lowShiftRB.toolTipText")); // NOI18N - lowShiftRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - lowShiftRBActionPerformed(evt); - } - }); - - precisionGroup.add(highShiftRB); - org.openide.awt.Mnemonics.setLocalizedText(highShiftRB, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.highShiftRB.text")); // NOI18N - highShiftRB.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.highShiftRB.toolTipText")); // NOI18N - highShiftRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - highShiftRBActionPerformed(evt); - } - }); + org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jButton3.text")); // NOI18N javax.swing.GroupLayout transformationPanelLayout = new javax.swing.GroupLayout(transformationPanel); transformationPanel.setLayout(transformationPanelLayout); @@ -887,50 +700,27 @@ public class RegistrationPanel extends ControlPanel { .addGap(580, 580, 580) .addComponent(shiftPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(transformationPanelLayout.createSequentialGroup() - .addGap(349, 349, 349) - .addComponent(jSeparator10, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap() + .addComponent(jButton3)) .addGroup(transformationPanelLayout.createSequentialGroup() - .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(transformationPanelLayout.createSequentialGroup() - .addGap(24, 24, 24) - .addComponent(shiftLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lowShiftRB) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(highShiftRB)) - .addComponent(translationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 227, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(transformationPanelLayout.createSequentialGroup() - .addGap(24, 24, 24) - .addComponent(resetAllButton, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(applyButton, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(transformationPanelLayout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rotationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scalePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addComponent(translationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(rotationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(scalePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGap(0, 0, Short.MAX_VALUE)) ); transformationPanelLayout.setVerticalGroup( transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(transformationPanelLayout.createSequentialGroup() .addContainerGap() - .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addComponent(scalePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(rotationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(translationPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(applyButton, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(transformationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(shiftLabel) - .addComponent(lowShiftRB) - .addComponent(highShiftRB) - .addComponent(resetAllButton))) - .addGap(39, 39, 39) - .addComponent(jSeparator10, javax.swing.GroupLayout.PREFERRED_SIZE, 62, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(25, 25, 25) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jButton3) + .addGap(59, 59, 59) .addComponent(shiftPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jSeparator5, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -961,8 +751,6 @@ public class RegistrationPanel extends ControlPanel { org.openide.awt.Mnemonics.setLocalizedText(jLabel8, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jLabel8.text")); // NOI18N - jComboBox1.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "None", "Random 200" })); - jButton1.setFont(new java.awt.Font("Ubuntu", 1, 15)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jButton1.text")); // NOI18N jButton1.setToolTipText(org.openide.util.NbBundle.getMessage(RegistrationPanel.class, "RegistrationPanel.jButton1.toolTipText")); // NOI18N @@ -978,25 +766,26 @@ public class RegistrationPanel extends ControlPanel { jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(jLabel8) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 166, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jButton1)) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(jLabel7) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jCheckBox1) - .addGap(18, 18, 18) - .addComponent(jLabel5) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jFormattedTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(jLabel6) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jFormattedTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel7) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jCheckBox1) + .addGap(18, 18, 18) + .addComponent(jLabel5) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jFormattedTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(comboSliderInteger1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(12, 12, 12) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel6) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jFormattedTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jLabel8))) + .addComponent(jButton1)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); jPanel1Layout.setVerticalGroup( @@ -1011,12 +800,15 @@ public class RegistrationPanel extends ControlPanel { .addComponent(jFormattedTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jLabel6) .addComponent(jFormattedTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(18, 18, 18) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel8) - .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(jButton1)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(5, 5, 5) + .addComponent(comboSliderInteger1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(26, 26, 26) + .addComponent(jLabel8))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButton1) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -1111,21 +903,22 @@ public class RegistrationPanel extends ControlPanel { jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel7Layout.createSequentialGroup() .addContainerGap() + .addComponent(jButton2) + .addGap(18, 18, 18) .addComponent(jLabel4) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jCheckBox2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jButton2) - .addGap(190, 190, 190)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); jPanel7Layout.setVerticalGroup( jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel7Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jButton2) .addComponent(jCheckBox2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jButton2))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); @@ -1154,7 +947,7 @@ public class RegistrationPanel extends ControlPanel { .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(30, Short.MAX_VALUE)) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1183,14 +976,16 @@ public class RegistrationPanel extends ControlPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jPanel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel7, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(transformationPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 585, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(153, 153, 153) - .addComponent(jSeparator7, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(jPanel7, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator7, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -1205,12 +1000,12 @@ public class RegistrationPanel extends ControlPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(transformationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 209, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(transformationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(232, 232, 232) + .addGap(328, 328, 328) .addComponent(jSeparator11, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(221, 221, 221) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) @@ -1220,7 +1015,6 @@ public class RegistrationPanel extends ControlPanel { private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - resetAllButtonMousePressed(null); }//GEN-LAST:event_jButton1ActionPerformed private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBox1ActionPerformed @@ -1239,38 +1033,26 @@ public class RegistrationPanel extends ControlPanel { thersholdFTF.postActionEvent(); }//GEN-LAST:event_thersholdUpButtonActionPerformed - private void highShiftRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_highShiftRBActionPerformed - this.moveModifier = HIGH_SHIFT_QUOTIENT; - }//GEN-LAST:event_highShiftRBActionPerformed - - private void lowShiftRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_lowShiftRBActionPerformed - this.moveModifier = LOW_SHIFT_QUOTIENT; - }//GEN-LAST:event_lowShiftRBActionPerformed - - private void applyButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_applyButtonMousePressed - resetAllButtonMousePressed(evt); - }//GEN-LAST:event_applyButtonMousePressed - - private void resetAllButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetAllButtonMousePressed - translationButtonMousePressed(evt); - rotationButtonMousePressed(evt); - scaleButtonMousePressed(evt); - }//GEN-LAST:event_resetAllButtonMousePressed - private void scaleMinusButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scaleMinusButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_scaleMinusButtonMouseReleased private void scaleMinusButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scaleMinusButtonMousePressed animator.startModelAnimation(Direction.ZOOM_OUT, this); }//GEN-LAST:event_scaleMinusButtonMousePressed - private void scaleButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scaleButtonMousePressed - scaleFTF.setValue(0.0); - }//GEN-LAST:event_scaleButtonMousePressed - private void scalePlusButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scalePlusButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_scalePlusButtonMouseReleased private void scalePlusButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_scalePlusButtonMousePressed @@ -1279,6 +1061,11 @@ public class RegistrationPanel extends ControlPanel { private void rightRotationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationXButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_rightRotationXButtonMouseReleased private void rightRotationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationXButtonMousePressed @@ -1287,6 +1074,11 @@ public class RegistrationPanel extends ControlPanel { private void leftRotationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationZButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_leftRotationZButtonMouseReleased private void leftRotationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationZButtonMousePressed @@ -1295,6 +1087,11 @@ public class RegistrationPanel extends ControlPanel { private void rightRotationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationYButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_rightRotationYButtonMouseReleased private void rightRotationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationYButtonMousePressed @@ -1303,20 +1100,24 @@ public class RegistrationPanel extends ControlPanel { private void rightRotationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationZButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_rightRotationZButtonMouseReleased private void rightRotationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightRotationZButtonMousePressed animator.startModelAnimation(Direction.ROTATE_OUT, this); }//GEN-LAST:event_rightRotationZButtonMousePressed - private void rotationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rotationButtonMousePressed - rotationXFTF.setValue(0.0); - rotationYFTF.setValue(0.0); - rotationZFTF.setValue(0.0); - }//GEN-LAST:event_rotationButtonMousePressed - private void leftRotationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationXButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_leftRotationXButtonMouseReleased private void leftRotationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationXButtonMousePressed @@ -1325,6 +1126,11 @@ public class RegistrationPanel extends ControlPanel { private void leftRotationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationYButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_leftRotationYButtonMouseReleased private void leftRotationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftRotationYButtonMousePressed @@ -1333,6 +1139,11 @@ public class RegistrationPanel extends ControlPanel { private void leftTranslationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationZButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_leftTranslationZButtonMouseReleased private void leftTranslationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationZButtonMousePressed @@ -1341,6 +1152,11 @@ public class RegistrationPanel extends ControlPanel { private void leftTranslationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationXButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_leftTranslationXButtonMouseReleased private void leftTranslationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationXButtonMousePressed @@ -1349,6 +1165,11 @@ public class RegistrationPanel extends ControlPanel { private void rightTranslationZButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationZButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_rightTranslationZButtonMouseReleased private void rightTranslationZButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationZButtonMousePressed @@ -1357,6 +1178,11 @@ public class RegistrationPanel extends ControlPanel { private void rightTranslationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationYButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_rightTranslationYButtonMouseReleased private void rightTranslationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationYButtonMousePressed @@ -1365,6 +1191,11 @@ public class RegistrationPanel extends ControlPanel { private void leftTranslationYButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationYButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_leftTranslationYButtonMouseReleased private void leftTranslationYButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftTranslationYButtonMousePressed @@ -1373,22 +1204,17 @@ public class RegistrationPanel extends ControlPanel { private void rightTranslationXButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationXButtonMouseReleased animator.stopModelAnimation(this); + action.actionPerformed(new ActionEvent( + evt, + ActionEvent.ACTION_PERFORMED, + ACTION_COMMAND_MANUAL_TRANSFORMATION_FINISHED) + ); }//GEN-LAST:event_rightTranslationXButtonMouseReleased private void rightTranslationXButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightTranslationXButtonMousePressed animator.startModelAnimation(Direction.TRANSLATE_RIGHT, this); }//GEN-LAST:event_rightTranslationXButtonMousePressed - private void translationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_translationButtonMousePressed - translationXFTF.setValue(0.0); - translationYFTF.setValue(0.0); - translationZFTF.setValue(0.0); - }//GEN-LAST:event_translationButtonMousePressed - - private void scaleFTFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleFTFActionPerformed - // TODO add your handling code here: - }//GEN-LAST:event_scaleFTFActionPerformed - private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed // TODO add your handling code here: }//GEN-LAST:event_jButton2ActionPerformed @@ -1399,14 +1225,13 @@ public class RegistrationPanel extends ControlPanel { // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton applyButton; + private cz.fidentis.analyst.core.ComboSliderInteger comboSliderInteger1; private javax.swing.JLabel featurePointsLabel; - private javax.swing.JRadioButton highShiftRB; private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; + private javax.swing.JButton jButton3; private javax.swing.JCheckBox jCheckBox1; private javax.swing.JCheckBox jCheckBox2; - private javax.swing.JComboBox<String> jComboBox1; private javax.swing.JFormattedTextField jFormattedTextField1; private javax.swing.JFormattedTextField jFormattedTextField2; private javax.swing.JLabel jLabel1; @@ -1420,7 +1245,6 @@ public class RegistrationPanel extends ControlPanel { private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel4; private javax.swing.JPanel jPanel7; - private javax.swing.JSeparator jSeparator10; private javax.swing.JSeparator jSeparator11; private javax.swing.JSeparator jSeparator2; private javax.swing.JSeparator jSeparator5; @@ -1433,10 +1257,8 @@ public class RegistrationPanel extends ControlPanel { private javax.swing.JButton leftTranslationXButton; private javax.swing.JButton leftTranslationYButton; private javax.swing.JButton leftTranslationZButton; - private javax.swing.JRadioButton lowShiftRB; private javax.swing.ButtonGroup precisionGroup; private javax.swing.ButtonGroup primaryRenderModeGroup; - private javax.swing.JButton resetAllButton; private javax.swing.JButton rightRotationXButton; private javax.swing.JButton rightRotationYButton; private javax.swing.JButton rightRotationZButton; @@ -1446,18 +1268,11 @@ public class RegistrationPanel extends ControlPanel { private javax.swing.JLabel rotatXLabel; private javax.swing.JLabel rotatYLabel; private javax.swing.JLabel rotatZLabel; - private javax.swing.JButton rotationButton; private javax.swing.JPanel rotationPanel; - private javax.swing.JFormattedTextField rotationXFTF; - private javax.swing.JFormattedTextField rotationYFTF; - private javax.swing.JFormattedTextField rotationZFTF; - private javax.swing.JButton scaleButton; - private javax.swing.JFormattedTextField scaleFTF; private javax.swing.JButton scaleMinusButton; private javax.swing.JPanel scalePanel; private javax.swing.JButton scalePlusButton; private javax.swing.ButtonGroup secondaryRenerModeGroup; - private javax.swing.JLabel shiftLabel; private javax.swing.JPanel shiftPanel; private javax.swing.JFormattedTextField thersholdFTF; private javax.swing.JButton thersholdUpButton; @@ -1466,10 +1281,6 @@ public class RegistrationPanel extends ControlPanel { private javax.swing.JLabel translXLabel; private javax.swing.JLabel translYLabel; private javax.swing.JLabel translZLabel; - private javax.swing.JButton translationButton; private javax.swing.JPanel translationPanel; - private javax.swing.JFormattedTextField translationXFTF; - private javax.swing.JFormattedTextField translationYFTF; - private javax.swing.JFormattedTextField translationZFTF; // End of variables declaration//GEN-END:variables } diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java b/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java index 90193a7ffd5f204fc8d4bdf1cd45c2d1f64897fc..3b60dee7000f46b2a9f5ffadbe1070d89c01979c 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Drawable.java @@ -4,7 +4,6 @@ import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2; import java.awt.Color; import java.util.Comparator; -import javax.vecmath.Vector3d; /** * A drawable object, i.e., an object with drawing state and capable to @@ -22,12 +21,6 @@ public abstract class Drawable { private float transparency = 1; // 0 = off, 1 = max private Color highlights = new Color(0, 0, 0, 1); - /* transformation */ - private Vector3d translation = new Vector3d(0, 0, 0); - private Vector3d rotation = new Vector3d(0, 0, 0); - private Vector3d scale = new Vector3d(0, 0, 0); - - /* rendering mode */ /** * Render mode to use, one from {@code GL_FILL}, {@code GL_LINE}, {@code GL_POINT} */ @@ -49,9 +42,6 @@ public abstract class Drawable { this.color = drawable.color; this.highlights = drawable.highlights; this.transparency = drawable.transparency; - this.translation = new Vector3d(drawable.translation); - this.rotation = new Vector3d(drawable.rotation); - this.scale = new Vector3d(drawable.scale); } /** @@ -78,22 +68,7 @@ public abstract class Drawable { */ public void render(GL2 gl) { initRendering(gl); - - gl.glPushMatrix(); - - // rotate - gl.glRotated(getRotation().x, 1, 0, 0); - gl.glRotated(getRotation().y, 0, 1, 0); - gl.glRotated(getRotation().z, 0, 0, 1); - // move - gl.glTranslated(getTranslation().x, getTranslation().y, getTranslation().z); - // scale - gl.glScaled(1 + getScale().x, 1 + getScale().y, 1 + getScale().z); - renderObject(gl); - - gl.glPopMatrix(); - finishRendering(gl); } @@ -175,51 +150,6 @@ public abstract class Drawable { this.highlights = highlights; } - /** - * @return Current translation - */ - public Vector3d getTranslation() { - return translation; - } - - /** - * Sets tranlation - * @param translation Translation - */ - public void setTranslation(Vector3d translation) { - this.translation = translation; - } - - /** - * @return Current rotation - */ - public Vector3d getRotation() { - return rotation; - } - - /** - * Sets rotation - * @param rotation - */ - public void setRotation(Vector3d rotation) { - this.rotation = rotation; - } - - /** - * @return Current scale - */ - public Vector3d getScale() { - return scale; - } - - /** - * Sets scale - * @param scale Scale - */ - public void setScale(Vector3d scale) { - this.scale = scale; - } - /** * @return Value of {@link #renderMode} */ diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java index c4f334e1ace5c5dab60871f3719bf5019ee983b5..2a8dab3ba0bfa2ded1290a884213ada662dcce99 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java @@ -1,10 +1,8 @@ package cz.fidentis.analyst.scene; -import cz.fidentis.analyst.mesh.core.MeshFacet; -import cz.fidentis.analyst.mesh.core.MeshFacetImpl; +import com.jogamp.opengl.GL2; import cz.fidentis.analyst.symmetry.Plane; -import javax.vecmath.Point3d; -import javax.vecmath.Vector3d; +import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; /** * Drawable plane with the possibility to shift it along the normal and, @@ -16,6 +14,17 @@ import javax.vecmath.Vector3d; public class DrawableCuttingPlane extends DrawablePlane { private double shift = 0.0; + private boolean showMirror = false; + + /** + * Constructor. + * + * @param plane plane + * @param bbox bounding box used to estimate cutting pale shape (rectangle) + */ + public DrawableCuttingPlane(Plane plane, BBox bbox) { + super(plane, bbox); + } /** * Copy constructor. @@ -28,58 +37,26 @@ public class DrawableCuttingPlane extends DrawablePlane { } /** - * Constructor. - * @param facet Mesh facet of the plane - * @param plane The plane - */ - public DrawableCuttingPlane(MeshFacet facet, Plane plane) { - super(facet, plane); - } - - /** - * Constructor. - * - * @param plane The plane - * @param midPoint A 3D point, which is projected to the plane and used as a center of the rectangular facet - * @param width Width - * @param height Height - * @throws NullPointerException if the {@code plane} or {@code midPoint} are {@code null} - * @throws IllegalArgumentException if {@code width} or {@code height} are <= 0 - */ - public DrawableCuttingPlane(Plane plane, Point3d midPoint, double width, double height) { - super(plane, midPoint, width, height); - } - - /** - * Moves the plane in the plane's normal direction. + * Moves the plane in the plane's normal direction relatively to the original position. * * @param dist Distance. If positive, then the movements is in the direction of the normal vector. * Otherwise, the movement is against the normal direction. */ public void shift(double dist) { - shift += dist; - - Vector3d move = getPlane().getNormal(); - move.scale(dist); - for (int i = 0; i < getFacets().get(0).getNumberOfVertices(); ++i) { - getFacets().get(0).getVertex(i).getPosition().sub(move); - } - - if (isMirrorPlaneShown()) { - move.scale(-1.0); - for (int i = 0; i < getFacets().get(1).getNumberOfVertices(); ++i) { - getFacets().get(1).getVertex(i).getPosition().sub(move); - } - } + this.shift = dist; } - /** - * Returns shifted cutting plane. - * @return shifted cutting plane. - */ @Override public Plane getPlane() { - return new Plane(super.getPlane().getNormal(), super.getPlane().getDistance() + shift); + return super.getPlane().shift(this.shift); + } + + /** + * Returns original non-shifted plane + * @return original non-shifted plane + */ + public Plane getNonShiftedPlane() { + return super.getPlane(); } /** @@ -87,7 +64,7 @@ public class DrawableCuttingPlane extends DrawablePlane { * @return the cutting plane shifted to opposite direction */ public Plane getMirrorPlane() { - return new Plane(super.getPlane().getNormal(), super.getPlane().getDistance() - shift); + return super.getPlane().shift(-this.shift); } /** @@ -95,20 +72,7 @@ public class DrawableCuttingPlane extends DrawablePlane { * @param show Shows if {@code true}, hides otherwise */ public void showMirrorPlane(boolean show) { - if (show) { - if (isMirrorPlaneShown()) { // already shown - return; - } - MeshFacetImpl mirror = new MeshFacetImpl(getModel().getFacets().get(0)); - Vector3d move = new Vector3d(super.getPlane().getNormal()); - move.scale(-2.0 * shift); - for (int i = 0; i < mirror.getNumberOfVertices(); ++i) { - mirror.getVertex(i).getPosition().sub(move); - } - getModel().addFacet(mirror); - } else if (isMirrorPlaneShown()) { - getModel().removeFacet(1); - } + this.showMirror = show; } /** @@ -116,6 +80,15 @@ public class DrawableCuttingPlane extends DrawablePlane { * @return {@code true} if the mirror planes are set to be shown. */ public boolean isMirrorPlaneShown() { - return getModel().getFacets().size() > 1; + return this.showMirror; + //return getModel().getFacets().size() > 1; + } + + @Override + protected void renderObject(GL2 gl) { + renderObject(gl, getPlane().getMesh(getBBox())); + if (showMirror) { + renderObject(gl, getMirrorPlane().getMesh(getBBox())); + } } } 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 3018786eef6d85c0396ff3282523be0aaa92b11c..d0d7723cc64657637d48656e1569667339b71204 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableFeaturePoints.java @@ -5,7 +5,6 @@ import com.jogamp.opengl.glu.GLU; import com.jogamp.opengl.glu.GLUquadric; import cz.fidentis.analyst.feature.FeaturePoint; import java.awt.Color; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -60,7 +59,8 @@ public class DrawableFeaturePoints extends Drawable { * @param defaultPerimeter Default perimeter */ public DrawableFeaturePoints(List<FeaturePoint> featurePoints, Color defaultColor, double defaultPerimeter) { - this.featurePoints = new ArrayList<>(featurePoints); + //this.featurePoints = new ArrayList<>(featurePoints); + this.featurePoints = featurePoints; this.defaultPerimeter = defaultPerimeter; setColor(defaultColor); } 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 7999836ca817a0e3bd6b3ffab87a770066c3e1e3..0796f9d7a9c207a60f13d0912333fda836bfb9b9 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java @@ -1,20 +1,35 @@ package cz.fidentis.analyst.scene; -import cz.fidentis.analyst.mesh.core.MeshFacet; -import cz.fidentis.analyst.mesh.core.MeshModel; +import com.jogamp.opengl.GL2; +import cz.fidentis.analyst.mesh.core.MeshRectangleFacet; import cz.fidentis.analyst.symmetry.Plane; +import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import javax.vecmath.Point3d; /** * A plane to be shown as a rectangular mesh facet. + * The rectangular shape is generated at run-time from the associated plane. * * @author Radek Oslejsek * @author Dominik Racek */ -public class DrawablePlane extends DrawableMesh { +public class DrawablePlane extends Drawable { - private final Plane plane; + private Plane plane; + private final BBox bbox; + + /** + * Constructor. + * + * @param plane plane + * @param bbox bounding box used to estimate cutting pale shape (rectangle) + */ + public DrawablePlane(Plane plane, BBox bbox) { + this.plane = plane; + this.bbox = bbox; + } + /** * Copy constructor. * @param drPlane Original plane @@ -23,51 +38,35 @@ public class DrawablePlane extends DrawableMesh { public DrawablePlane(DrawablePlane drPlane) { super(drPlane); this.plane = new Plane(drPlane.getPlane()); + this.bbox = drPlane.bbox; } - /** - * Constructor. - * @param model Mesh model of the plane - * @param plane The plane - */ - public DrawablePlane(MeshModel model, Plane plane) { - super(model); - if (plane == null) { - throw new IllegalArgumentException("plane"); - } + public Plane getPlane() { + return plane; + } + + protected void setPlane(Plane plane) { this.plane = plane; } + + @Override + protected void renderObject(GL2 gl) { + renderObject(gl, getPlane().getMesh(bbox)); + } - /** - * Constructor. - * @param facet Mesh facet of the plane - * @param plane The plane - */ - public DrawablePlane(MeshFacet facet, Plane plane) { - super(facet); - if (plane == null) { - throw new IllegalArgumentException("plane"); + protected void renderObject(GL2 gl, MeshRectangleFacet facet) { + gl.glBegin(GL2.GL_TRIANGLES); //vertices are rendered as triangles + // get the normal and tex coords indicies for face i + for (int v = 0; v < facet.getCornerTable().getSize(); v++) { + Point3d vert = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getPosition(); + if (v == 0) { + } + gl.glVertex3d(vert.x, vert.y, vert.z); } - this.plane = new Plane(plane); + gl.glEnd(); } - /** - * Constructor. - * - * @param plane The plane - * @param midPoint A 3D point, which is projected to the plane and used as a center of the rectangular facet - * @param width Width - * @param height Height - * @throws NullPointerException if the {@code plane} or {@code midPoint} are {@code null} - * @throws IllegalArgumentException if {@code width} or {@code height} are <= 0 - */ - public DrawablePlane(Plane plane, Point3d midPoint, double width, double height) { - super(plane.getMesh(midPoint, width, height)); - this.plane = new Plane(plane); + protected BBox getBBox() { + return this.bbox; } - - public Plane getPlane() { - return plane; - } - } diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java index 28613b1aee5c307c07aa179276282bb920897676..22fbdc2fd9c2825cda4dcfc3b4da9ca03e6a4225 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java @@ -3,12 +3,13 @@ package cz.fidentis.analyst.scene; import cz.fidentis.analyst.face.HumanFace; import java.awt.Color; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** * A simple 3D scene. The structure is as follows: * Drawable components of a single human face (mesh, symmetry plane, feature points. etc.) - * are always stored at the same index. One face can be labeled as "primary", one as "secondary". + * are always stored at the same index (slot). One face can be labeled as "primary", one as "secondary". * Other faces have no label. * Then, there is a special list of so-called other drawables. The size of this list can differ. * @@ -170,7 +171,6 @@ public class Scene { } drawableFaces.set(slot, new DrawableFace(face)); - return true; } @@ -184,7 +184,7 @@ public class Scene { public boolean setDrawableFeaturePoints(int slot, HumanFace face) { if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) { return false; - } else if (face == null) { // remove + } else if (face == null || face.getFeaturePoints() == null) { // remove if (slot >= getArraySize()){ return false; } else { @@ -195,13 +195,7 @@ public class Scene { return false; } - drawableFeaturePoints.set( - slot, - (face.getFeaturePoints() != null) - ? new DrawableFeaturePoints(face.getFeaturePoints()) - : null - ); - + drawableFeaturePoints.set(slot, new DrawableFeaturePoints(face.getFeaturePoints())); return true; } @@ -215,7 +209,7 @@ public class Scene { public boolean setDrawableSymmetryPlane(int slot, HumanFace face) { if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) { return false; - } else if (face == null) { // remove + } else if (face == null || face.getSymmetryPlane() == null) { // remove if (slot >= getArraySize()){ return false; } else { @@ -224,14 +218,13 @@ public class Scene { } } else if (!prepareArrays(slot, face)) { return false; - } + } - drawableSymmetryPlanes.set( - slot, - (face.getSymmetryPlane() != null && face.getSymmetryPlaneFacet() != null) - ? new DrawablePlane(face.getSymmetryPlaneFacet(), face.getSymmetryPlane()) - : null - ); + if (drawableSymmetryPlanes.get(slot) == null) { // add new + drawableSymmetryPlanes.set(slot, new DrawablePlane(face.getSymmetryPlane(), face.getBoundingBox())); + } else { // replace existing + drawableSymmetryPlanes.get(slot).setPlane(face.getSymmetryPlane()); + } return true; } @@ -376,6 +369,10 @@ public class Scene { return ret; } + public List<DrawableFace> getDrawableFaces() { + return Collections.unmodifiableList(this.drawableFaces); + } + protected Color getColorOfFeaturePoints(Color origColor) { return new Color( Math.min(255, origColor.getRed() + 40), diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java b/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java index cbd6d37ccad08421b66fc91cb4c024447878ecee..2e45de1efe8ca5b7ec9b1df231b8a7f00465d305 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java +++ b/GUI/src/main/java/cz/fidentis/analyst/scene/SceneRenderer.java @@ -127,6 +127,19 @@ public class SceneRenderer { } } + // draw coordinates: + /* + gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, new float[]{255,255,255,255}, 0); + gl.glBegin(GL2.GL_LINES); //vertices are rendered as triangles + gl.glVertex3d(-30, 0, 0); + gl.glVertex3d(30, 0, 0); + gl.glVertex3d(0, -30, 0); + gl.glVertex3d(0, 30, 0); + gl.glVertex3d(0, 0, -30); + gl.glVertex3d(0, 0, 30); + gl.glEnd(); + */ + gl.glFlush(); //out.printDuration("Scene rendering"); 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 6eab131fb490978fb610ada620284774d10f90d5..50c730c0d054d15f4021583b5dffab7ebf1a8d68 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java +++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java @@ -6,9 +6,7 @@ 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.face.events.SymmetryPlaneChangedEvent; -import cz.fidentis.analyst.mesh.core.MeshFacet; -import cz.fidentis.analyst.mesh.core.MeshFacetImpl; +import cz.fidentis.analyst.face.events.HumanFaceTransformedEvent; import cz.fidentis.analyst.scene.DrawableCuttingPlane; import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox; import cz.fidentis.analyst.visitors.mesh.CrossSectionZigZag; @@ -24,7 +22,6 @@ 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; import javax.vecmath.Vector3d; @@ -52,11 +49,10 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe private CrossSectionCurve primaryMirrorCurve; private CrossSectionCurve secondaryMirrorCurve; - private double lastSliderValue = 0.5; private boolean cuttingPlaneFromSymmetry; - private int priCuttingPlaneIndex = -1; - private int secCuttingPlaneIndex = -1; + private int priCuttingPlaneSlot = -1; + private int secCuttingPlaneSlot = -1; /** * Constructor. @@ -68,9 +64,9 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe super(canvas, topControlPanel); this.topControlPanel = topControlPanel; - computeOrthogonalCuttingPlanes(false); + computeVerticalCuttingPlanes(); // compute default cutting planes - //recomputePrimaryProfile(); + //recomputePrimaryProfile(); if (getSecondaryDrawableFace() != null) { //recomputeSecondaryProfile(); @@ -121,18 +117,17 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe } } break; - case ProfilesPanel.ACTION_OFFSET_CUTTING_PLANE: - double auxVal = ((ComboSliderDouble) ae.getSource()).getValue(); - double value = auxVal - lastSliderValue; - double multiplier = -150; - - setCuttingPlaneOffset(priCuttingPlaneIndex, multiplier * value); - + case ProfilesPanel.ACTION_SHIFT_CUTTING_PLANE: + double sliderVal = ((ComboSliderDouble) ae.getSource()).getValue(); + double xExtent = maxExtentX(); + double shift = (sliderVal >= 0.5) + ? ( (sliderVal - 0.5) / 0.5) * xExtent // move right + : -((0.5 - sliderVal) / 0.5) * xExtent; // move left + getDrawableCuttingPlane(priCuttingPlaneSlot).shift(shift); if (getSecondaryDrawableFace() != null) { - setCuttingPlaneOffset(secCuttingPlaneIndex, multiplier * value); + getDrawableCuttingPlane(secCuttingPlaneSlot).shift(shift); } recomputeProfiles(); - lastSliderValue = auxVal; break; case ProfilesPanel.ACTION_CHANGE_CUTTING_PLANE: String option = (String)((JComboBox) ae.getSource()).getSelectedItem(); @@ -140,9 +135,9 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe if (option.equals(ProfilesPanel.OPTION_SYMMETRY_PLANE)) { if (getScene().getDrawableSymmetryPlane(0) == null) { JOptionPane.showMessageDialog( - new JFrame(), + controlPanel, "Compute a symmetry plane at the Symmetry tab first.", - "Dialog", + "No symmetry plane", JOptionPane.INFORMATION_MESSAGE ); controlPanel.setDefaultPlaneSelection(); @@ -152,7 +147,7 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe computeCuttingPlanesFromSymmetry(); } else if (option.equals(ProfilesPanel.OPTION_VERTICAL_PLANE)) { controlPanel.resetSliderSilently(); - computeOrthogonalCuttingPlanes(false); + computeVerticalCuttingPlanes(); } showCuttingPlanes(true, controlPanel.isMirrorCutsChecked()); @@ -170,10 +165,19 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe @Override public void acceptEvent(HumanFaceEvent event) { - if (event instanceof SymmetryPlaneChangedEvent && cuttingPlaneFromSymmetry) { + // If some human face is transformed, then cutting planes have to updated. + if (event instanceof HumanFaceTransformedEvent) { controlPanel.resetSliderSilently(); - computeCuttingPlanesFromSymmetry(); // recompute cutting planes - //getCanvas().getScene().showCuttingPlanes(false, controlPanel.isMirrorCutsChecked()); + if (cuttingPlaneFromSymmetry) { + computeCuttingPlanesFromSymmetry(); // recompute cutting planes + //getCanvas().getScene().showCuttingPlanes(false, controlPanel.isMirrorCutsChecked()); + } else { + computeVerticalCuttingPlanes(); + } + getDrawableCuttingPlane(priCuttingPlaneSlot).show(false); // will be shown on the panel focus + if (getDrawableCuttingPlane(secCuttingPlaneSlot) != null) { + getDrawableCuttingPlane(secCuttingPlaneSlot).show(false); + } } } @@ -214,27 +218,27 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe System.out.println("ERROR writing to a file: " + ex); } } - + private void recomputePrimaryProfile() { //Main profile - CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneIndex).getPlane()); + CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneSlot).getPlane()); getPrimaryDrawableFace().getModel().compute(cs); this.primaryCurve = cs.getCrossSectionCurve(); //Mirror profile - CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneIndex).getMirrorPlane()); + CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(priCuttingPlaneSlot).getMirrorPlane()); getPrimaryDrawableFace().getModel().compute(mcs); this.primaryMirrorCurve = mcs.getCrossSectionCurve(); } private void recomputeSecondaryProfile() { //Main profile - CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneIndex).getPlane()); + CrossSectionZigZag cs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneSlot).getPlane()); getSecondaryDrawableFace().getModel().compute(cs); this.secondaryCurve = cs.getCrossSectionCurve(); //Mirror profile - CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneIndex).getMirrorPlane()); + CrossSectionZigZag mcs = new CrossSectionZigZag(getDrawableCuttingPlane(secCuttingPlaneSlot).getMirrorPlane()); getSecondaryDrawableFace().getModel().compute(mcs); this.secondaryMirrorCurve = mcs.getCrossSectionCurve(); } @@ -244,11 +248,11 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe projectCloseFeaturePoints( primaryCurve, getCanvas().getPrimaryFace(), - getDrawableCuttingPlane(priCuttingPlaneIndex).getPlane()); + getDrawableCuttingPlane(priCuttingPlaneSlot).getPlane()); projectCloseFeaturePoints( primaryMirrorCurve, getCanvas().getPrimaryFace(), - getDrawableCuttingPlane(priCuttingPlaneIndex).getPlane()); + getDrawableCuttingPlane(priCuttingPlaneSlot).getPlane()); controlPanel.getProfileRenderingPanel().setPrimarySegments(this.primaryCurve); controlPanel.getProfileRenderingPanel().setPrimaryMirrorSegments(this.primaryMirrorCurve); @@ -257,94 +261,73 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe projectCloseFeaturePoints( secondaryCurve, getCanvas().getSecondaryFace(), - getDrawableCuttingPlane(secCuttingPlaneIndex).getPlane()); + getDrawableCuttingPlane(secCuttingPlaneSlot).getPlane()); projectCloseFeaturePoints( secondaryMirrorCurve, getCanvas().getSecondaryFace(), - getDrawableCuttingPlane(secCuttingPlaneIndex).getPlane()); + getDrawableCuttingPlane(secCuttingPlaneSlot).getPlane()); controlPanel.getProfileRenderingPanel().setSecondarySegments(this.secondaryCurve); controlPanel.getProfileRenderingPanel().setSecondaryMirrorSegments(this.secondaryMirrorCurve); } } - private void setCuttingPlaneOffset(int index, double value) { - //Move cutting planes left and mirror planes right - //If normal is negative, need to negate value - if (getDrawableCuttingPlane(index).getPlane().getNormal().x < 0) { - getDrawableCuttingPlane(index).shift(-value); - } else { - getDrawableCuttingPlane(index).shift(value); - } - } - - /** - * Creates vertical or horizontal cutting and mirror planes from bounding box. - * - * @param horizontal - */ - protected void computeOrthogonalCuttingPlanes(boolean horizontal) { - DrawableCuttingPlane drPlane = getDrawableOrthogonalPlane(horizontal); - if (priCuttingPlaneIndex == -1) { - priCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables(); + protected void computeVerticalCuttingPlanes() { + BBox bbox = getCanvas().getPrimaryFace().getBoundingBox(); + Plane plane = new Plane(new Vector3d(1,0,0), bbox.getMidPoint().x); + DrawableCuttingPlane cuttingPlane = new DrawableCuttingPlane(plane, bbox); + cuttingPlane.setTransparency(0.5f); + if (priCuttingPlaneSlot == -1) { + priCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables(); } - getCanvas().getScene().setOtherDrawable(priCuttingPlaneIndex, drPlane); + getCanvas().getScene().setOtherDrawable(priCuttingPlaneSlot, cuttingPlane); if (getSecondaryDrawableFace() != null) { - if (secCuttingPlaneIndex == -1) { - secCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables(); + bbox = getCanvas().getSecondaryFace().getBoundingBox(); + plane = new Plane(new Vector3d(1,0,0), bbox.getMidPoint().x); + cuttingPlane = new DrawableCuttingPlane(plane, bbox); + cuttingPlane.setTransparency(0.5f); + if (secCuttingPlaneSlot == -1) { + secCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables(); } - getCanvas().getScene().setOtherDrawable(secCuttingPlaneIndex, new DrawableCuttingPlane(drPlane)); + getCanvas().getScene().setOtherDrawable(secCuttingPlaneSlot, new DrawableCuttingPlane(cuttingPlane)); } + cuttingPlaneFromSymmetry = false; } - protected DrawableCuttingPlane getDrawableOrthogonalPlane(boolean horizontal) { - BBox bbox = getCanvas().getPrimaryFace().getBoundingBox(); // use BBox of the first face for size and position estimation - Plane plane = new Plane( - (horizontal) ? new Vector3d(0,1,0) : new Vector3d(-1,0,0), - (horizontal) ? bbox.getMidPoint().y : bbox.getMidPoint().x - ); - DrawableCuttingPlane cuttingPlane = new DrawableCuttingPlane( - plane, - bbox.getMidPoint(), - bbox.getDiagonalLength(), - bbox.getDiagonalLength() - ); - cuttingPlane.setTransparency(0.5f); - return cuttingPlane; - } - - /** - * Copy rectangle from the symmetry plane. - * - * @param faceIndex - * @return - */ - protected DrawableCuttingPlane getCuttingPlaneFromSymmetry(int faceIndex) { - MeshFacet symmetryFacet = getCanvas().getHumanFace(faceIndex).getSymmetryPlaneFacet(); - Plane symmetryPlane = getCanvas().getHumanFace(faceIndex).getSymmetryPlane(); - return new DrawableCuttingPlane(new MeshFacetImpl(symmetryFacet), new Plane(symmetryPlane)); - } - /** * Creates cutting and mirror planes by copying the rectangle from the symmetry plane. */ protected void computeCuttingPlanesFromSymmetry() { - DrawableCuttingPlane cuttingPlane = getCuttingPlaneFromSymmetry(getCanvas().getPrimaryFaceIndex()); + Plane symmetryPlane = getCanvas().getPrimaryFace().getSymmetryPlane(); + if (symmetryPlane.getNormal().x < 0) { // orient to the right-hand direction + symmetryPlane = symmetryPlane.flip(); + } + DrawableCuttingPlane cuttingPlane = new DrawableCuttingPlane( + new Plane(symmetryPlane), + getCanvas().getPrimaryFace().getBoundingBox() + ); cuttingPlane.setTransparency(0.5f); - if (priCuttingPlaneIndex == -1) { - priCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables(); + if (priCuttingPlaneSlot == -1) { + priCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables(); } - getCanvas().getScene().setOtherDrawable(priCuttingPlaneIndex, cuttingPlane); + getCanvas().getScene().setOtherDrawable(priCuttingPlaneSlot, cuttingPlane); recomputePrimaryProfile(); - if (getSecondaryDrawableFace() != null) { - cuttingPlane = getCuttingPlaneFromSymmetry(getCanvas().getSecondaryFaceIndex()); + if (getCanvas().getSecondaryFace() != null) { + symmetryPlane = getCanvas().getSecondaryFace().getSymmetryPlane(); + if (symmetryPlane.getNormal().x < 0) { // orient to the right-hand direction + symmetryPlane = symmetryPlane.flip(); + } + cuttingPlane = new DrawableCuttingPlane( + new Plane(symmetryPlane), + getCanvas().getSecondaryFace().getBoundingBox() + ); cuttingPlane.setTransparency(0.5f); - if (secCuttingPlaneIndex == -1) { - secCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables(); + if (secCuttingPlaneSlot == -1) { + secCuttingPlaneSlot = getCanvas().getScene().getFreeSlotForOtherDrawables(); } - getCanvas().getScene().setOtherDrawable(secCuttingPlaneIndex, cuttingPlane); + getCanvas().getScene().setOtherDrawable(secCuttingPlaneSlot, cuttingPlane); recomputeSecondaryProfile(); } cuttingPlaneFromSymmetry = true; @@ -367,13 +350,34 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe } protected void showCuttingPlanes(boolean show, boolean showMirrors) { - if (getDrawableCuttingPlane(priCuttingPlaneIndex) != null) { - getDrawableCuttingPlane(priCuttingPlaneIndex).show(show); - getDrawableCuttingPlane(priCuttingPlaneIndex).showMirrorPlane(showMirrors); + if (getDrawableCuttingPlane(priCuttingPlaneSlot) != null) { + getDrawableCuttingPlane(priCuttingPlaneSlot).show(show); + getDrawableCuttingPlane(priCuttingPlaneSlot).showMirrorPlane(showMirrors); } - if (getDrawableCuttingPlane(secCuttingPlaneIndex) != null) { - getDrawableCuttingPlane(secCuttingPlaneIndex).show(show); - getDrawableCuttingPlane(secCuttingPlaneIndex).showMirrorPlane(showMirrors); + if (getDrawableCuttingPlane(secCuttingPlaneSlot) != null) { + getDrawableCuttingPlane(secCuttingPlaneSlot).show(show); + getDrawableCuttingPlane(secCuttingPlaneSlot).showMirrorPlane(showMirrors); } } + + protected double maxExtentX() { + double max = Double.NEGATIVE_INFINITY; + + double planeX = getDrawableCuttingPlane(priCuttingPlaneSlot).getNonShiftedPlane().getPlanePoint().x; + double bboxX = getCanvas().getPrimaryFace().getBoundingBox().getMaxPoint().x; + max = Math.max(max, Math.abs(bboxX - planeX)); + bboxX = getCanvas().getPrimaryFace().getBoundingBox().getMinPoint().x; + max = Math.max(max, Math.abs(bboxX - planeX)); + + if (getCanvas().getSecondaryFace() != null) { + planeX = getDrawableCuttingPlane(secCuttingPlaneSlot).getNonShiftedPlane().getPlanePoint().x; + bboxX = getCanvas().getSecondaryFace().getBoundingBox().getMaxPoint().x; + max = Math.max(max, Math.abs(bboxX - planeX)); + bboxX = getCanvas().getSecondaryFace().getBoundingBox().getMinPoint().x; + max = Math.max(max, Math.abs(bboxX - planeX)); + } + + return max; + } + } diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form index affc6fe65a3789e7d85801ca7c22cd486426aff0..652258b3a0b315ab88eb05e8c1852e0c7dbcb788 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form +++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.form @@ -20,7 +20,7 @@ <EmptySpace max="-2" attributes="0"/> <Group type="103" groupAlignment="1" max="-2" attributes="0"> <Component id="jPanel1" max="32767" attributes="0"/> - <Component id="polylinePanel1" max="32767" attributes="0"/> + <Component id="polylinePanel1" pref="500" max="32767" attributes="0"/> </Group> <EmptySpace max="32767" attributes="0"/> </Group> @@ -132,7 +132,7 @@ </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> - <EmptySpace min="0" pref="498" max="32767" attributes="0"/> + <EmptySpace min="0" pref="398" max="32767" attributes="0"/> </Group> </DimensionLayout> </Layout> 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 e9ac0b558c5e1574433758cc35be0720d0325f52..347c46eaba2516164c99e4919de0baa7b976029d 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java +++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java @@ -21,7 +21,7 @@ public class ProfilesPanel extends ControlPanel { * Handled actions */ public static final String ACTION_COMMAND_EXPORT = "export"; - public static final String ACTION_OFFSET_CUTTING_PLANE = "offset plane"; + public static final String ACTION_SHIFT_CUTTING_PLANE = "shift plane"; public static final String ACTION_MIRROR_CUTS = "mirror-cuts"; public static final String ACTION_CHANGE_CUTTING_PLANE = "change cutting plane"; @@ -60,7 +60,7 @@ public class ProfilesPanel extends ControlPanel { comboSliderDouble1.setRange(0, 1, 2); comboSliderDouble1.setValue(0.5); - comboSliderDouble1.addListener(createListener(action, ACTION_OFFSET_CUTTING_PLANE)); + comboSliderDouble1.addListener(createListener(action, ACTION_SHIFT_CUTTING_PLANE)); jCheckBox1.addActionListener(createListener(action, ACTION_MIRROR_CUTS)); jButton1.addActionListener(createListener(action, ACTION_COMMAND_EXPORT)); diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java index a044a14be0706fc051a44783b15ce129e8f336fe..c6a46ba130367314824d83d8196a13326796ea20 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java +++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java @@ -6,7 +6,6 @@ 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.face.events.MeshChangedEvent; import cz.fidentis.analyst.face.events.SymmetryPlaneChangedEvent; import cz.fidentis.analyst.feature.FeaturePoint; import cz.fidentis.analyst.mesh.core.MeshFacet; @@ -54,6 +53,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe // Place control panel to the topControlPanel this.topControlPanel.addTab(controlPanel.getName(), controlPanel.getIcon(), controlPanel); + /* this.topControlPanel.addChangeListener(e -> { // If the symmetry panel is focused... if (((JTabbedPane) e.getSource()).getSelectedComponent() instanceof SymmetryPanel) { @@ -65,6 +65,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getSecondaryFaceSlot(), false); } }); + */ // Be informed about changes in faces perfomed by other GUI elements getPrimaryDrawableFace().getHumanFace().registerListener(this); @@ -96,6 +97,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe @Override public void acceptEvent(HumanFaceEvent event) { + /* symmetry plane is transformed together with the mesh if (event instanceof MeshChangedEvent) { // recompute symmetry plane, if necessary switch (sPlane) { case 0: // none @@ -113,6 +115,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe default: } } + */ if (event instanceof SymmetryPlaneChangedEvent) { updatePrecision(event.getFace()); } @@ -127,6 +130,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe face.setSymmetryPlane(estimator.getSymmetryPlane()); log.printDuration("Symmetry plane estimation from mesh for " + face.getShortName()); setDrawablePlane(face, index); + face.announceEvent(new SymmetryPlaneChangedEvent(face, "", this)); } } @@ -169,6 +173,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe face.setSymmetryPlane(new Plane(planes)); // creates an average plane setDrawablePlane(face, index); + face.announceEvent(new SymmetryPlaneChangedEvent(face, "", this)); } protected void setDrawablePlane(HumanFace face, int index) { @@ -186,7 +191,7 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe MeshModel clone = new MeshModel(face.getMeshModel()); - for (MeshFacet facet: clone.getFacets()) { + for (MeshFacet facet: clone.getFacets()) { // invert mesh facet.getVertices().parallelStream().forEach(v -> { v.getPosition().set(face.getSymmetryPlane().reflectOverPlane(v.getPosition())); }); @@ -196,9 +201,9 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe HausdorffDistance visitor = new HausdorffDistance( face.getKdTree(), Strategy.POINT_TO_POINT_DISTANCE_ONLY, - false, - true, - false + false, // relative + true, // parallel + false // crop ); clone.compute(visitor); controlPanel.updateHausdorffDistanceStats(visitor.getStats(), getCanvas().getHumanFace(0) == face); diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityApproxHausdorff.java b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityApproxHausdorff.java deleted file mode 100644 index 7cc8988b4220d79f87e5aed318cecbd92856f6d2..0000000000000000000000000000000000000000 --- a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityApproxHausdorff.java +++ /dev/null @@ -1,145 +0,0 @@ -package cz.fidentis.analyst.tests; - -import cz.fidentis.analyst.face.HumanFace; -import cz.fidentis.analyst.icp.IcpTransformer; -import cz.fidentis.analyst.icp.NoUndersampling; -import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.DoubleSummaryStatistics; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * A class for testing the efficiency of batch processing algorithms. - * The goal of this tool is to measure time and precision of - * approximated Hausdorff distance (HD). - * - * - First, HD of the first face (primary face) with other faces is computed - * - Each secondary face is superimposed using ICP - * - Then it is stored in k-d tree - * - Relative (!) HD from the primary to secondary face is computed and stored. - * The order cannot be reverted because we need HD matrices of the same size. - * - TODO: First face should be replaced with average face - * - Then, the mutual distances are approximated: - * - For each pair of faces A and B, the distance is computed as the difference - * between distances A-P and B-P, where P is the primary face. - * - * @author Radek Oslejsek - */ -public class BatchSimilarityApproxHausdorff { - private static final String DATA_DIR = "../../analyst-data-antropologie/_ECA"; - private static final String OUTPUT_FILE = "../../SIMILARITY_APPROX_HAUSDORFF.csv"; - - /** - * Main method - * @param args Input arguments - * @throws IOException on IO error - */ - public static void main(String[] args) throws IOException, ClassNotFoundException, Exception { - List<Path> faces = Files.list(new File(DATA_DIR).toPath()) - .filter(f -> f.toString().endsWith(".obj")) - .sorted() - .limit(100) - .collect(Collectors.toList()); - - - Map<Integer, List<Double>> distances = new HashMap<>(); - - for (int i = 1; i < faces.size(); i++) { - HumanFace priFace = new HumanFace(faces.get(0).toFile()); - HumanFace secFace = new HumanFace(faces.get(i).toFile()); - - secFace.computeKdTree(false); - - System.out.println(i + "/" + (faces.size()-1) + " (" + priFace.getShortName() + "/" + secFace.getShortName() + ")"); - - IcpTransformer icp = new IcpTransformer(priFace.getMeshModel(), 50, true, 0.3, new NoUndersampling()); - secFace.getMeshModel().compute(icp, true); - - HausdorffDistance hd = new HausdorffDistance(secFace.getKdTree(), HausdorffDistance.Strategy.POINT_TO_POINT, true, true, true); - priFace.getMeshModel().compute(hd, true); - - //System.out.println(hd.getDistances().get(priFace.getMeshModel().getFacets().get(0)).size()); - distances.put(i, hd.getDistances().get(priFace.getMeshModel().getFacets().get(0))); - } - - BufferedWriter bfw = new BufferedWriter(new FileWriter(OUTPUT_FILE)); - bfw.write("PRI FACE;SEC FACE;MIN;MAX;AVG"); - bfw.newLine(); - - for (int i = 0; i < faces.size(); i++) { - for (int j = 0; j < faces.size(); j++) { - if (i == j) { - continue; - } - - DoubleSummaryStatistics stats; - if (i == 0 || j == 0) { - stats = getStats(distances.get((i == 0) ? j : i)); - } else { - stats = getStats(distances.get(i), distances.get(j)); - } - - bfw.write(getShortName(faces.get(i).toFile())+";"); - bfw.write(getShortName(faces.get(j).toFile())+";"); - if (stats != null) { - bfw.write(String.format("%.20f", stats.getMin())+";"); - bfw.write(String.format("%.20f", stats.getMax())+";"); - bfw.write(String.format("%.20f", stats.getAverage())+""); - bfw.newLine(); - } else { - bfw.write(String.format("%.20f", Double.NaN)+";"); - bfw.write(String.format("%.20f", Double.NaN)+";"); - bfw.write(String.format("%.20f", Double.NaN)+""); - bfw.newLine(); - } - bfw.flush(); - } - } - - bfw.close(); - - } - - private static DoubleSummaryStatistics getStats(List<Double> d1, List<Double> d2) { - if (d1.size() != d2.size()) { - return null; - } - - List<Double> ret = new ArrayList<>(d1.size()); - for (int i = 0; i < d1.size(); i++) { - ret.add(Math.abs(d2.get(i) - d1.get(i))); - } - - return ret.stream() - .mapToDouble(Double::doubleValue) - .summaryStatistics(); - } - - private static DoubleSummaryStatistics getStats(List<Double> d1) { - List<Double> ret = new ArrayList<>(d1.size()); - for (int i = 0; i < d1.size(); i++) { - ret.add(Math.abs(d1.get(i))); - } - - return d1.stream() - .mapToDouble(v -> Math.abs(v)) - .summaryStatistics(); - } - - private static String getShortName(File file) throws IOException { - String id = file.getCanonicalPath(); - String name = id.substring(0, id.lastIndexOf('.')); // remove extention - name = name.substring(id.lastIndexOf('/')+1, name.length()); - name = name.substring(name.lastIndexOf(File.separatorChar) + 1, name.length()); - return name; - } -} diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java index d6c43c62d5431ca7486f4d681f20e64a746154c9..f8dd484f18afa4150e29d19b38f4e45efe3f5376 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java +++ b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruth.java @@ -1,10 +1,8 @@ package cz.fidentis.analyst.tests; import cz.fidentis.analyst.face.HumanFace; -import cz.fidentis.analyst.icp.IcpTransformer; -import cz.fidentis.analyst.icp.NoUndersampling; +import cz.fidentis.analyst.face.HumanFaceUtils; import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; -import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; @@ -77,22 +75,41 @@ public class BatchSimilarityGroundTruth { // transform secondary face if (i != j) { // register only different faces long icpTime = System.currentTimeMillis(); - IcpTransformer icp = new IcpTransformer(priFace.getMeshModel(), 100, false, 0.3, new NoUndersampling()); - secFace.getMeshModel().compute(icp, true); + HumanFaceUtils.alignMeshes( + priFace, + secFace, // is transformed + 100, // max iterations + false,// scale + 0.3, // error + 100, // no undersampling + false // drop k-d tree, if exists + ); icpComputationTime += System.currentTimeMillis() - icpTime; } long hdTime = System.currentTimeMillis(); // compute HD from secondary to primary: - priFace.computeKdTree(true); - HausdorffDistance hd = new HausdorffDistance(priFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD); - secFace.getMeshModel().compute(hd, true); + HausdorffDistance hd = new HausdorffDistance( + priFace.getKdTree(), + HausdorffDistance.Strategy.POINT_TO_POINT, + false, // relative distance + true, // parallel + CROP_HD // crop + ); + secFace.getMeshModel().compute(hd); distances[j][i] = hd.getStats().getAverage(); + // compute HD from primary to secondary: - secFace.computeKdTree(true); - hd = new HausdorffDistance(secFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD); - priFace.getMeshModel().compute(hd, true); + hd = new HausdorffDistance( + secFace.getKdTree(), + HausdorffDistance.Strategy.POINT_TO_POINT, + false, // relative distance + true, // parallel + CROP_HD // crop + ); + priFace.getMeshModel().compute(hd); distances[i][j] = hd.getStats().getAverage(); + hdComputationTime += System.currentTimeMillis() - hdTime; } } diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruthOpt.java b/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruthOpt.java deleted file mode 100644 index c28f38325a3815be14911607a1c19af86a2e3c10..0000000000000000000000000000000000000000 --- a/GUI/src/main/java/cz/fidentis/analyst/tests/BatchSimilarityGroundTruthOpt.java +++ /dev/null @@ -1,169 +0,0 @@ -package cz.fidentis.analyst.tests; - -import cz.fidentis.analyst.visitors.kdtree.AvgFaceConstructor; -import cz.fidentis.analyst.face.HumanFace; -import cz.fidentis.analyst.face.HumanFaceFactory; -import cz.fidentis.analyst.icp.IcpTransformer; -import cz.fidentis.analyst.icp.NoUndersampling; -import cz.fidentis.analyst.mesh.io.MeshObjExporter; -import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; -import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.Duration; -import java.util.List; -import java.util.stream.Collectors; - -/** - * A class for testing the efficiency of batch processing algorithms. - * It works in the same way as {@link BatchSimilarityGroundTruth} with the following changes: - * <ul> - * <li>All faces are transformed (ICP) to the very first face of the collection. They are not transformed mutually. - * It enables us to compute ICP only once for every face, but with possible loss of precision. - * Moreover, {@code HumanFaceFactory} is used to quickly load/swap faces when used multiple times.</li> - * </ul> - * Stats for 100 faces WITH CROP: - * <pre> - * Time of AVG face computation time: 00:00:19,529 - * ICP computation time: 00:05:19,096 - * HD computation time: 03:17:29,446 - * Total computation time: 03:32:30,671 - * </pre> - * Stats for 100 faces WITHOUT CROP: - * <pre> - * Time of AVG face computation time: 00:00:19,386 - * ICP computation time: 00:05:39,318 - * HD computation time: 03:11:49,226 - * Total computation time: 03:25:50,957 - * </pre> - * - * @author Radek Oslejsek - */ -public class BatchSimilarityGroundTruthOpt { - - private static final String DATA_DIR = "../../analyst-data-antropologie/_ECA"; - private static final String OUTPUT_FILE = "../../SIMILARITY_GROUND_TRUTH_OPT.csv"; - private static final String TEMPLATE_FACE_PATH = "../../analyst-data-antropologie/template_face.obj"; - private static final int MAX_SAMPLES = 100; - private static final boolean CROP_HD = false; - - /** - * Main method - * @param args Input arguments - * @throws IOException on IO error - */ - public static void main(String[] args) throws IOException, ClassNotFoundException, Exception { - List<Path> faces = Files.list(new File(DATA_DIR).toPath()) - .filter(f -> f.toString().endsWith(".obj")) - .sorted() - .limit(MAX_SAMPLES) - .collect(Collectors.toList()); - - double[][] distances = new double[faces.size()][faces.size()]; - String[] names = new String[faces.size()]; - - long totalTime = System.currentTimeMillis(); - long avgFaceComputationTime = 0; - long icpComputationTime = 0; - long hdComputationTime = 0; - - AvgFaceConstructor avgFaceConstructor = new AvgFaceConstructor(new HumanFace(faces.get(0).toFile()).getMeshModel()); - - HumanFaceFactory factory = new HumanFaceFactory(); - factory.setReuseDumpFile(true); - factory.setStrategy(HumanFaceFactory.Strategy.MRU); - - int counter = 0; - for (int i = 0; i < faces.size(); i++) { - String priFaceId = factory.loadFace(faces.get(i).toFile()); - HumanFace priFace = factory.getFace(priFaceId); - names[i] = priFace.getShortName().replaceAll("_01_ECA", ""); - - for (int j = i; j < faces.size(); j++) { // starts with "i"! - priFace = factory.getFace(priFaceId); // re-read if dumped, at leat update the access time - - String secFaceId = factory.loadFace(faces.get(j).toFile()); - HumanFace secFace = factory.getFace(secFaceId); - - System.out.print(++counter + ": " + priFace.getShortName() + " - " + secFace.getShortName()); - - // transform secondary face, but only once. Transformed faces are stored in the HumanFaceFactory! Don't transform the same face - if (i == 0 && i != j) { - System.out.print(", ICP"); - long icpTime = System.currentTimeMillis(); - IcpTransformer icp = new IcpTransformer(priFace.getMeshModel(), 100, true, 0.3, new NoUndersampling()); - secFace.getMeshModel().compute(icp, true); - icpComputationTime += System.currentTimeMillis() - icpTime; - } - - long hdTime = System.currentTimeMillis(); - // compute HD from secondary to primary: - priFace.computeKdTree(true); - HausdorffDistance hd = new HausdorffDistance(priFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD); - secFace.getMeshModel().compute(hd, true); - distances[j][i] = hd.getStats().getAverage(); - // compute HD from primary to secondary: - secFace.computeKdTree(true); - hd = new HausdorffDistance(secFace.getKdTree(), Strategy.POINT_TO_POINT, false, true, CROP_HD); - priFace.getMeshModel().compute(hd, true); - distances[i][j] = hd.getStats().getAverage(); - hdComputationTime += System.currentTimeMillis() - hdTime; - - // Compute AVG face. Use each tranfromed face only once. Skip the very first face - if (i == 0 && j != 0) { - System.out.print(", AVG"); - long avgFaceTime = System.currentTimeMillis(); - priFace.getKdTree().accept(avgFaceConstructor); - avgFaceComputationTime += System.currentTimeMillis() - avgFaceTime; - } - - System.out.println(", " + factory.toString()); - } - - factory.removeFace(priFaceId); // the face is no longer needed - } - - MeshObjExporter exp = new MeshObjExporter(avgFaceConstructor.getAveragedMeshModel()); - exp.exportModelToObj(new File(TEMPLATE_FACE_PATH)); - - BufferedWriter w = new BufferedWriter(new FileWriter(OUTPUT_FILE)); - w.write("PRI FACE;SEC FACE;AVG HD from PRI to SEC;AVG HD from SEC to PRI"); - w.newLine(); - for (int i = 0; i < faces.size(); i++) { - for (int j = i; j < faces.size(); j++) { - w.write(names[i] + ";"); - w.write(names[j] + ";"); - w.write(String.format("%.8f", distances[i][j]) + ";"); - w.write(String.format("%.8f", distances[j][i]) + ";"); - if (distances[i][j] > distances[j][i]) { - w.write(String.format("%.8f", distances[i][j]) + ";"); - w.write(String.format("%.8f", distances[j][i]) + ""); - } else { - w.write(String.format("%.8f", distances[j][i]) + ";"); - w.write(String.format("%.8f", distances[i][j]) + ""); - } - w.newLine(); - } - } - w.close(); - - System.out.println(); - Duration duration = Duration.ofMillis(avgFaceComputationTime); - System.out.println("Time of AVG face computation time: " + - String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart())); - duration = Duration.ofMillis(icpComputationTime); - System.out.println("ICP computation time: " + - String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart())); - duration = Duration.ofMillis(hdComputationTime); - System.out.println("HD computation time: " + - String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart())); - duration = Duration.ofMillis(System.currentTimeMillis() - totalTime); - System.out.println("Total computation time: " + - String.format("%02d:%02d:%02d,%03d", duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(), duration.toMillisPart())); - } - -} diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java b/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java deleted file mode 100644 index 1de0990da9bbac754363edc8dcae0e3b62aa528d..0000000000000000000000000000000000000000 --- a/GUI/src/main/java/cz/fidentis/analyst/tests/EfficiencyTests.java +++ /dev/null @@ -1,141 +0,0 @@ -package cz.fidentis.analyst.tests; - -import cz.fidentis.analyst.face.HumanFace; -import cz.fidentis.analyst.kdtree.KdTree; -import cz.fidentis.analyst.mesh.core.MeshFacet; -import cz.fidentis.analyst.symmetry.SymmetryConfig; -import cz.fidentis.analyst.symmetry.Plane; -import cz.fidentis.analyst.symmetry.SymmetryEstimator; -import cz.fidentis.analyst.visitors.mesh.HausdorffDistance; -import cz.fidentis.analyst.visitors.mesh.HausdorffDistance.Strategy; -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Map; - -/** - * A class for testing the efficiency of algorithms. - * - * @author Radek Oslejsek - */ -public class EfficiencyTests { - - private static File girlFile = new File("src/test/resources/cz/fidentis/analyst/average_girl_17-20.obj"); - private static File boyFile = new File("src/test/resources/cz/fidentis/analyst/average_boy_17-20.obj"); - private static File faceFile2 = new File("src/test/resources/cz/fidentis/analyst/00002_01_ECA.obj"); - private static File faceFile4 = new File("/home/oslejsek/GIT/HCI/analyst2/GUI/src/test/resources/cz/fidentis/analyst/00004_01_ECA.obj"); - private static File basicFaceFile = new File("src/test/resources/cz/fidentis/analyst/basic-model-04.obj"); - - private static HumanFace face1; - private static HumanFace face2; - - /** - * Main method - * @param args Input arguments - * @throws IOException on IO error - */ - public static void main(String[] args) throws IOException, ClassNotFoundException, Exception { - face1 = printFaceLoad(faceFile4); - face2 = printFaceLoad(faceFile2); - - face1.getMeshModel().simplifyModel(); - face2.getMeshModel().simplifyModel(); - - //for (int i = 0; i < 10; i++) { - // printFaceDump(face1); - //} - - boolean relativeDist = false; - boolean printDetails = false; - - - //face1.getMeshModel().compute(new GaussianCurvature()); // initialize everything, then measure - - System.out.println("Symmetry plane calculation:"); - //printSymmetryPlane(face1, true, CurvatureAlg.MEAN); - //printSymmetryPlane(face1, true, CurvatureAlg.GAUSSIAN); - //printSymmetryPlane(face1, false, CurvatureAlg.MEAN); - //printSymmetryPlane(face1, false, CurvatureAlg.GAUSSIAN); - - System.out.println(); - System.out.println(measureKdTreeCreation(face1) + "\tmsec:\tKd-tree creation of first face"); - System.out.println(measureKdTreeCreation(face2) + "\tmsec:\tKd-tree creation of second face"); - - System.out.println(); - System.out.println("Hausdorff distance sequentially:"); - testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, false, false), printDetails); - testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT_DISTANCE_ONLY, false, false, false), printDetails); - testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, false, false), printDetails); - testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_TRIANGLE_APPROXIMATE, relativeDist, false, false), printDetails); - - System.out.println(); - System.out.println("Hausdorff distance concurrently:"); - testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT_DISTANCE_ONLY, false, true, false), printDetails); - testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_POINT, relativeDist, true, false), printDetails); - testAndPrint(face1, new HausdorffDistance(face2.getMeshModel(), Strategy.POINT_TO_TRIANGLE_APPROXIMATE, relativeDist, true, false), printDetails); - } - - protected static void testAndPrint(HumanFace face, HausdorffDistance vis, boolean printDetails) { - long startTime = System.currentTimeMillis(); - face.getMeshModel().compute(vis); - long endTime = System.currentTimeMillis(); - - System.out.println( - (endTime-startTime) + - "\tmsec: " + - //"\t" + (vis.inParallel() ? "concurrently" : "sequentially") + - "\t" + (vis.relativeDistance()? "relative" : "absolute") + - "\t" + vis.getStrategy() - ); - - if (printDetails) { - Map<MeshFacet, List<Double>> results = vis.getDistances(); - for (MeshFacet facet: results.keySet()) { - System.out.println(results.get(facet)); - } - } - } - - private static long measureKdTreeCreation(HumanFace face) { - long startTime = System.currentTimeMillis(); - KdTree kdTree = new KdTree(face.getMeshModel().getFacets()); - return System.currentTimeMillis() - startTime; - } - - private static void printSymmetryPlane(HumanFace face, boolean concurrently) { - long startTime = System.currentTimeMillis(); - SymmetryEstimator est = new SymmetryEstimator(new SymmetryConfig()); - face.getMeshModel().compute(est, false); - Plane plane = est.getSymmetryPlane(concurrently); - long endTime = System.currentTimeMillis(); - - System.out.println( - (endTime-startTime) + - "\tmsec: " + - "\t" + (concurrently ? "concurrently" : "sequentially") + -// "\t" + curvatureAlg + " curvature " + - "\t" + plane.getNormal() + ", " + plane.getDistance() - ); - } - - private static void printFaceDump(HumanFace face) throws IOException, ClassNotFoundException, Exception { - long startTime = System.currentTimeMillis(); - File file = face.dumpToFile(); - long endTime = System.currentTimeMillis(); - System.out.println("Human face dumping:\t " +(endTime-startTime) + " msec"); - - startTime = System.currentTimeMillis(); - HumanFace f = HumanFace.restoreFromFile(file); - endTime = System.currentTimeMillis(); - System.out.println("Human face restore:\t " +(endTime-startTime) + " msec"); - } - - private static HumanFace printFaceLoad(File file) throws IOException { - long startTime = System.currentTimeMillis(); - HumanFace face = new HumanFace(file); - long endTime = System.currentTimeMillis(); - System.out.println("Human face loading:\t " +(endTime-startTime) + " msec"); - return face; - } - -} diff --git a/GUI/src/main/java/cz/fidentis/analyst/tests/ICPTest.java b/GUI/src/main/java/cz/fidentis/analyst/tests/ICPTest.java deleted file mode 100644 index 13fa88165cc21a36e28d0c07c150cf24cd2fb545..0000000000000000000000000000000000000000 --- a/GUI/src/main/java/cz/fidentis/analyst/tests/ICPTest.java +++ /dev/null @@ -1,82 +0,0 @@ -package cz.fidentis.analyst.tests; - -import cz.fidentis.analyst.face.HumanFace; -import cz.fidentis.analyst.icp.IcpTransformer; -import cz.fidentis.analyst.icp.NoUndersampling; -import cz.fidentis.analyst.kdtree.KdTree; -import cz.fidentis.analyst.mesh.core.MeshFacet; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author Radek Oslejsek - */ -public class ICPTest { - - private static final String DATA_DIR = "../../analyst-data/multi-scan-models-anonymized-fixed/"; - - private static String[] faceFiles = new String[] { - DATA_DIR + "02/00002_01_ECA.obj", - DATA_DIR + "04/00004_01_ECA.obj", - DATA_DIR + "06/00006_01_ECA.obj", - DATA_DIR + "07/00007_01_ECA.obj", - DATA_DIR + "10/00010_01_ECA.obj" - }; - - private static int tests = 0; - private static int iters = 0; - - /** - * - * @param args - * @throws IOException - */ - public static void main(String[] args) throws IOException { - long time = 0; - for (int i = 0; i < faceFiles.length; i++) { - time += test(i); - } - System.out.println("tests: " + tests); - System.out.println("iters: " + iters); - System.out.println("time: " + time + " ms"); - System.out.println("AVG iters: " + ((double)iters/tests)); - System.out.println("AVG time: " + ((double)time/tests) + " ms"); - } - - /** - * - * @param index - * @return - * @throws IOException - */ - public static long test(int index) throws IOException { - List<HumanFace> faces = new ArrayList<>(); - for (int i = 0; i < faceFiles.length; i++) { - faces.add(new HumanFace(new File(faceFiles[i]))); - } - HumanFace prim = faces.remove(index); - KdTree primKdTree = prim.computeKdTree(true); - - - System.out.println(); - System.out.println(prim.getId()); - long startTime = System.currentTimeMillis(); - for (HumanFace sec: faces) { - tests++; - IcpTransformer icpTransformer = new IcpTransformer(primKdTree, 10, false, 0.05, new NoUndersampling()); - System.out.println(sec.getId()); - sec.getMeshModel().compute(icpTransformer); - - for (MeshFacet f: icpTransformer.getTransformations().keySet()) { - //System.out.println("AAA"+icpTransformer.getTransformations().get(f).size()); - iters += icpTransformer.getTransformations().get(f).size(); - } - } - long endTime = System.currentTimeMillis(); - - return endTime - startTime; - } -} diff --git a/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties b/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties index 2aebc13cd2c31cf89cc7ca01a38465004949e788..9ccc35ef4b090c148807585922f896f0b212f078 100644 --- a/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties +++ b/GUI/src/main/resources/cz/fidentis/analyst/canvas/toolbar/Bundle.properties @@ -8,3 +8,4 @@ SceneToolboxSingleFace.landButton.tooltip=show-hide feature points SceneToolboxSingleFace.faceButton.tooltip=show-hide face SceneToolboxSingleFace.slider.tooltip=change face transparency SceneToolboxFaceToFace.distButton.tooltip=show-hide distance heatmap +SceneToolboxFaceToFace.symmetryButton.tooltip=show-hide symmetry plane diff --git a/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties b/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties index c9ef96eb1e4e07bd7bb8813cd733d3b00561cf08..d966ae397d3f270a0cb9c713a30fb9e1f3bdbb2b 100644 --- a/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties +++ b/GUI/src/main/resources/cz/fidentis/analyst/registration/Bundle.properties @@ -5,30 +5,15 @@ RegistrationPanel.jLabel5.text=min. error: RegistrationPanel.jFormattedTextField2.text=50 RegistrationPanel.jLabel6.text=iterations: RegistrationPanel.jLabel7.text=scale: -RegistrationPanel.jLabel8.text=undersampling: +RegistrationPanel.jLabel8.text=undersampling (100% = none) RegistrationPanel.thersholdUpButton.text= RegistrationPanel.thresholdDownButton.text= RegistrationPanel.featurePointsLabel.text=Highlight feature point pairs closer than: 2 -RegistrationPanel.translationButton.text= RegistrationPanel.translationPanel.border.title=translation -RegistrationPanel.highShiftRB.toolTipText=set high shifting amount -RegistrationPanel.highShiftRB.text=big -RegistrationPanel.lowShiftRB.toolTipText=set low shifting amount -RegistrationPanel.lowShiftRB.text=small -RegistrationPanel.shiftLabel.toolTipText=transformation amount -RegistrationPanel.shiftLabel.text=step: -RegistrationPanel.applyButton.toolTipText=apply transformations -RegistrationPanel.applyButton.text=Apply changes -RegistrationPanel.resetAllButton.toolTipText=reset all transformations -RegistrationPanel.resetAllButton.text=reset all RegistrationPanel.scaleMinusButton.text= -RegistrationPanel.scaleButton.toolTipText=reset scale -RegistrationPanel.scaleButton.text= -RegistrationPanel.scaleFTF.toolTipText= RegistrationPanel.scalePlusButton.text= RegistrationPanel.scalePanel.border.title=scale -RegistrationPanel.rotationXFTF.toolTipText= # To change this license header, choose License Headers in Project Properties. # To change this template file, choose Tools | Templates # and open the template in the editor. @@ -36,8 +21,6 @@ RegistrationPanel.rightRotationXButton.text= RegistrationPanel.leftRotationZButton.text= RegistrationPanel.rightRotationYButton.text= RegistrationPanel.rightRotationZButton.text= -RegistrationPanel.rotationButton.toolTipText=reset rotation -RegistrationPanel.rotationButton.text= RegistrationPanel.rotatXLabel.text=x RegistrationPanel.rotatYLabel.text=y RegistrationPanel.rotatZLabel.text=z @@ -52,9 +35,7 @@ RegistrationPanel.translZLabel.text=front-back RegistrationPanel.translXLabel.text=horizontal RegistrationPanel.rightTranslationYButton.text= RegistrationPanel.leftTranslationYButton.text= -RegistrationPanel.translationXFTF.toolTipText= RegistrationPanel.rightTranslationXButton.text= -RegistrationPanel.translationButton.toolTipText=reset translation RegistrationPanel.jButton2.text=Apply RegistrationPanel.jButton1.toolTipText=Apply ICP RegistrationPanel.jButton2.toolTipText=Apply Procrustes @@ -62,7 +43,7 @@ RegistrationPanel.jLabel4.text=scale: RegistrationPanel.jCheckBox2.text= RegistrationPanel.jPanel7.border.title=Feature points alignment (Procrustes): RegistrationPanel.jPanel1.border.title=Mesh alignment (ICP): -RegistrationPanel.transformationPanel.border.title=Fine-tuning the mutual position: +RegistrationPanel.transformationPanel.border.title=Manual alignment: RegistrationPanel.jPanel4.border.title=View: RegistrationPanel.jLabel1.text=Hausdorff distance: RegistrationPanel.jPanel2.border.title=Measurements: @@ -72,3 +53,4 @@ RegistrationPanel.jTextField1.text= BatchRegistrationPanel.jPanel2.border.title=Dataset BatchRegistrationPanel.jCheckBox1.text=compute average face from BatchRegistrationPanel.jPanel3.border.title=Similarity +RegistrationPanel.jButton3.text=Aling symmetry planes diff --git a/GUI/src/main/resources/na.png b/GUI/src/main/resources/na.png new file mode 100644 index 0000000000000000000000000000000000000000..d1ea8cf0ab404a5ee1ea10a211027d143e64f677 Binary files /dev/null and b/GUI/src/main/resources/na.png differ diff --git a/GUI/src/main/resources/na28x28.png b/GUI/src/main/resources/na28x28.png new file mode 100644 index 0000000000000000000000000000000000000000..07fac02a43b648c2960bc751dbe07ff7737fb97c Binary files /dev/null and b/GUI/src/main/resources/na28x28.png differ 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 c9f81ed95121b9b5467257d6c989d758646689b8..d590c86f451dd9bc35cdafee9ada1bdbc3f18a54 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 @@ -67,7 +67,7 @@ public interface MeshFacet extends Iterable<MeshTriangle>, Serializable { * @return number of triangles */ int getNumTriangles(); - + /** * Return triangle instances. The order corresponds with with the corner * table, i.e., the i-th returned triangle corresponds to i-th triangle in 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 baaddfb488f472cdb29cbd4cab3a27a67d74805c..bb0e75f75e5d1293dab21729a5f03ba41eb76120 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 @@ -428,7 +428,7 @@ public class MeshTriangle implements Iterable<MeshPoint> { * * @param point vertex from which the projection is created * @return projection to plane of triangle - * @throws {@code NullPointerException} if the point is {@code null} + * @throws NullPointerException if the point is {@code null} */ protected Point3d getProjectionToTrianglePlane(Point3d point) { Vector3d normal = computeNormal(); @@ -559,10 +559,10 @@ public class MeshTriangle implements Iterable<MeshPoint> { * @return true if the triangle is intersected by the plane */ public boolean checkIntersectionWithPlane(Vector3d normal, double d) { - double p1 = (normal.x * getVertex1().x) + (normal.y * getVertex1().y) + (normal.z * getVertex1().z) + d; - double p2 = (normal.x * getVertex2().x) + (normal.y * getVertex2().y) + (normal.z * getVertex2().z) + d; - double p3 = (normal.x * getVertex3().x) + (normal.y * getVertex3().y) + (normal.z * getVertex3().z) + d; - + double p1 = (normal.x * getVertex1().x) + (normal.y * getVertex1().y) + (normal.z * getVertex1().z) - d; + double p2 = (normal.x * getVertex2().x) + (normal.y * getVertex2().y) + (normal.z * getVertex2().z) - d; + double p3 = (normal.x * getVertex3().x) + (normal.y * getVertex3().y) + (normal.z * getVertex3().z) - d; + //If one point is on one side of the plane and the other on the other side return ((p1 <= 0 || p2 <= 0 || p3 <= 0) && (p1 >= 0 || p2 >= 0 || p3 >= 0)); } diff --git a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java index b7e2b12b983636ed9e84d2f7a8024ec6cea70230..65eba7e832f1d52b2a8344bd2922bbc03c8d79bd 100644 --- a/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java +++ b/MeshModel/src/test/java/cz/fidentis/analyst/mesh/core/MeshTriangleTest.java @@ -23,22 +23,25 @@ public class MeshTriangleTest { ); return triangle; } + */ @Test public void getClosestPointTest() { - MeshTriangle tri = 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), - 0, 1, 2 - ); - Assertions.assertEquals(new Vector3d(1, 0, 0), tri.getClosestPoint(new Vector3d(0, 0, 0))); - Assertions.assertEquals(new Vector3d(1, 1, 0), tri.getClosestPoint(new Vector3d(0, 1, 0))); - Assertions.assertEquals(new Vector3d(1, 2, 0), tri.getClosestPoint(new Vector3d(0, 3, 0))); - Assertions.assertEquals(new Vector3d(1, 0, 0), tri.getClosestPoint(new Vector3d(1, 0, -1))); - Assertions.assertEquals(new Vector3d(1.2, 0.2, 0), tri.getClosestPoint(new Vector3d(1.2, 0.2, -1))); + MeshFacet facet = createFacet(); + MeshTriangle tri = new MeshTriangle(facet, 0, 1, 2); + + Assertions.assertEquals(new Point3d(0.25, 0.25, 0), tri.getClosestPoint(new Point3d(0, 0.5, -1))); + Assertions.assertEquals(new Point3d(0.25, 0.25, 0), tri.getClosestPoint(new Point3d(0, 0.5, 0))); + Assertions.assertEquals(new Point3d(0.25, 0.25, 0), tri.getClosestPoint(new Point3d(0, 0.5, 1))); + + Assertions.assertEquals(new Point3d(1, 1, 0), tri.getClosestPoint(new Point3d(1, 1, -1))); + Assertions.assertEquals(new Point3d(1, 1, 0), tri.getClosestPoint(new Point3d(1, 1, 0))); + Assertions.assertEquals(new Point3d(1, 1, 0), tri.getClosestPoint(new Point3d(1, 1, 1))); + + Assertions.assertEquals(new Point3d(0.7, 0.7, 0), tri.getClosestPoint(new Point3d(0.7, 0.7, -1))); + Assertions.assertEquals(new Point3d(0.7, 0.7, 0), tri.getClosestPoint(new Point3d(0.7, 0.7, 0))); + Assertions.assertEquals(new Point3d(0.7, 0.7, 0), tri.getClosestPoint(new Point3d(0.7, 0.7, 1))); } - */ private MeshFacet createFacet() { MeshFacet facet = new MeshFacetImpl(); @@ -114,8 +117,8 @@ public class MeshTriangleTest { MeshFacet facet = createFacet(); Vector3d normal = new Vector3d(1, 0, 0); - double d1 = -1; - double d2 = -0.5; + double d1 = 1; + double d2 = 0.5; MeshTriangle tri1 = new MeshTriangle(facet, 0, 1, 2); MeshTriangle tri2 = new MeshTriangle(facet, 1, 2, 3); @@ -131,5 +134,12 @@ public class MeshTriangleTest { Assertions.assertFalse(tri2.checkIntersectionWithPlane(normal, d2)); Assertions.assertFalse(tri3.checkIntersectionWithPlane(normal, d2)); Assertions.assertFalse(tri4.checkIntersectionWithPlane(normal, d2)); + + Vector3d n2 = new Vector3d(-1, -1, 0); + n2.normalize(); + Assertions.assertTrue(tri1.checkIntersectionWithPlane(n2, -0.5)); + Assertions.assertFalse(tri2.checkIntersectionWithPlane(n2, -0.5)); + Assertions.assertFalse(tri3.checkIntersectionWithPlane(n2, -0.5)); + Assertions.assertFalse(tri4.checkIntersectionWithPlane(n2, -0.5)); } }