From 265034b6b9e66dc3a6549532c00d11da4b101dd0 Mon Sep 17 00:00:00 2001
From: Richard Pajersky <xpajersk@fi.muni.cz>
Date: Mon, 10 May 2021 17:38:15 +0200
Subject: [PATCH] Added mock feature points and their functionality

---
 .../gui/RegistrationCPEventListener.java      | 156 ++++++++++++------
 .../gui/RegistrationTestTopComponent.java     |  19 +++
 .../analyst/gui/scene/DrawableMesh.java       |  25 ++-
 .../analyst/gui/scene/SceneRenderer.java      |  33 +++-
 .../analyst/gui/tab/PostRegistrationCP.form   | 131 ++++++++-------
 .../analyst/gui/tab/PostRegistrationCP.java   | 118 +++++++------
 .../analyst/gui/tab/Bundle.properties         |   3 +-
 7 files changed, 327 insertions(+), 158 deletions(-)

diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationCPEventListener.java b/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationCPEventListener.java
index 0899a74a..317cf345 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationCPEventListener.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationCPEventListener.java
@@ -12,6 +12,7 @@ import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshPoint;
 import cz.fidentis.analyst.visitors.mesh.BoundingBox;
 import java.awt.Color;
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collections;
 import javax.vecmath.Point3d;
