diff --git a/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java b/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java
index 1adce12f5c10f12798eddbb13e3809b29a6e5299..1d8f26378635695932a09f2c6631e91a57ec6885 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/BatchProcessor.java
@@ -71,7 +71,6 @@ public class BatchProcessor {
             HumanFace face = HumanFaceFactory.instance().getFace(faceId);
             SymmetryEstimator se = new SymmetryEstimator(this.symmetryConfig);
             face.getMeshModel().compute(se);
-            face.setSymmetryPlane(se.getSymmetryPlane(), se.getSymmetryPlaneMesh());
         }
     }
     
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 4ad68932a1073c8ac3c5490e7b35db98bb34e6f1..54f54923256c3b9c93ccbd356f56d38e70482b02 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
@@ -10,11 +10,13 @@ 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.MeshFacet;
 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;
+import cz.fidentis.analyst.visitors.mesh.BoundingBox;
+import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 
@@ -54,7 +56,8 @@ public class HumanFace implements Serializable {
 
     private Plane symmetryPlane;
     
-    private MeshFacet symmetryPlaneMesh;
+    //private MeshFacet symmetryPlaneMesh;
+    private BBox bbox;
 
     private List<FeaturePoint> featurePoints;
     
@@ -78,6 +81,10 @@ public class HumanFace implements Serializable {
         meshModel = MeshObjLoader.read(new FileInputStream(file));
         meshModel.simplifyModel();
         this.id = file.getCanonicalPath();
+        
+        BoundingBox visitor = new BoundingBox();
+        meshModel.compute(visitor);
+        bbox = visitor.getBoundingBox();
     }
     
     /**
@@ -101,6 +108,11 @@ 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));
     }
 
@@ -135,21 +147,13 @@ public class HumanFace implements Serializable {
     }
 
     /**
-     * Sets the symmetry plane. If both arguments are {@code null}, then removes the plane.
+     * 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}
-     * @param planeFacet The symmetry plane mesh; Must not be {@code null}
      */
-    public void setSymmetryPlane(Plane plane, MeshFacet planeFacet) {
-        if (plane == null) {
-            throw new IllegalArgumentException("plane");
-        }
-        if (planeFacet == null) {
-            throw new IllegalArgumentException("planeFacet");
-        }
+    public void setSymmetryPlane(Plane plane) {
         this.symmetryPlane = plane;
-        this.symmetryPlaneMesh = planeFacet;
         this.announceEvent(new SymmetryPlaneChangedEvent(this, getShortName(), this));
     }
 
@@ -161,8 +165,20 @@ public class HumanFace implements Serializable {
         return symmetryPlane;
     }
     
-    public MeshFacet getSymmetryPlaneFacet() {
-        return this.symmetryPlaneMesh;
+    /**
+     * 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);
+    }
+    
+    /**
+     * Returns bounding box of this face.
+     * @return bounding box of this face.
+     */
+    public BBox getBoundingBox() {
+        return bbox;
     }
 
     /**
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 6a46bc19962b9e0f6ca30397b137eea8390978e7..4516b41eec3f7160e1abc635bb502085860e4f51 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java
@@ -1,5 +1,7 @@
 package cz.fidentis.analyst.symmetry;
 
+import cz.fidentis.analyst.mesh.core.MeshRectangleFacet;
+import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import java.io.Serializable;
 import java.util.List;
 import javax.vecmath.Point3d;
@@ -33,7 +35,7 @@ public class Plane implements Serializable {
      * Constructor.
      * @param normal Normal vector of the plane
      * @param dist distance
-     * @throws IllegalArgumentExpcption if the @code{plane} argument is null
+     * @throws IllegalArgumentException if the @code{plane} argument is null
      */
     public Plane(Vector3d normal, double dist) {
         this(normal.x, normal.y, normal.z, dist);
@@ -42,7 +44,7 @@ public class Plane implements Serializable {
     /**
      * Copy constructor.
      * @param plane original plane
-     * @throws IllegalArgumentExpcption if the @code{plane} argument is null
+     * @throws IllegalArgumentException if the @code{plane} argument is null
      */
     public Plane(Plane plane) {
         this(plane.getNormal(), plane.getDistance());
@@ -52,7 +54,7 @@ public class Plane implements Serializable {
      * Creates average plane from existing planes.
      * 
      * @param planes Source planes
-     * @throws {@code IllegalArgumentException} the {@code planes} list is {@code null} or empty
+     * @throws IllegalArgumentException if the {@code planes} list is {@code null} or empty
      */
     public Plane(List<Plane> planes) {
         if (planes == null || planes.isEmpty()) {
@@ -121,6 +123,64 @@ public class Plane implements Serializable {
         this.distance += value;
     }
     
+    /**
+     * Returns rectangular mesh facet of this symmetry 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
+     * @return a rectangular mesh facet of this symmetry plane
+     * @throws NullPointerException if the {@code midPoint} is {@code null}
+     * @throws IllegalArgumentException if {@code width} or {@code height} are &lt;= 0
+     */
+    public MeshRectangleFacet getMesh(Point3d midPoint, double width, double height) {
+        if (width <= 0) {
+            throw new IllegalArgumentException("width");
+        }
+        
+        if (height <= 0) {
+            throw new IllegalArgumentException("height");
+        }
+        
+        double alpha = 
+                -((normal.x * midPoint.x) + 
+                  (normal.y * midPoint.y) + 
+                  (normal.z * midPoint.z) +
+                  distance) / (normal.dot(normal));
+        
+        Point3d midPointOnPlane = new Point3d(midPoint);
+        Vector3d nn = new Vector3d(normal);
+        nn.scale(alpha);
+        midPointOnPlane.add(nn);
+        
+        return new MeshRectangleFacet(midPointOnPlane, normal, width, height);
+    }
+    
+    /**
+     * Returns rectangular mesh facet of this symmetry plane.
+     * 
+     * @param midPoint A 3D point, which is projected to the plane and used as a center of the rectangular facet
+     * @param size Edge length
+     * @return a rectangular mesh facet of this symmetry plane
+     * @throws NullPointerException if the {@code midPoint} is {@code null}
+     * @throws IllegalArgumentException if {@code size} is &lt;= 0
+     */
+    public MeshRectangleFacet getMesh(Point3d midPoint, double size) {
+        return Plane.this.getMesh(midPoint, size, size);
+    }
+
+    /**
+     * Returns rectangular mesh facet of this symmetry plane. The centroid and size
+     * are estimated from bounding box.
+     * 
+     * @param bbox Bounding box
+     * @return a rectangular mesh facet of this symmetry plane
+     * @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());
+    }
+
     protected void setNormal(Vector3d normal) {
         this.normal = normal;
     }
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
index 38b451c5436318b2a1710a227e31d5cd14bfccc5..993c2996ec49e4f4f7bfee9da9b63bd7a1dd05e4 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/SymmetryEstimator.java
@@ -2,7 +2,6 @@ package cz.fidentis.analyst.symmetry;
 
 import cz.fidentis.analyst.mesh.MeshVisitor;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
-import cz.fidentis.analyst.mesh.core.MeshRectangleFacet;
 import cz.fidentis.analyst.visitors.mesh.BoundingBox;
 import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import java.util.ArrayList;
@@ -14,8 +13,6 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.vecmath.Point3d;
-import javax.vecmath.Vector3d;
 
 /**
  * Main class for computing approximate plane of symmetry of the 3D model.
@@ -92,56 +89,6 @@ public class SymmetryEstimator extends MeshVisitor {
         return symmetryPlane;
     }
     
-    /**
-     * Computes and returns a triangular mesh for the symmetry plane (a rectangle). 
-     * Its size is restricted by the bounding box of the original mesh facet.
-     * 
-     * @return mesh facet of the symmetry plane or {@code null}
-     */
-    public MeshFacet getSymmetryPlaneMesh() {
-        if (symmetryPlane == null) {
-            getSymmetryPlane(); // compute the symmetry plane
-        }
-        
-        BBox bbox = bbVisitor.getBoundingBox();
-        
-        Vector3d normal = symmetryPlane.getNormal();
-        Point3d midPoint = bbox.getMidPoint();
-
-        double alpha = 
-                -((normal.x * midPoint.x) + 
-                  (normal.y * midPoint.y) + 
-                  (normal.z * midPoint.z) +
-                  symmetryPlane.getDistance()) / (normal.dot(normal));
-        
-        Point3d midPointOnPlane = new Point3d(midPoint);
-        Vector3d nn = new Vector3d(normal);
-        nn.scale(alpha);
-        midPointOnPlane.add(nn);
-
-        double val = 
-                normal.x * midPointOnPlane.x + 
-                normal.y * midPointOnPlane.y + 
-                normal.z * midPointOnPlane.z + 
-                symmetryPlane.getDistance();
-
-        Vector3d frontDir = new Vector3d();
-        if (Math.abs(normal.dot(new Vector3d(0.0, 1.0, 0.0))) > Math.abs(normal.dot(new Vector3d (1.0, 0.0, 0.0)))) {
-            frontDir.cross(normal, new Vector3d(1.0, 0.0, 0.0));
-        } else {
-            frontDir.cross(normal, new Vector3d(0.0, 1.0, 0.0));
-        }
-        frontDir.normalize();
-
-        Vector3d upDir = new Vector3d();
-        upDir.cross(normal,frontDir);
-        upDir.normalize();
-        
-        double scale = bbox.getMaxPoint().x - bbox.getMinPoint().x;
-        
-        return new MeshRectangleFacet(midPointOnPlane, frontDir, upDir, symmetryPlane.getNormal(), 2*scale, 2*scale);
-    }
-    
     /**
      * Returns the bounding box computed during the {@link SymmetryEstimator#calculateSymmetryPlane}.
      * @return the bounding box or {@code null}
@@ -157,7 +104,7 @@ public class SymmetryEstimator extends MeshVisitor {
      */
     protected void calculateSymmetryPlane(boolean concurrently) {
         final List<Plane> planes = new ArrayList<>();
-        final double maxDistance = bbVisitor.getBoundingBox().getMaxDiag() * config.getMaxRelDistance();
+        final double maxDistance = bbVisitor.getBoundingBox().getDiagonalLength() * config.getMaxRelDistance();
         
         /*
          * Sequential computation
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/BoundingBox.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/BoundingBox.java
index 52a56159c03091c9c7e20b01579a9d371a98712e..a1d5efe5d9e6d2e5bc3ac4f70f5cb8a4f271fcc8 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/BoundingBox.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/BoundingBox.java
@@ -118,7 +118,7 @@ public class BoundingBox extends MeshVisitor {
          * Return volume diagonal of the bounding box.
          * @return maximal diagonal of bounding box
          */
-        public double getMaxDiag() {
+        public double getDiagonalLength() {
             Vector3d v = new Vector3d(maxPoint);
             v.sub(minPoint);
             return v.length();
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java
index 5b815eef88514684f645aa39d0456fec6b01ddee..befe27888118ed1a6b897713c5d1fc7c1214dc3e 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java
@@ -23,12 +23,12 @@ import java.util.stream.Collectors;
  * @author Radek Oslejsek
  */
 public class CrossSectionZigZag extends MeshVisitor {
-    private CrossSectionCurve curve;
-    private Set<Point3d> usedPoints;
+    private final CrossSectionCurve curve;
+    private final Set<Point3d> usedPoints;
     private Set<MeshTriangle> visited;
     private Set<MeshTriangle> toVisit;
 
-    private Plane plane;
+    private final Plane plane;
 
     /**
      * Constructor for CrossSectionZigZag visitor
@@ -37,7 +37,6 @@ public class CrossSectionZigZag extends MeshVisitor {
      */
     public CrossSectionZigZag(Plane plane) {
         this.plane = plane;
-        //this.points = new ArrayList<>();
         this.curve = new CrossSectionCurve();
         this.usedPoints = new HashSet<>();
     }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4f334e1ace5c5dab60871f3719bf5019ee983b5
--- /dev/null
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawableCuttingPlane.java
@@ -0,0 +1,121 @@
+package cz.fidentis.analyst.scene;
+
+import cz.fidentis.analyst.mesh.core.MeshFacet;
+import cz.fidentis.analyst.mesh.core.MeshFacetImpl;
+import cz.fidentis.analyst.symmetry.Plane;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
+
+/**
+ * Drawable plane with the possibility to shift it along the normal and,
+ * moreover, to show a "mirror" plane (a plane shifted in the opposite direction).
+ * 
+ * @author Radek Oslejsek
+ * @author Dominik Racek
+ */
+public class DrawableCuttingPlane extends DrawablePlane {
+    
+    private double shift = 0.0;
+    
+    /**
+     * Copy constructor.
+     * @param drPlane Original plane
+     * @throws NullPointException if the input argument is {@code null}
+     */
+    public DrawableCuttingPlane(DrawableCuttingPlane drPlane) {
+        super(drPlane);
+        this.shift = drPlane.shift;
+    }
+    
+    /**
+     * 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 &lt;= 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.
+     * 
+     * @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);
+            }
+        }
+    }
+    
+    /**
+     * Returns shifted cutting plane.
+     * @return shifted cutting plane.
+     */
+    @Override
+    public Plane getPlane() {
+        return new Plane(super.getPlane().getNormal(), super.getPlane().getDistance() + shift);
+    }
+    
+    /**
+     * Returns the cutting plane shifted to opposite direction.
+     * @return the cutting plane shifted to opposite direction
+     */
+    public Plane getMirrorPlane() {
+        return new Plane(super.getPlane().getNormal(), super.getPlane().getDistance() - shift);
+    }
+    
+    /**
+     * Shows/hides the mirror plane (i.e., the cutting plane shifted in the opposite direction
+     * @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);
+        }
+    }
+    
+    /**
+     * Returns {@code true} if the mirror planes are set to be shown.
+     * @return {@code true} if the mirror planes are set to be shown.
+     */
+    public boolean isMirrorPlaneShown() {
+        return getModel().getFacets().size() > 1;
+    }
+}
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 2c7aa70d56275da41e0428d266e2b018b3047506..7999836ca817a0e3bd6b3ffab87a770066c3e1e3 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java
@@ -3,13 +3,13 @@ package cz.fidentis.analyst.scene;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshModel;
 import cz.fidentis.analyst.symmetry.Plane;
-
-import javax.vecmath.Vector3d;
+import javax.vecmath.Point3d;
 
 /**
- * A cutting plane.
+ * A plane to be shown as a rectangular mesh facet.
  * 
  * @author Radek Oslejsek
+ * @author Dominik Racek
  */
 public class DrawablePlane extends DrawableMesh {
     
@@ -50,25 +50,24 @@ public class DrawablePlane extends DrawableMesh {
         }
         this.plane = new Plane(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 &lt;= 0
+     */
+    public DrawablePlane(Plane plane, Point3d midPoint, double width, double height) {
+        super(plane.getMesh(midPoint, width, height));
+        this.plane = new Plane(plane);
+    }
 
     public Plane getPlane() {
         return plane;
     }
 
-    /**
-     * Translate the plane along its normal
-     *
-     * @param value
-     */
-    public void translatePlane(double value) {
-        // Move real plane
-        this.plane.translate(value);
-        
-        // Move Drawable plane
-        Vector3d move = this.plane.getNormal();
-        move.scale(value);
-        for (int i = 0; i < 4; ++i) {
-            getFacets().get(0).getVertex(i).getPosition().sub(move);
-        }
-    }    
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
index 060500597ebdea48be367bd53b8fb931b1d85dae..62e3ed8d30817e2ff2d24cf44a391906fea48ed0 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
@@ -14,11 +14,11 @@ import java.util.List;
 public class Scene {
     
     private final List<HumanFace> faces = new ArrayList<>();
+    
     private final List<DrawableFace> drawableFaces = new ArrayList<>();
     private final List<DrawableFeaturePoints> drawableFeaturePoints = new ArrayList<>();
     private final List<DrawablePlane> drawableSymmetryPlanes = new ArrayList<>();
-    private final List<DrawablePlane> drawableCuttingPlanes = new ArrayList<>();
-    private final List<DrawablePlane> drawableMirrorPlanes = new ArrayList<>();
+    private final List<DrawableCuttingPlane> drawableCuttingPlanes = new ArrayList<>();
     private final List<Drawable> otherDrawables = new ArrayList<>();
     
     /**
@@ -41,7 +41,6 @@ public class Scene {
         }
         drawableSymmetryPlanes.add(null);
         drawableCuttingPlanes.add(null);
-        drawableMirrorPlanes.add(null);
         
         setDefaultColors();
     }
@@ -80,12 +79,10 @@ public class Scene {
 
         drawableSymmetryPlanes.add(null);
         drawableCuttingPlanes.add(null);
-        drawableMirrorPlanes.add(null);
-
+        
         drawableSymmetryPlanes.add(null);
         drawableCuttingPlanes.add(null);
-        drawableMirrorPlanes.add(null);
-
+        
         setDefaultColors();
     }
     
@@ -212,8 +209,8 @@ public class Scene {
      * @param index Index of the face
      * @return drawable plane or {@code null}
      */
-    public DrawablePlane getDrawableCuttingPlane(int index) {
-        return (index >= 0 && index < getNumFaces()) ? drawableCuttingPlanes.get(index) : null;
+    public DrawableCuttingPlane getDrawableCuttingPlane(int index) {
+        return (index >= 0 && index < drawableCuttingPlanes.size()) ? drawableCuttingPlanes.get(index) : null;
     }
 
     /**
@@ -222,18 +219,19 @@ public class Scene {
      * @param index Index of the face
      * @param cPlane New cutting plane
      */
-    public void setDrawableCuttingPlane(int index, DrawablePlane cPlane) {
-        if (index >= 0 && index < getNumFaces() && cPlane != null) {
+    public void setDrawableCuttingPlane(int index, DrawableCuttingPlane cPlane) {
+        if (index >= 0 && index < drawableCuttingPlanes.size() && cPlane != null) {
             this.drawableCuttingPlanes.set(index, cPlane);
         }
     }
 
     /**
-     * Helper function for showing or hiding all cutting planes
+     * Show/hide cutting planes and their mirrors
      *
      * @param show determines whether to hide or show the planes
+     * @param show determines whether to hide or show the mirror planes
      */
-    private void hideShowCuttingPlanes(boolean show) {
+    public void showCuttingPlanes(boolean show, boolean showMirrors) {
         for (int i = 0; i < drawableCuttingPlanes.size(); ++i) {
             if (drawableCuttingPlanes.get(i) != null) {
                 if (show) {
@@ -241,77 +239,11 @@ public class Scene {
                 } else {
                     drawableCuttingPlanes.get(i).hide();
                 }
+                drawableCuttingPlanes.get(i).showMirrorPlane(showMirrors);
             }
         }
     }
 
-    /**
-     * Show all cutting planes
-     */
-    public void showCuttingPlanes() {
-        hideShowCuttingPlanes(true);
-    }
-
-    /**
-     * Hide all cutting planes
-     */
-    public void hideCuttingPlanes() {
-        hideShowCuttingPlanes(false);
-    }
-
-    /**
-     * Returns drawable mirror plane.
-     *
-     * @param index Index of the face
-     * @return drawable face or {@code null}
-     */
-    public DrawablePlane getDrawableMirrorPlane(int index) {
-        return (index >= 0 && index < getNumFaces()) ? drawableMirrorPlanes.get(index) : null;
-    }
-
-    /**
-     * Sets the drawable mirror plane.
-     *
-     * @param index Index of the face
-     * @param mPlane New mirror plane
-     */
-    public void setDrawableMirrorPlane(int index, DrawablePlane mPlane) {
-        if (index >= 0 && index < getNumFaces() && mPlane != null) {
-            this.drawableMirrorPlanes.set(index, mPlane);
-        }
-    }
-
-    /**
-     * Helper function for showing or hiding all mirror planes
-     *
-     * @param show determines whether to hide or show the planes
-     */
-    private void hideShowMirrorPlanes(boolean show) {
-        for (int i = 0; i < drawableMirrorPlanes.size(); ++i) {
-            if (drawableMirrorPlanes.get(i) != null) {
-                if (show) {
-                    drawableMirrorPlanes.get(i).show();
-                } else {
-                    drawableMirrorPlanes.get(i).hide();
-                }
-            }
-        }
-    }
-
-    /**
-     * Show all mirror planes
-     */
-    public void showMirrorPlanes() {
-        hideShowMirrorPlanes(true);
-    }
-
-    /**
-     * Hide all mirror planes
-     */
-    public void hideMirrorPlanes() {
-        hideShowMirrorPlanes(false);
-    }
-
     /**
      * Adds new drawable object to the scene.
      * 
@@ -337,7 +269,6 @@ public class Scene {
         ret.addAll(this.drawableFeaturePoints);
         ret.addAll(this.drawableSymmetryPlanes);
         ret.addAll(this.drawableCuttingPlanes);
-        ret.addAll(this.drawableMirrorPlanes);
         ret.addAll(this.otherDrawables);
         while (ret.remove(null)) {}
         return ret;
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java
index 7c30646625bc75f9fd37e0ae5790657a09222799..73a34c4ac9cfe771db4b9338590a74cda92c8080 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/CurveRenderingPanel.java
@@ -9,7 +9,6 @@ import java.awt.Graphics2D;
 import java.awt.Stroke;
 import java.awt.geom.Ellipse2D;
 import java.awt.geom.Line2D;
-import java.util.ArrayList;
 import java.util.List;
 import javax.swing.JPanel;
 import javax.vecmath.Point3d;
@@ -156,7 +155,6 @@ public class CurveRenderingPanel extends JPanel {
 
     protected void drawCurveSegment(Graphics2D g2, List<Point3d> curveSegment, Color faceColor, double offsetZ) {
         //Draw lines
-        List<Ellipse2D.Double> points = new ArrayList<>();
         g2.setColor(faceColor);
         g2.setStroke(GRAPH_STROKE);
         for (int i = 0; i < curveSegment.size() - 1; i++) {
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 a611171c9e3a7b6cfe292cbe8e4a64ed8214ff96..b9506962a17618bd868d959daf094fbcda544a8d 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
@@ -9,9 +9,8 @@ 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.mesh.core.MeshRectangleFacet;
-import cz.fidentis.analyst.scene.DrawablePlane;
-import cz.fidentis.analyst.visitors.mesh.BoundingBox;
+import cz.fidentis.analyst.scene.DrawableCuttingPlane;
+import cz.fidentis.analyst.visitors.mesh.BoundingBox.BBox;
 import cz.fidentis.analyst.visitors.mesh.CrossSectionZigZag;
 import org.openide.filesystems.FileChooserBuilder;
 
@@ -85,19 +84,14 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
             // If the symmetry panel is focused...
             if (((JTabbedPane) e.getSource()).getSelectedComponent() instanceof ProfilesPanel) {
                 getCanvas().getScene().setDefaultColors();
-                getCanvas().getScene().showCuttingPlanes();
-                if (controlPanel.isMirrorCutsChecked()) {
-                    getCanvas().getScene().showMirrorPlanes();
-                }
+                getCanvas().getScene().showCuttingPlanes(true, controlPanel.isMirrorCutsChecked());
                 recomputeProfiles();
             } else {
-                getCanvas().getScene().hideCuttingPlanes();
-                getCanvas().getScene().hideMirrorPlanes();
+                getCanvas().getScene().showCuttingPlanes(false, false);
             }
         });
         
-        getCanvas().getScene().hideCuttingPlanes();
-        getCanvas().getScene().hideMirrorPlanes();
+        getCanvas().getScene().showCuttingPlanes(false, false);
         
         // Be informed about changes in faces perfomed by other GUI elements
         getPrimaryDrawableFace().getHumanFace().registerListener(this);
@@ -142,7 +136,12 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
                 
                 if (option.equals(ProfilesPanel.OPTION_SYMMETRY_PLANE)) {
                     if (getScene().getDrawableSymmetryPlane(0) == null) {
-                       JOptionPane.showMessageDialog(new JFrame(), "Compute a symmetry plane at the Symmetry tab first.", "Dialog", JOptionPane.INFORMATION_MESSAGE);
+                       JOptionPane.showMessageDialog(
+                               new JFrame(), 
+                               "Compute a symmetry plane at the Symmetry tab first.", 
+                               "Dialog", 
+                               JOptionPane.INFORMATION_MESSAGE
+                       );
                        controlPanel.setDefaultPlaneSelection();
                        return;
                     }
@@ -153,21 +152,12 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
                     computeOrthogonalCuttingPlanes(false);
                 }
                 
-                if (controlPanel.isMirrorCutsChecked()) {
-                    getCanvas().getScene().showMirrorPlanes();
-                } else {
-                    getCanvas().getScene().hideMirrorPlanes();
-                }
-
+                getCanvas().getScene().showCuttingPlanes(true, controlPanel.isMirrorCutsChecked());
                 recomputeProfiles();
                 break;
             case ProfilesPanel.ACTION_MIRROR_CUTS:
                 controlPanel.getProfileRenderingPanel().setMirrorCuts(controlPanel.isMirrorCutsChecked());
-                if (controlPanel.isMirrorCutsChecked()) {
-                    getCanvas().getScene().showMirrorPlanes();
-                } else {
-                    getCanvas().getScene().hideMirrorPlanes();
-                }
+                getCanvas().getScene().showCuttingPlanes(true, controlPanel.isMirrorCutsChecked());
                 break;
             default:
                 // do nothing
@@ -178,12 +168,9 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
     @Override
     public void acceptEvent(HumanFaceEvent event) {
         if (event instanceof SymmetryPlaneChangedEvent && cuttingPlaneFromSymmetry) {
+            controlPanel.resetSliderSilently();
             computeCuttingPlanesFromSymmetry(); // recompute cutting planes
-            if (controlPanel.isMirrorCutsChecked()) {
-                getCanvas().getScene().showMirrorPlanes();
-            } else {
-                getCanvas().getScene().hideMirrorPlanes();
-            }
+            //getCanvas().getScene().showCuttingPlanes(false, controlPanel.isMirrorCutsChecked());
         }
     }
 
@@ -232,7 +219,7 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
         this.primaryCurve = cs.getCrossSectionCurve();
 
         //Mirror profile
-        CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(0).getPlane());
+        CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(0).getMirrorPlane());
         getPrimaryDrawableFace().getModel().compute(mcs);
         this.primaryMirrorCurve = mcs.getCrossSectionCurve();
     }
@@ -244,7 +231,7 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
         this.secondaryCurve = cs.getCrossSectionCurve();
 
         //Mirror profile
-        CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(1).getPlane());
+        CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(1).getMirrorPlane());
         getSecondaryDrawableFace().getModel().compute(mcs);
         this.secondaryMirrorCurve = mcs.getCrossSectionCurve();
     }
@@ -281,15 +268,9 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
         //Move cutting planes left and mirror planes right
         //If normal is negative, need to negate value
         if (getScene().getDrawableCuttingPlane(index).getPlane().getNormal().x < 0) {
-            getScene().getDrawableCuttingPlane(index).translatePlane(-value);
+            getScene().getDrawableCuttingPlane(index).shift(-value);
         } else {
-            getScene().getDrawableCuttingPlane(index).translatePlane(value);
-        }
-        
-        if (getScene().getDrawableMirrorPlane(index).getPlane().getNormal().x < 0) {
-            getScene().getDrawableMirrorPlane(index).translatePlane(value);
-        } else {
-            getScene().getDrawableMirrorPlane(index).translatePlane(-value);
+            getScene().getDrawableCuttingPlane(index).shift(value);
         }
     }
     
@@ -299,58 +280,26 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
      * @param horizontal 
      */
     protected void computeOrthogonalCuttingPlanes(boolean horizontal) {
-        DrawablePlane drPlane = getDrawableOrthogonalPlane(horizontal);
+        DrawableCuttingPlane drPlane = getDrawableOrthogonalPlane(horizontal);
         getCanvas().getScene().setDrawableCuttingPlane(0, drPlane);
-        getCanvas().getScene().setDrawableMirrorPlane(0, new DrawablePlane(drPlane));
         if (getSecondaryDrawableFace() != null) {
-            getCanvas().getScene().setDrawableCuttingPlane(1, new DrawablePlane(drPlane));
-            getCanvas().getScene().setDrawableMirrorPlane(1, new DrawablePlane(drPlane));
+            getCanvas().getScene().setDrawableCuttingPlane(1, new DrawableCuttingPlane(drPlane));
         }
         cuttingPlaneFromSymmetry = false;
     }
     
-    protected DrawablePlane getDrawableOrthogonalPlane(boolean horizontal) {
-        BoundingBox bbox = new BoundingBox();
-        getPrimaryDrawableFace().getModel().compute(bbox);
-        if (getSecondaryDrawableFace() != null) {
-            getSecondaryDrawableFace().getModel().compute(bbox);
-        }
-        
-        Vector3d normal = (horizontal) ? new Vector3d(0,1,0) : new Vector3d(-1,0,0);
-        Point3d midPoint = bbox.getBoundingBox().getMidPoint();
-        Point3d minPoint = bbox.getBoundingBox().getMinPoint();
-        Point3d maxPoint = bbox.getBoundingBox().getMaxPoint();
-        
-        // add border:
-        Vector3d diagonal = new Vector3d(maxPoint);
-        diagonal.sub(minPoint);
-        diagonal.scale(0.15); // border size
-        maxPoint.add(diagonal);
-        diagonal.scale(-1);
-        minPoint.add(diagonal);
-        
-        Plane plane = new Plane(normal, (horizontal) ? midPoint.y : midPoint.x);
-        
-        MeshRectangleFacet planeMesh;
-        if (horizontal) {
-            planeMesh = new MeshRectangleFacet(
-                    midPoint,
-                    new Vector3d(1, 0, 0),
-                    new Vector3d(0, 0, 1),
-                    maxPoint.x - minPoint.x,
-                    maxPoint.z - minPoint.z
-            );
-        } else {
-            planeMesh = new MeshRectangleFacet(
-                    midPoint,
-                    new Vector3d(0, 0, 1),
-                    new Vector3d(0, 1, 0),
-                    maxPoint.z - minPoint.z,
-                    maxPoint.y - minPoint.y
-            );
-        }
-
-        DrawablePlane cuttingPlane = new DrawablePlane(planeMesh, plane);
+    protected DrawableCuttingPlane getDrawableOrthogonalPlane(boolean horizontal) {
+        BBox bbox = getScene().getHumanFace(0).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;
     }
@@ -361,34 +310,32 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
      * @param faceIndex
      * @return 
      */
-    protected DrawablePlane getCuttingPlaneFromSymmetry(int faceIndex) {
+    protected DrawableCuttingPlane getCuttingPlaneFromSymmetry(int faceIndex) {
         MeshFacet symmetryFacet = getScene().getHumanFace(faceIndex).getSymmetryPlaneFacet();
         Plane symmetryPlane = getScene().getHumanFace(faceIndex).getSymmetryPlane();
-        return new DrawablePlane(new MeshFacetImpl(symmetryFacet), new Plane(symmetryPlane));
+        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() {
-        DrawablePlane cuttingPlane = getCuttingPlaneFromSymmetry(0);
+        DrawableCuttingPlane cuttingPlane = getCuttingPlaneFromSymmetry(0);
         cuttingPlane.setTransparency(0.5f);
         getCanvas().getScene().setDrawableCuttingPlane(0, cuttingPlane);
-        getCanvas().getScene().setDrawableMirrorPlane(0, new DrawablePlane(cuttingPlane));
         recomputePrimaryProfile();
         
         if (getSecondaryDrawableFace() != null) {
             cuttingPlane = getCuttingPlaneFromSymmetry(1);
             cuttingPlane.setTransparency(0.5f);
             getCanvas().getScene().setDrawableCuttingPlane(1, cuttingPlane);
-            getCanvas().getScene().setDrawableMirrorPlane(1, new DrawablePlane(cuttingPlane));
             recomputeSecondaryProfile();
         }
         cuttingPlaneFromSymmetry = true;
     }
 
     protected void projectCloseFeaturePoints(CrossSectionCurve curve, HumanFace face, Plane cuttingPlane) {
-        if (!face.hasFeaturePoints()) {
+        if (!face.hasFeaturePoints() || curve.getNumSegments() == 0) {
             return;
         }
         List<Point3d> close = face.getFeaturePoints()
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 793552f59eb682f3297e5e5be1916f3bd5bc931b..610426d58b88a422e20f37fb0920a0c3f08c33f2 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java
@@ -3,14 +3,20 @@ package cz.fidentis.analyst.symmetry;
 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.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.scene.DrawableFace;
 import cz.fidentis.analyst.scene.DrawablePlane;
 
 import java.awt.event.ActionEvent;
+import java.util.HashMap;
+import java.util.Map;
 import javax.swing.JTabbedPane;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
 
 /**
  * Action listener for the manipulation with the symmetry plane.
@@ -33,6 +39,8 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
         this.topControlPanel = topControlPanel;
         //this.controlPanel = new SymmetryPanel(this);
         this.controlPanel = new SymmetryPanel(this);
+        
+        controlPanel.setComputeFromFPs(getPrimaryFeaturePoints() != null || getSecondaryFeaturePoints() != null);
 
         // Place control panel to the topControlPanel
         this.topControlPanel.addTab(controlPanel.getName(), controlPanel.getIcon(), controlPanel);
@@ -46,9 +54,6 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
             }
         });
 
-        //recomputeSymmetryPlane(0);
-        //recomputeSymmetryPlane(1);
-        
         // Be informed about changes in faces perfomed by other GUI elements
         getPrimaryDrawableFace().getHumanFace().registerListener(this);
         if (getSecondaryDrawableFace() != null) {
@@ -64,7 +69,11 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
             case SymmetryPanel.ACTION_COMMAND_RECOMPUTE: 
                 recomputeSymmetryPlane(0);
                 recomputeSymmetryPlane(1);
-                break;  
+                break; 
+            case SymmetryPanel.ACTION_COMMAND_COMPUTE_FROM_FPS: 
+                computeFromFeaturePoints(0);
+                computeFromFeaturePoints(1);
+                break;     
             default:
                 // do nothing
         }
@@ -82,24 +91,88 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
         }    
     }
     
-    private void recomputeSymmetryPlane(int index) {
-        DrawableFace face = getCanvas().getScene().getDrawableFace(index);
+    protected void recomputeSymmetryPlane(int index) {
+        HumanFace face = getCanvas().getScene().getHumanFace(index);
+        if (face != null) {
+            Logger log = Logger.measureTime();
+            SymmetryEstimator estimator = new SymmetryEstimator(controlPanel.getSymmetryConfig());        
+            face.getMeshModel().compute(estimator);
+            face.setSymmetryPlane(estimator.getSymmetryPlane());
+            log.printDuration("Symmetry plane estimation for " + face.getShortName());
+            setDrawablePlane(face, index);
+        }
+    }
+    
+    protected void computeFromFeaturePoints(int index) {
+        HumanFace face = getCanvas().getScene().getHumanFace(index);
         if (face == null) {
             return;
         }
         
-        Logger log = Logger.measureTime();
-        SymmetryEstimator estimator = new SymmetryEstimator(controlPanel.getSymmetryConfig());        
-        face.getModel().compute(estimator);
-        face.getHumanFace().setSymmetryPlane(estimator.getSymmetryPlane(), estimator.getSymmetryPlaneMesh());
-        log.printDuration("Symmetry plane estimation for " + face.getHumanFace().getShortName());
+        //FeaturePointTypeProvider.getInstance();
+        Map<String, Point3d> processFP = new HashMap<>();
+        Vector3d dir = new Vector3d();
+        int numDirs = 0;
+        Point3d centroid = new Point3d();
+        
+        for (FeaturePoint fp: face.getFeaturePoints()) {
+            Point3d auxCentroid = new Point3d(fp.getPosition());
+                auxCentroid.scale(1.0 / face.getFeaturePoints().size());
+            if (numDirs == 0) {
+                centroid.set(auxCentroid);
+            } else {
+                
+                centroid.add(auxCentroid);
+            }
 
+            String code = fp.getFeaturePointType().getCode();
+            if (code.endsWith("_R")) {
+                String pairCode = code.replaceAll("_R", "_L");
+                if (processFP.containsKey(pairCode)) {
+                    computeDir(processFP.remove(pairCode), fp.getPosition(), dir, numDirs++);
+                } else {
+                    processFP.put(code, fp.getPosition());
+                }
+            } else if (code.endsWith("_L")) {
+                String pairCode = code.replaceAll("_L", "_R");
+                if (processFP.containsKey(pairCode)) {
+                    computeDir(fp.getPosition(), processFP.remove(pairCode), dir, numDirs++);
+                } else {
+                    processFP.put(code, fp.getPosition());
+                }                
+            }
+        }
+        
+        if (numDirs == 0) { // no pair found
+            return;
+        }
+        
+        dir.scale(1.0 / numDirs);
+        dir.normalize();
+        
+        face.setSymmetryPlane(new Plane(dir, dir.dot(new Vector3d(centroid))));
+        setDrawablePlane(face, index);
+    }
+    
+    protected void computeDir(Point3d left, Point3d right, Vector3d dir, int numDirs) {
+        Vector3d auxDir = new Vector3d(right);
+        auxDir.sub(left);
+        auxDir.normalize();
+        if (numDirs == 0) {
+            dir.set(auxDir);
+        } else {
+            dir.add(auxDir);
+        }
+    }
+
+    protected void setDrawablePlane(HumanFace face, int index) {
         DrawablePlane symmetryPlane = new DrawablePlane(
-                face.getHumanFace().getSymmetryPlaneFacet(),
-                face.getHumanFace().getSymmetryPlane()
+                face.getSymmetryPlaneFacet(),
+                face.getSymmetryPlane()
         );
         symmetryPlane.setTransparency(0.5f);
         symmetryPlane.setColor((index == 0) ? DrawableFace.SKIN_COLOR_PRIMARY.darker() : DrawableFace.SKIN_COLOR_SECONDARY.darker());
         getCanvas().getScene().setDrawableSymmetryPlane(index, symmetryPlane);
     }
+    
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.form b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.form
index 0ad51283523e82bebed4b0ea961cdd347add187f..7b7730230d14a3f4ec7a4500de0918caf3b9fefb 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.form
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.form
@@ -16,15 +16,11 @@
   <Layout>
     <DimensionLayout dim="0">
       <Group type="103" groupAlignment="0" attributes="0">
-          <Group type="102" alignment="0" attributes="0">
+          <Group type="102" attributes="0">
               <EmptySpace max="-2" attributes="0"/>
               <Group type="103" groupAlignment="0" attributes="0">
-                  <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
-                  <Group type="102" attributes="0">
-                      <Component id="jButton1" min="-2" max="-2" attributes="0"/>
-                      <EmptySpace max="-2" attributes="0"/>
-                      <Component id="jButton2" min="-2" max="-2" attributes="0"/>
-                  </Group>
+                  <Component id="jPanel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButton3" alignment="0" min="-2" max="-2" attributes="0"/>
               </Group>
               <EmptySpace max="32767" attributes="0"/>
           </Group>
@@ -35,12 +31,9 @@
           <Group type="102" alignment="0" attributes="0">
               <EmptySpace max="-2" attributes="0"/>
               <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
-              <EmptySpace max="-2" attributes="0"/>
-              <Group type="103" groupAlignment="3" attributes="0">
-                  <Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
-                  <Component id="jButton2" alignment="3" min="-2" max="-2" attributes="0"/>
-              </Group>
-              <EmptySpace max="32767" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Component id="jButton3" min="-2" max="-2" attributes="0"/>
+              <EmptySpace pref="22" max="32767" attributes="0"/>
           </Group>
       </Group>
     </DimensionLayout>
@@ -50,7 +43,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="Configuration">
+            <TitledBorder title="Symmetry from mesh">
               <ResourceString PropertyName="titleX" bundle="cz/fidentis/analyst/symmetry/Bundle.properties" key="SymmetryPanel.jPanel1.border.title_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
               <Font PropertyName="font" name="Dialog" size="14" style="1"/>
             </TitledBorder>
@@ -81,7 +74,6 @@
                           </Group>
                           <EmptySpace max="-2" attributes="0"/>
                           <Group type="103" groupAlignment="0" attributes="0">
-                              <Component id="comboSliderDouble4" alignment="0" min="-2" max="-2" attributes="0"/>
                               <Group type="102" alignment="0" attributes="0">
                                   <Group type="103" groupAlignment="0" attributes="0">
                                       <Group type="103" alignment="0" groupAlignment="0" attributes="0">
@@ -101,6 +93,14 @@
                                       <Component id="jButtonInfo3" min="-2" max="-2" attributes="0"/>
                                   </Group>
                               </Group>
+                              <Group type="103" alignment="0" groupAlignment="1" attributes="0">
+                                  <Group type="102" attributes="0">
+                                      <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Component id="jButton2" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <Component id="comboSliderDouble4" min="-2" max="-2" attributes="0"/>
+                              </Group>
                           </Group>
                       </Group>
                   </Group>
@@ -168,12 +168,16 @@
                           <Component id="jButtonInfo4" min="-2" max="-2" attributes="0"/>
                       </Group>
                   </Group>
-                  <EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
+                  <EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
                   <Group type="103" groupAlignment="1" attributes="0">
                       <Component id="jLabel6" min="-2" max="-2" attributes="0"/>
                       <Component id="jCheckBox1" min="-2" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jButton1" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jButton2" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
                   </Group>
-                  <EmptySpace pref="28" max="32767" attributes="0"/>
+                  <EmptySpace max="32767" attributes="0"/>
               </Group>
           </Group>
         </DimensionLayout>
@@ -283,24 +287,31 @@
             <Property name="borderPainted" type="boolean" value="false"/>
           </Properties>
         </Component>
+        <Component class="javax.swing.JButton" name="jButton1">
+          <Properties>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="cz/fidentis/analyst/symmetry/Bundle.properties" key="SymmetryPanel.jButton1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="jButton2">
+          <Properties>
+            <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+              <ResourceString bundle="cz/fidentis/analyst/symmetry/Bundle.properties" key="SymmetryPanel.jButton2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton2ActionPerformed"/>
+          </Events>
+        </Component>
       </SubComponents>
     </Container>
-    <Component class="javax.swing.JButton" name="jButton1">
-      <Properties>
-        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString bundle="cz/fidentis/analyst/symmetry/Bundle.properties" key="SymmetryPanel.jButton1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
-        </Property>
-      </Properties>
-    </Component>
-    <Component class="javax.swing.JButton" name="jButton2">
+    <Component class="javax.swing.JButton" name="jButton3">
       <Properties>
         <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
-          <ResourceString bundle="cz/fidentis/analyst/symmetry/Bundle.properties" key="SymmetryPanel.jButton2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+          <ResourceString bundle="cz/fidentis/analyst/symmetry/Bundle.properties" key="SymmetryPanel.jButton3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
         </Property>
       </Properties>
-      <Events>
-        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton2ActionPerformed"/>
-      </Events>
     </Component>
   </SubComponents>
 </Form>
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.java
index 0e2bd223afafba80a7180dd7934e2e06b7bdd01c..bd5a82602d5086ae26a589ad67b583f82a119039 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryPanel.java
@@ -18,6 +18,7 @@ public class SymmetryPanel extends ControlPanel  {
      * Handled actions
      */
     public static final String ACTION_COMMAND_RECOMPUTE = "recompute";
+    public static final String ACTION_COMMAND_COMPUTE_FROM_FPS = "compute from FPs";
     
     /*
      * Mandatory design elements
@@ -132,6 +133,16 @@ public class SymmetryPanel extends ControlPanel  {
                     this.showNormalAngleHelp();
                 }
         );
+        
+        jButton3.addActionListener(
+                (ActionEvent e) -> { 
+                    action.actionPerformed(new ActionEvent( // compute from FPs
+                            e.getSource(), 
+                            ActionEvent.ACTION_PERFORMED, 
+                            ACTION_COMMAND_COMPUTE_FROM_FPS)
+                    ); 
+                }
+        );
     }
     
     @Override
@@ -155,6 +166,14 @@ public class SymmetryPanel extends ControlPanel  {
     public static ImageIcon getStaticIcon() {
         return new ImageIcon(SymmetryPanel.class.getClassLoader().getResource("/" + ICON));
     }
+
+    /**
+     * Enables/disables the button for the computation of the symmetry from feature points.
+     * @param on {@code true} = enable
+     */
+    public void setComputeFromFPs(boolean on) {
+        jButton3.setEnabled(on);
+    }
     
     private void showSignPointsHelp() {
         JOptionPane.showMessageDialog(this,
@@ -251,6 +270,7 @@ public class SymmetryPanel extends ControlPanel  {
         jButtonInfo3 = new javax.swing.JButton();
         jButton1 = new javax.swing.JButton();
         jButton2 = new javax.swing.JButton();
+        jButton3 = new javax.swing.JButton();
 
         jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(SymmetryPanel.class, "SymmetryPanel.jPanel1.border.title_1"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Dialog", 1, 14))); // NOI18N
 
@@ -285,6 +305,15 @@ public class SymmetryPanel extends ControlPanel  {
         org.openide.awt.Mnemonics.setLocalizedText(jButtonInfo3, org.openide.util.NbBundle.getMessage(SymmetryPanel.class, "SymmetryPanel.jButtonInfo3.text")); // NOI18N
         jButtonInfo3.setBorderPainted(false);
 
+        org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(SymmetryPanel.class, "SymmetryPanel.jButton1.text")); // NOI18N
+
+        org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(SymmetryPanel.class, "SymmetryPanel.jButton2.text")); // NOI18N
+        jButton2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton2ActionPerformed(evt);
+            }
+        });
+
         javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
         jPanel1.setLayout(jPanel1Layout);
         jPanel1Layout.setHorizontalGroup(
@@ -306,7 +335,6 @@ public class SymmetryPanel extends ControlPanel  {
                             .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 143, Short.MAX_VALUE))
                         .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                         .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
-                            .addComponent(comboSliderDouble4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                             .addGroup(jPanel1Layout.createSequentialGroup()
                                 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                     .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -320,7 +348,13 @@ public class SymmetryPanel extends ControlPanel  {
                                     .addComponent(jButtonInfo1)
                                     .addComponent(jButtonInfo2)
                                     .addComponent(jButtonInfo4)
-                                    .addComponent(jButtonInfo3))))))
+                                    .addComponent(jButtonInfo3)))
+                            .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                                .addGroup(jPanel1Layout.createSequentialGroup()
+                                    .addComponent(jButton1)
+                                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                    .addComponent(jButton2))
+                                .addComponent(comboSliderDouble4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))))
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
         jPanel1Layout.setVerticalGroup(
@@ -368,21 +402,17 @@ public class SymmetryPanel extends ControlPanel  {
                     .addGroup(jPanel1Layout.createSequentialGroup()
                         .addGap(11, 11, 11)
                         .addComponent(jButtonInfo4)))
-                .addGap(29, 29, 29)
+                .addGap(24, 24, 24)
                 .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                     .addComponent(jLabel6)
-                    .addComponent(jCheckBox1))
-                .addContainerGap(28, Short.MAX_VALUE))
+                    .addComponent(jCheckBox1)
+                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(jButton1)
+                        .addComponent(jButton2)))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
 
-        org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(SymmetryPanel.class, "SymmetryPanel.jButton1.text")); // NOI18N
-
-        org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(SymmetryPanel.class, "SymmetryPanel.jButton2.text")); // NOI18N
-        jButton2.addActionListener(new java.awt.event.ActionListener() {
-            public void actionPerformed(java.awt.event.ActionEvent evt) {
-                jButton2ActionPerformed(evt);
-            }
-        });
+        org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(SymmetryPanel.class, "SymmetryPanel.jButton3.text")); // NOI18N
 
         javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
         this.setLayout(layout);
@@ -392,10 +422,7 @@ public class SymmetryPanel extends ControlPanel  {
                 .addContainerGap()
                 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                     .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                    .addGroup(layout.createSequentialGroup()
-                        .addComponent(jButton1)
-                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                        .addComponent(jButton2)))
+                    .addComponent(jButton3))
                 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
         );
         layout.setVerticalGroup(
@@ -403,11 +430,9 @@ public class SymmetryPanel extends ControlPanel  {
             .addGroup(layout.createSequentialGroup()
                 .addContainerGap()
                 .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
-                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
-                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
-                    .addComponent(jButton1)
-                    .addComponent(jButton2))
-                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jButton3)
+                .addContainerGap(22, Short.MAX_VALUE))
         );
     }// </editor-fold>//GEN-END:initComponents
 
@@ -424,6 +449,7 @@ public class SymmetryPanel extends ControlPanel  {
     private cz.fidentis.analyst.core.ComboSliderInteger comboSliderInteger1;
     private javax.swing.JButton jButton1;
     private javax.swing.JButton jButton2;
+    private javax.swing.JButton jButton3;
     private javax.swing.JButton jButtonInfo1;
     private javax.swing.JButton jButtonInfo2;
     private javax.swing.JButton jButtonInfo3;
diff --git a/GUI/src/main/resources/cz/fidentis/analyst/symmetry/Bundle.properties b/GUI/src/main/resources/cz/fidentis/analyst/symmetry/Bundle.properties
index c6a2985a23be17b00739ff8af828d7c523c634a7..6a9163d800f6a7741f78386c4cd580f64b253c28 100644
--- a/GUI/src/main/resources/cz/fidentis/analyst/symmetry/Bundle.properties
+++ b/GUI/src/main/resources/cz/fidentis/analyst/symmetry/Bundle.properties
@@ -26,7 +26,7 @@ SymmetryPanel.jButtonInfo1.text=
 SymmetryPanel.jLabel3.text_1=Min. angle cosine
 SymmetryPanel.jLabel2.text_1=Min. curvature ratio
 SymmetryPanel.jLabel1.text_1=Undersampling
-SymmetryPanel.jPanel1.border.title_1=Configuration
+SymmetryPanel.jPanel1.border.title_1=Symmetry from mesh
 SymmetryPanel.jButton2.text=Compute
 SymmetryPanel.jButton1.text=Reset to defaults
 SymmetryPanel.jCheckBox1.text=
@@ -36,3 +36,4 @@ SymmetryPanel.jLabel5.text_1=Relative distance
 SymmetryPanel.jButtonInfo4.text=
 ProfilesPanel.jCheckBox1.text=Mirror cuts
 ProfilesPanel.jButton1.text=Export
+SymmetryPanel.jButton3.text=Compute from feature points
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
index f046f5f948ffc74e693bd2f0b5de662298fdd059..ae5462997554ea1a954b513f1150529efe57e9dc 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
@@ -65,6 +65,17 @@ public class MeshModel implements Serializable {
         facets.add(facet);
     }
     
+    /**
+     * Removes facet from the model.
+     * 
+     * @param index Index of the facet
+     * @return Removed facet or {@code null}
+     * @throws IndexOutOfBoundsException if the facet does not exist
+     */
+    public MeshFacet removeFacet(int index) {
+        return facets.remove(index);
+    }
+    
     /**
      * Adds a new mesh facets to the model. 
      *
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshRectangleFacet.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshRectangleFacet.java
index 6c54facb7d3580a09106e84b14bb044706bfdc58..cd5fc6d7ea06642d1443891868c27f301eb1d210 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshRectangleFacet.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshRectangleFacet.java
@@ -10,6 +10,30 @@ import javax.vecmath.Vector3d;
  */
 public class MeshRectangleFacet extends MeshFacetImpl {
     
+    /**
+     * Constructor. The vertical and horizontal direction are estimated automatically.
+     * 
+     * @param center Central point of the rectangle
+     * @param normal Normalized normal vector 
+     * @param w Width
+     * @param h Height
+     */
+    public MeshRectangleFacet(Point3d center, Vector3d normal, double w, double h) {
+        Vector3d hDir = new Vector3d();
+        if (Math.abs(normal.dot(new Vector3d(0.0, 1.0, 0.0))) > Math.abs(normal.dot(new Vector3d (1.0, 0.0, 0.0)))) {
+            hDir.cross(normal, new Vector3d(1.0, 0.0, 0.0));
+        } else {
+            hDir.cross(normal, new Vector3d(0.0, 1.0, 0.0));
+        }
+        hDir.normalize();
+
+        Vector3d vDir = new Vector3d();
+        vDir.cross(normal, hDir);
+        vDir.normalize();
+        
+        initRectangle(center, hDir, vDir, normal, w, h);
+    }
+    
     /**
      * Constructor.
      *