commit c9f953c2004e7265005492a3ea858657e837b67b
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Wed Apr 19 11:38:54 2017 +0100

    Node: Sort children IDs when generating their list for the Map of (List<Children IDs>,NodeData).
    This makes two internal nodes with the same children always isomorphic, no matter what is their order.

diff --git a/src/main/java/org/distorted/library/DistortedNode.java b/src/main/java/org/distorted/library/DistortedNode.java
index ce0c626..b0f2e76 100644
--- a/src/main/java/org/distorted/library/DistortedNode.java
+++ b/src/main/java/org/distorted/library/DistortedNode.java
@@ -20,6 +20,7 @@
 package org.distorted.library;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -120,22 +121,42 @@ public class DistortedNode implements DistortedSlave
   private ArrayList<Long> generateIDList()
     {
     ArrayList<Long> ret = new ArrayList<>();
-     
-    ret.add( mSurface.getID() );
 
     if( mNumChildren[0]==0 )
       {
+      // add a negative number so this leaf never gets confused with a internal node
+      // with a single child that happens to have ID identical to some leaf's Effects ID.
       ret.add(-mEffects.getID());
       }
-
-    DistortedNode node;
-   
-    for(int i=0; i<mNumChildren[0]; i++)
+    else
       {
-      node = mChildren.get(i);
-      ret.add(node.mData.ID);
-      }
+      DistortedNode node;
    
+      for(int i=0; i<mNumChildren[0]; i++)
+        {
+        node = mChildren.get(i);
+        ret.add(node.mData.ID);
+        }
+
+      // A bit questionable decision here - we are sorting the children IDs, which means
+      // that order in which we draw the children is going to be undefined (well, this is not
+      // strictly speaking true - when rendering, if no postprocessing and isomorphism are
+      // involved, we *DO* render the children in order they were added; if however there
+      // are two internal nodes with the same list of identical children, just added in a
+      // different order each time, then we consider them isomorphic, i.e. identical and only
+      // render the first one. If then two children of such 'pseudo-isomorphic' nodes are at
+      // exactly the same Z-height this might result in some unexpected sights).
+      //
+      // Reason: with the children being sorted by postprocessing buckets, the order is
+      // undefined anyway (although only when postprocessing is applied).
+      //
+      // See the consequences in the 'Olympic' app - remove a few leaves and add them back in
+      // different order. You will see the number of renders go back to the original 14.
+      Collections.sort(ret);
+      }
+
+    ret.add( 0, mSurface.getID() );
+
     return ret;
     }
 
