From 36329521cc504c7b061ec77d7925ed01eb6ddcc5 Mon Sep 17 00:00:00 2001
From: Radek Oslejsek <oslejsek@fi.muni.cz>
Date: Thu, 25 Feb 2021 08:03:44 +0100
Subject: [PATCH] Project refactoring; HumanFace implementation; Introduction
 of listeners

---
 Comparison/pom.xml                            |   5 +
 .../java/cz/fidentis/analyst/HumanFace.java   |  46 ------
 .../cz/fidentis/analyst/face/HumanFace.java   | 136 ++++++++++++++++++
 .../analyst/face/HumanFaceListener.java       |  14 ++
 .../analyst/face/KdTreeBuiltEvent.java        |  27 ++++
 .../fidentis/analyst/face/package-info.java   |  13 ++
 .../analyst/symmetry/package-info.java        |   4 +
 .../analyst/visitors/kdtree/package-info.java |   5 +
 .../analyst/visitors/mesh/package-info.java   |   5 +
 MeshModel/pom.xml                             |   5 +
 .../analyst/feature/package-info.java         |   4 +
 .../cz/fidentis/analyst/kdtree/KdTree.java    |  42 +++++-
 .../fidentis/analyst/kdtree/KdTreeEvent.java  |  11 ++
 .../analyst/kdtree/KdTreeListener.java        |  21 +++
 .../fidentis/analyst/kdtree/package-info.java |   4 +
 .../fidentis/analyst/mesh/core/MeshModel.java |  58 +++++++-
 .../analyst/mesh/core/package-info.java       |   6 +
 .../analyst/mesh/events/FacetAddedEvent.java  |  22 +++
 .../analyst/mesh/events/MeshEvent.java        |  11 ++
 .../analyst/mesh/events/MeshListener.java     |  22 +++
 .../analyst/mesh/events/package-info.java     |   7 +
 .../analyst/mesh/io/package-info.java         |   5 +
 .../analyst/mesh/material/package-info.java   |   6 +
 .../fidentis/analyst/mesh/package-info.java   |   4 +
 24 files changed, 429 insertions(+), 54 deletions(-)
 delete mode 100644 Comparison/src/main/java/cz/fidentis/analyst/HumanFace.java
 create mode 100644 Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
 create mode 100644 Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceListener.java
 create mode 100644 Comparison/src/main/java/cz/fidentis/analyst/face/KdTreeBuiltEvent.java
 create mode 100644 Comparison/src/main/java/cz/fidentis/analyst/face/package-info.java
 create mode 100644 Comparison/src/main/java/cz/fidentis/analyst/symmetry/package-info.java
 create mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/package-info.java
 create mode 100644 Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/package-info.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/feature/package-info.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeEvent.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeListener.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/kdtree/package-info.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/package-info.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/FacetAddedEvent.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshEvent.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshListener.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/package-info.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/io/package-info.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/material/package-info.java
 create mode 100644 MeshModel/src/main/java/cz/fidentis/analyst/mesh/package-info.java

diff --git a/Comparison/pom.xml b/Comparison/pom.xml
index 8db660f5..8276a50a 100644
--- a/Comparison/pom.xml
+++ b/Comparison/pom.xml
@@ -82,6 +82,11 @@
             <artifactId>javafx-controls</artifactId>
             <version>11.0.2</version>
         </dependency> -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>30.1-jre</version>