@@ -24,11 +25,12 @@ import javax.vecmath.Vector3d;
  */
 public class RegistrationCPEventListener {
     
-    private final Canvas canvas;
+    private final double featurePointsThreshold = 0.1;
     private final Color defaultPrimaryColor = new Color(51, 51, 153);
     private final Color defaultSecondaryColor = new Color(255, 239, 0);
     private final int transparencyRange = 10;
     private final double changeAmount = 500d;
+    private final Canvas canvas;
     private final double moveX;
     private final double moveY;
     private final double moveZ;
@@ -56,58 +58,100 @@ public class RegistrationCPEventListener {
         scaleXYZ = (visitor.getBoundingBox().getMaxDiag() / (10 * changeAmount));
     }
     
+    /**
+     * Calculates feature points which are too far away
+     */
+    private void calculateFeaturePoints() {
+        if (!primaryFace.isRenderFeaturePoints()) {
+            return;
+        }
+        ArrayList<AbstractMap.SimpleEntry<Point3d, Color>> adjusted = new ArrayList<>();
+        for (int i = 0; i < primaryFace.getFeaturePoints().size(); i++) {
+            Point3d primaryPoint = primaryFace.getFeaturePoints().get(i).getKey();
+            Point3d secondaryPoint = new Point3d(secondaryFace.getFeaturePoints().get(i).getKey());
+            transformPoint(secondaryPoint);
+            double distance = Math.sqrt(
+                Math.pow(secondaryPoint.x - primaryPoint.x, 2) + 
+                Math.pow(secondaryPoint.y - primaryPoint.y, 2) + 
+                Math.pow(secondaryPoint.z - primaryPoint.z, 2));
+            Point3d point = new Point3d(secondaryFace.getFeaturePoints().get(i).getKey());
+            if (distance > featurePointsThreshold) {
+                adjusted.add(new AbstractMap.SimpleEntry<>(
+                        point, Color.RED));
+            } else {
+                adjusted.add(new AbstractMap.SimpleEntry<>(
+                        point, Color.YELLOW));
+            }
+            secondaryFace.setFeaturePoints(adjusted);
+        }
+    }
+    
+    /**
+     * Applies carried out transformations
+     */
     public void transformFace() {
         for (MeshFacet transformedFacet : secondaryFace.getFacets()) {
             for (MeshPoint comparedPoint : transformedFacet.getVertices()) {
-                Point3d point = comparedPoint.getPosition();
-                Point3d newPoint = new Point3d(0, 0, 0);
-                double quotient;
+                transformPoint(comparedPoint.getPosition());
+            }
+        }
+        for (var point : secondaryFace.getFeaturePoints()) {
+            transformPoint(point.getKey());
+        }
+        canvas.renderScene();
+    }
+    
+    /**
+     * Transforms point based on transformation info from secondary face
+     * 
+     * @param point Point to transform
+     */
+    public void transformPoint(Point3d point) {
+        Point3d newPoint = new Point3d(0, 0, 0);
+        double quotient;
 
-                // rotate around X
-                quotient = Math.toRadians(secondaryFace.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 X
+        quotient = Math.toRadians(secondaryFace.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(secondaryFace.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 Y
+        quotient = Math.toRadians(secondaryFace.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(secondaryFace.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;
-                }
-                
-                // translate
-                point.x += secondaryFace.getTranslation().x;
-                point.y += secondaryFace.getTranslation().y;
-                point.z += secondaryFace.getTranslation().z;
-                
-                // scale
-                point.x *= 1 + secondaryFace.getScale().x;
-                point.y *= 1 + secondaryFace.getScale().y;
-                point.z *= 1 + secondaryFace.getScale().z;
-            }
+        // rotate around Z
+        quotient = Math.toRadians(secondaryFace.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;
         }
-        canvas.renderScene();
+
+        // translate
+        point.x += secondaryFace.getTranslation().x;
+        point.y += secondaryFace.getTranslation().y;
+        point.z += secondaryFace.getTranslation().z;
+
+        // scale
+        point.x *= 1 + secondaryFace.getScale().x;
+        point.y *= 1 + secondaryFace.getScale().y;
+        point.z *= 1 + secondaryFace.getScale().z;
     }
     
     public final void setDeafultColor() {
@@ -191,46 +235,55 @@ public class RegistrationCPEventListener {
     
     public void resetTranslation() {
         secondaryFace.setTranslation(new Vector3d(0, 0, 0));
+        calculateFeaturePoints();
         canvas.renderScene();
     }
     
     public void resetRotation() {
         secondaryFace.setRotation(new Vector3d(0, 0, 0));
+        calculateFeaturePoints();
         canvas.renderScene();
     }
 
     public void resetScale() {
         secondaryFace.setScale(new Vector3d(0, 0, 0));
+        calculateFeaturePoints();
         canvas.renderScene();
     }
     
     public void setXTranslation(double value) {
         secondaryFace.getTranslation().x = value * moveX;
+        calculateFeaturePoints();
         canvas.renderScene();
     }
     
     public void setYTranslation(double value) {
         secondaryFace.getTranslation().y = value * moveY;
+        calculateFeaturePoints();
         canvas.renderScene();
     }
         
     public void setZTranslation(double value) {
         secondaryFace.getTranslation().z = value * moveZ;
+        calculateFeaturePoints();
         canvas.renderScene();
     }
     
     public void setXRotation(double value) {
         secondaryFace.getRotation().x = value * moveX;
+        calculateFeaturePoints();
         canvas.renderScene();
     }
     
     public void setYRotation(double value) {
         secondaryFace.getRotation().y = value * moveY;
+        calculateFeaturePoints();
         canvas.renderScene();
     }
         
     public void setZRotation(double value) {
         secondaryFace.getRotation().z = value * moveZ;
+        calculateFeaturePoints();
         canvas.renderScene();
     }
     
@@ -238,6 +291,7 @@ public class RegistrationCPEventListener {
         secondaryFace.getScale().x = value * scaleXYZ;
         secondaryFace.getScale().y = value * scaleXYZ;
         secondaryFace.getScale().z = value * scaleXYZ;
+        calculateFeaturePoints();
         canvas.renderScene();
     }
     
@@ -291,4 +345,14 @@ public class RegistrationCPEventListener {
         canvas.renderScene();
     }
     
+    public boolean isFeaturePointsActive() {
+        return primaryFace.isRenderFeaturePoints();
+    }
+    
+    public void setFeaturePointsActive(boolean state) {
+        primaryFace.setRenderFeaturePoints(state);
+        secondaryFace.setRenderFeaturePoints(state);
+        calculateFeaturePoints();
+        canvas.renderScene();
+    }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationTestTopComponent.java b/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationTestTopComponent.java
index 7c67c689..561e0009 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationTestTopComponent.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/RegistrationTestTopComponent.java
@@ -6,12 +6,17 @@
 package cz.fidentis.analyst.gui;
 
 import cz.fidentis.analyst.face.HumanFace;
+import cz.fidentis.analyst.gui.scene.DrawableMesh;
 import cz.fidentis.analyst.gui.tab.PostRegistrationCP;
 import cz.fidentis.analyst.mesh.io.ModelFileFilter;
+import java.awt.Color;
 import java.awt.Dimension;
 import java.io.File;
 import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.ArrayList;
 import javax.swing.JFileChooser;
+import javax.vecmath.Point3d;
 import org.netbeans.api.settings.ConvertAsProperties;
 import org.openide.awt.ActionID;
 import org.openide.awt.ActionReference;
@@ -72,7 +77,21 @@ public final class RegistrationTestTopComponent extends TopComponent {
         } catch (Exception ex) {}
         
         canvas1.initScene(primary, secondary);
+        // feature points test
+        ArrayList<DrawableMesh> drawables = new ArrayList<>(canvas1.getScene().getDrawables());
+        DrawableMesh primaryFace = drawables.get(0);
+        DrawableMesh secondaryFace = drawables.get(1);
+        ArrayList<AbstractMap.SimpleEntry<Point3d, Color>> primar = new ArrayList<>();
+        primar.add(new AbstractMap.SimpleEntry<>(new Point3d(100, 0, 0), Color.BLUE));
+        primaryFace.setFeaturePoints(primar);
+        ArrayList<AbstractMap.SimpleEntry<Point3d, Color>> secondar = new ArrayList<>();
+        secondar.add(new AbstractMap.SimpleEntry<>(new Point3d(101, 0, 0), Color.YELLOW));
+        secondaryFace.setFeaturePoints(secondar);
+        
         postRegistrationCP1.initPostRegistrationCP(new RegistrationCPEventListener(canvas1));
+
+        
+
     }
 
     /**
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/scene/DrawableMesh.java b/GUI/src/main/java/cz/fidentis/analyst/gui/scene/DrawableMesh.java
index 8e460dae..b25cdd68 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/scene/DrawableMesh.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/scene/DrawableMesh.java
@@ -4,7 +4,10 @@ import com.jogamp.opengl.GL2;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshModel;
 import java.awt.Color;
+import java.util.AbstractMap;
+import java.util.ArrayList;
 import java.util.List;
+import javax.vecmath.Point3d;
 import javax.vecmath.Vector3d;
 
 /**
@@ -20,14 +23,19 @@ public class DrawableMesh {
     
     private boolean display = true;
     
-    // TO DO - R. Pajersky: add transformation attributes and methods
+    // material info
     private Color color = new Color(255, 255, 255);
     private Color highlights = new Color(0, 0, 0, 1);
     private float transparency = 1;
+    // transformation info
     private Vector3d translation = new Vector3d(0, 0, 0);
     private Vector3d rotation = new Vector3d(0, 0, 0);
     private Vector3d scale = new Vector3d(0, 0, 0);
+    // render mode
     private int renderMode = GL2.GL_FILL;
+    // feature points
+    private ArrayList<AbstractMap.SimpleEntry<Point3d, Color>> featurePoints = new ArrayList<>();
+    boolean renderFeaturePoints = false;
     
     /**
      * Constructor. 
@@ -132,5 +140,20 @@ public class DrawableMesh {
     public void setRenderMode(int renderMode) {
         this.renderMode = renderMode;
     }
+
+    public ArrayList<AbstractMap.SimpleEntry<Point3d, Color>> getFeaturePoints() {
+        return featurePoints;
+    }
+
+    public void setFeaturePoints(ArrayList<AbstractMap.SimpleEntry<Point3d, Color>> featurePoints) {
+        this.featurePoints = featurePoints;
+    }   
     
+    public boolean isRenderFeaturePoints() {
+        return renderFeaturePoints;
+    }
+
+    public void setRenderFeaturePoints(boolean renderFeaturePoints) {
+        this.renderFeaturePoints = renderFeaturePoints;
+    }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/scene/SceneRenderer.java b/GUI/src/main/java/cz/fidentis/analyst/gui/scene/SceneRenderer.java
index aa0b3b9b..10d45da9 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/scene/SceneRenderer.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/scene/SceneRenderer.java
@@ -5,8 +5,10 @@ import static com.jogamp.opengl.GL.GL_DEPTH_TEST;
 import static com.jogamp.opengl.GL.GL_FRONT_AND_BACK;
 import com.jogamp.opengl.GL2;
 import com.jogamp.opengl.glu.GLU;
+import com.jogamp.opengl.glu.GLUquadric;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import java.awt.Color;
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -60,7 +62,7 @@ public class SceneRenderer {
         gl.glEnable(GL2.GL_NORMALIZE);
         gl.glDisable(GL2.GL_CULL_FACE);
         
-        gl.glEnable(GL2.GL_BLEND);    // enabled transparency
+        gl.glEnable(GL2.GL_BLEND);    // enable transparency
         gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
     }
     
@@ -125,7 +127,6 @@ public class SceneRenderer {
             Collections.reverse((ArrayList)drawables);
         }
         
-        
         for (DrawableMesh obj: drawables) {
             gl.glPolygonMode( GL_FRONT_AND_BACK, obj.getRenderMode());
             setMaterial(obj);
@@ -134,9 +135,12 @@ public class SceneRenderer {
             for (MeshFacet facet: obj.getFacets()) {
                 renderFacet(facet);
             }
+            if (obj.isRenderFeaturePoints()) {
+                renderFeaturePoints(obj);
+            }
             gl.glPopMatrix();
         }
-         gl.glFlush();
+        gl.glFlush();
     }
     
     /**
@@ -170,6 +174,29 @@ public class SceneRenderer {
         gl.glScaled(1 + obj.getScale().x, 1 + obj.getScale().y, 1 + obj.getScale().z);
     }
     
+    /**
+     * Renders feature points
+     */
+    private void renderFeaturePoints(DrawableMesh obj) {
+            for (AbstractMap.SimpleEntry<Point3d, Color> featurePoint: obj.getFeaturePoints()) {
+                Color color = featurePoint.getValue();
+                Point3d point = featurePoint.getKey();
+                gl.glPushMatrix();
+                gl.glTranslated(point.x, point.y, point.z);
+                float[] rgba = {color.getRed() / 255f, color.getGreen() / 255f, 
+                    color.getBlue() / 255f , obj.getTransparency()};
+                gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_AMBIENT, rgba, 0);
+                gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, rgba, 0);
+                GLUquadric center = glu.gluNewQuadric();
+                glu.gluQuadricDrawStyle(center, GLU.GLU_FILL);
+                glu.gluQuadricNormals(center, GLU.GLU_FLAT);
+                glu.gluQuadricOrientation(center, GLU.GLU_OUTSIDE);
+                glu.gluSphere(center, 3f, 16, 16);
+                glu.gluDeleteQuadric(center);
+                gl.glPopMatrix();
+            }
+    }
+    
     /**
      * Clears the scene and prepares it for the re-drawing.
      */
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.form b/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.form
index 86cee818..7936d521 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.form
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.form
@@ -173,88 +173,85 @@
                           <Component id="jSeparator2" alignment="0" max="32767" attributes="0"/>
                           <Group type="103" alignment="1" groupAlignment="0" attributes="0">
                               <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
-                              <Component id="featurePointsButton" alignment="0" min="-2" max="-2" attributes="0"/>
                               <Component id="jSeparator1" alignment="0" min="-2" pref="385" max="-2" attributes="0"/>
                               <Group type="102" alignment="0" attributes="0">
                                   <Group type="103" groupAlignment="0" attributes="0">
                                       <Component id="secondaryLabel" alignment="0" min="-2" max="-2" attributes="0"/>
                                       <Component id="primaryLabel" alignment="0" min="-2" max="-2" attributes="0"/>
                                       <Component id="modelLabel" alignment="0" min="-2" max="-2" attributes="0"/>
-                                      <Component id="viewLabel" alignment="0" min="-2" max="-2" attributes="0"/>
                                   </Group>
+                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                                      <Component id="secondaryColorPanel" pref="50" max="32767" attributes="0"/>
+                                      <Component id="primaryColorPanel" pref="50" max="32767" attributes="0"/>
+                                      <Component id="colorButton" alignment="1" pref="50" max="32767" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace type="separate" max="-2" attributes="0"/>
                                   <Group type="103" groupAlignment="0" attributes="0">
-                                      <Group type="102" attributes="0">
-                                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                                          <Group type="103" groupAlignment="0" max="-2" attributes="0">
-                                              <Component id="secondaryColorPanel" pref="50" max="32767" attributes="0"/>
-                                              <Component id="primaryColorPanel" pref="50" max="32767" attributes="0"/>
-                                              <Component id="colorButton" alignment="1" pref="50" max="32767" attributes="0"/>
-                                          </Group>
-                                      </Group>
+                                      <Component id="highlightsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
                                       <Group type="102" alignment="0" attributes="0">
-                                          <EmptySpace min="-2" pref="16" max="-2" attributes="0"/>
-                                          <Component id="frontButton" min="-2" pref="50" max="-2" attributes="0"/>
+                                          <EmptySpace min="10" pref="10" max="-2" attributes="0"/>
+                                          <Group type="103" groupAlignment="0" attributes="0">
+                                              <Component id="primaryHighlightsCB" min="-2" max="-2" attributes="0"/>
+                                              <Component id="secondaryHighlightsCB" alignment="0" min="-2" max="-2" attributes="0"/>
+                                          </Group>
                                       </Group>
                                   </Group>
                                   <EmptySpace type="separate" max="-2" attributes="0"/>
                                   <Group type="103" groupAlignment="0" attributes="0">
-                                      <Group type="102" attributes="0">
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Component id="fillLabel" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace type="separate" max="-2" attributes="0"/>
+                                          <Component id="linesLabel" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                                          <Component id="pointsLabel" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <Group type="102" alignment="0" attributes="0">
                                           <Group type="103" groupAlignment="0" attributes="0">
-                                              <Component id="highlightsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
                                               <Group type="102" alignment="0" attributes="0">
-                                                  <EmptySpace min="10" pref="10" max="-2" attributes="0"/>
-                                                  <Group type="103" groupAlignment="0" attributes="0">
-                                                      <Component id="primaryHighlightsCB" min="-2" max="-2" attributes="0"/>
-                                                      <Component id="secondaryHighlightsCB" alignment="0" min="-2" max="-2" attributes="0"/>
-                                                  </Group>
+                                                  <Component id="secondaryFillRB" min="-2" max="-2" attributes="0"/>
+                                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                                  <Component id="secondaryLinesRB" min="-2" max="-2" attributes="0"/>
+                                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                                  <Component id="secondaryPointsRB" min="-2" max="-2" attributes="0"/>
                                               </Group>
-                                          </Group>
-                                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                                          <Group type="103" groupAlignment="0" attributes="0">
                                               <Group type="102" alignment="0" attributes="0">
-                                                  <Component id="fillLabel" min="-2" max="-2" attributes="0"/>
+                                                  <Component id="primaryFillRB" min="-2" max="-2" attributes="0"/>
+                                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                                  <Component id="primaryLinesRB" min="-2" max="-2" attributes="0"/>
                                                   <EmptySpace type="separate" max="-2" attributes="0"/>
-                                                  <Component id="linesLabel" min="-2" max="-2" attributes="0"/>
-                                                  <EmptySpace type="unrelated" max="-2" attributes="0"/>
-                                                  <Component id="pointsLabel" min="-2" max="-2" attributes="0"/>
+                                                  <Component id="primaryPointsRB" min="-2" max="-2" attributes="0"/>
+                                              </Group>
+                                              <Group type="102" alignment="0" attributes="0">
+                                                  <EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
+                                                  <Component id="renderModeLabel" min="-2" max="-2" attributes="0"/>
+                                              </Group>
+                                          </Group>
+                                          <Group type="103" groupAlignment="0" attributes="0">
+                                              <Group type="102" attributes="0">
+                                                  <EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
+                                                  <Component id="transparencySlider" min="-2" max="-2" attributes="0"/>
                                               </Group>
                                               <Group type="102" alignment="0" attributes="0">
-                                                  <Group type="103" groupAlignment="0" attributes="0">
-                                                      <Group type="102" alignment="0" attributes="0">
-                                                          <Component id="secondaryFillRB" min="-2" max="-2" attributes="0"/>
-                                                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                                                          <Component id="secondaryLinesRB" min="-2" max="-2" attributes="0"/>
-                                                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                                                          <Component id="secondaryPointsRB" min="-2" max="-2" attributes="0"/>
-                                                      </Group>
-                                                      <Group type="102" alignment="0" attributes="0">
-                                                          <Component id="primaryFillRB" min="-2" max="-2" attributes="0"/>
-                                                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                                                          <Component id="primaryLinesRB" min="-2" max="-2" attributes="0"/>
-                                                          <EmptySpace type="separate" max="-2" attributes="0"/>
-                                                          <Component id="primaryPointsRB" min="-2" max="-2" attributes="0"/>
-                                                      </Group>
-                                                      <Group type="102" alignment="0" attributes="0">
-                                                          <EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
-                                                          <Component id="renderModeLabel" min="-2" max="-2" attributes="0"/>
-                                                      </Group>
-                                                  </Group>
-                                                  <Group type="103" groupAlignment="0" attributes="0">
-                                                      <Group type="102" attributes="0">
-                                                          <EmptySpace min="-2" pref="25" max="-2" attributes="0"/>
-                                                          <Component id="transparencySlider" min="-2" max="-2" attributes="0"/>
-                                                      </Group>
-                                                      <Group type="102" alignment="0" attributes="0">
-                                                          <EmptySpace min="-2" pref="17" max="-2" attributes="0"/>
-                                                          <Component id="transparencyButton" min="-2" pref="50" max="-2" attributes="0"/>
-                                                      </Group>
-                                                  </Group>
+                                                  <EmptySpace min="-2" pref="17" max="-2" attributes="0"/>
+                                                  <Component id="transparencyButton" min="-2" pref="50" max="-2" attributes="0"/>
                                               </Group>
                                           </Group>
                                       </Group>
-                                      <Component id="profileButton" alignment="0" min="-2" pref="50" max="-2" attributes="0"/>
                                   </Group>
                               </Group>
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Component id="featurePointsLabel" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                  <Component id="featurePointsButton" min="-2" pref="50" max="-2" attributes="0"/>
+                              </Group>
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Component id="viewLabel" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                  <Component id="frontButton" min="-2" pref="50" max="-2" attributes="0"/>
+                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                  <Component id="profileButton" min="-2" pref="50" max="-2" attributes="0"/>
+                              </Group>
                           </Group>
                           <Component id="transformationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
                       </Group>
@@ -333,7 +330,10 @@
               <EmptySpace max="-2" attributes="0"/>
               <Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
-              <Component id="featurePointsButton" min="-2" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="featurePointsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="featurePointsButton" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
               <EmptySpace max="-2" attributes="0"/>
               <Component id="jSeparator7" min="-2" pref="10" max="-2" attributes="0"/>
               <EmptySpace max="-2" attributes="0"/>
@@ -414,7 +414,7 @@
                   <Component id="resetAllButton" alignment="3" min="-2" max="-2" attributes="0"/>
                   <Component id="applyButton" alignment="3" min="-2" max="-2" attributes="0"/>
               </Group>
-              <EmptySpace max="32767" attributes="0"/>
+              <EmptySpace pref="41" max="32767" attributes="0"/>
           </Group>
       </Group>
     </DimensionLayout>
@@ -1050,7 +1050,13 @@
         <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
           <ResourceString bundle="cz/fidentis/analyst/gui/tab/Bundle.properties" key="PostRegistrationCP.featurePointsButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
         </Property>
+        <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+          <Insets value="[0, 0, 0, 0]"/>
+        </Property>
       </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="featurePointsButtonActionPerformed"/>
+      </Events>
     </Component>
     <Component class="javax.swing.JLabel" name="jLabel2">
       <Properties>
@@ -1493,5 +1499,12 @@
         </Property>
       </Properties>
     </Component>
+    <Component class="javax.swing.JLabel" name="featurePointsLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="cz/fidentis/analyst/gui/tab/Bundle.properties" key="PostRegistrationCP.featurePointsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
   </SubComponents>
 </Form>
diff --git a/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.java b/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.java
index 271a6622..85315d01 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/gui/tab/PostRegistrationCP.java
@@ -133,6 +133,7 @@ public class PostRegistrationCP extends javax.swing.JPanel {
         secondaryPointsRB = new javax.swing.JRadioButton();
         primaryPointsRB = new javax.swing.JRadioButton();
         transformationLabel = new javax.swing.JLabel();
+        featurePointsLabel = new javax.swing.JLabel();
 
         setBackground(new java.awt.Color(176, 230, 226));
         setPreferredSize(new java.awt.Dimension(405, 600));
@@ -492,6 +493,12 @@ public class PostRegistrationCP extends javax.swing.JPanel {
         org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(PostRegistrationCP.class, "PostRegistrationCP.jLabel1.text")); // NOI18N
 
         org.openide.awt.Mnemonics.setLocalizedText(featurePointsButton, org.openide.util.NbBundle.getMessage(PostRegistrationCP.class, "PostRegistrationCP.featurePointsButton.text")); // NOI18N
+        featurePointsButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
+        featurePointsButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                featurePointsButtonActionPerformed(evt);
+            }
+        });
 
         org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(PostRegistrationCP.class, "PostRegistrationCP.jLabel2.text")); // NOI18N
 
