Author: clopes
Date: 2012-01-02 09:42:19 -0800 (Mon, 02 Jan 2012)
New Revision: 27893

Added:
   cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/
   cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/
   cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as
Modified:
   cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
   cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as
   cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as
   
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
Log:
Implemented #2611: Deterministic Force Directed Layout (using a seeded random 
generator)

Modified: cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js    
2012-01-02 16:29:19 UTC (rev 27892)
+++ cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js    
2012-01-02 17:42:19 UTC (rev 27893)
@@ -2570,6 +2570,9 @@
      *                                                Any lesser distances 
will be treated as the minimum.</li>
      *         <li><code>maxDistance</code> {Number}: The maximum distance 
over which forces are exerted. 
      *                                                Any greater distances 
will be ignored.</li>
+     *         <li><code>seed</code> {Number}: Optional positive integer which 
is used to set the random seed for generating the initial node positions.
+     *                                         Force-directed layouts are 
non-deterministic by nature, but this option can be used to reproduce the same 
topology.
+     *                                         Just leave this property 
<code>undefined</code> or set <code>0</code> if you want to keep the layout 
non-deterministic (i.e. a random seed is used).</li>
      *         <li><code>autoStabilize</code> {Boolean}: A common problem with 
force-directed layouts is that they can be highly unstable.
      *                                                   If this parameter is 
<code>true</code> and the edges are being stretched too much
      *                                                   between each 
iteration, Cytoscape Web automatically tries to stabilize 

Added: cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as              
                (rev 0)
+++ cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as      
2012-01-02 17:42:19 UTC (rev 27893)
@@ -0,0 +1,121 @@
+/**
+* Rndm by Grant Skinner. Jan 15, 2008
+* Visit www.gskinner.com/blog for documentation, updates and more free code.
+*
+* Incorporates implementation of the Park Miller (1988) "minimal standard" 
linear 
+* congruential pseudo-random number generator by Michael Baczynski, 
www.polygonal.de.
+* (seed * 16807) % 2147483647
+*
+* Slightly modified by Christian Lopes
+*
+* Copyright (c) 2008 Grant Skinner
+* 
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+* 
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+* 
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.gskinner.utils {
+
+    import flash.display.BitmapData;
+    
+    /**
+     * Provides common random functions using a seeded random system.
+     */
+    public class Rndm {
+    
+        // ========[ PRIVATE PROPERTIES 
]===========================================================
+        
+        private var _seed:uint;
+        private var _currentSeed:uint;
+    
+        // ========[ PUBLIC PROPERTIES 
]============================================================
+        
+        /**
+         *  seed = Math.random()*0xFFFFFF; // sets a random seed
+         *  seed = 50; // sets a static seed
+         */
+        public function get seed():uint {
+            return _seed;
+        }
+        
+        public function set seed(value:uint):void {
+            _seed = _currentSeed = value;
+        }
+        
+        public function get currentSeed():uint {
+            return _currentSeed;
+        }
+        
+        // ========[ CONSTRUCTOR 
]==================================================================
+        
+        public function Rndm(seed:uint=1) {
+            this.seed = seed;
+        }
+        
+        // ========[ PROTECTED METHODS 
]============================================================
+    
+        /**
+         * @return a number between 0-1 exclusive.
+         */
+        public function random():Number {
+            return (_currentSeed = (_currentSeed * 16807) % 
2147483647)/0x7FFFFFFF+0.000000000233;
+        }
+        
+        // float(50); // returns a number between 0-50 exclusive
+        // float(20,50); // returns a number between 20-50 exclusive
+        public function float(min:Number,max:Number=NaN):Number {
+            if (isNaN(max)) { max = min; min=0; }
+            return random()*(max-min)+min;
+        }
+        
+        // boolean(); // returns true or false (50% chance of true)
+        // boolean(0.8); // returns true or false (80% chance of true)
+        public function boolean(chance:Number=0.5):Boolean {
+            return (random() < chance);
+        }
+        
+        // sign(); // returns 1 or -1 (50% chance of 1)
+        // sign(0.8); // returns 1 or -1 (80% chance of 1)
+        public function sign(chance:Number=0.5):int {
+            return (random() < chance) ? 1 : -1;
+        }
+        
+        // bit(); // returns 1 or 0 (50% chance of 1)
+        // bit(0.8); // returns 1 or 0 (80% chance of 1)
+        public function bit(chance:Number=0.5):int {
+            return (random() < chance) ? 1 : 0;
+        }
+        
+        // integer(50); // returns an integer between 0-49 inclusive
+        // integer(20,50); // returns an integer between 20-49 inclusive
+        public function integer(min:Number,max:Number=NaN):int {
+            if (isNaN(max)) { max = min; min=0; }
+            // Need to use floor instead of bit shift to work properly with 
negative values:
+            return Math.floor(float(min,max));
+        }
+        
+        /**
+         * Resets the number series, retaining the same seed.
+         */
+        public function reset():void {
+            _seed = _currentSeed;
+        }
+    }
+}

Modified: 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as   
2012-01-02 16:29:19 UTC (rev 27892)
+++ cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as   
2012-01-02 17:42:19 UTC (rev 27893)
@@ -180,7 +180,7 @@
         public function ApplicationFacade(lock:SingletonLock) {
                super();
             if (lock == null)
-                throw new Error( "Invalid Singleton access. Use 
ApplicationFacade.instance().");
+                throw new Error("Invalid Singleton access. Use 
ApplicationFacade.getInstance().");
         }
         
         public static function getInstance():ApplicationFacade {

Modified: cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as        
2012-01-02 16:29:19 UTC (rev 27892)
+++ cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as        
2012-01-02 17:42:19 UTC (rev 27893)
@@ -73,6 +73,7 @@
                 mass:        3,
                 tension:     0.1,
                 restLength:  "auto",
+                seed:        undefined, // optional integer
                 weightAttr:  null,
                 weightNorm:  ForceDirectedLayout.NORMALIZED_WEIGHT,
                 minWeight:   undefined,

Modified: 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
===================================================================
--- 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
    2012-01-02 16:29:19 UTC (rev 27892)
+++ 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
    2012-01-02 17:42:19 UTC (rev 27893)
@@ -28,6 +28,7 @@
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
 package org.cytoscapeweb.view.components {
+    import com.gskinner.utils.Rndm;
     import com.senocular.drawing.DashedLine;
     
     import flare.animate.Sequence;
@@ -291,14 +292,17 @@
                 _appliedLayouts.push(layout);
             } else {
                 if (_layoutName === Layouts.FORCE_DIRECTED) {
+                    // Is there a seed?
+                    var seed:* = layoutObj.options.seed;
+                    var rndm:* = (seed is Number && uint(seed) > 0) ? new 
Rndm(uint(seed)) : Math;
                     // If the previous layout is ForceDirected, we need to set 
the nodes' particles and
                     // the edges' springs to null, otherwise the layout may 
not render very well
                     // when it is applied again.
                     data.nodes.visit(function(n:NodeSprite):void {
                         n.props.particle = null;
                         // It is also important to set random positions to 
nodes:
-                        n.x = Math.random() * _initialWidth;
-                        n.y = Math.random() * _initialHeight;
+                        n.x = rndm.random() * _initialWidth;
+                        n.y = rndm.random() * _initialHeight;
                     });
                     data.edges.visit(function(e:EdgeSprite):void {
                        e.props.spring = null;

-- 
You received this message because you are subscribed to the Google Groups 
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/cytoscape-cvs?hl=en.

Reply via email to