From 3956ed7f4c52740c38179dc69880455b61862ad5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Radek=20O=C5=A1lej=C5=A1ek?= <oslejsek@fi.muni.cz>
Date: Tue, 25 Jan 2022 14:48:17 +0100
Subject: [PATCH] Resolve "Compute HD batch finalization by using OpenCL"

---
 GUI/pom.xml                                   |   5 +
 .../batch/ApproxHausdorffDistTask.java        | 104 ++----
 .../batch/ApproxHausdorffDistTaskGPU.java     | 352 ++++++++++++++++++
 .../fidentis/analyst/batch/BatchAction.java   |   4 +-
 .../cz/fidentis/analyst/batch/IcpTask.java    |   2 +-
 .../cz/fidentis/analyst/canvas/Canvas.java    |   8 +-
 .../canvas/toolbar/RenderingModeToolbox.java  |   6 +-
 .../toolbar/SceneToolboxFaceToFace.java       |  30 +-
 .../toolbar/SceneToolboxSingleFace.java       |   6 +-
 .../analyst/core/ControlPanelAction.java      |   8 +-
 .../analyst/distance/DistanceAction.java      |   2 +-
 .../java/cz/fidentis/analyst/scene/Scene.java | 205 +++++-----
 .../analyst/symmetry/ProfilesAction.java      |   8 +-
 .../analyst/symmetry/SymmetryAction.java      |  24 +-
 14 files changed, 542 insertions(+), 222 deletions(-)
 create mode 100644 GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java

diff --git a/GUI/pom.xml b/GUI/pom.xml
index 5caa94cf..4a1aeea3 100644
--- a/GUI/pom.xml
+++ b/GUI/pom.xml
@@ -97,6 +97,11 @@
             <artifactId>jogl-all-main</artifactId>
             <version>2.3.2</version>
         </dependency>
+        <dependency>
+            <groupId>org.jocl</groupId>
+            <artifactId>jocl</artifactId>
+            <version>2.0.4</version>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>MeshModel</artifactId>
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java
index 12ff1ab8..b904a525 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTask.java
@@ -21,8 +21,11 @@ import java.util.stream.DoubleStream;
  * A task that computes similarity of a set of faces by computing
  * the distance of faces to an average face and then combining these values
  * to get mutual similarity for all pairs.
+ * <p>
+ * The computation is accelerated by using multiple CPU cores concurrently.
  * The exact computation parameters are taken from the {@code BatchPanel}.