@@ -726,6 +733,8 @@ public class PostRegistrationCP extends javax.swing.JPanel {
         transformationLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N
         org.openide.awt.Mnemonics.setLocalizedText(transformationLabel, org.openide.util.NbBundle.getMessage(PostRegistrationCP.class, "PostRegistrationCP.transformationLabel.text")); // NOI18N
 
+        org.openide.awt.Mnemonics.setLocalizedText(featurePointsLabel, org.openide.util.NbBundle.getMessage(PostRegistrationCP.class, "PostRegistrationCP.featurePointsLabel.text")); // NOI18N
+
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
         this.setLayout(layout);
         layout.setHorizontalGroup(
@@ -849,67 +858,67 @@ public class PostRegistrationCP extends javax.swing.JPanel {
                             .addComponent(jSeparator2)
                             .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                 .addComponent(jLabel1)
-                                .addComponent(featurePointsButton)
                                 .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 385, javax.swing.GroupLayout.PREFERRED_SIZE)
                                 .addGroup(layout.createSequentialGroup()
                                     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                         .addComponent(secondaryLabel)
                                         .addComponent(primaryLabel)
-                                        .addComponent(modelLabel)
-                                        .addComponent(viewLabel))
+                                        .addComponent(modelLabel))
+                                    .addGap(18, 18, 18)
+                                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                                        .addComponent(secondaryColorPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 50, Short.MAX_VALUE)
+                                        .addComponent(primaryColorPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 50, Short.MAX_VALUE)
+                                        .addComponent(colorButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 50, Short.MAX_VALUE))
+                                    .addGap(18, 18, 18)
                                     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                        .addComponent(highlightsLabel)
                                         .addGroup(layout.createSequentialGroup()
-                                            .addGap(18, 18, 18)
-                                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
-                                                .addComponent(secondaryColorPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 50, Short.MAX_VALUE)
-                                                .addComponent(primaryColorPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 50, Short.MAX_VALUE)
-                                                .addComponent(colorButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 50, Short.MAX_VALUE)))
-                                        .addGroup(layout.createSequentialGroup()
-                                            .addGap(16, 16, 16)
-                                            .addComponent(frontButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                                            .addGap(10, 10, 10)
+                                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                                .addComponent(primaryHighlightsCB)
+                                                .addComponent(secondaryHighlightsCB))))
                                     .addGap(18, 18, 18)
                                     .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                         .addGroup(layout.createSequentialGroup()
-                                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                                                .addComponent(highlightsLabel)
-                                                .addGroup(layout.createSequentialGroup()
-                                                    .addGap(10, 10, 10)
-                                                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                                                        .addComponent(primaryHighlightsCB)
-                                                        .addComponent(secondaryHighlightsCB))))
+                                            .addComponent(fillLabel)
                                             .addGap(18, 18, 18)
