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 83fa87ff2f3000993c32e2c9e5798f62357e9727..c7951081c7ccc80c47ed8a76dc2db42e87eb8bc2 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/Plane.java
@@ -2,12 +2,14 @@ package cz.fidentis.analyst.symmetry;
 
 import java.io.Serializable;
 import java.util.List;
+import javax.vecmath.Point3d;
 import javax.vecmath.Vector3d;
 
 /**
  * Symmetry plane.
  * 
  * @author Natalia Bebjakova
+ * @author Dominik Racek
  */
 public class Plane implements Serializable {
    
@@ -103,12 +105,21 @@ public class Plane implements Serializable {
     }
     
     public Vector3d getNormal() {
-        return normal;
+        return new Vector3d(normal);
     }
     
     public double getDistance() {
         return distance;
     }
+
+    /**
+     * Translate the plane along its normal
+     *
+     * @param value
+     */
+    public void translate(double value) {
+        this.distance += value;
+    }
     
     protected void setNormal(Vector3d normal) {
         this.normal = normal;
@@ -117,4 +128,32 @@ public class Plane implements Serializable {
     protected void setDistance(double dist) {
         this.distance = dist;
     }
+
+    /**
+     * Calculates an intersection of a plane and a line given by two points
+     *
+     * @param p1 first point of the line
+     * @param p2 second point of the line
+     * @return The point of intersection of null if no point found
+     */
+    public Point3d getIntersectionWithLine(Point3d p1, Point3d p2) {
+        double distance1 = ((normal.x * p1.x) + (normal.y * p1.y) + (normal.z * p1.z) + distance)
+                / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
+
+        double distance2 = ((normal.x * p2.x) + (normal.y * p2.y) + (normal.z * p2.z) + distance)
+                / Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
+
+        double t = distance1 / (distance1 - distance2);
+
+        if (distance1 * distance2 > 0) {
+            return null;
+        }
+
+        Point3d output = new Point3d(p2);
+        output.sub(p1);
+        output.scale(t);
+        output.add(p1);
+
+        return output;
+    }
 }
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSection.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSection.java
index 186d429cec9e952caa8a09320bff7cbd17a23a41..aedee2ece3a5f0b183c5505f7af6a75d9a66a0a2 100644
--- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSection.java
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSection.java
@@ -1,15 +1,19 @@
 package cz.fidentis.analyst.visitors.mesh;
 
+import cz.fidentis.analyst.Logger;
 import cz.fidentis.analyst.mesh.MeshVisitor;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshTriangle;
+import cz.fidentis.analyst.symmetry.Plane;
 
 import javax.vecmath.Point3d;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
- * A visitor that calculates the cross-section of a face and a cutting plane.
+ * A visitor that calculates the cross-section of a face and a cutting plane using the triangles.
  * <p>
  * This visitor is thread-safe.
  * </p>
@@ -18,39 +22,142 @@ import java.util.List;
  */
 public class CrossSection extends MeshVisitor {
     private List<Point3d> points;
-    private MeshFacet plane;
+    private Set<Point3d> usedPoints;
+    private Plane plane;
+
+    private Set<MeshTriangle> visited;
 
     /**
      *  Constructor
      * @param plane the cutting plane
      */
-    public CrossSection(MeshFacet plane) {
+    public CrossSection(Plane plane) {
         this.plane = plane;
         this.points = new ArrayList<>();
+        this.usedPoints = new HashSet<>();
+    }
+
+    private List<MeshTriangle> getValidNeighboringTriangles(MeshFacet facet, MeshTriangle tri) {
+        List<MeshTriangle> output = facet.getNeighboringTriangles(tri);
+        output.removeIf(n -> ((visited.contains(n))
+                || (!n.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance()))));
+        return output;
+    }
+
+    private List<MeshTriangle> getValidAdjacentTriangles(MeshFacet facet, MeshTriangle tri) {
+        List<MeshTriangle> output = facet.getAdjacentTriangles(tri);
+        output.removeIf(n -> ((visited.contains(n))
+                || (!n.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance()))));
+        return output;
+    }
+
+    private void addPoint(MeshTriangle tri, MeshTriangle previous, boolean direction) {
+        List<Point3d> commonEdge = tri.getCommonPoints(previous);
+        if (commonEdge.size() == 2) {
+            Point3d p = plane.getIntersectionWithLine(commonEdge.get(0), commonEdge.get(1));
+            if (p == null) {
+                return;
+            }
+
+            if (!usedPoints.contains(p)) {
+                usedPoints.add(p);
+
+                if (direction) {
+                    points.add(p);
+                } else {
+                    points.add(0, p);
+                }
+            }
+        }
+    }
+
+    private void visitMeshFacetRec(MeshFacet facet, MeshTriangle tri, MeshTriangle previous, boolean direction) {
+        visited.add(tri);
+
+        // Depending on the direction, add the point to the start or to the end of points
+        addPoint(tri, previous, direction);
+
+        // Recursively call to the end
+        // Get all neighbors that have not been visited and are intercepted
+        List<MeshTriangle> neighbors = getValidNeighboringTriangles(facet, tri);
+
+        // If no valid neighbours are found, try to look further
+        if (neighbors.size() == 0) {
+            neighbors = getValidAdjacentTriangles(facet, tri);
+        }
+
+        if (neighbors.size() == 1) {
+            //Only one neighbor - go there
+            visitMeshFacetRec(facet, neighbors.get(0), tri, direction);
+        } else if (neighbors.size() == 2) {
+            //Two neighbors - they are valid to each other, but one of them has another valid neighbor.
+            //                Select the one that only has the other as a neighbor so the route is linear.
+            List<MeshTriangle> valid = getValidNeighboringTriangles(facet, neighbors.get(0));
+
+            if (valid.size() == 1) {
+                visitMeshFacetRec(facet, neighbors.get(0), tri, direction);
+            } else {
+                visitMeshFacetRec(facet, neighbors.get(1), tri, direction);
+            }
+        }
     }
 
     @Override
     public void visitMeshFacet(MeshFacet facet) {
-        //TODO Dont check every triangle, find first and then check it's neighbors and new neighbors and so on
+        Logger out = Logger.measureTime();
+
+        this.visited = new HashSet<>();
+
         synchronized (this) {
-            Point3d last = null;
+
+            // Find the first triangle
+            MeshTriangle first = null;
             for (MeshTriangle tri : facet) {
-                if (tri.checkIntersectionWithPlane(plane)) {
-                    Point3d p = tri.getVertex1();
-
-                    // Check for duplicates
-                    if (last != null) {
-                        if (last == p) {
-                            continue;
-                        }
-                    }
+                if (tri.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance())) {
+                    first = tri;
+                    break;
+                }
+            }
 
-                    points.add(p);
-                    last = p;
+            if (first == null) {
+                return;
+            }
+
+            // Set found and visited and add to points
+            visited.add(first);
+
+            // Find the valid neighboring triangles and act based on the amount
+            List<MeshTriangle> neighbors = getValidNeighboringTriangles(facet, first);
+
+            if (neighbors.size() == 1) {
+                //Only one neighbor - go there
+                visitMeshFacetRec(facet, neighbors.get(0), first, true);
+            } else if (neighbors.size() == 2) {
+                //Two neighbors - one on each side
+                visitMeshFacetRec(facet, neighbors.get(0), first, true);
+                visitMeshFacetRec(facet, neighbors.get(1), first, false);
+            } else if (neighbors.size() == 3) {
+                //Three neighbors - select the two with only one valid neighbor
+                List<MeshTriangle> valid = getValidNeighboringTriangles(facet, neighbors.get(0));
+                if (valid.size() == 1) {
+                    //Index 0 is one of the correct ones, find the other
+                    visitMeshFacetRec(facet, neighbors.get(0), first, true);
+                    List<MeshTriangle> valid1 = getValidNeighboringTriangles(facet, neighbors.get(1));
+
+                    if (valid1.size() == 1) {
+                        visitMeshFacetRec(facet, neighbors.get(1), first, false);
+                    } else {
+                        visitMeshFacetRec(facet, neighbors.get(2), first, false);
+                    }
+                } else {
+                    //Index 0 is not one of the correct ones, 1 and 2 are
+                    visitMeshFacetRec(facet, neighbors.get(1), first, true);
+                    visitMeshFacetRec(facet, neighbors.get(2), first, false);
                 }
             }
         }
 
+        out.printDuration("Cross section with triangle method");
     }
 
     public List<Point3d> getPoints() {
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
new file mode 100644
index 0000000000000000000000000000000000000000..c4f96c24048ba2c0206096676961e0ef5cdd5d2a
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/CrossSectionZigZag.java
@@ -0,0 +1,150 @@
+package cz.fidentis.analyst.visitors.mesh;
+
+import cz.fidentis.analyst.Logger;
+import cz.fidentis.analyst.mesh.MeshVisitor;
+import cz.fidentis.analyst.mesh.core.MeshFacet;
+import cz.fidentis.analyst.mesh.core.MeshTriangle;
+import cz.fidentis.analyst.symmetry.Plane;
+
+import javax.vecmath.Point3d;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * A visitor that calculates the cross-section of a face and a cutting plane using the edges between triangles.
+ * <p>
+ * This visitor is thread-safe.
+ * </p>
+ *
+ * @author Dominik Racek
+ */
+public class CrossSectionZigZag extends MeshVisitor {
+    private List<Point3d> points;
+    private Set<Point3d> usedPoints;
+    private Set<MeshTriangle> visited;
+
+    private Plane plane;
+
+    public CrossSectionZigZag(Plane plane) {
+        this.plane = plane;
+        this.points = new ArrayList<>();
+        this.usedPoints = new HashSet<>();
+    }
+
+    private void addPoint(Point3d p, boolean direction) {
+        if (!usedPoints.contains(p)) {
+            usedPoints.add(p);
+
+            if (direction) {
+                points.add(p);
+            } else {
+                points.add(0, p);
+            }
+        }
+    }
+
+    private void visitMeshFacetRec(MeshFacet facet, int p1, int p2, MeshTriangle previous, boolean direction) {
+        List<MeshTriangle> triangles = facet.getAdjacentTriangles(p1, p2);
+        triangles.remove(previous);
+        if (triangles.isEmpty()) {
+            return;
+        }
+
+        //Find the next intersected edge
+        MeshTriangle current = triangles.get(0);
+
+        if (visited.contains(current)) {
+            return;
+        }
+        visited.add(current);
+
+        //Find the index of the last vertex of current (first ones being p1 and p2)
+        int p3;
+        if (current.index1 != p1 && current.index1 != p2) {
+            p3 = current.index1;
+        } else if (current.index2 != p1 && current.index2 != p2) {
+            p3 = current.index2;
+        } else {
+            p3 = current.index3;
+        }
+
+        //Next intersected edge will be between p1-p3 or p2-p3
+        Point3d intersection = plane.getIntersectionWithLine(facet.getVertex(p1).getPosition(),
+                facet.getVertex(p3).getPosition());
+
+        if (intersection == null) {
+            intersection = plane.getIntersectionWithLine(facet.getVertex(p2).getPosition(),
+                    facet.getVertex(p3).getPosition());
+
+            addPoint(intersection, direction);
+            visitMeshFacetRec(facet, p2, p3, current, direction);
+        } else {
+            addPoint(intersection, direction);
+            visitMeshFacetRec(facet, p1, p3, current, direction);
+        }
+
+    }
+
+    @Override
+    public void visitMeshFacet(MeshFacet facet) {
+        Logger out = Logger.measureTime();
+
+        visited = new HashSet<>();
+
+        synchronized (this) {
+
+            // Find the first triangle
+            MeshTriangle first = null;
+            for (MeshTriangle tri : facet) {
+                if (tri.checkIntersectionWithPlane(plane.getNormal(), plane.getDistance())) {
+                    first = tri;
+                    break;
+                }
+            }
+
+            if (first == null) {
+                return;
+            }
+
+            visited.add(first);
+
+            //Figure out which lines are intersected
+            Point3d intersection1 = plane.getIntersectionWithLine(first.getVertex1(), first.getVertex2());
+            Point3d intersection2 = plane.getIntersectionWithLine(first.getVertex2(), first.getVertex3());
+            Point3d intersection3 = plane.getIntersectionWithLine(first.getVertex3(), first.getVertex1());
+
+            if (intersection1 != null) {
+                //Intersection 1
+                visitMeshFacetRec(facet, first.index1, first.index2, first, true);
+                if (intersection2 != null) {
+                    //Intersection 1 and 2
+                    visitMeshFacetRec(facet, first.index2, first.index3, first, false);
+                } else if (intersection3 != null) {
+                    //Intersection 1 and 3
+                    visitMeshFacetRec(facet, first.index3, first.index1, first, false);
+                }
+            } else if (intersection2 != null) {
+                //Intersection 2
+                visitMeshFacetRec(facet, first.index2, first.index3, first, true);
+                if (intersection3 != null) {
+                    //Intersection 2 and 3
+                    visitMeshFacetRec(facet, first.index3, first.index1, first, false);
+                }
+
+            } else if (intersection3 != null) {
+                //Intersection 3 only
+                visitMeshFacetRec(facet, first.index3, first.index1, first, true);
+            }
+            //No intersection
+        }
+
+        out.printDuration("Cross section with zigzag method");
+    }
+
+    public List<Point3d> getPoints() {
+        return points;
+    }
+}
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 795bddc0c7d9bec925588f81aca244f363ade894..dbd1322e021b3e72b531099f60f46ffd3ae0e589 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/DrawablePlane.java
@@ -4,6 +4,8 @@ import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshModel;
 import cz.fidentis.analyst.symmetry.Plane;
 
+import javax.vecmath.Vector3d;
+
 /**
  * A cutting plane.
  * 
@@ -36,6 +38,30 @@ public class DrawablePlane extends DrawableMesh {
         if (plane == null) {
             throw new IllegalArgumentException("plane");
         }
-        this.plane = plane;
+        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.x *= value;
+        move.y *= value;
+        move.z *= value;
+
+        for (int i = 0; i < 4; ++i) {
+            getFacets().get(0).getVertex(i).getPosition().sub(move);
+        }
     }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/PolylinePanel.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/PolylinePanel.java
index 2fde656939aa0d5a79537f6cc2aa372d937fb224..8d70c78428f7ab1a5f674aa10c9d7fcde19f6d22 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/PolylinePanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/PolylinePanel.java
@@ -7,8 +7,6 @@ import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Stroke;
 import java.awt.geom.Line2D;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import javax.swing.JPanel;
 import javax.vecmath.Point3d;
@@ -38,33 +36,11 @@ public class PolylinePanel extends JPanel {
 
     private double scale = Double.POSITIVE_INFINITY;
 
-    /**
-     * Comparator for Point3d based on Y value
-     *
-     * @author Dominik Racek
-     */
-    public class CompareY implements Comparator<Point3d> {
-
-        /**
-         * Compare two Points3d objects
-         */
-        public int compare(final Point3d a, final Point3d b) {
-            if (a.y < b.y) {
-                return -1;
-            } else if (a.y > b.y) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
-    }
-
     /**
      * Constructor for one face
      */
     public PolylinePanel(List<Point3d> values) {
         this.primaryPoints = values;
-        Collections.sort(this.primaryPoints, new CompareY());
     }
 
     /**
@@ -73,8 +49,6 @@ public class PolylinePanel extends JPanel {
     public PolylinePanel(List<Point3d> primaryPoints, List<Point3d> secondaryPoints) {
         this.primaryPoints = primaryPoints;
         this.secondaryPoints = secondaryPoints;
-        Collections.sort(this.primaryPoints, new CompareY());
-        Collections.sort(this.secondaryPoints, new CompareY());
     }
 
     protected void drawFace(Graphics2D g2, List<Point3d> values, Color faceColor, boolean isPrimary) {
@@ -168,7 +142,6 @@ public class PolylinePanel extends JPanel {
      */
     public void setPrimaryPoints(List<Point3d> points) {
         this.primaryPoints = points;
-        Collections.sort(this.primaryPoints, new CompareY());
         repaint();
     }
 
@@ -180,7 +153,6 @@ public class PolylinePanel extends JPanel {
      */
     public void setPrimaryMirrorPoints(List<Point3d> points) {
         this.primaryMirrorPoints = points;
-        Collections.sort(this.primaryMirrorPoints, new CompareY());
         repaint();
     }
 
@@ -191,7 +163,6 @@ public class PolylinePanel extends JPanel {
      */
     public void setSecondaryPoints(List<Point3d> points) {
         this.secondaryPoints = points;
-        Collections.sort(this.secondaryPoints, new CompareY());
         repaint();
     }
 
@@ -203,7 +174,6 @@ public class PolylinePanel extends JPanel {
      */
     public void setSecondaryMirrorPoints(List<Point3d> points) {
         this.secondaryMirrorPoints = points;
-        Collections.sort(this.secondaryMirrorPoints, new CompareY());
         repaint();
     }
 
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 dec51a69aea0a9a49959c7563accd11b4c05558e..67463fc3ff3f2a238150ba9d2a3061c70d1969a8 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
@@ -3,6 +3,7 @@ package cz.fidentis.analyst.symmetry;
 import cz.fidentis.analyst.canvas.Canvas;
 import cz.fidentis.analyst.core.ControlPanelAction;
 import cz.fidentis.analyst.visitors.mesh.CrossSection;
+import cz.fidentis.analyst.visitors.mesh.CrossSectionZigZag;
 import org.openide.filesystems.FileChooserBuilder;
 
 import javax.swing.JTabbedPane;
@@ -36,6 +37,8 @@ public class ProfilesAction extends ControlPanelAction {
     private List<Point3d> primaryMirrorPoints;
     private List<Point3d> secondaryMirrorPoints;
 
+    private double lastSliderValue = 0.5;
+
     /**
      * Constructor.
      *
@@ -119,24 +122,24 @@ public class ProfilesAction extends ControlPanelAction {
 
     private void recomputePrimaryProfile() {
         //Main profile
-        CrossSection cs = new CrossSection(getScene().getDrawableCuttingPlane(0).getFacets().get(0));
+        CrossSectionZigZag cs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(0).getPlane());
         getPrimaryDrawableFace().getModel().compute(cs);
         this.primaryPoints = cs.getPoints();
 
         //Mirror profile
-        CrossSection mcs = new CrossSection(getScene().getDrawableMirrorPlane(0).getFacets().get(0));
+        CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(0).getPlane());
         getPrimaryDrawableFace().getModel().compute(mcs);
         this.primaryMirrorPoints = mcs.getPoints();
     }
 
     private void recomputeSecondaryProfile() {
         //Main profile
-        CrossSection cs = new CrossSection(getScene().getDrawableCuttingPlane(1).getFacets().get(0));
+        CrossSectionZigZag cs = new CrossSectionZigZag(getScene().getDrawableCuttingPlane(1).getPlane());
         getSecondaryDrawableFace().getModel().compute(cs);
         this.secondaryPoints = cs.getPoints();
 
         //Mirror profile
-        CrossSection mcs = new CrossSection(getScene().getDrawableMirrorPlane(1).getFacets().get(0));
+        CrossSectionZigZag mcs = new CrossSectionZigZag(getScene().getDrawableMirrorPlane(1).getPlane());
         getSecondaryDrawableFace().getModel().compute(mcs);
         this.secondaryMirrorPoints = mcs.getPoints();
     }
@@ -154,9 +157,18 @@ public class ProfilesAction extends ControlPanelAction {
     }
 
     private void setCuttingPlaneOffset(int index, double value) {
-        for (int i = 0; i < 4; ++i) {
-            getScene().getDrawableCuttingPlane(index).getFacets().get(0).getVertex(i).getPosition().x = value;
-            getScene().getDrawableMirrorPlane(index).getFacets().get(0).getVertex(i).getPosition().x = value * -1.0;
+        //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);
+        } 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);
         }
     }
 
@@ -176,20 +188,28 @@ public class ProfilesAction extends ControlPanelAction {
                 break;
             case ProfilesPanel.ACTION_COMMAND_EXPORT:
                 exportProfile(this.primaryPoints, "Export primary face profile to file");
+                if (controlPanel.isMirrorCutsChecked()) {
+                    exportProfile(this.primaryMirrorPoints, "Export primary face mirror profile to file");
+                }
+
                 if (getSecondaryDrawableFace() != null) {
                     exportProfile(this.secondaryPoints, "Export secondary face profile to file");
+                    if (controlPanel.isMirrorCutsChecked()) {
+                        exportProfile(this.secondaryMirrorPoints, "Export secondary face mirror profile to file");
+                    }
                 }
                 break;
             case ProfilesPanel.ACTION_OFFSET_CUTTING_PLANE:
-                double value = controlPanel.getOffsetValue();
-                double multiplier = 150;
+                double value = controlPanel.getOffsetValue() - lastSliderValue;
+                double multiplier = -150;
 
-                setCuttingPlaneOffset(0, multiplier * (value - 0.5));
+                setCuttingPlaneOffset(0, multiplier * value);
 
                 if (getSecondaryDrawableFace() != null) {
-                    setCuttingPlaneOffset(1, multiplier * (value - 0.5));
+                    setCuttingPlaneOffset(1, multiplier * value);
                 }
                 recomputeProfiles();
+                lastSliderValue = controlPanel.getOffsetValue();
                 break;
             case ProfilesPanel.ACTION_COMMAND_RECOMPUTE:
                 recomputeProfiles();
diff --git a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java
index d5adeaa0bea62d3573268e8e1669955c7e908ec6..69be05ea0053088a8405dd656327918c123c104e 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesPanel.java
@@ -117,26 +117,15 @@ public class ProfilesPanel extends ControlPanel {
         );
         builder.addLine();
 
-        builder.addButtons(
-                List.of("Recompute",
-                        "Export Profile(s)"),
-                List.of(
-                        (ActionEvent e) -> {
-                            action.actionPerformed(new ActionEvent(
-                                    e.getSource(),
-                                    ActionEvent.ACTION_PERFORMED,
-                                    ACTION_COMMAND_RECOMPUTE
-                            ));
-                        },
-                        (ActionEvent e) -> {
-                            action.actionPerformed(new ActionEvent(
-                                    e.getSource(),
-                                    ActionEvent.ACTION_PERFORMED,
-                                    ACTION_COMMAND_EXPORT
-                            ));
-                        }
-                )
-        );
+        builder.addButton(
+                "Export Profile(s)",
+                (ActionEvent e) -> {
+                    action.actionPerformed(new ActionEvent(
+                            e.getSource(),
+                            ActionEvent.ACTION_PERFORMED,
+                            ACTION_COMMAND_EXPORT
+                    ));
+                });
     }
 
     @Override
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java
index e002bd80fdc3e78ddeaef3f3a3889ba0d38f9cce..c9f81ed95121b9b5467257d6c989d758646689b8 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacet.java
@@ -84,6 +84,33 @@ public interface MeshFacet extends Iterable<MeshTriangle>, Serializable {
      * @return Triangles sharing the mesh vertex
      */
     List<MeshTriangle> getAdjacentTriangles(int vertexIndex);
+
+    /**
+     * Returns triangles sharing the given edge.
+     *
+     * @param index1 Index of the first point of the edge
+     * @param index2 Index of the second point of the edge
+     * @return Triangles sharing the edge
+     */
+    List<MeshTriangle> getAdjacentTriangles(int index1, int index2);
+
+    /**
+     * Returns adjacent triangles, i.e., triangles sharing an edge or a vertex with the given triangle
+     *
+     * @param triangle The triangle
+     * @return Unique adjacent triangles
+     */
+    List<MeshTriangle> getAdjacentTriangles(MeshTriangle triangle);
+
+    /**
+     * Returns neighboring triangles, i.e., triangles sharing an edge with the given triangle.
+     * In contrast to the {@link #getAdjacentTriangles(cz.fidentis.analyst.mesh.core.MeshTriangle)},
+     * triangles sharing only a vertex are omitted.
+     *
+     * @param triangle The triangle
+     * @return Unique neighboring triangles
+     */
+    List<MeshTriangle> getNeighboringTriangles(MeshTriangle triangle);
     
     /**
      * Finds and returns a point lying at triangles around (sharing) the given mesh vertex
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java
index a12a2f78f338ff0430bdc1598e63f49180103bb8..f1b9f0c5154dc4088384558d95b782ad3fd19ba3 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshFacetImpl.java
@@ -3,10 +3,12 @@ package cz.fidentis.analyst.mesh.core;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import javax.vecmath.Vector3d;
 import cz.fidentis.analyst.mesh.MeshVisitor;
 import javax.vecmath.Point3d;
@@ -15,6 +17,7 @@ import javax.vecmath.Point3d;
  * Mash facet is a compact triangular mesh without duplicated vertices.
  *
  * @author Matej Lukes
+ * @author Dominik Racek
  */
 public class MeshFacetImpl implements MeshFacet {
     
@@ -149,6 +152,52 @@ public class MeshFacetImpl implements MeshFacet {
         
         return ret;
     }
+
+    @Override
+    public List<MeshTriangle> getAdjacentTriangles(int index1, int index2) {
+        List<MeshTriangle> output = getAdjacentTriangles(index1);
+        List<MeshTriangle> other = getAdjacentTriangles(index2);
+        output.retainAll(other);
+        return output;
+    }
+
+    @Override
+    public List<MeshTriangle> getAdjacentTriangles(MeshTriangle tri) {
+        Set<MeshTriangle> output = new HashSet<>();
+        output.addAll(getAdjacentTriangles(tri.index1));
+        output.addAll(getAdjacentTriangles(tri.index2));
+        output.addAll(getAdjacentTriangles(tri.index3));
+        output.remove(tri);
+
+        return new ArrayList<>(output);
+    }
+
+    @Override
+    public List<MeshTriangle> getNeighboringTriangles(MeshTriangle tri) {
+        Set<MeshTriangle> output = new HashSet<>();
+
+        //Find only the three triangles sharing edges with tri
+        List<MeshTriangle> l1 = getAdjacentTriangles(tri.index1);
+        List<MeshTriangle> l2 = getAdjacentTriangles(tri.index2);
+        List<MeshTriangle> l3 = getAdjacentTriangles(tri.index3);
+
+        //Calculate the three intersections
+        List<MeshTriangle> i1 = new ArrayList<>(l1);
+        i1.retainAll(l2);
+
+        List<MeshTriangle> i2 = new ArrayList<>(l2);
+        i2.retainAll(l3);
+
+        List<MeshTriangle> i3 = new ArrayList<>(l3);
+        i3.retainAll(l1);
+
+        output.addAll(i1);
+        output.addAll(i2);
+        output.addAll(i3);
+        output.remove(tri);
+
+        return new ArrayList<>(output);
+    }
     
     @Override
     public Point3d getClosestAdjacentPoint(Point3d point, int vertexIndex) {
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java
index 31ef4cde576946a4072c53a335c19bb397417697..86badda1f40bd9053aa38aeeab81dfab205acf30 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshTriangle.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import javax.vecmath.Point3d;
 import javax.vecmath.Vector3d;
 
@@ -11,6 +12,7 @@ import javax.vecmath.Vector3d;
  * Adapter for the corner table representing a single triangle of {@code MeshFacet}.
  * 
  * @author Natalia Bebjakova
+ * @author Dominik Racek
  */
 
 public class MeshTriangle implements Iterable<MeshPoint> { 
@@ -69,6 +71,28 @@ public class MeshTriangle implements Iterable<MeshPoint> {
     public MeshPoint getPoint3() {
         return facet.getVertex(index3);
     }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if(this == obj)
+            return true;
+
+        if(obj == null || obj.getClass()!= this.getClass())
+            return false;
+
+        MeshTriangle mt = (MeshTriangle) obj;
+
+        return ((index1 == mt.index1 || index1 == mt.index2 || index1 == mt.index3)
+                && (index2 == mt.index1 || index2 == mt.index2 || index2 == mt.index3)
+                && (index3 == mt.index1 || index3 == mt.index2 || index3 == mt.index3));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(index1, index2, index3);
+    }
+
     
     /**
      * Computes and returns normalized normal vector from the vertices.
@@ -364,7 +388,7 @@ public class MeshTriangle implements Iterable<MeshPoint> {
         ab.sub(v1);
         Vector3d ap = new Vector3d(point);
         ap.sub(v1);
-        
+
         double abLenSquared = ab.lengthSquared();
         
         double t = ab.dot(ap) / abLenSquared;
@@ -401,39 +425,43 @@ public class MeshTriangle implements Iterable<MeshPoint> {
     /**
      * Checks whether the triangle is intersected by a cutting plane
      *
-     * @param plane cutting plane
+     * @param normal normal defining the plane
+     * @param d distance defining the plane
      * @return true if the triangle is intersected by the plane
      */
-    public boolean checkIntersectionWithPlane(MeshFacet plane) {
-        Point3d min = getVertex1(), max = getVertex1();
-
-        if (getVertex2().x < min.x) {
-            min = getVertex2();
-        }
+    public boolean checkIntersectionWithPlane(Vector3d normal, double d) {
+        double p1 = (normal.x * getVertex1().x) + (normal.y * getVertex1().y) + (normal.z * getVertex1().z) + d;
+        double p2 = (normal.x * getVertex2().x) + (normal.y * getVertex2().y) + (normal.z * getVertex2().z) + d;
+        double p3 = (normal.x * getVertex3().x) + (normal.y * getVertex3().y) + (normal.z * getVertex3().z) + d;
 
-        if (getVertex3().x < min.x) {
-            min = getVertex3();
-        }
+        //If one point is on one side of the plane and the other on the other side
+        return ((p1 <= 0 || p2 <= 0 || p3 <= 0) && (p1 >= 0 || p2 >= 0 || p3 >= 0));
+    }
 
-        if (getVertex2().x > max.x) {
-            max = getVertex2();
-        }
+    /**
+     * Selects the common points between two triangles
+     *
+     * @param other The other triangle
+     * @return the common points of two triangles
+     */
+    public List<Point3d> getCommonPoints(MeshTriangle other) {
+        List<Point3d> output = new ArrayList<>();
 
-        if (getVertex3().x > max.x) {
-            max = getVertex3();
+        if (getVertex1().equals(other.getVertex1()) || getVertex1().equals(other.getVertex2())
+                || getVertex1().equals(other.getVertex3())) {
+            output.add(getVertex1());
         }
 
-        Point3d projMin = plane.getTriangles().get(0).getProjectionToTrianglePlane(min);
-        Point3d projMax = plane.getTriangles().get(0).getProjectionToTrianglePlane(max);
-
-        if (projMin == null) {
-            projMin = plane.getTriangles().get(1).getProjectionToTrianglePlane(min);
+        if (getVertex2().equals(other.getVertex1()) || getVertex2().equals(other.getVertex2())
+                || getVertex2().equals(other.getVertex3())) {
+            output.add(getVertex2());
         }
 
-        if (projMax == null) {
-            projMax = plane.getTriangles().get(1).getProjectionToTrianglePlane(max);
+        if (getVertex3().equals(other.getVertex1()) || getVertex3().equals(other.getVertex2())
+                || getVertex3().equals(other.getVertex3())) {
+            output.add(getVertex3());
         }
 
-        return (min.x < projMin.x && max.x > projMax.x);
+        return output;
     }
 }