- * 
+ * </p>
+  * 
  * @author Radek Oslejsek
  */
 public class ApproxHausdorffDistTask extends SimilarityTask {
@@ -97,7 +100,7 @@ public class ApproxHausdorffDistTask extends SimilarityTask {
                 );
                 templateFace.getMeshModel().compute(hd, true);
                 
-                // Store relative distances of individual vertices to the cache
+                // Store relative distances of individual vertices to the cache                
                 distCache.add(hd.getDistances()
                         .values()
                         .stream()
@@ -105,7 +108,6 @@ public class ApproxHausdorffDistTask extends SimilarityTask {
                         .collect(Collectors.toList()));
                 face.removeKdTree(); // TO BE TESTED
                 
-                //dist[i] = hd.getStats().getAverage();
                 hdComputationTime.stop();
             } else {
                 distCache.add(DoubleStream.generate(() -> 0.0d)
@@ -142,10 +144,6 @@ public class ApproxHausdorffDistTask extends SimilarityTask {
         Logger.print(totalTime.toString());
     }
     
-    protected double numCycles(int nFaces) {
-        return 0.5 * nFaces * (nFaces + 1);
-    }
-
     @Deprecated
     protected void finalizeHD(List<List<Double>> distCache, long numVertices) {
         for (int i = 0; i < distCache.size(); i++) {
@@ -174,11 +172,34 @@ public class ApproxHausdorffDistTask extends SimilarityTask {
     
     protected void finalizeHdConcurrently(List<List<Double>> distCache, long numVertices) {
         ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
-        final List<Future<PairComparisonResult>> results = new ArrayList<>();
+        final List<Future<Void>> results = new ArrayList<>();
         
         for (int i = 0; i < distCache.size(); i++) {
             for (int j = i; j < distCache.size(); j++) {
-                results.add(executor.submit(new CallableHd(i, j, distCache.get(i), distCache.get(j))));                
+                assert(distCache.get(i).size() == distCache.get(i).size()); // should never happen
+                
+                final int fi = i;
+                final int fj = j;
+                
+                // Compute average HD for the pair of faces in a separate threat:
+                results.add(executor.submit(new Callable<Void>() {
+                    @Override
+                    public Void call() throws Exception {
+                        double sum = 0.0;
+                        int counter = 0;
+                        for (int k = 0; k < distCache.get(fi).size(); k++) {
+                            double d1 = distCache.get(fi).get(k);
+                            double d2 = distCache.get(fj).get(k);
+                            if (Double.isFinite(d1) && Double.isFinite(d2)) {
+                                sum += Math.abs(d1 - d2);
+                                counter++;
+                            }
+                        }
+                        setDistSimilarity(fi, fj, sum / counter);
+                        setDistSimilarity(fj, fi, sum / counter);
+                        return null;
+                    }
+                }));
             }
         }
         
@@ -186,13 +207,9 @@ public class ApproxHausdorffDistTask extends SimilarityTask {
         while (!executor.isTerminated()){}
         try {
             int i = 0;
-            for (Future<PairComparisonResult> res: results) {
-                final PairComparisonResult hd = (PairComparisonResult) res.get(); // waits until all computations are finished
-                setDistSimilarity(hd.i, hd.j, hd.val);
-                setDistSimilarity(hd.j, hd.i, hd.val);
-
-                // update progress bar
-                int progress = (int) Math.round(100.0 * (++i) / distCache.size());
+            for (Future<Void> res: results) {
+                res.get(); // waits until all computations are finished
+                int progress = (int) Math.round(100.0 * (i+1) / results.size());
                 getProgressDialog().setValue(progress);
             }
         } catch (final InterruptedException | ExecutionException ex) {
@@ -200,59 +217,4 @@ public class ApproxHausdorffDistTask extends SimilarityTask {
         }
     }
     
-    /**
-     * @author Radek Oslejsek
-     */
-    private class PairComparisonResult {
-        public final int i;
-        public final int j;
-        public final double val;
-        
-        PairComparisonResult(int i, int j, double val) {
-            this.i = i;
-            this.j = j;
-            this.val = val;
-        }
-    }
-    
-    /**
-     * @author Radek Oslejsek
-     */
-    private class CallableHd implements Callable<PairComparisonResult> {
-        private final List<Double> distancesI;
-        private final List<Double> distancesJ;
-        private final int i;
-        private final int j;
-        
-        /**
-         * Constructor.
-         * 
-         * @param i index of the fist face
-         * @param j index of the second face
-         * @param distancesI distances of the first face vertices to the template face
-         * @param distancesJ distances of the second face vertices to the template face
-         */
-        CallableHd(int i, int j, List<Double> distancesI, List<Double> distancesJ) {
-            this.i = i;
-            this.j = j;
-            this.distancesI = distancesI;
-            this.distancesJ = distancesJ;
-        }
-        
-        @Override
-        public PairComparisonResult call() throws Exception {
-            assert(distancesI.size() == distancesJ.size()); // should never happen
-            double sum = 0.0;
-            int counter = 0;
-            for (int k = 0; k < distancesI.size(); k++) {
-                double d1 = distancesI.get(k);
-                double d2 = distancesJ.get(k);
-                if (Double.isFinite(d1) && Double.isFinite(d2)) {
-                    sum += Math.abs(d1 - d2);
-                    counter++;
-                }
-            }
-            return new PairComparisonResult(i, j, sum / counter);
-        }
-    }
 }
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java
new file mode 100644
index 00000000..b95faa4a
--- /dev/null
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/ApproxHausdorffDistTaskGPU.java
@@ -0,0 +1,352 @@
+package cz.fidentis.analyst.batch;
+
+import cz.fidentis.analyst.Logger;
+import cz.fidentis.analyst.core.ProgressDialog;
+import cz.fidentis.analyst.face.HumanFace;
+import cz.fidentis.analyst.face.HumanFaceFactory;
+import cz.fidentis.analyst.visitors.mesh.HausdorffDistance;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.stream.Collectors;
+import org.jocl.CL;
+import org.jocl.Pointer;
+import org.jocl.Sizeof;
+import org.jocl.cl_command_queue;
+import org.jocl.cl_context;
+import org.jocl.cl_context_properties;
+import org.jocl.cl_device_id;
+import org.jocl.cl_kernel;
+import org.jocl.cl_mem;
+import org.jocl.cl_platform_id;
+import org.jocl.cl_program;
+import org.jocl.cl_queue_properties;
+
+/**
+ * A GPU accelerated variant of {@link ApproxHausdorffDistTask}.
+ * The computation is accelerated by using both the CPU and GPU parallelism.
+ * The OpenCL code is based on 
+ * {@see https://github.com/gpu/JOCLSamples/blob/master/src/main/java/org/jocl/samples/JOCLSample.java}.
+ * However, the computation is slower than using CPU-based multitasking only
+ * (For 500 faces, 40 seconds of the HD finalization phase on GPU compared to 18 second on 8-core CPU)
+ * This class is marked as deprecated for this reason. 
+ * Use {@link ApproxHausdorffDistTask} instead.
+ * <p>
+ * The exact computation parameters are taken from the {@code BatchPanel}.
+ * </p> 
+ * 
+ * @author Radek Oslejsek
+ */
+@Deprecated
+public class ApproxHausdorffDistTaskGPU extends SimilarityTask {
+    
+    /**
+     * OpenCL device
+     */
+    private cl_device_id device;
+    
+    /**
+     * OpenCL context
+     */
+    private cl_context context;
+    
+    /**
+     * OpenCL command queue
+     */
+    private cl_command_queue commandQueue;
+    
+    /**
+     * Built OpenCL program
+     */
+    private cl_program program;
+    
+    /**
+     * GPU memory where the distances of faces to the template face are stored
+     */
+    private cl_mem[] srcArrays;
+    
+    private final Stopwatch totalTime = new Stopwatch("Total computation time:\t\t");
+    private final Stopwatch hdComputationTime = new Stopwatch("Hausdorff distance preparation time:\t");
+    private final Stopwatch loadTime = new Stopwatch("Disk access time:\t\t");
+    private final Stopwatch kdTreeConstructionTime = new Stopwatch("KD trees construction time:\t\t");
+    private final Stopwatch finalHdComputationTime = new Stopwatch("Hausdorff distance finalization time:\t");
+    
+    private final int templateFaceIndex;
+    
+    /**
+     * The source code of the OpenCL program to execute
+     */
+    private static final String PROGRAM_SOURCE =
+        "__kernel void "+
+        "hdKernel(__global const float *a,"+
+        "         __global const float *b,"+
+        "         __global float *c)"+
+        "{"+
+        "    int gid = get_global_id(0);"+
+        "    c[gid] = fabs(a[gid] - b[gid]);"+
+        "}";
+
+    /**
+     * Constructor.
+     * 
+     * @param progressDialog A window that show the progress of the computation. Must not be {@code null}
+     * @param controlPanel A control panel with computation parameters. Must not be {@code null}
+     * @param avgFace average face
+     */
+    public ApproxHausdorffDistTaskGPU(ProgressDialog progressDialog, BatchPanel controlPanel, int templateFaceIndex) {
+        super(progressDialog, controlPanel);
+        this.templateFaceIndex = templateFaceIndex;
+    }
+    
+    @Override
+    protected Void doInBackground() throws Exception {
+        initOpenCL();
+
+        HumanFaceFactory factory = getControlPanel().getHumanFaceFactory();
+        List<Path> faces = getControlPanel().getFacePaths();
+        
+        totalTime.start();
+        
+        factory.setReuseDumpFile(true); // it's safe because no changes are made to models 
+        factory.setStrategy(HumanFaceFactory.Strategy.MRU); // keep first X faces in the memory
+        
+        // We don't need to reaload the initFace periodically for two reasons:
+        //   - It is never dumped from memory to disk because we use MRU
+        //   - Even if dumped, the face keeps in the mempry until we hold the pointer to it
+        loadTime.start();
+        String templateFaceId = factory.loadFace(faces.get(templateFaceIndex).toFile());
+        HumanFace templateFace = factory.getFace(templateFaceId);
+        loadTime.stop();
+        
+        // Cache of distances of individual vertices in the GPU memory
+        // srcArrays[i] stores distance of vertices of i-th face to the template face
+        srcArrays = new cl_mem[faces.size()];
+        int numVertices = (int) templateFace.getMeshModel().getNumVertices();
+        
+        for (int i = 0; i < faces.size(); i++) {
+            
+            if (isCancelled()) { // the user canceled the process
+                return null;
+            }
+            
+            if (i != templateFaceIndex) {
+                
+                loadTime.start();
+                String faceId = factory.loadFace(faces.get(i).toFile());
+                HumanFace face = factory.getFace(faceId);
+                loadTime.stop();
+                
+                kdTreeConstructionTime.start();
+                face.computeKdTree(false);
+                kdTreeConstructionTime.stop();
+
+                hdComputationTime.start();
+                HausdorffDistance hd = new HausdorffDistance(
+                        face.getKdTree(),
+                        HausdorffDistance.Strategy.POINT_TO_POINT,
+                        true, // relative
+                        true, // parallel
+                        true  // crop
+                );
+                templateFace.getMeshModel().compute(hd, true);
+                
+                // Copy commputed distances into the GPU memory:
+                float[] auxDist = new float[numVertices];
+                int k = 0;
+                for (float val: hd.getDistances().values().stream().flatMap(List::stream)
+                        .map(x -> x.floatValue()).collect(Collectors.toList())) {
+                    auxDist[k++] = val;
+                }
+                Pointer arrayP = Pointer.to(auxDist);
+                srcArrays[i] = CL.clCreateBuffer(context,
+                        CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR,
+                        Sizeof.cl_float * numVertices, arrayP, null);
+
+                face.removeKdTree(); // TO BE TESTED
+                
+                hdComputationTime.stop();
+            } else { // distance to template face itself is zero
+                float[] auxDist = new float[numVertices]; // filled by zeros by default
+                Pointer arrayP = Pointer.to(auxDist);
+                srcArrays[i] = CL.clCreateBuffer(context,
+                        CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR,
+                        Sizeof.cl_float * numVertices, arrayP, null);
+            }
+            
+            // update progress bar
+            int progress = (int) Math.round(100.0 * (i+1) / faces.size());
+            getProgressDialog().setValue(progress);
+            
+            //Logger.print(factory.toString());
+        }
+        
+        finalHdComputationTime.start();
+        finalizeHdConcurrently(faces.size(), numVertices);
+        finalHdComputationTime.stop();
+        
+        totalTime.stop();
+
+        printTimeStats();
+        
+        return null;
+    }
+    
+    @Override
+    protected void done() {
+        super.done();
+        CL.clReleaseCommandQueue(commandQueue);
+        CL.clReleaseContext(context);
+    }
+    
+    protected void printTimeStats() {
+        Logger.print(hdComputationTime.toString());
+        Logger.print(loadTime.toString());
+        Logger.print(finalHdComputationTime.toString());
+        Logger.print(kdTreeConstructionTime.toString());
+        Logger.print(totalTime.toString());
+    }
+    
+    private void initOpenCL() {
+        // The platform, device type and device number that will be used
+        final int platformIndex = 0;
+        final long deviceType = CL.CL_DEVICE_TYPE_ALL;
+        final int deviceIndex = 0;
+
+        // Enable exceptions and subsequently omit error checks in this sample
+        CL.setExceptionsEnabled(true);
+
+        // Obtain the number of platforms
+        int[] numPlatformsArray = new int[1];
+        CL.clGetPlatformIDs(0, null, numPlatformsArray);
+        int numPlatforms = numPlatformsArray[0];
+
+        // Obtain a platform ID
+        cl_platform_id[] platforms = new cl_platform_id[numPlatforms];
+        CL.clGetPlatformIDs(platforms.length, platforms, null);
+        cl_platform_id platform = platforms[platformIndex];
+
+        // Initialize the context properties
+        cl_context_properties contextProperties = new cl_context_properties();
+        contextProperties.addProperty(CL.CL_CONTEXT_PLATFORM, platform);
+        
+        // Obtain the number of devices for the platform
+        int[] numDevicesArray= new int[1];
+        CL.clGetDeviceIDs(platform, deviceType, 0, null, numDevicesArray);
+        int numDevices = numDevicesArray[0];
+        
+        // Obtain a device ID 
+        cl_device_id[] devices= new cl_device_id[numDevices];
+        CL.clGetDeviceIDs(platform, deviceType, numDevices, devices, null);
+        this.device = devices[deviceIndex];
+
+        // Create a context for the selected device
+        this.context = CL.clCreateContext(
+            contextProperties, 1, new cl_device_id[]{device}, 
+            null, null, null);        
+        
+        // Create a command-queue for the selected device
+        cl_queue_properties properties = new cl_queue_properties();
+        commandQueue = CL.clCreateCommandQueueWithProperties(
+            context, device, properties, null);
+
+        // Create the program from the source code
+        program = CL.clCreateProgramWithSource(context,
+            1, new String[]{ PROGRAM_SOURCE }, null, null);
+        
+        // Build the program
+        CL.clBuildProgram(program, 0, null, null, null, null);
+    }
+
+    protected void finalizeHdConcurrently(int numFaces, int numVertices) {
+        // Set the work-item dimensions
+        long[] globalWorkSize = new long[]{numVertices};
+        
+        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+        final List<Future<Void>> results = new ArrayList<>();
+        
+        for (int i = 0; i < numFaces; i++) {
+            for (int j = i; j < numFaces; j++) {
+
+                if (i == j) {
+                    continue;
+                }
+
+                final int finalI = i;
+                final int finalJ = j;
+
+                results.add(executor.submit(new Callable<Void>() {
+                    @Override
+                    public Void call() throws Exception {
+                        float[] dstArray = new float[numVertices];
+
+                        cl_mem dstMem = CL.clCreateBuffer(context,
+                                CL.CL_MEM_READ_WRITE,
+                                Sizeof.cl_float * numVertices, null, null);
+                        Pointer dstP = Pointer.to(dstArray);
+
+                        // Create the kernel
+                        cl_kernel kernel = CL.clCreateKernel(program, "hdKernel", null);
+
+                        // Set the arguments for the kernel
+                        int a = 0;
+                        CL.clSetKernelArg(kernel, a++, Sizeof.cl_mem, Pointer.to(srcArrays[finalI]));
+                        CL.clSetKernelArg(kernel, a++, Sizeof.cl_mem, Pointer.to(srcArrays[finalJ]));
+                        CL.clSetKernelArg(kernel, a++, Sizeof.cl_mem, Pointer.to(dstMem));
+
+                        // Execute the kernel
+                        CL.clEnqueueNDRangeKernel(commandQueue, kernel, 1, null,
+                                globalWorkSize, null, 0, null, null);
+
+                        // Read the output data
+                        CL.clEnqueueReadBuffer(commandQueue, dstMem, CL.CL_TRUE, 0,
+                                numVertices * Sizeof.cl_float, dstP, 0, null, null);
+
+                        // Release kernel
+                        CL.clReleaseKernel(kernel);
+                        CL.clReleaseMemObject(dstMem);
+
+                        // Compute average HD of the face pair
+                        double sum = 0.0;
+                        int counter = 0;
+                        for (int k = 0; k < numVertices; k++) {
+                            double d = dstArray[k];
+                            if (Double.isFinite(d)) {
+                                sum += d;
+                                counter++;
+                            }
+                        }
+                        setDistSimilarity(finalI, finalJ, sum / counter);
+                        setDistSimilarity(finalJ, finalI, sum / counter);
+
+                        return null;
+                    }
+                }));
+            }
+        }
+        
+        executor.shutdown();
+        while (!executor.isTerminated()){}
+        try {
+            int i = 0;
+            for (Future<Void> res: results) {
+                res.get(); // waits until all computations are finished
+                int progress = (int) Math.round(100.0 * (i+1) / results.size());
+                getProgressDialog().setValue(progress);
+            }
+        } catch (final InterruptedException | ExecutionException ex) {
+            java.util.logging.Logger.getLogger(ApproxHausdorffDistTask.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        
+        // Release Program, and memory objects
+        for (int i = 0; i < numFaces; i++) {
+            CL.clReleaseMemObject(srcArrays[i]);
+        }
+        CL.clReleaseProgram(program);
+    }    
+}
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/BatchAction.java b/GUI/src/main/java/cz/fidentis/analyst/batch/BatchAction.java
index 18f1840e..79f143e9 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/BatchAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/BatchAction.java
@@ -118,7 +118,7 @@ public class BatchAction extends ControlPanelAction implements HumanFaceListener
         HumanFace selectedFace = controlPanel.getSelectedFace();
         if (controlPanel.showIcpPreview() && selectedFace != null) {
             getScene().clearScene(); // scene is recovered automatically - see the event handler above
-            faceSceneSlot = getScene().getFreeIndex();
+            faceSceneSlot = getScene().getFreeSlot();
             
             // Add inital face to the scene:
             getScene().setDrawableFace(faceSceneSlot, selectedFace);
@@ -167,7 +167,7 @@ public class BatchAction extends ControlPanelAction implements HumanFaceListener
         HumanFace face = controlPanel.getSelectedFace();
         if (face != null) {
             if (faceSceneSlot == -1) {
-                faceSceneSlot = getScene().getFreeIndex();
+                faceSceneSlot = getScene().getFreeSlot();
             }
             getScene().setDrawableFace(faceSceneSlot, face); 
             getScene().setFaceAsPrimary(faceSceneSlot);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java b/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
index 2da9a800..8dac7dd7 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/batch/IcpTask.java
@@ -177,7 +177,7 @@ public class IcpTask extends SwingWorker<MeshModel, HumanFace> {
             }
             if (controlPanel.showIcpPreview()) {
                 if (faceSceneSlot == -1) {
-                    faceSceneSlot = canvas.getScene().getFreeIndex();
+                    faceSceneSlot = canvas.getScene().getFreeSlot();
                 }
                 canvas.getScene().setDrawableFace(faceSceneSlot, f);
                 canvas.getScene().getDrawableFace(faceSceneSlot).setTransparency(0.5f);
diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java
index c0be1ee3..29feb057 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/Canvas.java
@@ -84,7 +84,7 @@ public class Canvas extends JPanel {
     public int addPrimaryFace(HumanFace face) {
         if (face != null) {
             faces.add(face);
-            int index = scene.getFreeIndex();
+            int index = scene.getFreeSlot();
             scene.setHumanFace(index, face);
             scene.setFaceAsPrimary(index);
             return index;
@@ -101,7 +101,7 @@ public class Canvas extends JPanel {
     public int addSecondaryFace(HumanFace face) {
         if (face != null) {
             faces.add(face);
-            int index = scene.getFreeIndex();
+            int index = scene.getFreeSlot();
             scene.setHumanFace(index, face);
             scene.setFaceAsSecondary(index);
             return index;
@@ -148,7 +148,7 @@ public class Canvas extends JPanel {
      * @return index of the primary face or -1
      */
     public int getPrimaryFaceIndex() {
-        return scene.getPrimaryFaceIndex();
+        return scene.getPrimaryFaceSlot();
     }
     
     /**
@@ -156,7 +156,7 @@ public class Canvas extends JPanel {
      * @return index of the secondary face or -1
      */
     public int getSecondaryFaceIndex() {
-        return scene.getSecondaryFaceIndex();
+        return scene.getSecondaryFaceSlot();
     }
     
     /**
diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/RenderingModeToolbox.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/RenderingModeToolbox.java
index 36292aaa..5aa3e880 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/RenderingModeToolbox.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/RenderingModeToolbox.java
@@ -36,7 +36,7 @@ public class RenderingModeToolbox extends JPopupMenu {
         JMenuItem menuItem1 = new JMenuItem(new AbstractAction() { // fill
             @Override
             public void actionPerformed(ActionEvent e) {
-                canvas.getScene().getFaceIndices().forEach(i -> {
+                canvas.getScene().getFaceSlots().forEach(i -> {
                     canvas.getScene().getDrawableFace(i).setRenderMode(GL2.GL_FILL);
                 });
                 canvas.renderScene();
@@ -46,7 +46,7 @@ public class RenderingModeToolbox extends JPopupMenu {
         JMenuItem menuItem2 = new JMenuItem(new AbstractAction() { // lines
             @Override
             public void actionPerformed(ActionEvent e) {
-                canvas.getScene().getFaceIndices().forEach(i -> {
+                canvas.getScene().getFaceSlots().forEach(i -> {
                    canvas.getScene().getDrawableFace(i).setRenderMode(GL2.GL_LINE);
                 });
                 canvas.renderScene();
@@ -56,7 +56,7 @@ public class RenderingModeToolbox extends JPopupMenu {
         JMenuItem menuItem3 = new JMenuItem(new AbstractAction() { // points
             @Override
             public void actionPerformed(ActionEvent e) {
-                canvas.getScene().getFaceIndices().forEach(i -> {
+                canvas.getScene().getFaceSlots().forEach(i -> {
                    canvas.getScene().getDrawableFace(i).setRenderMode(GL2.GL_POINT);
                 });
                 canvas.renderScene();
diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java
index c0423288..984f9ac2 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxFaceToFace.java
@@ -51,23 +51,23 @@ public class SceneToolboxFaceToFace extends JPanel {
         
         // Change inital state:
         primLandButton.setSelected(false);
-        DrawableFeaturePoints fp0 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceIndex());
+        DrawableFeaturePoints fp0 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot());
         if (fp0 != null) {
             fp0.show(false);
         }
         
         secLandButton.setSelected(false);
-        DrawableFeaturePoints fp1 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceIndex());
+        DrawableFeaturePoints fp1 = canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceSlot());
         if (fp1 != null) {
             fp1.show(false);
         }
         
         secDistButton.setSelected(true);
-        canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceIndex()).setRenderHeatmap(true);
+        canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(true);
         
         slider.setValue(30);
-        canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceIndex()).setTransparency(30/(float)TRANSPARENCY_RANGE);
-        canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceIndex()).setTransparency(1);
+        canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceSlot()).setTransparency(30/(float)TRANSPARENCY_RANGE);
+        canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setTransparency(1);
     }
 
     private void initComponents() {
@@ -94,7 +94,7 @@ public class SceneToolboxFaceToFace extends JPanel {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
-                canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceIndex()).show(onOff);
+                canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()).show(onOff);
                 canvas.renderScene();
             }
         });
@@ -119,7 +119,7 @@ public class SceneToolboxFaceToFace extends JPanel {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
-                canvas.getScene().showDrawableFace(canvas.getScene().getPrimaryFaceIndex(), onOff);
+                canvas.getScene().showDrawableFace(canvas.getScene().getPrimaryFaceSlot(), onOff);
                 canvas.renderScene();
             }
         });
@@ -138,12 +138,12 @@ public class SceneToolboxFaceToFace extends JPanel {
         slider.addChangeListener((ChangeEvent e) -> {
             int val = ((JSlider) e.getSource()).getValue();
             if (val <= TRANSPARENCY_RANGE) {
-                canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceIndex())
+                canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceSlot())
                         .setTransparency(val/(float)TRANSPARENCY_RANGE);
-                canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceIndex()).setTransparency(1);
+                canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setTransparency(1);
             } else if (val > TRANSPARENCY_RANGE) {
-                canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceIndex()).setTransparency(1);
-                canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceIndex())
+                canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceSlot()).setTransparency(1);
+                canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot())
                         .setTransparency((2 * TRANSPARENCY_RANGE - val) / (float)TRANSPARENCY_RANGE);
             }
             canvas.renderScene();
@@ -169,7 +169,7 @@ public class SceneToolboxFaceToFace extends JPanel {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
-                canvas.getScene().showDrawableFace(canvas.getScene().getSecondaryFaceIndex(), onOff);
+                canvas.getScene().showDrawableFace(canvas.getScene().getSecondaryFaceSlot(), onOff);
                 canvas.renderScene();
             }
         });
@@ -195,7 +195,7 @@ public class SceneToolboxFaceToFace extends JPanel {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
-                canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceIndex()).show(onOff);
+                canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceSlot()).show(onOff);
                 canvas.renderScene();
             }
         });
@@ -220,9 +220,9 @@ public class SceneToolboxFaceToFace extends JPanel {
             @Override
             public void actionPerformed(ActionEvent e) {
                 if (((JToggleButton) e.getSource()).isSelected()) {
-                    canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceIndex()).setRenderHeatmap(true);
+                    canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(true);
                 } else {
-                    canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceIndex()).setRenderHeatmap(false);
+                    canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()).setRenderHeatmap(false);
                 }
                 // Switch:
                 //canvas.getScene().getDrawableFace(secIndex).setRenderHeatmap(
diff --git a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java
index a0e045dc..b5078bcb 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/canvas/toolbar/SceneToolboxSingleFace.java
@@ -68,7 +68,7 @@ public class SceneToolboxSingleFace extends JPanel {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
-                canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceIndex()).show(onOff);
+                canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()).show(onOff);
                 canvas.renderScene();
             }
         });
@@ -93,7 +93,7 @@ public class SceneToolboxSingleFace extends JPanel {
             @Override
             public void actionPerformed(ActionEvent e) {
                 boolean onOff = ((JToggleButton) e.getSource()).isSelected();
-                canvas.getScene().showDrawableFace(canvas.getScene().getPrimaryFaceIndex(), onOff);
+                canvas.getScene().showDrawableFace(canvas.getScene().getPrimaryFaceSlot(), onOff);
                 canvas.renderScene();
             }
         });
@@ -111,7 +111,7 @@ public class SceneToolboxSingleFace extends JPanel {
         
         slider.addChangeListener((ChangeEvent e) -> {
             int val = ((JSlider) e.getSource()).getValue();
-            canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceIndex()).setTransparency(val/100f);
+            canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceSlot()).setTransparency(val/100f);
             canvas.renderScene();
         });
         
diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelAction.java b/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelAction.java
index 0ca16a83..75021c0f 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/core/ControlPanelAction.java
@@ -72,25 +72,25 @@ public abstract class ControlPanelAction extends AbstractAction {
     
     protected DrawableFace getPrimaryDrawableFace() {
         return (canvas.getScene() != null) 
-                ? canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceIndex()) 
+                ? canvas.getScene().getDrawableFace(canvas.getScene().getPrimaryFaceSlot()) 
                 : null;
     }
     
     protected DrawableFace getSecondaryDrawableFace() {
         return (canvas.getScene() != null) 
-                ? canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceIndex()) 
+                ? canvas.getScene().getDrawableFace(canvas.getScene().getSecondaryFaceSlot()) 
                 : null;
     }
     
     protected DrawableFeaturePoints getPrimaryFeaturePoints() {
         return (canvas.getScene() != null) 
-                ? canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceIndex()) 
+                ? canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getPrimaryFaceSlot()) 
                 : null;
     }
     
     protected DrawableFeaturePoints getSecondaryFeaturePoints() {
         return (canvas.getScene() != null) 
-                ? canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceIndex()) 
+                ? canvas.getScene().getDrawableFeaturePoints(canvas.getScene().getSecondaryFaceSlot()) 
                 : null;
     }
 
diff --git a/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java b/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
index 71162781..455ab3f8 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/distance/DistanceAction.java
@@ -93,7 +93,7 @@ public class DistanceAction extends ControlPanelAction implements HumanFaceListe
         
         // Add spheres to the scene
         fpSpheres = new DrawableFpWeights(getSecondaryFeaturePoints().getFeaturePoints());
-        getCanvas().getScene().setOtherDrawable(getCanvas().getScene().getFreeIndexForOtherDrawables(), fpSpheres);
+        getCanvas().getScene().setOtherDrawable(getCanvas().getScene().getFreeSlotForOtherDrawables(), fpSpheres);
         
         // Place control panel to the topControlPanel
         topControlPanel.addTab(controlPanel.getName(), controlPanel.getIcon(), controlPanel);
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 0a319fc0..28613b1a 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/scene/Scene.java
@@ -22,8 +22,8 @@ public class Scene {
     private final List<DrawablePlane> drawableSymmetryPlanes = new ArrayList<>();
     private final List<Drawable> otherDrawables = new ArrayList<>();
     
-    private int primaryFaceIndex = -1;
-    private int secondaryFaceIndex = -1;
+    private int primaryFaceSlot = -1;
+    private int secondaryFaceSlot = -1;
     
     public static final int MAX_FACES_IN_SCENE = 20;
     
@@ -35,87 +35,87 @@ public class Scene {
         this.drawableFeaturePoints.clear();
         this.drawableSymmetryPlanes.clear();
         this.otherDrawables.clear();
-        primaryFaceIndex = -1;
-        secondaryFaceIndex = -1;
+        primaryFaceSlot = -1;
+        secondaryFaceSlot = -1;
     }
     
     /**
-     * Finds and returns a first free index for human face and its drawables.
-     * @return a first free index for human face and its drawables.
+     * Finds and returns a first free slot for human face and its drawables.
+     * @return a first free slot for human face and its drawables.
      */
-    public int getFreeIndex() {
-        int index = -1;
+    public int getFreeSlot() {
+        int slot = -1;
         for (int i = 0; i < getArraySize(); i++) {
             if (this.drawableFaces.get(i) == null) {
-                index = i;
+                slot = i;
                 break;
             }
         }
-        if (index == -1) {
-            index = getArraySize();
+        if (slot == -1) {
+            slot = getArraySize();
         }
-        return (index < Scene.MAX_FACES_IN_SCENE) ? index : -1;
+        return (slot < Scene.MAX_FACES_IN_SCENE) ? slot : -1;
     }
     
     /**
-     * Finds and returns a first free index for other drawable objects.
-     * @return a first free index for other drawable objects.
+     * Finds and returns a first free slot for other drawable objects.
+     * @return a first free slot for other drawable objects.
      */
-    public int getFreeIndexForOtherDrawables() {
-        int index = -1;
+    public int getFreeSlotForOtherDrawables() {
+        int slot = -1;
         for (int i = 0; i < this.otherDrawables.size(); i++) {
             if (this.otherDrawables.get(i) == null) {
-                index = i;
+                slot = i;
                 break;
             }
         }
-        if (index == -1) {
-            index = otherDrawables.size();
+        if (slot == -1) {
+            slot = otherDrawables.size();
         }
-        return (index < Scene.MAX_FACES_IN_SCENE) ? index : -1;
+        return (slot < Scene.MAX_FACES_IN_SCENE) ? slot : -1;
     }
     
     /**
-     * Returns index of the primary face or -1
-     * @return index of the primary face or -1
+     * Returns slot of the primary face or -1
+     * @return slot of the primary face or -1
      */
-    public int getPrimaryFaceIndex() {
-        return this.primaryFaceIndex;
+    public int getPrimaryFaceSlot() {
+        return this.primaryFaceSlot;
     }
     
     /**
-     * Returns index of the secondary face or -1
-     * @return index of the secondary face or -1
+     * Returns slot of the secondary face or -1
+     * @return slot of the secondary face or -1
      */
-    public int getSecondaryFaceIndex() {
-        return this.secondaryFaceIndex;
+    public int getSecondaryFaceSlot() {
+        return this.secondaryFaceSlot;
     }
     
     /**
      * Sets the given face as primary.
-     * @param index Index of the face that should be set as primary
+     * @param slot slot of the face that should be set as primary
      */
-    public void setFaceAsPrimary(int index) {
-        if (index >= 0 && index < getArraySize()) {
-            this.primaryFaceIndex = index;
+    public void setFaceAsPrimary(int slot) {
+        if (slot >= 0 && slot < getArraySize()) {
+            this.primaryFaceSlot = slot;
         }
     }
     
     /**
      * Sets the given face as secondary.
-     * @param index Index of the face that should be set as secondary
+     * @param slot slot of the face that should be set as secondary
      */
-    public void setFaceAsSecondary(int index) {
-        if (index >= 0 && index < getArraySize()) {
-            this.secondaryFaceIndex = index;
+    public void setFaceAsSecondary(int slot) {
+        if (slot >= 0 && slot < getArraySize()) {
+            this.secondaryFaceSlot = slot;
         }
     }
     
     /**
-     * Returns all "occupied" indices, i.e., indexes where is stored some human face.
-     * @return "occupied" indices, i.e., indexes where is stored some human face.
+     * Returns all "occupied" slots, i.e., indexes where some human face is stored.
+     * @return "occupied" slots, i.e., indexes where some human face is stored.
      */
-    public List<Integer> getFaceIndices() {
+    public List<Integer> getFaceSlots() {
         List<Integer> ret = new ArrayList<>();
         for (int i = 0; i < this.drawableFaces.size(); i++) {
             if (this.drawableFaces.get(i) != null) {
@@ -128,48 +128,48 @@ public class Scene {
     /**
      * Returns drawable face.
      * 
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @return drawable face or {@code null}
      */
-    public DrawableFace getDrawableFace(int index) {
-        return (index < 0 || index >= getArraySize()) ? null : drawableFaces.get(index);
+    public DrawableFace getDrawableFace(int slot) {
+        return (slot < 0 || slot >= getArraySize()) ? null : drawableFaces.get(slot);
     }
     
     /**
      * Sets the face and all its existing drawable components.   
      * If the face is {@code null}, then the drawable face and all its components are removed.
      * 
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @param face New face or {@code null}
      * @return 
      */
-    public boolean setHumanFace(int index, HumanFace face) {
-        return setDrawableFace(index, face) &&
-                setDrawableFeaturePoints(index, face) &&
-                setDrawableSymmetryPlane(index, face);
+    public boolean setHumanFace(int slot, HumanFace face) {
+        return setDrawableFace(slot, face) &&
+                setDrawableFeaturePoints(slot, face) &&
+                setDrawableSymmetryPlane(slot, face);
     }
     
     /**
      * Sets the drawable face (mesh). If the face is {@code null}, then the drawable face is removed.
      *
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @param face New face or {@code null}
      */
-    public boolean setDrawableFace(int index, HumanFace face) {
-        if (index < 0 || index >= Scene.MAX_FACES_IN_SCENE) {
+    public boolean setDrawableFace(int slot, HumanFace face) {
+        if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) {
             return false;
         } else if (face == null) { // remove
-            if (index >= getArraySize()){
+            if (slot >= getArraySize()){
                 return false;
             } else {
-                this.drawableFaces.set(index, null);
+                this.drawableFaces.set(slot, null);
                 return true;
             }
-        } else if (!prepareArrays(index, face)) {
+        } else if (!prepareArrays(slot, face)) {
             return false;
         }        
         
-        drawableFaces.set(index, new DrawableFace(face));
+        drawableFaces.set(slot, new DrawableFace(face));
         
         return true;
     }
@@ -178,25 +178,25 @@ public class Scene {
      * Sets the drawable feature points of the face. 
      * If the face is {@code null}, then the drawable feature points are removed.
      *
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @param face New face or {@code null}
      */
-    public boolean setDrawableFeaturePoints(int index, HumanFace face) {
-        if (index < 0 || index >= Scene.MAX_FACES_IN_SCENE) {
+    public boolean setDrawableFeaturePoints(int slot, HumanFace face) {
+        if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) {
             return false;
         } else if (face == null) { // remove
-            if (index >= getArraySize()){
+            if (slot >= getArraySize()){
                 return false;
             } else {
-                this.drawableFeaturePoints.set(index, null);
+                this.drawableFeaturePoints.set(slot, null);
                 return true;
             }
-        } else if (!prepareArrays(index, face)) {
+        } else if (!prepareArrays(slot, face)) {
             return false;
         }        
         
         drawableFeaturePoints.set(
-                index,
+                slot,
                 (face.getFeaturePoints() != null) 
                         ? new DrawableFeaturePoints(face.getFeaturePoints())
                         : null
@@ -209,25 +209,25 @@ public class Scene {
      * Sets the drawable symmetry plane of the face. 
      * If the face is {@code null}, then the drawable symmetry plane is removed.
      *
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @param face New face or {@code null}
      */
-    public boolean setDrawableSymmetryPlane(int index, HumanFace face) {
-        if (index < 0 || index >= Scene.MAX_FACES_IN_SCENE) {
+    public boolean setDrawableSymmetryPlane(int slot, HumanFace face) {
+        if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) {
             return false;
         } else if (face == null) { // remove
-            if (index >= getArraySize()){
+            if (slot >= getArraySize()){
                 return false;
             } else {
-                this.drawableSymmetryPlanes.set(index, null);
+                this.drawableSymmetryPlanes.set(slot, null);
                 return true;
             }
-        } else if (!prepareArrays(index, face)) {
+        } else if (!prepareArrays(slot, face)) {
             return false;
         }        
         
         drawableSymmetryPlanes.set(
-                index,
+                slot,
                 (face.getSymmetryPlane() != null && face.getSymmetryPlaneFacet() != null) 
                         ? new DrawablePlane(face.getSymmetryPlaneFacet(), face.getSymmetryPlane())
                         : null
@@ -240,25 +240,25 @@ public class Scene {
      * Sets other drawable. 
      * If the drawable is {@code null}, then the drawable is removed.
      *
-     * @param index Index of the drawable
+     * @param slot Slot of the drawable
      * @param face New face or {@code null}
      */
-    public boolean setOtherDrawable(int index, Drawable dr) {
-        if (index < 0 || index >= Scene.MAX_FACES_IN_SCENE) {
+    public boolean setOtherDrawable(int slot, Drawable dr) {
+        if (slot < 0 || slot >= Scene.MAX_FACES_IN_SCENE) {
             return false;
         } else if (dr == null) { // remove
-            if (index >= otherDrawables.size()){
+            if (slot >= otherDrawables.size()){
                 return false;
             } else {
-                otherDrawables.set(index, null);
+                otherDrawables.set(slot, null);
                 return true;
             }
         } 
         
-        for (int i = otherDrawables.size(); i <= index; i++) {
+        for (int i = otherDrawables.size(); i <= slot; i++) {
             otherDrawables.add(null);
         }
-        otherDrawables.set(index, dr);
+        otherDrawables.set(slot, dr);
         return true;
     }
     
@@ -268,18 +268,18 @@ public class Scene {
     public final void setDefaultColors() {
         for (int i = 0; i < getArraySize(); i++) {
             if (drawableFaces.get(i) != null) {
-                if (i == this.primaryFaceIndex) {
+                if (i == this.primaryFaceSlot) {
                     drawableFaces.get(i).setColor(DrawableFace.SKIN_COLOR_PRIMARY);
-                } else if (i == this.secondaryFaceIndex) {
+                } else if (i == this.secondaryFaceSlot) {
                     drawableFaces.get(i).setColor(DrawableFace.SKIN_COLOR_SECONDARY);
                 } else {
                     drawableFaces.get(i).setColor(DrawableFace.SKIN_COLOR_DEFAULT);
                 }
             }
             if (drawableFeaturePoints.get(i) != null) {
-                if (i == this.primaryFaceIndex) {
+                if (i == this.primaryFaceSlot) {
                     drawableFeaturePoints.get(i).setColor(getColorOfFeaturePoints(DrawableFace.SKIN_COLOR_PRIMARY));
-                } else if (i == this.secondaryFaceIndex) {
+                } else if (i == this.secondaryFaceSlot) {
                     drawableFeaturePoints.get(i).setColor(getColorOfFeaturePoints(DrawableFace.SKIN_COLOR_SECONDARY));
                 } else {
                     drawableFeaturePoints.get(i).setColor(getColorOfFeaturePoints(DrawableFace.SKIN_COLOR_DEFAULT));
@@ -298,66 +298,67 @@ public class Scene {
     /**
      * Returns drawable feature points.
      * 
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @return drawable face or {@code null}
      */
-    public DrawableFeaturePoints getDrawableFeaturePoints(int index) {
-        return (index >= 0 && index < getArraySize()) ? drawableFeaturePoints.get(index) : null;
+    public DrawableFeaturePoints getDrawableFeaturePoints(int slot) {
+        return (slot >= 0 && slot < getArraySize()) ? drawableFeaturePoints.get(slot) : null;
     }
     
     /**
      * Returns drawable symmetry plane.
      * 
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @return drawable plane or {@code null}
      */
-    public DrawablePlane getDrawableSymmetryPlane(int index) {
-        return (index >= 0 && index < getArraySize()) ? drawableSymmetryPlanes.get(index) : null;
+    public DrawablePlane getDrawableSymmetryPlane(int slot) {
+        return (slot >= 0 && slot < getArraySize()) ? drawableSymmetryPlanes.get(slot) : null;
     }
     
     /**
      * Showing or hiding the face (its mesh)
      *
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @param show determines whether to hide or show the object
      */
-    public void showDrawableFace(int index, boolean show) {
-        if (index >= 0 && index < getArraySize() && this.drawableFaces.get(index) != null) {
-            this.drawableFaces.get(index).show(show);
+    public void showDrawableFace(int slot, boolean show) {
+        if (slot >= 0 && slot < getArraySize() && this.drawableFaces.get(slot) != null) {
+            this.drawableFaces.get(slot).show(show);
         }
     }
 
     /**
      * Showing or hiding the feature points
      *
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @param show determines whether to hide or show the object
      */
-    public void showFeaturePoints(int index, boolean show) {
-        if (index >= 0 && index < getArraySize() && this.drawableFeaturePoints.get(index) != null) {
-            this.drawableFeaturePoints.get(index).show(show);
+    public void showFeaturePoints(int slot, boolean show) {
+        if (slot >= 0 && slot < getArraySize() && this.drawableFeaturePoints.get(slot) != null) {
+            this.drawableFeaturePoints.get(slot).show(show);
         }
     }
     
     /**
      * Showing or hiding the symmetry plane
      *
-     * @param index Index of the face
+     * @param slot Slot of the face
      * @param show determines whether to hide or show the object
      */
-    public void showSymmetryPlane(int index, boolean show) {
-        if (index >= 0 && index < getArraySize() && this.drawableSymmetryPlanes.get(index) != null) {
-            this.drawableSymmetryPlanes.get(index).show(show);
+    public void showSymmetryPlane(int slot, boolean show) {
+        if (slot >= 0 && slot < getArraySize() && this.drawableSymmetryPlanes.get(slot) != null) {
+            this.drawableSymmetryPlanes.get(slot).show(show);
         }
     }
 
     /**
      * Returns other drawable object.
      * 
+     * @param slot Slot of the drawable object
      * @return drawable object or {@code null}
      */
-    public Drawable getOtherDrawable(int index) {
-        return (index >= 0 && index < this.otherDrawables.size()) ? this.otherDrawables.get(index) : null;
+    public Drawable getOtherDrawable(int slot) {
+        return (slot >= 0 && slot < this.otherDrawables.size()) ? this.otherDrawables.get(slot) : null;
     }
     
     /**
@@ -383,13 +384,13 @@ public class Scene {
         );
     }
     
-    protected boolean prepareArrays(int index, Object drawable) {
-        if (index >= Scene.MAX_FACES_IN_SCENE) {
+    protected boolean prepareArrays(int slot, Object drawable) {
+        if (slot >= Scene.MAX_FACES_IN_SCENE) {
             return false;
         }
         
         // extend the 
-        for (int i = getArraySize(); i <= index; i++) {
+        for (int i = getArraySize(); i <= slot; i++) {
             this.drawableFaces.add(null);
             this.drawableFeaturePoints.add(null);
             this.drawableSymmetryPlanes.add(null);
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 4aa180ad..6eab131f 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/ProfilesAction.java
@@ -285,13 +285,13 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
     protected void computeOrthogonalCuttingPlanes(boolean horizontal) {
         DrawableCuttingPlane drPlane = getDrawableOrthogonalPlane(horizontal);
         if (priCuttingPlaneIndex == -1) {
-            priCuttingPlaneIndex = getCanvas().getScene().getFreeIndexForOtherDrawables();
+            priCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
         }
         getCanvas().getScene().setOtherDrawable(priCuttingPlaneIndex, drPlane);
         
         if (getSecondaryDrawableFace() != null) {
             if (secCuttingPlaneIndex == -1) {
-                secCuttingPlaneIndex = getCanvas().getScene().getFreeIndexForOtherDrawables();
+                secCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
             }
             getCanvas().getScene().setOtherDrawable(secCuttingPlaneIndex, new DrawableCuttingPlane(drPlane));
         }
@@ -333,7 +333,7 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
         DrawableCuttingPlane cuttingPlane = getCuttingPlaneFromSymmetry(getCanvas().getPrimaryFaceIndex());
         cuttingPlane.setTransparency(0.5f);
         if (priCuttingPlaneIndex == -1) {
-            priCuttingPlaneIndex = getCanvas().getScene().getFreeIndexForOtherDrawables();
+            priCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
         }
         getCanvas().getScene().setOtherDrawable(priCuttingPlaneIndex, cuttingPlane);
         recomputePrimaryProfile();
@@ -342,7 +342,7 @@ public class ProfilesAction extends ControlPanelAction implements HumanFaceListe
             cuttingPlane = getCuttingPlaneFromSymmetry(getCanvas().getSecondaryFaceIndex());
             cuttingPlane.setTransparency(0.5f);
             if (secCuttingPlaneIndex == -1) {
-                secCuttingPlaneIndex = getCanvas().getScene().getFreeIndexForOtherDrawables();
+                secCuttingPlaneIndex = getCanvas().getScene().getFreeSlotForOtherDrawables();
             }
             getCanvas().getScene().setOtherDrawable(secCuttingPlaneIndex, cuttingPlane);
             recomputeSecondaryProfile();
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 45315518..a044a14b 100644
--- a/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java
+++ b/GUI/src/main/java/cz/fidentis/analyst/symmetry/SymmetryAction.java
@@ -58,11 +58,11 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
             // If the symmetry panel is focused...
             if (((JTabbedPane) e.getSource()).getSelectedComponent() instanceof SymmetryPanel) {
                 getCanvas().getScene().setDefaultColors();
-                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getPrimaryFaceIndex(), true);
-                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getSecondaryFaceIndex(), true);
+                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getPrimaryFaceSlot(), true);
+                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getSecondaryFaceSlot(), true);
             } else {
-                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getPrimaryFaceIndex(), false);
-                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getSecondaryFaceIndex(), false);
+                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getPrimaryFaceSlot(), false);
+                getCanvas().getScene().showSymmetryPlane(getCanvas().getScene().getSecondaryFaceSlot(), false);
             }
         });
 
@@ -80,13 +80,13 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
         switch (action) {
             case SymmetryPanel.ACTION_COMMAND_RECOMPUTE_FROM_MESH: 
                 sPlane = 1;
-                recomputeFromMesh(getCanvas().getScene().getPrimaryFaceIndex());
-                recomputeFromMesh(getCanvas().getScene().getSecondaryFaceIndex());
+                recomputeFromMesh(getCanvas().getScene().getPrimaryFaceSlot());
+                recomputeFromMesh(getCanvas().getScene().getSecondaryFaceSlot());
                 break; 
             case SymmetryPanel.ACTION_COMMAND_COMPUTE_FROM_FPS: 
                 sPlane = 2;
-                recomputeFromFeaturePoints(getCanvas().getScene().getPrimaryFaceIndex());
-                recomputeFromFeaturePoints(getCanvas().getScene().getSecondaryFaceIndex());
+                recomputeFromFeaturePoints(getCanvas().getScene().getPrimaryFaceSlot());
+                recomputeFromFeaturePoints(getCanvas().getScene().getSecondaryFaceSlot());
                 break;
             default:
                 // do nothing
@@ -102,13 +102,13 @@ public class SymmetryAction extends ControlPanelAction implements HumanFaceListe
                     return;
                 case 1: // from mesh
                     recomputeFromMesh(event.getFace().equals(getPrimaryDrawableFace().getHumanFace()) 
-                            ? getCanvas().getScene().getPrimaryFaceIndex()
-                            : getCanvas().getScene().getSecondaryFaceIndex());
+                            ? getCanvas().getScene().getPrimaryFaceSlot()
+                            : getCanvas().getScene().getSecondaryFaceSlot());
                     break;
                 case 2: // from FPs
                     recomputeFromFeaturePoints(event.getFace().equals(getPrimaryDrawableFace().getHumanFace())
-                            ? getCanvas().getScene().getPrimaryFaceIndex() 
-                            : getCanvas().getScene().getSecondaryFaceIndex());
+                            ? getCanvas().getScene().getPrimaryFaceSlot() 
+                            : getCanvas().getScene().getSecondaryFaceSlot());
                     break;
                 default:
             }
-- 
GitLab