+                                            .addComponent(linesLabel)
+                                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                                            .addComponent(pointsLabel))
+                                        .addGroup(layout.createSequentialGroup()
                                             .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                 .addGroup(layout.createSequentialGroup()
-                                                    .addComponent(fillLabel)
+                                                    .addComponent(secondaryFillRB)
+                                                    .addGap(18, 18, 18)
+                                                    .addComponent(secondaryLinesRB)
+                                                    .addGap(18, 18, 18)
+                                                    .addComponent(secondaryPointsRB))
+                                                .addGroup(layout.createSequentialGroup()
+                                                    .addComponent(primaryFillRB)
                                                     .addGap(18, 18, 18)
-                                                    .addComponent(linesLabel)
-                                                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
-                                                    .addComponent(pointsLabel))
+                                                    .addComponent(primaryLinesRB)
+                                                    .addGap(18, 18, 18)
+                                                    .addComponent(primaryPointsRB))
                                                 .addGroup(layout.createSequentialGroup()
-                                                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                                                        .addGroup(layout.createSequentialGroup()
-                                                            .addComponent(secondaryFillRB)
-                                                            .addGap(18, 18, 18)
-                                                            .addComponent(secondaryLinesRB)
-                                                            .addGap(18, 18, 18)
-                                                            .addComponent(secondaryPointsRB))
-                                                        .addGroup(layout.createSequentialGroup()
-                                                            .addComponent(primaryFillRB)
-                                                            .addGap(18, 18, 18)
-                                                            .addComponent(primaryLinesRB)
-                                                            .addGap(18, 18, 18)
-                                                            .addComponent(primaryPointsRB))
-                                                        .addGroup(layout.createSequentialGroup()
-                                                            .addGap(14, 14, 14)
-                                                            .addComponent(renderModeLabel)))
-                                                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                                                        .addGroup(layout.createSequentialGroup()
-                                                            .addGap(25, 25, 25)
-                                                            .addComponent(transparencySlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
-                                                        .addGroup(layout.createSequentialGroup()
-                                                            .addGap(17, 17, 17)
-                                                            .addComponent(transparencyButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))))))
-                                        .addComponent(profileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))))
+                                                    .addGap(14, 14, 14)
+                                                    .addComponent(renderModeLabel)))
+                                            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                                .addGroup(layout.createSequentialGroup()
+                                                    .addGap(25, 25, 25)
+                                                    .addComponent(transparencySlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                                                .addGroup(layout.createSequentialGroup()
+                                                    .addGap(17, 17, 17)
+                                                    .addComponent(transparencyButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))))))
+                                .addGroup(layout.createSequentialGroup()
+                                    .addComponent(featurePointsLabel)
+                                    .addGap(18, 18, 18)
+                                    .addComponent(featurePointsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))
+                                .addGroup(layout.createSequentialGroup()
+                                    .addComponent(viewLabel)
+                                    .addGap(18, 18, 18)
+                                    .addComponent(frontButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
+                                    .addGap(18, 18, 18)
+                                    .addComponent(profileButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)))
                             .addComponent(transformationLabel))
                         .addGap(0, 0, Short.MAX_VALUE)))
                 .addContainerGap())