+        </dependency>
         <dependency>
             <groupId>org.junit.jupiter</groupId>
             <artifactId>junit-jupiter</artifactId>
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/HumanFace.java b/Comparison/src/main/java/cz/fidentis/analyst/HumanFace.java
deleted file mode 100644
index e5ef7373..00000000
--- a/Comparison/src/main/java/cz/fidentis/analyst/HumanFace.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package cz.fidentis.analyst;
-
-import cz.fidentis.analyst.mesh.core.MeshModel;
-import cz.fidentis.analyst.mesh.io.MeshObjLoader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * This class encapsulates data for 3D scan of a single human face.
- * 
- * @author Radek Oslejsek
- */
-public class HumanFace {
-    
-    private MeshModel meshModel;
-    
-    /**
-     * Reads a 3D human phase from file.
-     * 
-     * @param file OBJ file
-     * @throws IOException on I/O failure
-     */
-    public HumanFace(File file) throws IOException {
-        meshModel = MeshObjLoader.read(file);
-    }
-    
-    /**
-     * Reads a 3D human phase from file.
-     * 
-     * @param is input stream with OBJ data
-     * @throws IOException on I/O failure
-     */
-    public HumanFace(InputStream is) throws IOException {
-        meshModel = MeshObjLoader.read(is);
-    }
-    
-    /**
-     * Returns the triangular mesh model of the human face.
-     * 
-     * @return the triangular mesh model of the human face
-     */
-    public MeshModel getMeshModel() {
-        return meshModel;
-    }
-}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
new file mode 100644
index 00000000..28836f6c
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFace.java
@@ -0,0 +1,136 @@
+package cz.fidentis.analyst.face;
+
+import com.google.common.eventbus.EventBus;
+import cz.fidentis.analyst.kdtree.KdTree;
+import cz.fidentis.analyst.kdtree.KdTreeEvent;
+import cz.fidentis.analyst.kdtree.KdTreeListener;
+import cz.fidentis.analyst.mesh.core.MeshModel;
+import cz.fidentis.analyst.mesh.events.MeshEvent;
+import cz.fidentis.analyst.mesh.events.MeshListener;
+import cz.fidentis.analyst.mesh.io.MeshObjLoader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class encapsulates data for a 3D scan of a single human face.
+ * <p>
+ * Changes in the human face and its data structures (e.g., jesh model, kd-tree, etc.)
+ * can be monitored by listeners. Listeners have to implement the 
+ * {@link cz.fidentis.analyst.face.HumanFaceListener} iterface and they have to 
+ * register using the {@link cz.fidentis.analyst.face.HumanFace#registerListener} method.
+ * Then the are informed about changes in the human automatically via methods 
+ * prescribed by the interface.
+ * </p>
+ * Events fired by the class:
+ * <ul>
+ * <li>{@link cz.fidentis.analyst.mesh.events.MeshEvent} or its sub-type if 
+ * the mesh model changes (see {@link cz.fidentis.analyst.mesh.MeshModel} 
+ * documentation for monitored changes).</li>
+ * <li>{@link cz.fidentis.analyst.kdtree.KdTreeEvent} or its sub-type if 
+ * the kd-tree changes (see {@link cz.fidentis.analyst.kdtree.KdTree} 
+ * documentation for monitored changes).</li>
+ * <li>{@link cz.fidentis.analyst.face.KdTreeBuiltEvent} if the kd-tree has been 
+ * completely (re-)built.</li>
+ * </ul>
+ * </p>
+ * 
+ * @author Radek Oslejsek
+ */
+public class HumanFace implements MeshListener, KdTreeListener {
+    
+    private MeshModel meshModel;
+    private KdTree kdTree;
+    
+    private EventBus eventBus = new EventBus();
+    
+    /**
+     * Reads a 3D human phase from file.
+     * 
+     * @param file OBJ file
+     * @throws IOException on I/O failure
+     */
+    public HumanFace(File file) throws IOException {
+        meshModel = MeshObjLoader.read(file);
+        meshModel.registerListener(this);
+    }
+    
+    /**
+     * Reads a 3D human phase from file.
+     * 
+     * @param is input stream with OBJ data
+     * @throws IOException on I/O failure
+     */
+    public HumanFace(InputStream is) throws IOException {
+        meshModel = MeshObjLoader.read(is);
+        meshModel.registerListener(this);
+    }
+    
+    /**
+     * Returns the triangular mesh model of the human face.
+     * 
+     * @return the triangular mesh model of the human face
+     */
+    public MeshModel getMeshModel() {
+        return meshModel;
+    }
+    
+    /**
+     * Builds new kd-tree and fires the {@link cz.fidentis.analyst.face.KdTreeBuiltEvent}
+     * with the old tree (if any) stored in the event.
+     */
+    public void buildKdTree() {
+        KdTree old = kdTree;
+        kdTree = new KdTree(meshModel.getFacets());
+        eventBus.post(new KdTreeBuiltEvent(old));
+    }
+    
+    /**
+     * Returns true if the kd-tree is computed.
+     * 
+     * @return true if the kd-tree is computed.
+     */
+    public boolean hasKdTree() {
+        return kdTree != null;
+    }
+    
+    public KdTree getKdTree() {
+        return kdTree;
+    }
+    
+    /**
+     * Registers listeners (objects concerned in the human face changes) to receive events.
+     * If listener is {@code null}, no exception is thrown and no action is taken.
+     * 
+     * @param listener Listener concerned in the human face changes.
+     */
+    public void registerListener(MeshListener listener) {
+        eventBus.register(listener);
+    }
+    
+    /**
+     * Unregisters listeners from receiving events.
+     * 
+     * @param listener Registered listener
+     */
+    public void unregisterListener(MeshListener listener) {
+        eventBus.unregister(listener);
+    }
+
+    /**
+     * Captures events fired by {@link cz.fidentis.analyst.mesh.MeshModel} and
+     * redirects them to our listeners.
+     * 
+     * @param event A fired event.
+     */
+    @Override
+    public void meshEvent(MeshEvent event) {
+        eventBus.post(event);
+    }
+
+    @Override
+    public void kdTreeEvent(KdTreeEvent event) {
+        eventBus.post(event);
+    }
+    
+}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceListener.java b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceListener.java
new file mode 100644
index 00000000..aa6cd03a
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/HumanFaceListener.java
@@ -0,0 +1,14 @@
+package cz.fidentis.analyst.face;
+
+import cz.fidentis.analyst.mesh.events.MeshListener;
+
+/**
+ * Objects implementing this interface can be registered with 
+ * a {@link cz.fidentis.analyst.face.HumanFace} object 
+ * and then be informed when the human face (some of its internal data strcutures) changes.
+ * 
+ * @author Radek Oslejsek
+ */
+public interface HumanFaceListener extends MeshListener {
+    
+}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/KdTreeBuiltEvent.java b/Comparison/src/main/java/cz/fidentis/analyst/face/KdTreeBuiltEvent.java
new file mode 100644
index 00000000..25d87d1e
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/KdTreeBuiltEvent.java
@@ -0,0 +1,27 @@
+package cz.fidentis.analyst.face;
+
+import cz.fidentis.analyst.kdtree.KdTree;
+import cz.fidentis.analyst.kdtree.KdTreeEvent;
+
+/**
+ * Event indicating that a new kd-tree has been buit.
+ * The old tree is stored in the event.
+ * 
+ * @author Radek Oslejsek
+ */
+public class KdTreeBuiltEvent implements KdTreeEvent {
+    
+    private KdTree oldTree;
+    
+    /**
+     * 
+     * @param oldTree Old kd-tree. Can be {@code null}
+     */
+    public KdTreeBuiltEvent(KdTree oldTree) {
+        this.oldTree = oldTree;
+    }
+
+    public KdTree getOldTree() {
+        return oldTree;
+    }
+}
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/face/package-info.java b/Comparison/src/main/java/cz/fidentis/analyst/face/package-info.java
new file mode 100644
index 00000000..2897e3b9
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/face/package-info.java
@@ -0,0 +1,13 @@
+/**
+ * The {@code HumanFace} class serving as the main entry point for
+ * dealing with a single face, and related interfaces and classes, e.g.,
+ * classes necessary for publish-subscribe notification of changes in the human face.
+ * <p>
+ * While events triggered directly by the underlying data structures are defined  
+ * in {@link cz.fidentis.analyst.mesh.events} and {@link cz.fidentis.analyst.kdtree}
+ * packages and forwarded by the {@code HumanFace}, events defined in this package are
+ * face-specific. They are not triggered by the underlying structures, but fired directly by 
+ * the {@code HumanFace}.
+ * </p>
+ */
+package cz.fidentis.analyst.face;
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/symmetry/package-info.java b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/package-info.java
new file mode 100644
index 00000000..f6cb0030
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/symmetry/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Symmetry plane.
+ */
+package cz.fidentis.analyst.symmetry;
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/package-info.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/package-info.java
new file mode 100644
index 00000000..2c39a0d2
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Visitors used to explore kd-trees (i.e., implementing the 
+ * {@link cz.fidentis.analyst.kdtree.KdTreeVisitor}).
+ */
+package cz.fidentis.analyst.visitors.kdtree;
diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/package-info.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/package-info.java
new file mode 100644
index 00000000..ca114de3
--- /dev/null
+++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/mesh/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Visitors used to explore triangular meshes (i.e., implementing the 
+ * {@link cz.fidentis.analyst.mesh.MeshVisitor}).
+ */
+package cz.fidentis.analyst.visitors.mesh;
diff --git a/MeshModel/pom.xml b/MeshModel/pom.xml
index 3b896c0f..00dcd815 100644
--- a/MeshModel/pom.xml
+++ b/MeshModel/pom.xml
@@ -88,6 +88,11 @@
             <artifactId>vecmath</artifactId>
             <version>${version.javax.vecmath}</version>
         </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>30.1-jre</version>
+        </dependency>
         <!-- https://mvnrepository.com/artifact/junit/junit -->
         <dependency>
             <groupId>org.junit.jupiter</groupId>
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/feature/package-info.java b/MeshModel/src/main/java/cz/fidentis/analyst/feature/package-info.java
new file mode 100644
index 00000000..570a3ccc
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/feature/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The top-level package for data structures related to feature points.
+ */
+package cz.fidentis.analyst.feature;
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java
index 36c0e2c2..bff207dc 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTree.java
@@ -1,5 +1,6 @@
 package cz.fidentis.analyst.kdtree;
 
+import com.google.common.eventbus.EventBus;
 import cz.fidentis.analyst.mesh.core.MeshFacet;
 import cz.fidentis.analyst.mesh.core.MeshFacetImpl;
 import cz.fidentis.analyst.mesh.core.MeshPoint;
@@ -16,16 +17,32 @@ import javax.vecmath.Vector3d;
 
 
 /**
- * KD-tree for storing vertices (MeshPoints) of triangular meshes (MeshFacets).
+ * KD-tree for storing vertices ({@code MeshPoint}s) of triangular meshes ({@code MeshFacet}s).
  * Multiple mesh facets can by stored in a single kd-tree. In this case, 
  * vertices that are shared across multiple facets (have the same 3D location) 
  * are shared in the same node of the kd-tree.
+ * <p>
+ * This class implements the publish-subscribe notifications to changes. 
+ * However, the {@link cz.fidentis.analyst.face.HumanFace} class provides similar
+ * functionality at the higher level of abstraction. Therefore, we recomend
+ * to monitor this class when you want to be informed about changes in concrete human face.
+ * </p>
+ * <p>
+ * Events fired by the class:
+ * <ul>
+ * <li>None because no modification method is available so far.</li>
+ * </ul>
+ * </p>
  *
  * @author Maria Kocurekova
+ * @author Radek Oslejsek
  */
 public class KdTree {
+    
     private KdNode root;
     
+    private EventBus eventBus = new EventBus();
+    
     /**
      * Constructor.
      *
@@ -34,12 +51,12 @@ public class KdTree {
      * KD-tree is constructed (with the root node set to null).
      */
     public KdTree(Set<MeshPoint> points) {
-        if(points == null) {
+        if (points == null) {
             this.root = null;
             return;
         }
         MeshFacet newFacet = new MeshFacetImpl();
-        for(MeshPoint point : points) {
+        for (MeshPoint point : points) {
             newFacet.addVertex(point);
         }
         buildTree(new LinkedList<>(Collections.singleton(newFacet)));
@@ -71,6 +88,25 @@ public class KdTree {
         buildTree(facets);        
     }
     
+    /**
+     * Registers listeners (objects concerned in the kd-tree changes) to receive events.
+     * If listener is {@code null}, no exception is thrown and no action is taken.
+     * 
+     * @param listener Listener concerned in the kd-tree changes.
+     */
+    public void registerListener(KdTreeListener listener) {
+        eventBus.register(listener);
+    }
+    
+    /**
+     * Unregisters listeners from receiving events.
+     * 
+     * @param listener Registered listener
+     */
+    public void unregisterListener(KdTreeListener listener) {
+        eventBus.unregister(listener);
+    }
+    
     /**
      * Finds the closest node for given mesh point.
      *
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeEvent.java b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeEvent.java
new file mode 100644
index 00000000..c436e3a6
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeEvent.java
@@ -0,0 +1,11 @@
+package cz.fidentis.analyst.kdtree;
+
+/**
+ * The root type for events fired by 
+ * the {@link cz.fidentis.analyst.kdtree.KdTree}.
+ * 
+ * @author Radek Oslejsek
+ */
+public interface KdTreeEvent {
+    
+}
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeListener.java b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeListener.java
new file mode 100644
index 00000000..813fab21
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/KdTreeListener.java
@@ -0,0 +1,21 @@
+package cz.fidentis.analyst.kdtree;
+
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * Objects implementing this interface can be registered with 
+ * a {@link cz.fidentis.analyst.kdtree.KdTree} object 
+ * and then be informed when the tree changes.
+ * 
+ * @author Radek Oslejsek
+ */
+public interface KdTreeListener {
+    
+    /**
+     * Captures events fired by {@link cz.fidentis.analyst.kdtree.KdTree}.
+     * 
+     * @param event A fired event.
+     */
+    @Subscribe
+    void kdTreeEvent(KdTreeEvent event);
+}
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/package-info.java b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/package-info.java
new file mode 100644
index 00000000..0742c9d3
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/kdtree/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The top-level package for kd-tree structure.
+ */
+package cz.fidentis.analyst.kdtree;
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
index 9f323778..9f89753c 100644
--- a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/MeshModel.java
@@ -1,17 +1,43 @@
 package cz.fidentis.analyst.mesh.core;
 
+import com.google.common.eventbus.EventBus;
 import java.util.ArrayList;
 import java.util.List;
 import cz.fidentis.analyst.mesh.MeshVisitor;
+import cz.fidentis.analyst.mesh.events.FacetAddedEvent;
+import java.util.Collections;
+import cz.fidentis.analyst.mesh.events.MeshListener;
 
 /**
- * MeshModel is a root node of the hierarchy
- *
+ * The main object for triangular meshes. Each mesh model consists  
+ * of one or more mesh facets.
+ * <p>
+ * This class implements the <i>Visitor</i> design pattern for exploration. 
+ * Internal structure can be explored by using an object implementing 
+ * {@link cz.fidentis.analyst.mesh.MeshVisitor}.
+ * </p>
+ * <p>
+ * This class implements the publish-subscribe notifications to changes. 
+ * However, the {@link cz.fidentis.analyst.face.HumanFace} class provides similar
+ * functionality at the higher level of abstraction. Therefore, we recomend
+ * to monitor this class when you want to be informed about changes in concrete human face.
+ * </p>
+ * <p>
+ * Events fired by the class:
+ * <ul>
+ * <li>{@link cz.fidentis.analyst.mesh.events.FacetAddedEvent} when new facet is added.</li>
+ * </ul>
+ * </p>
+ * 
  * @author Matej Lukes
+ * @author Radek Oslejsek
  */
 public class MeshModel {
+    
     private final List<MeshFacet> facets = new ArrayList<>();
-
+    
+    private EventBus eventBus = new EventBus();
+    
     /**
      * Constructor of MeshModel
      */
@@ -36,16 +62,19 @@ public class MeshModel {
      * @return list of MeshFacets
      */
     public List<MeshFacet> getFacets() {
-        return facets;
+        return Collections.unmodifiableList(facets);
     }
 
     /**
-     * adds new MeshFacet to the model
+     * Adds a new mesh facet to the model. 
+     * Fires {@link zz.fidentis.analyst.mesh.events.FacetAddedEvent} to
+     * registered listeners.
      *
      * @param facet new MeshFacet
      */
     public void addFacet(MeshFacet facet) {
         facets.add(facet);
+        eventBus.post(new FacetAddedEvent(facet));
     }
     
     /**
@@ -56,4 +85,23 @@ public class MeshModel {
     public void accept(MeshVisitor visitor) {
         visitor.visitMeshModel(this);
     }
+    
+    /**
+     * Registers listeners (objects concerned in the mesh model changes) to receive events.
+     * If listener is {@code null}, no exception is thrown and no action is taken.
+     * 
+     * @param listener Listener concerned in the mesh model changes.
+     */
+    public void registerListener(MeshListener listener) {
+        eventBus.register(listener);
+    }
+    
+    /**
+     * Unregisters listeners from receiving events.
+     * 
+     * @param listener Registered listener
+     */
+    public void unregisterListener(MeshListener listener) {
+        eventBus.unregister(listener);
+    }
 }
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/package-info.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/package-info.java
new file mode 100644
index 00000000..4a67d9f7
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/core/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * {@code cz.fidentis.analyst.mesh.core} package includes the core classes 
+ * implementing the triangular meshes, i.e., the corner table and classes 
+ * representing the mesh structure (facet, triangle, point).
+ */
+package cz.fidentis.analyst.mesh.core;
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/FacetAddedEvent.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/FacetAddedEvent.java
new file mode 100644
index 00000000..b0c2a8f7
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/FacetAddedEvent.java
@@ -0,0 +1,22 @@
+package cz.fidentis.analyst.mesh.events;
+
+import cz.fidentis.analyst.mesh.core.MeshFacet;
+
+/**
+ * An event fired by the {@see cz.fidentis.analyst.mesh.MeshModel} when 
+ * a new mesh facet has been added.
+
+ * @author Radek Oslejsek
+ */
+public class FacetAddedEvent implements MeshEvent {
+    
+    private final MeshFacet facet;
+    
+    public FacetAddedEvent(MeshFacet facet) {
+        this.facet = facet;
+    }
+
+    public MeshFacet getFacet() {
+        return facet;
+    }
+}
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshEvent.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshEvent.java
new file mode 100644
index 00000000..42fd61f4
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshEvent.java
@@ -0,0 +1,11 @@
+package cz.fidentis.analyst.mesh.events;
+
+/**
+ * The root type for events fired by 
+ * the {@link cz.fidentis.analyst.mesh.MeshModel}.
+ * 
+ * @author Radek Oslejsek
+ */
+public interface MeshEvent {
+    
+}
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshListener.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshListener.java
new file mode 100644
index 00000000..dfbcfcbf
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/MeshListener.java
@@ -0,0 +1,22 @@
+package cz.fidentis.analyst.mesh.events;
+
+import com.google.common.eventbus.Subscribe;
+
+/**
+ * Objects implementing this interface can be registered with 
+ * a {@link cz.fidentis.analyst.mesh.MeshModel} object 
+ * and then be informed when the mesh model changes.
+ * 
+ * @author Radek Oslejsek
+ */
+public interface MeshListener {
+
+    /**
+     * Captures events fired by {@link cz.fidentis.analyst.mesh.MeshModel}.
+     * 
+     * @param event A fired event.
+     */
+    @Subscribe
+    void meshEvent(MeshEvent event);
+    
+}
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/package-info.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/package-info.java
new file mode 100644
index 00000000..a149dee5
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/events/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * {@code cz.fidentis.analyst.mesh.events} package contains interfaces and 
+ * classes necessary for publish-subscribe notification of changes in the mesh model.
+ * The package includes the definition of specific events that are triggered 
+ * when the mesh model is changed.
+ */
+package cz.fidentis.analyst.mesh.events;
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/io/package-info.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/io/package-info.java
new file mode 100644
index 00000000..bb96796c
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/io/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * {@code cz.fidentis.analyst.mesh.io} package includes classes for reading 
+ * and writing triangular meshes.
+ */
+package cz.fidentis.analyst.mesh.io;
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/material/package-info.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/material/package-info.java
new file mode 100644
index 00000000..42747c07
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/material/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * {@code cz.fidentis.analyst.mesh.material} package includes classes implementing
+ * material assosiated with triangular meshes (photo scans of human faces and their
+ * mapping to the mesh, etc.)
+ */
+package cz.fidentis.analyst.mesh.material;
diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/mesh/package-info.java b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/package-info.java
new file mode 100644
index 00000000..f32b74c9
--- /dev/null
+++ b/MeshModel/src/main/java/cz/fidentis/analyst/mesh/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * The top-level package for data structures related to triangular meshes.
+ */
+package cz.fidentis.analyst.mesh;
-- 
GitLab