@@ -969,7 +978,9 @@ public class PostRegistrationCP extends javax.swing.JPanel {
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addComponent(featurePointsButton)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(featurePointsLabel)
+                    .addComponent(featurePointsButton))
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                 .addComponent(jSeparator7, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@@ -1042,7 +1053,7 @@ public class PostRegistrationCP extends javax.swing.JPanel {
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                     .addComponent(resetAllButton)
                     .addComponent(applyButton))
-                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addContainerGap(41, Short.MAX_VALUE))
         );
     }// </editor-fold>//GEN-END:initComponents
 
@@ -1329,11 +1340,22 @@ public class PostRegistrationCP extends javax.swing.JPanel {
         resetAllButtonActionPerformed(evt);
     }//GEN-LAST:event_applyButtonActionPerformed
 
+    private void featurePointsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_featurePointsButtonActionPerformed
+        if (listener.isFeaturePointsActive()) {
+            listener.setFeaturePointsActive(false);
+            featurePointsButton.setText("show");
+        } else {
+            listener.setFeaturePointsActive(true);
+            featurePointsButton.setText("hide");
+        }
+    }//GEN-LAST:event_featurePointsButtonActionPerformed
+
 
     // Variables declaration - do not modify//GEN-BEGIN:variables
     private javax.swing.JButton applyButton;
     private javax.swing.JButton colorButton;
     private javax.swing.JToggleButton featurePointsButton;
+    private javax.swing.JLabel featurePointsLabel;
     private javax.swing.JLabel fillLabel;
     private javax.swing.JButton frontButton;
     private javax.swing.JLabel highlightsLabel;
diff --git a/GUI/src/main/resources/cz/fidentis/analyst/gui/tab/Bundle.properties b/GUI/src/main/resources/cz/fidentis/analyst/gui/tab/Bundle.properties
index 165dbe5e..6812c229 100644
--- a/GUI/src/main/resources/cz/fidentis/analyst/gui/tab/Bundle.properties
+++ b/GUI/src/main/resources/cz/fidentis/analyst/gui/tab/Bundle.properties
@@ -23,7 +23,7 @@ PostRegistrationCP.profileButton.toolTipText=model profile view
 PostRegistrationCP.profileButton.text=side
 PostRegistrationCP.frontButton.toolTipText=model front view
 PostRegistrationCP.frontButton.text=front
-PostRegistrationCP.featurePointsButton.text=Feature points
+PostRegistrationCP.featurePointsButton.text=show
 PostRegistrationCP.viewLabel.text=View:
 PostRegistrationCP.modelLabel.text=Model:
 PostRegistrationCP.transparencyButton.toolTipText=reset transparency
@@ -87,3 +87,4 @@ PostRegistrationCP.primaryPointsRB.text=
 PostRegistrationCP.colorButton.toolTipText=reset colors
 PostRegistrationCP.colorButton.text=color
 PostRegistrationCP.transformationLabel.text=Transformation
+PostRegistrationCP.featurePointsLabel.text=Feature points:
-- 
GitLab