You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by jb...@apache.org on 2010/08/10 19:13:06 UTC

svn commit: r984129 [1/3] - in /commons/sandbox/gsoc/2010/scxml-js/trunk: demo/hierarchical-layout-drag-and-drop/ demo/hierarchical_layout/ src/javascript/scxml/cgf/ src/javascript/scxml/cgf/backends/js/ src/javascript/scxml/cgf/layout/ src/javascript/...

Author: jbeard
Date: Tue Aug 10 17:13:04 2010
New Revision: 984129

URL: http://svn.apache.org/viewvc?rev=984129&view=rev
Log:
Merge branch 'debugger'

Conflicts:
	src/javascript/scxml/cgf/Transformer.js
	src/javascript/scxml/cgf/backends/js/AbstractEnumeratedStatechartGenerator.js
	src/javascript/scxml/cgf/backends/js/StatePatternStatechartGenerator.js
	src/xslt/backends/js/AbstractStatechartGenerator.xsl
	src/xslt/ir-compiler/numberStatesAndTransitions.xsl
	test/testBrowserTransform.html

Added:
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/drag-and-drop.xml   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/test.html   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/display.html   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test.html   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.sh   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test_with_dom.html   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/ForceTransferLayout.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/LinkOptimizer.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/PrepLayout.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/graphics.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/CrossingModule.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/HorizontalPositioner.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/LayeringModule.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/NodeWrapper.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/shrinkwrapLayout.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/listener/
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/listener/GraphicalSimulator.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/listener/Logger.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/listener/api.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/util/geometry.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/util/svg.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/util/xpath.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/xslt/layout/
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/xslt/layout/addTransitionTargetIds.xsl   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/xslt/layout/computeAncestorOrSelfAndChildOfLCA.xsl   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/xslt/layout/scxmlToSVG.xsl   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/batik/
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/batik/testBatik.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/batik/testBatik.sh   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/batik/testBatik.svg   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/in.scxml
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/in.xml   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/randomLayout.js   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/testBrowserTransformAndGraphicalSimulator.html   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/testBrowserTransformAndLayoutWithDragAndDropBehaviour.html   (with props)
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/testBrowserTransformAndLogListener.html   (with props)
Modified:
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/AbstractEnumeratedStatechartGenerator.js
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/StatePatternStatechartGenerator.js
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/main.js
    commons/sandbox/gsoc/2010/scxml-js/trunk/src/xslt/backends/js/AbstractStatechartGenerator.xsl
    commons/sandbox/gsoc/2010/scxml-js/trunk/test/testBrowserTransform.html

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/drag-and-drop.xml
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/drag-and-drop.xml?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/drag-and-drop.xml (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/drag-and-drop.xml Tue Aug 10 17:13:04 2010
@@ -0,0 +1,83 @@
+<scxml 
+	xmlns="http://www.w3.org/2005/07/scxml"
+	version="1.0"
+	profile="ecmascript"
+	id="scxmlRoot"
+	initial="initial_default">
+
+	<script>
+		function computeTDelta(oldEvent,newEvent){
+			//summary:computes the offset between two events; to be later used with this.translate
+			var dx = newEvent.clientX - oldEvent.clientX;
+			var dy = newEvent.clientY - oldEvent.clientY;
+
+			return {'dx':dx,'dy':dy};
+		}
+
+		function translate(rawNode,tDelta){
+			var tl = rawNode.transform.baseVal;
+			var t = tl.numberOfItems ? tl.getItem(0) : rawNode.ownerSVGElement.createSVGTransform();
+			var m = t.matrix;
+			var newM = rawNode.ownerSVGElement.createSVGMatrix().translate(tDelta.dx,tDelta.dy).multiply(m);
+			t.setMatrix(newM);
+			tl.initialize(t);
+			return newM;
+		}
+	</script>
+
+	<datamodel>
+		<data id="firstEvent"/>
+		<data id="eventStamp"/>
+		<data id="tDelta"/>
+		<data id="rawNode"/>
+		<data id="linkNodeList"/>
+	</datamodel>
+
+	<state id="initial_default">
+		<transition event="init" target="idle">
+			<assign location="rawNode" expr="_event.data.rawNode"/>
+			<assign location="linkNodeList" expr="_event.data.linkNodeList"/>
+			<assign location="LinkOptimizer" expr="_event.data.LinkOptimizer"/>
+		</transition>
+	</state>
+
+	<state id="idle">
+		<transition event="mousedown" target="dragging">
+			<assign location="firstEvent" expr="_event.data"/>
+			<assign location="eventStamp" expr="_event.data"/>
+
+			<script>
+				//make invisible
+				linkNodeList.forEach(function(n){
+					n.visualObject._rawNode.style.visibility = "hidden";
+				})
+			</script>
+		</transition>
+	</state>
+
+	<state id="dragging">
+
+		<transition event="mouseup" target="idle">
+			<script>
+					//re-layout the edges
+					linkNodeList.forEach(function(n){
+						LinkOptimizer.optimizeConnectionPorts(n);	
+					});
+					
+					//make visible
+					linkNodeList.forEach(function(n){
+						n.visualObject._rawNode.style.visibility = "visible";
+					})
+			</script>
+		</transition>
+
+		<transition event="mousemove" target="dragging">
+			<assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+			<script>
+				translate(rawNode,tDelta);
+			</script>
+			<assign location="eventStamp" expr="_event.data"/>
+		</transition>
+	</state>
+
+</scxml>

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/drag-and-drop.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/test.html
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/test.html?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/test.html (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/test.html Tue Aug 10 17:13:04 2010
@@ -0,0 +1,78 @@
+<html>
+  <head>
+    <script src="../../lib/js/requirejs/require.js" type="text/javascript">true;</script>
+    <script src="../../lib/js/requirejs/require/xml.js" type="text/javascript">true;</script>
+    <script src="../../test/testHelpers.js" type="text/javascript">true;</script>
+    <script>
+	var resultText;
+
+	require(
+		{
+			"baseUrl":"/"
+		},
+		[ "src/javascript/scxml/cgf/SCXMLCompiler",
+			"xml!test/kitchen_sink/KitchenSink.xml",
+			"src/javascript/scxml/cgf/layout",
+			"xml!demo/hierarchical-layout-drag-and-drop/drag-and-drop.xml",
+			"src/javascript/scxml/cgf/util/xpath",
+			"src/javascript/scxml/cgf/layout/LinkOptimizer"],
+
+
+
+		function(compiler,scxmlDoc,layout,dragAndDropBehaviourSCXMLDoc,xpath,LinkOptimizer){
+
+			var layoutInfo = layout.applyHierarchicalLayout(scxmlDoc);
+			var svgDoc = layoutInfo.svgDoc, 
+				linkNodeList = layoutInfo.linkNodeList, 
+				entityNodeList = layoutInfo.entityNodeList;
+
+			//enough graphical stuff, let's do some compilation
+			compiler.compile({
+				inFiles:[dragAndDropBehaviourSCXMLDoc],
+				backend:"state",
+				beautify:true,
+				verbose:false,
+				log:false,
+				ie:false,
+				genListenerHooks:true
+			}, function(scArr){
+				var dragAndDropBehaviourTransformedJs = scArr[0];
+
+				console.log(dragAndDropBehaviourTransformedJs);
+
+				//hook up graphical node drag and drop behaviour
+				eval(dragAndDropBehaviourTransformedJs);
+
+				DragAndDropStatechartExecutionContext = StatechartExecutionContext;
+
+				var graphEntityNodes = xpath.query("//svg:g[@c:graphEntity = 'true']",svgDoc.documentElement)
+				graphEntityNodes.forEach(function(groupNode){
+					var compiledStatechartInstance = new DragAndDropStatechartExecutionContext();
+					
+					//initialize
+					compiledStatechartInstance.initialize();
+
+					console.log(groupNode);
+					
+					//pass in reference to rect
+					compiledStatechartInstance.init({rawNode:groupNode,linkNodeList:linkNodeList,LinkOptimizer:LinkOptimizer}); 
+
+					//hook up DOM events
+					["mousedown","mouseup","mousemove"].forEach(function(eventName){
+						groupNode.addEventListener(eventName,
+						function(e){
+							e.preventDefault();
+							compiledStatechartInstance[eventName](e);
+							e.stopPropagation();
+						},
+						false);
+					});
+				});
+			});
+		}
+	);
+</script>
+  </head>
+  <body/>
+</html>
+

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical-layout-drag-and-drop/test.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/display.html
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/display.html?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/display.html (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/display.html Tue Aug 10 17:13:04 2010
@@ -0,0 +1,4 @@
+<html>
+	<head></head>
+	<body style="width:98%;height:98%"></body>
+</html>

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/display.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test.html
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test.html?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test.html (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test.html Tue Aug 10 17:13:04 2010
@@ -0,0 +1,26 @@
+<html>
+	<head>	
+		<script src="../../lib/js/requirejs/require.js" type="text/javascript">true;</script>
+		<script src="../../lib/js/requirejs/require/xml.js" type="text/javascript">true;</script>
+		<script src="../../lib/js/requirejs/require/text.js" type="text/javascript">true;</script>
+
+		<script type="text/javascript">
+			var resultText;
+
+			require(
+				{
+					"baseUrl":"/"
+				},
+				[
+					"xml!test/kitchen_sink/KitchenSink.xml",
+					"src/javascript/scxml/cgf/layout"],
+
+				function(scxmlDoc,layout){
+					layout.applyHierarchicalLayout(scxmlDoc);
+				}
+			);
+		</script>
+
+	</head>
+	<body style="width:99%;height:98%"></body>
+</html>

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,40 @@
+console = {
+	log : print,
+	debug : print,
+	error : print
+}
+
+var absoluteScriptDir = arguments[0];
+var pathToRequireJsDir = absoluteScriptDir + "/lib/js/requirejs/";
+
+load(pathToRequireJsDir + "require.js");
+load(pathToRequireJsDir + "require/rhino.js");
+load(pathToRequireJsDir + "require/text.js");
+load(pathToRequireJsDir + "require/xml.js");
+
+//bootstrap require.js
+require({
+	baseUrl : absoluteScriptDir 
+	},
+	function(){
+		require(
+			[
+				"xml!test/kitchen_sink/KitchenSink.xml",
+				"src/javascript/scxml/cgf/layout",
+				"src/javascript/scxml/cgf/util/xml",
+				"src/javascript/scxml/cgf/util/file"
+				],
+
+
+			function(scxmlDoc,layout,xml,file){
+
+				var layoutInfo = layout.applyHierarchicalLayout(scxmlDoc);
+				var svgDoc = layoutInfo.svgDoc;
+
+				//serialize to SVG, PDF, etc.
+				file.writeFile(xml.serializeToString(svgDoc),"out.svg");
+
+			}
+		)
+	}
+);

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.sh
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.sh?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.sh (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.sh Tue Aug 10 17:13:04 2010
@@ -0,0 +1,31 @@
+#!/bin/bash
+dn=`dirname $0`
+abspath=`cd $dn; cd ../../; pwd`
+
+java -cp \
+../../lib/java/batik-anim.jar:\
+../../lib/java/batik-awt-util.jar:\
+../../lib/java/batik-bridge.jar:\
+../../lib/java/batik-codec.jar:\
+../../lib/java/batik-css.jar:\
+../../lib/java/batik-dom.jar:\
+../../lib/java/batik-extension.jar:\
+../../lib/java/batik-ext.jar:\
+../../lib/java/batik-gui-util.jar:\
+../../lib/java/batik-gvt.jar:\
+../../lib/java/batik-parser.jar:\
+../../lib/java/batik-script.jar:\
+../../lib/java/batik-svg-dom.jar:\
+../../lib/java/batik-svggen.jar:\
+../../lib/java/batik-swing.jar:\
+../../lib/java/batik-transcoder.jar:\
+../../lib/java/batik-util.jar:\
+../../lib/java/batik-xml.jar:\
+../../lib/java/commons-cli.jar:\
+../../lib/java/js.jar:\
+../../lib/java/serializer.jar:\
+../../lib/java/xalan.jar:\
+../../lib/java/xercesImpl.jar:\
+../../lib/java/xml-apis.jar:\
+../../lib/java/xml-apis-ext.jar:\
+ org.mozilla.javascript.tools.shell.Main -debug testBatik.js $abspath

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.sh
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/testBatik.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test_with_dom.html
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test_with_dom.html?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test_with_dom.html (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test_with_dom.html Tue Aug 10 17:13:04 2010
@@ -0,0 +1,98 @@
+<html>
+	<head>	
+		<style type="text/css">
+			body {
+				height:95%;
+			}
+
+			textarea{
+				width:100%;
+				height:85%;
+			}
+		
+			div{ height:100% }
+		</style>
+		<script type="text/javascript">
+			if((typeof console == "undefined") || !console.log){
+				   console = {log : function(str){}}
+			} 
+		</script>
+		<script src="../../lib/js/requirejs/require.js" type="text/javascript">true;</script>
+		<script src="../../lib/js/requirejs/require/xml.js" type="text/javascript">true;</script>
+		<script src="../../lib/js/requirejs/require/text.js" type="text/javascript">true;</script>
+
+	</head>
+	<body>
+		<textarea id="scxml_input"></textarea>
+		<br/>
+		<button id="LONGEST_PATH_LAYERING_BOTTOM_UP">Hierarchical Layout with Longest Path Layering Bottom Up Heuristic</button>
+		<br/>
+		<button id="LONGEST_PATH_LAYERING_TOP_DOWN">Hierarchical Layout with Longest Path Layering Top Down Heuristic</button>
+		<br/>
+		<button id="MINIMUM_WIDTH_LAYERING">Hierarchical Layout with Longest Path Minimum Width Layering Heuristic</button>
+		<script type="text/javascript">
+			//get DOM elements
+			var scxml_input = document.getElementById("scxml_input");
+			var LONGEST_PATH_LAYERING_BOTTOM_UP_button = document.getElementById("LONGEST_PATH_LAYERING_BOTTOM_UP");
+			var LONGEST_PATH_LAYERING_TOP_DOWN_button = document.getElementById("LONGEST_PATH_LAYERING_TOP_DOWN");
+			var MINIMUM_WIDTH_LAYERING_button = document.getElementById("MINIMUM_WIDTH_LAYERING");
+
+			var resultText;
+
+			require(
+				{
+					"baseUrl":"/"
+				},
+				[
+					"xml!test/kitchen_sink/KitchenSink.xml",
+					"src/javascript/scxml/cgf/layout",
+					"src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout",
+					"src/javascript/scxml/cgf/util/xml"],
+
+				function(scxmlDoc,layout,HierarchicalLayout,xmlUtils){
+
+					//set the initial XML content in the textarea
+					var xmlString = xmlUtils.serializeToString(scxmlDoc);
+					scxml_input.textContent = xmlString;
+
+					//main callback on buttons
+					function applyHierLayout(heuristic,domAttachPoint,scxmlInputDoc){
+						layout.applyHierarchicalLayout(scxmlInputDoc,{heuristic : heuristic},domAttachPoint)
+					}
+
+					function parseTextareaPopupWindowAndApplyLayout(heuristic){
+						//parse from textarea dom
+						var scxmlInputDoc = xmlUtils.parseFromString(scxml_input.textContent);
+
+						//open new window and get DOM attach point
+						var w = window.open("display.html");
+						//debugger;
+						w.addEventListener("DOMContentLoaded",function(e){
+							var domAttachPoint = w.document.body;
+
+							//debugger;
+							//apply layout
+							console.log("dom attach point",domAttachPoint)
+							applyHierLayout(heuristic,domAttachPoint,scxmlInputDoc);
+						},true);
+
+					}
+
+					//hook up event listeners
+					LONGEST_PATH_LAYERING_BOTTOM_UP_button.addEventListener("mousedown",function(e){
+						parseTextareaPopupWindowAndApplyLayout(HierarchicalLayout.HEURISTICS_ENUM.LONGEST_PATH_LAYERING_BOTTOM_UP)
+					},true); 
+					LONGEST_PATH_LAYERING_TOP_DOWN_button.addEventListener("mousedown",function(e){
+						parseTextareaPopupWindowAndApplyLayout(HierarchicalLayout.HEURISTICS_ENUM.LONGEST_PATH_LAYERING_TOP_DOWN)
+					},true);
+					MINIMUM_WIDTH_LAYERING_button.addEventListener("mousedown",function(e){
+						parseTextareaPopupWindowAndApplyLayout(HierarchicalLayout.HEURISTICS_ENUM.MINIMUM_WIDTH_LAYERING)
+					},true);
+
+				}
+			);
+		</script>
+
+
+	</body>
+</html>

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/demo/hierarchical_layout/test_with_dom.html
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/AbstractEnumeratedStatechartGenerator.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/AbstractEnumeratedStatechartGenerator.js?rev=984129&r1=984128&r2=984129&view=diff
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/AbstractEnumeratedStatechartGenerator.js (original)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/AbstractEnumeratedStatechartGenerator.js Tue Aug 10 17:13:04 2010
@@ -11,7 +11,9 @@ require.def(
 		"xml!src/xslt/ir-compiler/enumerateEvents.xsl",
 		"xml!src/xslt/ir-compiler/addEventRegularExpressions.xsl",
 		"xml!src/xslt/ir-compiler/expandStarEvent.xsl",
-		"xml!src/xslt/ir-compiler/numberStatesAndTransitions.xsl" ],
+		"xml!src/xslt/ir-compiler/numberStatesAndTransitions.xsl" 
+		"xml!src/xslt/layout/addTransitionTargetIds.xsl" ],
+		
 	function(
 		AbstractStatechartGenerator,
 		flattenTransitions,
@@ -21,7 +23,8 @@ require.def(
 		enumerateEvents,
 		addEventRegularExpressions,
 		expandStarEvent,
-		numberStatesAndTransitions
+		numberStatesAndTransitions,
+		addTransitionTargetIds
 	){
 		return {
 			"transformations" : AbstractStatechartGenerator.transformations.concat([flattenTransitions,
@@ -31,7 +34,8 @@ require.def(
 													enumerateEvents,
 													addEventRegularExpressions,
 													expandStarEvent,
-													numberStatesAndTransitions] )
+													numberStatesAndTransitions,
+													addTransitionTargetIds] )
 		};
 	}
 );

Modified: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/StatePatternStatechartGenerator.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/StatePatternStatechartGenerator.js?rev=984129&r1=984128&r2=984129&view=diff
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/StatePatternStatechartGenerator.js (original)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/backends/js/StatePatternStatechartGenerator.js Tue Aug 10 17:13:04 2010
@@ -9,6 +9,7 @@ require.def(
 		"xml!src/xslt/ir-compiler/enumerateEvents.xsl",
 		"xml!src/xslt/ir-compiler/addEventRegularExpressions.xsl",
 		"xml!src/xslt/ir-compiler/expandStarEvent.xsl",
+		"xml!src/xslt/layout/addTransitionTargetIds.xsl", 
 		"xml!build/StatePatternStatechartGenerator_combined.xsl" //preprocessed stylesheet
 	],
 
@@ -19,12 +20,14 @@ require.def(
 		enumerateEvents,
 		addEventRegularExpressions,
 		expandStarEvent,
+		addTransitionTargetIds,
 		StatePatternStatechartGenerator
 	){
 
 		return {
 			"transformations" : AbstractStatechartGenerator.transformations.concat([
 				appendTransitionInformation,
+				addTransitionTargetIds,
 				copyEnumeratedEventTransitions,
 				enumerateEvents,
 				addEventRegularExpressions,

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,84 @@
+/*
+This module provides a convenient front-end to one or more layout algorithms.
+*/
+require.def("src/javascript/scxml/cgf/layout",
+[
+	"xml!src/xslt/ir-compiler/generateUniqueStateIds.xsl",
+	"xml!src/xslt/ir-compiler/generateUniqueInitialStateIds.xsl",
+	"xml!src/xslt/ir-compiler/normalizeInitialStates.xsl",
+	"xml!src/xslt/ir-compiler/nameTransitions.xsl",
+	"xml!src/xslt/ir-compiler/splitTransitionTargets.xsl",
+	"xml!src/xslt/ir-compiler/computeLCA.xsl",
+	"xml!src/xslt/layout/computeAncestorOrSelfAndChildOfLCA.xsl",
+	"xml!src/xslt/layout/addTransitionTargetIds.xsl",
+	"xml!src/xslt/layout/scxmlToSVG.xsl",
+	"src/javascript/scxml/cgf/Transformer",
+	"src/javascript/scxml/cgf/layout/PrepLayout",
+	"src/javascript/scxml/cgf/layout/hierarchical/NodeWrapper",
+	"src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout",
+	"src/javascript/scxml/cgf/layout/shrinkwrapLayout",
+	"src/javascript/scxml/cgf/layout/LinkOptimizer"],
+
+function(
+		nameTransitions,generateUniqueStateIds,generateUniqueInitialStateIds,normalizeInitialStates,
+			splitTransitionTargets,computeLCA,computeAncestorOrSelfAndChildOfLCA,addTransitionTargetIds,
+		scxmlToSvgXsl,
+		Transformer,
+		PrepLayout,NodeWrapper,HierarchicalLayout,shrinkwrapLayout,
+		LinkOptimizer){
+
+	return {
+		applyHierarchicalLayout : function(scxmlDoc,options,domAttachPoint){
+			var ir = Transformer(scxmlDoc,
+				[generateUniqueStateIds,normalizeInitialStates,generateUniqueInitialStateIds,
+					nameTransitions,splitTransitionTargets,computeLCA,
+					computeAncestorOrSelfAndChildOfLCA,addTransitionTargetIds
+				],
+				null,"xml");  //transform to IR
+
+			var svgDoc = Transformer(ir,[scxmlToSvgXsl],null,"xml");	//transform scxml to non-laid out, svg graphical representation
+
+			//console.dirxml(ir);
+			svgDoc = PrepLayout.bootSVGDOM(svgDoc,domAttachPoint);
+
+			var lists = PrepLayout.scxmlToEntityNodeListAndLinkList(ir,svgDoc);
+			var rootEntity = lists.rootEntity, 
+				entityNodeList = lists.entityList,
+				linkNodeList = lists.linkNodeList;
+
+			//perform a preorder traversal
+			//lay out all composites
+			//for each composite node, do hierarchical layout, followed by shrinkwrap layout of all children
+			//FIXME: we really need to know root nodes for this to be effective...
+			//TODO: try applying force-based layout as well...
+			//HierarchicalLayout.hierarchicalLayout(entityNodeList,linkNodeList);
+
+			// Initilize the node wrapper class attributes
+			//TODO: move this into hier layout
+			NodeWrapper.initilizeNodeWrapper()
+			HierarchicalLayout.recursivelyApplyHierarchicalLayout(rootEntity,
+				{heuristic : HierarchicalLayout.HEURISTICS_ENUM.LONGEST_PATH_LAYERING_BOTTOM_UP })
+
+			//shrinkwrap layout
+			console.log("Recursively applying shrinkwrap layout")
+			shrinkwrapLayout.recursivelyApplyShrinkwrapLayout(rootEntity)
+
+			//optimize links again
+			//linkNodeList.forEach(LinkOptimizer.optimizeConnectionPorts)
+			LinkOptimizer.optimizeLinks(linkNodeList);
+
+			//recentering push
+			console.log("Recentering")
+			rootEntity.visualObject.moveTo(0,0);
+
+			//adjust canvas viewbox
+			rootEntity.visualObject.setCanvasViewBox(rootEntity.visualObject.getBBoxInCanvasSpace());
+
+			return {
+				svgDoc:svgDoc, 
+				linkNodeList:linkNodeList, 
+				entityNodeList:entityNodeList
+			};
+		}
+	}
+});

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/ForceTransferLayout.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/ForceTransferLayout.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/ForceTransferLayout.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/ForceTransferLayout.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,261 @@
+/*
+Based on ForceTransfer.py by Denis Dube
+
+Applies force to all nodes that are too close to each other
+Loops until a stable configuration is reached
+Times out after 50 iterations, to avoid depriving the user of interactivity for too long.
+*/
+
+//require.def("src/javascript/scxml/cgf/debugger/layout/ForceTransfer",
+
+ForceTransfer = {
+	//need to be given graphical objects
+	applyLayout : function(options,svgGraphObjects,dc,statusText){
+
+		options = options || {
+			autoApply : false,
+			useStatusBar : false,
+			minNodeDist : 5,
+			minLinkDist : 5,
+			minControlDist : 5,
+			seperationForce	: 1,
+			animationTime : 0,
+			maxAnimIterations : 15,
+			maxIterations	: 50,
+			borderDistance : 30
+		};
+
+		//TODO: convert SVG objects to abstract graphical objects
+		var nodes = svgGraphObjects.nodes.map(function(n){
+			//get the bounding box from the object, I guess in Canvas coordinates
+			//although local coordinates might actually be more appropriate...
+			var bbox = n.getBBox(); //getBBoxInCanvasSpace(n);
+			var x = bbox.x, y = bbox.y, width = bbox.width, height=bbox.height;
+			var center = [ x + width/2, y + height/2 ]
+
+			return new NodeObject( n, center, [width,height], options.minNodeDist, [x,y] )
+		});
+		var edges = svgGraphObjects.edges.map(function(e){
+			var bbox = n.getBBox(); //getBBoxInCanvasSpace(e);
+			var x = bbox.x, y = bbox.y, width = bbox.width, height=bbox.height;
+			var center = [ x + width/2, y + height/2 ]
+
+			return new EdgeObject( obj, center, options.minLinkDist )
+		});
+		/*
+		var controlPoints = svgGraphObjects.controlPoints.map(function(cp){
+			new ControlPoint( c[i:i+2], options.minControlDist, itemHandler, i, dc )
+		});
+		*/
+
+		graphicalObjectList = nodes.concat(edges);
+
+		/*
+		Sorts the nodes according to their distance from the origin (0,0) 
+		This can have a large impact on performance, especially as the number
+		of objects in contact with one another goes up.
+		*/
+		graphicalObjectList = graphicalObjectList.sort(function(n1,n2){return n1.distance > n2.distance});
+							
+		var totalNodes = graphicalObjectList.length;
+			
+		var isLayoutStable = false
+					
+		// Keep at it till the layout is stable
+		var i = 0;
+		while(! isLayoutStable ){
+			isLayoutStable = true // Optimism is good...
+			calculationLoop()
+				
+			if( i > options.maxIterations ){	 
+				break;
+			}
+
+			i++;
+		}
+			
+			
+		// Hijack the status bar to show what the FTA is doing...
+		if( i >= options.maxIterations ){
+			statusText.textValue = "FTA halted at max iterations, layout unstable";
+		}
+		else{
+			statusText.textValue  = "FTA needed "+i+" iterations to find stable layout";
+		}
+
+		// Keep the whole thing in the viewable area of the canvas
+		minX = Math.min.apply(this,graphicalObjectList.map(function(o){return (o.topLeftPos && o.topLeftPos[0]) || o.pos[0]}));
+		minY = Math.min.apply(this,graphicalObjectList.map(function(o){return (o.topLeftPos && o.topLeftPos[1]) || o.pos[1]}));
+			
+		minX = minX < options.borderDistance ? Math.abs(minX) + options.borderDistance : 0;
+		minY = minY < options.borderDistance ? Math.abs(minY) + options.borderDistance : 0;
+
+		// Push on it!
+		//graphicalObjectList.forEach(function(n){n.recenteringPush(minX, minY)});
+			
+		// All that moving stuff around can mess up the connections...
+		//TODO
+		/*
+		if( selection )
+				optimizeConnectionPorts(atom3i, entityList=selection )
+		else
+				optimizeConnectionPorts(atom3i, doAllLinks=True )
+		*/
+				
+		function calculationLoop(){
+			
+			// Go through all the nodes, and find the overlap forces
+			graphicalObjectList.forEach(function(n1){
+				graphicalObjectList.forEach(function(n2){
+					if(n1!==n2) calculateForce( n1, n2 );
+			})});
+				
+			// Go through all the nodes and apply the forces to the positions
+			graphicalObjectList.forEach(function(n){n.commitForceApplication()});
+		}
+				
+				
+		function calculateForce( n1,n2 ){
+			/*
+			Evaluates distances betweens nodes (ie: do they overlap) and
+			calculates a force sufficient to pry them apart.
+			*/
+			
+			// Absolute distance along X and Y vectors between the nodes
+			var pointA = n1.pos
+			var pointB = n2.pos
+	 
+			var dx = Math.abs( pointB[0] - pointA[0] ) 
+			var dy = Math.abs( pointB[1] - pointA[1] ) 
+			
+			// Zero division error prevention measures
+			if (dx == 0.0)	dx = 0.1
+			if (dy == 0.0)	dy = 0.1
+			
+			// Node-Node Distances
+			var dist = Math.sqrt(dx*dx+dy*dy)
+			
+			// Normalized-Vector
+			var norm = [ dx / dist , dy / dist ]
+
+			// Overlap due to size of nodes
+			var sizeA = n1.size
+			var sizeB = n2.size
+			var sizeOverlap = [ ( sizeA[0] + sizeB[0] ) / 2 , ( sizeA[1] + sizeB[1] ) / 2 ]	
+			
+			// Desired distance with resulting force
+			var minSeperationDist = Math.min( n1.seperationDist,n2.seperationDist )
+			var d1 = (1.0 / norm[0]) * (sizeOverlap[0] + minSeperationDist)
+			var d2 = (1.0 / norm[1]) * (sizeOverlap[1] + minSeperationDist)
+			var forceMagnitude = options.seperationForce * ( dist - Math.min(d1,d2) )
+		
+			// The force should be less than -1 (or it won't be having much of an effect)
+			if (forceMagnitude < -1){
+				var force = [ forceMagnitude * norm[0],	forceMagnitude * norm[1] ]
+				
+				// Maximize compactness by only pushing nodes along a single axis
+				if( force[0] > force[1] ) 
+					force[0] = 0
+				else
+					force[1] = 0
+				
+				// Determine the direction of the force
+				var direction = [ 1, 1 ]
+				if( pointA[0] > pointB[0] ) direction[0] = -1
+				if( pointA[1] > pointB[1] ) direction[1] = -1
+		
+				// Add up the forces to the two interacting objects
+				n1.incrementForce( force )
+				n2.incrementForce( [ -force[0], -force[1] ] )
+				
+				// If a force was applied this iteration, definately not stable yet
+				isLayoutStable = false			
+			}
+		}
+				
+		function GraphicalObject(visualObject, pos, size, seperationDist){
+			/*
+			A convenient class to store just the information necessary for the 
+			application of the force transfer algorithm.
+			*/
+			
+			this.visualObject = visualObject
+			this.pos = pos
+			this.size = size
+			this.force = [0,0]
+			this.seperationDist = seperationDist
+			this.distance = Math.sqrt( pos[0]*pos[0] + pos[1]*pos[1] );
+
+			this.incrementForce = function(force){
+				this.force = force
+			}
+					 
+			this.commitForceApplication = function(){
+				/*
+				Moves the object to the origin, then to the position it is forced to
+				Forces are then reset
+				*/
+
+				translate( this.visualObject, {dx:this.force[0],dy:this.force[1]} ) 
+				this.pos = [ this.pos[0] + this.force[0], this.pos[1] + this.force[1] ]
+				this.force = [0,0] 
+			}
+				
+			this.recenteringPush = function(x, y){
+				// Puts the object back onto the canvas if it got forced off 
+				translate( this.visualObject, {dx:x,dy:y} ) 
+			}
+					
+		}
+					
+		function NodeObject(visualObject, pos, size, seperationDist, topLeftPos){
+			// Regular node entity with position and size attributes 
+			
+			this.topLeftPos = topLeftPos
+
+			GraphicalObject.apply(this,[visualObject, pos, size, seperationDist]);
+				
+		}
+					
+		function EdgeObject(visualObject, pos, seperationDist){
+			/*
+			Idea for improvement: find the label/drawing attached to the center of the
+			edge, and use its size instead of treating this as an object with no size.
+			*/
+
+			GraphicalObject.apply(this,[visualObject, pos, [1,1],seperationDist]);
+		}
+
+		function ControlPoint(pos, seperationDist,itemHandler,index){
+			/*
+			Control point is merely a point along the edge, thus it needs a customized
+			approach for moving it around. It also has no real size concept.
+			*/
+
+			GraphicalObject.apply(this,[None, pos, [1,1],seperationDist]);
+
+			this.itemHandler = itemHandler
+			this.index = index
+				
+			/*
+			this.recenteringPush = function(x, y):
+				// No need for this since the Edge 'Move' method handles it
+				return
+				cCoords = this.dc.coords( this.itemHandler )
+				cCoords[this.index] += x
+				cCoords[this.index+1] += y
+				this.dc.coords( * [this.itemHandler] + cCoords )
+			*/
+				
+			this.commitForceApplication = function(){
+				var cCoords = dc.coords( this.itemHandler )
+				cCoords[this.index] += this.force[0]
+				cCoords[this.index+1] += this.force[1]
+				dc.coords( * [this.itemHandler] + cCoords )
+				
+				this.pos = [ this.pos[0] + this.force[0], this.pos[1] + this.force[1] ]
+				this.force = [0,0] 
+			}
+		}	
+	}
+}

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/ForceTransferLayout.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/LinkOptimizer.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/LinkOptimizer.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/LinkOptimizer.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/LinkOptimizer.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,162 @@
+require.def("src/javascript/scxml/cgf/layout/LinkOptimizer",
+["src/javascript/scxml/cgf/util/geometry"],
+function(geometry){
+	function optimizeConnectionPorts(linkNode){
+		/*
+		given a set of linkNodes (preferably semantic objects to start out)
+			for each linkNode find what entities he connects to (in and out)
+				for each of these entities
+					snap to the nearest connection point on that entity
+		*/
+
+		//find the closest two connection points
+
+		var startAndEndInfo = linkNode.getClosestStartAndEndConnectionPoints();
+		
+		linkNode.visualObject.setStartPoint(startAndEndInfo.fromConnector);
+
+		linkNode.visualObject.setEndpoint(startAndEndInfo.toConnector); 
+
+	}
+ 
+	function optimizeLinks(selectedLinks, setSmooth, setCurved, curveDirection){
+		/*
+		Optimizes the links associated with the nodes in entityList or all the nodes
+		in the graph if entityList is not provided.
+		The links are set straight, with the endpoints at the nearest connectors of
+		the nodes they connect.
+		Optionally, additional control points can be added to make a smooth arrow,
+		and give it some curvature (setCurved is a pixel distance perpendicular to
+		what would have been a straight arrow ).
+		It is possible to pass a list of link objects directly, and optimize those.
+		It is also possible to specify the direction of the curve, Random=-1, Right=0, Left=1
+
+		Created July 25, 2004 by Denis Dube
+		*/
+		setSmooth = setSmooth || true;
+		setCurved = setCurved || 10;
+		selectedLinks= selectedLinks || [];
+		curveDirection = curveDirection || -1;
+
+		// Optimize all the selected links
+		//FIXME: s/obj/ln
+		selectedLinks.forEach(function(ln){
+
+			// Optimize the end point connection ports
+			optimizeConnectionPorts(ln)
+
+			// Find all the entities that the edge is linking to
+			// (general enough to handle hyperedges)
+			var graphicalObjectsFrom = ln.inConnections.map(function(en){return en.visualObject})
+			var graphicalObjectsTo = ln.outConnections.map(function(en){return en.visualObject})
+
+			// Edge with 2 endpoints
+			if(graphicalObjectsFrom.length == 1 &&  graphicalObjectsTo.length == 1){
+
+				// Edge with both endpoints on one object
+				if( graphicalObjectsFrom[0] == graphicalObjectsTo[0] ){
+					optimizeSelfLink(ln, graphicalObjectsFrom[0], setSmooth, setCurved)
+				}
+
+				// Regular edge
+				else{
+					optimizeRegularLink( ln, graphicalObjectsFrom[0], graphicalObjectsTo[0],
+						setSmooth, setCurved, curveDirection)
+				}
+			}
+			// Hyper-edge with multiple endpoints
+			else{
+				optimizerHyperLink( ln, graphicalObjectsFrom, graphicalObjectsTo,
+					setSmooth, setCurved, curveDirection	)
+			}
+		})
+	}
+
+	function optimizeRegularLink( interObj, fromObj, toObj, setSmooth, curvature, curveDirection ){
+		/* Optimizes one edge with 2 endpoints in 2 different objects */
+
+		// Find the optimally near connector points
+		//TODO: here
+		var connectorInfo = fromObj.getClosestConnectorToGraphicalObject( toObj,interObj.visualObject );
+		var inPoint = connectorInfo.toConnector, outPoint = connectorInfo.fromConnector;
+
+		var newCenter = geometry.getMidpoint2D( inPoint, outPoint)
+
+		// Move the intermediate object into the new center point
+		var g = interObj.visualObject;
+		var oldCenter = g.getCenterCoord()
+		var dx = newCenter.x - oldCenter.x
+		var dy = newCenter.y - oldCenter.y
+
+		// Add a bit of curvature
+		var finalCenter;
+		if( curvature ){
+			var v = curvinator( inPoint, outPoint, curvature, curveDirection )
+			dx += v[0]
+			dy += v[1]
+			finalCenter = [ newCenter[0] + v[0], newCenter[1] + v[1] ]
+		}
+		else{
+			finalCenter = newCenter
+		}
+
+		// Move the intermediate object
+		g.move( dx, dy )
+
+	}
+
+	function curvinator( p1, p2, curveAmount, curveDirection ){
+		/*
+		Returns a vector that is orthongonal to the p1-p2 vector with length curveAmount
+		*/
+		var v = [ - ( p1.y - p2.y ), p1.x - p2.x ]
+		var d = geometry.vectorLength2D( v )
+		d = d || 1
+
+		// Direction of the curvature bulge is random
+		if( curveDirection == -1 && 
+			(Math.round(Math.random()) || curveDirection == 1 )){
+			curveAmount = -curveAmount
+		}
+
+		// Normalized orthogonal vector times the curvature bulge
+		v = [ v[0] * curveAmount / d, v[1] * curveAmount / d	]
+
+		return v
+	}
+
+	function optimizeSelfLink( interObj, selfObj, setSmooth, curvature ){
+		/*
+		 * Makes a nice loop positioned at upper right-hand corner.
+		 */
+
+		// Require this much distance between link and entity
+		var labelMinDistY = 20,
+			labelMinDistX = 20,
+			bezierMinDistY = 40,
+			bezierMinDistX = 40;
+
+		// Add additional minimum distance according to link object size
+		var g = interObj.visualObject;
+
+		// Add additional minimum distance according to entity object size
+		var box = selfObj.getBBoxInCanvasSpace();
+
+		g.setStartPoint({x:box.width/2 + box.x,y:box.y})
+		g.setEndpoint({x:box.width + box.x,y:box.height/2 + box.y})
+
+		g.setControlPoint({x:box.width + box.x + bezierMinDistX,y:box.y - bezierMinDistY})
+		g.moveLabelTo(box.width + box.x + labelMinDistX,box.y - labelMinDistY)
+
+	}
+
+	function optimizerHyperLink( interObj, objectsFrom, objectsTo, setSmooth, curvature, curveDirection, newCenter ){
+		throw new Error("Hyperlinks are not supported yet.");
+	}
+
+	return {
+		optimizeConnectionPorts : optimizeConnectionPorts,
+		optimizeLinks: optimizeLinks
+	}
+
+})

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/LinkOptimizer.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/PrepLayout.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/PrepLayout.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/PrepLayout.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/PrepLayout.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,191 @@
+/* 
+ *  Copyright 2010 jacob.
+ * 
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ * 
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *  under the License.
+ */
+
+require.def("src/javascript/scxml/cgf/layout/PrepLayout",
+[
+	"src/javascript/scxml/cgf/util/svg",
+	"src/javascript/scxml/cgf/Transformer",
+	"src/javascript/scxml/cgf/layout/graphics",
+	"src/javascript/scxml/cgf/util/xpath" ],
+
+function(commonSVG,Transformer,graphics,xpath){
+
+
+	//FIXME: this method is something that will need to be moved out as well, as we may use batik when running under Rhino
+	var bootSVGDOM = require.isBrowser? 
+				function(svgDoc,attachPointNode){
+					attachPointNode = attachPointNode || document.body;
+
+					//in order to use this SVG document, it needs to be rendered, so we append the contents to the current document,
+					//which works well in the html context in Firefox
+					var newDocumentElement = svgDoc.documentElement.cloneNode(true)
+					attachPointNode.appendChild(newDocumentElement)
+
+					/*
+					var impl = document.implementation;
+					var svgDoc2 = impl.createDocument(commonSVG.SVG_NS, "svg", null);
+					svgDoc2.replaceChild(svgDoc.documentElement.cloneNode(true), svgDoc2.documentElement);
+					*/
+					//console.log(newDocumentElement.getBBox)
+					//console.log(newDocumentElement.getBBox())
+					return newDocumentElement.ownerDocument;
+
+				} :
+				function(svgDoc){
+					//FIXME: somewhat evil, assumes batik
+
+					//copy svgDoc into SVGDOMImplementation
+					var impl = org.apache.batik.dom.svg.SVGDOMImplementation.getDOMImplementation();
+					var svgNS = org.apache.batik.dom.svg.SVGDOMImplementation.SVG_NAMESPACE_URI;
+					var svgDoc2 = impl.createDocument(svgNS, "svg", null);
+					svgDoc2.replaceChild(svgDoc2.importNode(svgDoc.documentElement,true), svgDoc2.documentElement);
+					
+
+					//boot SVG and CSS DOM: http://wiki.apache.org/xmlgraphics-batik/BootSvgAndCssDom
+					var userAgent = new org.apache.batik.bridge.UserAgentAdapter();
+					var loader    = new org.apache.batik.bridge.DocumentLoader(userAgent);
+					var ctx       = new org.apache.batik.bridge.BridgeContext(userAgent, loader);
+					ctx.setDynamicState(org.apache.batik.bridge.BridgeContext.DYNAMIC);
+					var builder   = new org.apache.batik.bridge.GVTBuilder();
+					var rootGN    = builder.build(ctx, svgDoc2);
+
+					return svgDoc2;
+				};
+
+
+	var statesPredicate = "[self::s:state or self::s:parallel or self::s:final or self::s:initial or self::s:history]";
+
+	function scxmlToEntityNodeListAndLinkList(scxmlDoc,svgDoc){
+		//TODO: refactor all of this to be OO and use constructor functions and stuff
+		var root = scxmlDoc.documentElement;
+		var rootEntity = (function(scxmlNode){
+			var stateId = scxmlNode.getAttributeNS(null,"id");
+			var childrenIds = xpath.query("*" + statesPredicate + "/@id",scxmlNode).map(function(n){return n.nodeValue});
+
+			return {
+				id : stateId,
+				outConnections : [],
+				inConnections : [],
+				parent : null,
+				children : childrenIds,
+				visualObject : new graphics.BoxedGraphEntity(svgDoc.getElementById(stateId))
+			}
+		})(root);
+
+		function createStateEntity(s,graphicalClass){
+			var stateId = s.getAttributeNS(null,"id");
+			var outTransitionIds = xpath.query("s:transition/c:targets/c:target/@c:id",s).map(function(n){return n.nodeValue});;
+			var inTransitionIds = xpath.query("//s:transition/c:targets/c:target[c:targetState/text()='" + stateId + "']/@c:id",
+				scxmlDoc.documentElement).map(function(n){return n.nodeValue});
+			var parentId = s.parentNode.getAttributeNS(null,"id");
+			var childrenIds = xpath.query("*" + statesPredicate + "/@id",s).map(function(n){return n.nodeValue});
+
+			return {
+				id : stateId,
+				outConnections : outTransitionIds,
+				inConnections : inTransitionIds,
+				parent : parentId,
+				children : childrenIds,
+				visualObject : new graphicalClass(svgDoc.getElementById(stateId))
+			}
+		}
+		var states = xpath.query("//s:*[self::s:state or self::s:parallel]",scxmlDoc.documentElement);
+		var stateEntityList = states.map(function(s){return createStateEntity(s,graphics.BoxedGraphEntity)})
+
+		var initialFinalAndHistoryStateEntityList = xpath.query("//s:*[self::s:final or self::s:initial or self::s:history]",scxmlDoc.documentElement);
+		var initialStateEntityList = initialFinalAndHistoryStateEntityList.map(function(s){return createStateEntity(s,graphics.GraphEntity)})
+
+		var entityList = stateEntityList.concat(initialStateEntityList)
+
+
+		var transitionTargets = xpath.query("//s:transition/c:targets/c:target",scxmlDoc.documentElement)
+		var linkNodeList = transitionTargets.map(function(t){
+			var transitionId = t.getAttributeNS(commonSVG.SCXML_JS_NS,"id");
+			var originId = xpath.query("../../../@id",t)[0].nodeValue;
+			var targetId = xpath.query("c:targetState",t)[0].textContent;
+
+			//these attributes needed for hierarchical layout
+			var sourceAncestorOrSelfAndChildOfLCAId = xpath.query("c:sourceAncestorOrSelfAndChildOfLCA",t)[0].textContent;
+			var targetAncestorOrSelfAndChildOfLCAId = xpath.query("c:targetAncestorOrSelfAndChildOfLCA",t)[0].textContent;
+			var lcaId = xpath.query("../../c:lca",t)[0].textContent;
+
+			return {
+				id : transitionId,
+				outConnections : [targetId],
+				inConnections : [originId],
+				sourceAncestorOrSelfAndChildOfLCA : [sourceAncestorOrSelfAndChildOfLCAId],
+				lca : lcaId,
+				targetAncestorOrSelfAndChildOfLCA : [targetAncestorOrSelfAndChildOfLCAId],
+				getClosestStartAndEndConnectionPoints : function(){
+					//right now, only snap to first element of in and outConnections (no intelligent handling of hyperedges)
+					var inGraphObject = this.inConnections[0].visualObject;
+					var outGraphObject = this.outConnections[0].visualObject;
+
+					return inGraphObject.getClosestConnectorToGraphicalObject(outGraphObject,this.visualObject);
+				},
+				visualObject : new graphics.GraphLink(svgDoc.getElementById(transitionId))
+			}
+		})
+
+		var entityAndLinkList = entityList.concat(linkNodeList).concat(rootEntity);
+
+		var getNodeFromId = function(cIdOrNode){
+			return entityAndLinkList.filter(function(e){return cIdOrNode == e.id})[0] || cIdOrNode;
+
+		}
+
+		//now that all objects have been created, hook up references to other objects via in and out connections
+		//it's OK to use a new list to do this, because we're operating on objects, which is like C pointer semantics
+		entityAndLinkList.forEach(function(s){
+			s.outConnections = s.outConnections.map(getNodeFromId);
+
+			s.inConnections = s.inConnections.map(getNodeFromId);
+
+			s.parent = s.parent && getNodeFromId(s.parent);
+
+			s.children = s.children && s.children.map(getNodeFromId);
+
+			if(s.sourceAncestorOrSelfAndChildOfLCA)
+				s.sourceAncestorOrSelfAndChildOfLCA = s.sourceAncestorOrSelfAndChildOfLCA.map(getNodeFromId);
+
+			if(s.targetAncestorOrSelfAndChildOfLCA)
+				s.targetAncestorOrSelfAndChildOfLCA = s.targetAncestorOrSelfAndChildOfLCA.map(getNodeFromId);
+
+			if(s.lca)
+				s.lca = getNodeFromId(s.lca)
+
+		});
+
+		return {rootEntity : rootEntity, entityList : entityList, linkNodeList : linkNodeList};
+	}
+
+
+/*
+	function addGraphicalNodeReference(graphNodeList,svgDoc,graphicalClass){
+		//mapped based on id
+		graphNodeList.forEach(function(e){
+			e.visualObject = new graphicalClass(svgDoc.getElementById(e.id));
+		});
+	}
+	*/
+
+
+	return {
+		scxmlToEntityNodeListAndLinkList : scxmlToEntityNodeListAndLinkList,
+		bootSVGDOM : bootSVGDOM
+	}
+})

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/PrepLayout.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/graphics.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/graphics.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/graphics.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/graphics.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,214 @@
+require.def("src/javascript/scxml/cgf/layout/graphics",
+["src/javascript/scxml/cgf/util/svg",
+	"src/javascript/scxml/cgf/util/geometry",
+	"src/javascript/scxml/cgf/util/xpath" ],
+function(commonSVG,geometry,xpath){
+
+	//constructor functions
+	function VisualObject(rootNode){
+		//a visual object. wraps a raw SVG node. also, exposes connection points
+
+		this._rawNode = rootNode; //rawNode
+		this._connectionPoints = _getConnectionPointsFromSVGNode(rootNode) //connection points
+
+		function _getConnectionPointsFromSVGNode(node){
+			return xpath.query("svg:*[@class='connectionPoint']",node);
+		}
+
+		this.getBBox = function(){
+			return this._rawNode.getBBox();
+		}
+
+		this.getBBoxInCanvasSpace = function(){
+			return commonSVG.getBBoxInCanvasSpace(this._rawNode);
+		}
+
+		this.getBBoxInEntitySpace = function(e){
+			return commonSVG.getBBoxInElementSpace(this._rawNode,e._rawNode);
+		}
+
+		this.moveTo = function(x,y){
+			var bbox = this._rawNode.getBBox();
+			var curX = bbox.x, curY = bbox.y;
+			var dx = x - curX;
+			var dy = y - curY; 
+			return this.move(dx,dy);
+		}
+
+		this.getClosestConnectorToPoint = function(fx, fy, contextVisualObj){
+			/*
+			 Returns the connector (cx, cy) of visualObject which makes minimum 
+			 the distance to (fx, fy)
+			*/									
+			return this._connectionPoints.reduce(function(o,c){
+				//compute distance from given point to connector
+				var bbox = commonSVG.getBBoxInElementSpace(c,contextVisualObj._rawNode);
+				var newDistance = geometry.distance(bbox.x,bbox.y,fx,fy);
+
+				return o.distance < newDistance ?  o : {distance:newDistance,connector:bbox};
+			},{distance:Number.MAX_VALUE,connector:{x:0,y:0}});
+		}
+
+		this.getClosestConnectorToGraphicalObject = function(graphicalObject,contextVisualObj){
+			/*
+				for each connection point A on this object
+					find the closest connection point B on a given graphicalObject
+			*/
+			return this._connectionPoints.reduce(function(o,c){
+				//compute distance from given point to connector
+				var bbox = commonSVG.getBBoxInElementSpace(c,contextVisualObj._rawNode);
+				var connPtInfo = graphicalObject.getClosestConnectorToPoint(bbox.x,bbox.y,contextVisualObj);
+
+				return o.distance < connPtInfo.distance ?  
+					o : 
+					{distance:connPtInfo.distance,fromConnector:bbox,toConnector:connPtInfo.connector};
+			},{distance:Number.MAX_VALUE,fromConnector:{x:0,y:0},toConnector:{x:0,y:0}});
+		}
+
+		this.setCanvasViewBox = function(r){
+			var svg = this._rawNode.ownerSVGElement;
+			svg.viewBox.baseVal.x = r.x;
+			svg.viewBox.baseVal.y = r.y;
+			svg.viewBox.baseVal.width = r.width;
+			svg.viewBox.baseVal.height = r.height;
+		}
+	}
+
+	function GraphEntity(rootNode){
+		//wraps a graph node
+
+		VisualObject.apply(this,arguments);
+
+		//Move method
+		this.move = function(dx,dy){
+			return commonSVG.translate(this._rawNode,dx,dy);
+		}
+	}
+
+	function BoxedGraphEntity(rootNode){
+		GraphEntity.apply(this,arguments);
+
+		this._boundingBoxRectElement = _getBBoxRectElement(rootNode);
+		this._boundingBoxLabelElement = _getBBoxLabelElement(rootNode);
+
+		function _getBBoxRectElement(node){
+			return xpath.query("svg:*[@class='groupBoundingRect']",node)[0];
+		}
+
+		function _getBBoxLabelElement(node){
+			return xpath.query("svg:text[@class='label']",node)[0];
+		}
+
+		this.resizeBBoxElement = function(newBBox){
+			//update connection points
+			var dx = newBBox.x - this._boundingBoxRectElement.x.baseVal.value,
+				dy = newBBox.y - this._boundingBoxRectElement.y.baseVal.value,
+				sx = newBBox.width / this._boundingBoxRectElement.width.baseVal.value,
+				sy = newBBox.height / this._boundingBoxRectElement.height.baseVal.value;
+
+			this._connectionPoints.forEach(function(pt){
+				pt.cx.baseVal.value *= sx;
+				pt.cy.baseVal.value *= sy;
+				pt.cx.baseVal.value += dx;
+				pt.cy.baseVal.value += dy;
+			})
+
+			//resize bbox
+			this._boundingBoxRectElement.width.baseVal.value = newBBox.width;
+			this._boundingBoxRectElement.height.baseVal.value = newBBox.height;
+			this._boundingBoxRectElement.x.baseVal.value = newBBox.x;
+			this._boundingBoxRectElement.y.baseVal.value = newBBox.y;
+
+			return newBBox;
+		}
+
+		this.moveLabelElementTo = function(x,y){
+			//update label
+			if(this._boundingBoxLabelElement){
+				this._boundingBoxLabelElement.x.baseVal.getItem(0).value = x;
+				this._boundingBoxLabelElement.y.baseVal.getItem(0).value = y;
+			}
+		}
+
+		this.resizeBBoxElementAndUpdateLabel = function(bbox,options){
+			options = options || {
+				labelPadding : 3
+			}
+
+			this.resizeBBoxElement(bbox);
+			this.moveLabelElementTo(bbox.x,bbox.y - options.labelPadding);
+		}
+	}
+
+	function GraphLink(rootNode){
+		//wraps a quadratic bezier curve, which has a (possibly empty) label
+
+		VisualObject.apply(this,arguments);
+
+		//label node
+		this._labelNode = _getLabelNodeFromSVGNode(rootNode);
+		this._pathNode = _getPathNodeFromSVGNode(rootNode);
+		this._startPoint = this._pathNode.pathSegList.getItem(0);
+		this._controlPoint = this._pathNode.pathSegList.getItem(1);
+
+		function _getLabelNodeFromSVGNode(node){
+			return xpath.query("svg:text[@class='label']",node)[0];
+		}
+
+		function _getPathNodeFromSVGNode(node){
+			return xpath.query("svg:path[@class='edge']",node)[0];
+		}
+
+		//Move method
+		this.move = function(dx,dy){
+			//move the control point?
+			this._controlPoint.x1 += dx
+			this._controlPoint.y1 += dy
+
+			//move the label
+			return commonSVG.translate(this._labelNode,dx,dy);
+		}
+
+
+		this.moveLabelTo = function(x,y){
+			var bbox = this._labelNode.getBBox();
+			var curX = bbox.x, curY = bbox.y;
+			var dx = x - curX;
+			var dy = y - curY;
+			return commonSVG.translate(this._labelNode,dx,dy);
+		}
+
+		//methods to adjust start, end and control point
+		this.setStartPoint = function(pt){
+			this._startPoint.x = pt.x
+			this._startPoint.y = pt.y
+		}
+
+		this.setControlPoint = function(pt){
+			this._controlPoint.x1 = pt.x
+			this._controlPoint.y1 = pt.y
+		}
+
+		this.setEndpoint = function(pt){
+			this._controlPoint.x = pt.x
+			this._controlPoint.y = pt.y
+		}
+
+		this.setCoords = function(coordsObj){
+			this.setStartPoint(coordsObj.startPoint);
+			if(coordsObj.controlPoint) this.setControlPoint(coordsObj.controlPoint);
+			this.setEndpoint(coordsObj.endPoint);
+		}
+
+		this.getCenterCoord = function(){
+			return this._labelNode.getBBox() || {x:0,y:0}; //batik will return null if the element has no size
+		}
+	}
+
+	return {
+		GraphLink : GraphLink,
+		GraphEntity : GraphEntity,
+		BoxedGraphEntity : BoxedGraphEntity
+	}
+
+});

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/graphics.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/CrossingModule.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/CrossingModule.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/CrossingModule.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/CrossingModule.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,234 @@
+/*
+CrossingModule.py
+
+Collection of algorithms responsible for phase II of Sugiyama-style hierarchical
+layout... crossing reduction.
+
+By Denis Dube, 2005
+*/
+
+require.def("src/javascript/scxml/cgf/layout/hierarchical/CrossingModule",
+["src/javascript/scxml/cgf/layout/hierarchical/NodeWrapper"],
+function(NodeWrapper){
+
+	function barycentricOrdering(levelDictionary, phaseOneMax, phaseTwoMax){
+		/*
+		Given a dictionary mapping of integer levels to nodes
+		Re-orders the nodes on each level to have fewer edge crossings
+		Implementation draws from:
+			CROSSING REDUCTION FOR LAYERED HIERARCHICAL GRAPH DRAWING
+			By PITCH PATARASUK
+		However, I don't perform same barycenter order reversals; for some reason
+		this yielded MORE crossings rather than less. I DO use random order 
+		restarts however, which has given me good to optimal results in tests.
+		*/
+
+			
+		// Init variables
+		var totalLevelsInt = levelDictionary.length
+		var bestGlobalCrossings = Number.MAX_VALUE	 // Minimum # of crossings found so far
+		var bestLevelDictionary = null				 // Copy of the level dict with min cross
+		var phaseOneIterations = 0
+		var phaseTwoIterations = 0
+		
+		// Initilize layer orderings 
+		levelDictionary.forEach(function(level){
+			__updateOrder(level)
+		})
+		
+		// Main crossing reduction loop
+		while(phaseTwoIterations < phaseTwoMax){
+			
+			// Iterate over all the levels in the level dictionary
+			// If totalLevelsInt = 3, then this range yields [0, 1]
+			for(var j = 0; j < totalLevelsInt - 1; j++){
+				
+				//// Down-Barycenter (Parent to child)
+				levelDictionary[j].forEach(function(node){
+					node.computeBarycenter(true)
+				});
+
+				// Sort the list in place according to barycenter values
+				levelDictionary[j].sort(function(a,b){ return a.getBarycenter() < b.getBarycenter()})
+
+				// Save the node's sorted position in it's internal parameter
+				__updateOrder(levelDictionary[j])
+					
+				//// Up-Barycenter (Child to parent)
+				levelDictionary[j + 1].forEach(function(node){
+					node.computeBarycenter(false)
+				});
+
+				// Sort the list in place according to barycenter values
+				levelDictionary[j + 1].sort(function(a, b){ return a.getBarycenter() < b.getBarycenter() })
+
+				// Save the node's sorted position in it's internal parameter
+				__updateOrder(levelDictionary[j + 1])
+			}
+				
+
+			// Count crossings
+			var globalCrossings = 0
+			for(var j = 0; j < totalLevelsInt - 1; j++){
+				globalCrossings += countCrossings(levelDictionary[j], 
+									 levelDictionary[j + 1])
+			}
+				
+			// Did the last iteration of the algorithm reduce crossings?
+			if(globalCrossings < bestGlobalCrossings){
+				// Crossings reduced, reset counter since more reductions are possible
+				phaseOneIterations = 0				
+				// Store a copy of levelDictionary, best ordering yet
+				bestLevelDictionary = __copyDict(levelDictionary)						
+				bestGlobalCrossings = globalCrossings		
+			}
+			else{
+				// Crossings not reduced, keep trying, might reduce later
+				phaseOneIterations += 1
+				if(phaseOneIterations > phaseOneMax){
+					// Reductions have ceased, try a random restart...
+					phaseOneIterations = 0
+					phaseTwoIterations += 1
+					
+					// Randomize layer orderings
+					//get a list of indexes
+					//shuffle them
+					//set the order property of each node at that level, according to the random index
+					levelDictionary.forEach(function(currentLevel){
+						var indexList = range(0, currentLevel.length)
+						var shuffledList = indexList.slice()
+						fisherYates(shuffledList)
+	
+						shuffledList.forEach(function(k){
+							currentLevel[indexList.pop()].setOrder(k)
+						});
+					});
+				}
+			}
+		}
+
+		// Return the levelDictionary with the least crossings
+		return bestLevelDictionary
+	}
+
+	function range(from,to,increment){
+		increment = increment || 1;
+		var toReturn = [];
+		for(var i = from; i < to; i+= increment){
+			toReturn.push(i);
+		}
+		return toReturn;
+	}
+		 
+	//JavaScript array shuffle implementation taken from http://sedition.com/perl/javascript-fy.html
+	function fisherYates ( myArray ) {
+		var i = myArray.length;
+		if ( i == 0 ) return false;
+		while ( --i ) {
+			var j = Math.floor( Math.random() * ( i + 1 ) );
+			var tempi = myArray[i];
+			var tempj = myArray[j];
+			myArray[i] = tempj;
+			myArray[j] = tempi;
+		}
+	}
+		 
+	function countCrossings(layerA, layerB){
+		/*
+		Inputs: layerA and layerB are lists of NodeWrapper objects
+		Output: // of crossings between two node layers in O(|E| log |Vsmall|)
+		
+		NOTE: Most other algorithms for this are O(|E| + Number of crossings)
+		Implementation of:
+			Simple and Efficient Bilayer Cross Counting
+			Wilhelm Barth, Michael Junger, and Petra Mutzel
+			GD 2002, LNCS 2528, pp. 130-141, 2002
+		*/
+		// Assumed that layerA is above layerB, so children of A are in B
+		// Now figure out which layer is smaller to improve running time a bit
+
+		var smallLayer, largeLayer, isParent2Child;
+
+		if(layerA.length < layerB.length){
+			smallLayer = layerA
+			largeLayer = layerB
+			isParent2Child = false
+		}
+		else{
+			smallLayer = layerB
+			largeLayer = layerA
+			isParent2Child = true
+		}
+		
+	 
+		// Sort the edges and come up with a sequence of edges (integer indices)
+		var edgeSequence = []
+		largeLayer.forEach(function(node){
+			var tempList = []
+			// Get all possible nodes connected to this node
+			var targetNodeList = NodeWrapper.Source2TargetListMap[node.id]
+			targetNodeList.forEach(function(targetNode){
+				// Restrict ourselves to just those nodes that are in smallLayer
+				if(targetNode in smallLayer) tempList.append(targetNode.getOrder())
+			});
+			tempList.sort()
+			edgeSequence = edgeSequence.concat(tempList)
+		});
+			
+		// Build the accumulator tree
+		var firstindex = 1		
+		while(firstindex < smallLayer.length)
+			firstindex *= 2
+
+		var treesize = (2 * firstindex) - 1
+		firstindex -= 1
+		var tree = {}
+
+		for(var i = 0; i < treesize; i++){
+			tree[i] = 0
+		}
+		
+		// Count the crossings
+		var crosscount = 0
+		for(var k = 0; k < edgeSequence.length; k++){
+			var index = edgeSequence[k] + firstindex
+			tree[index] += 1
+			while(index > 0){
+
+				if(index % 2)
+					crosscount += tree[index + 1]
+
+				index = (index - 1) / 2
+				tree[index] += 1
+			}
+		}
+
+		return crosscount
+	}
+		
+		
+
+	function __updateOrder(orderedLayer){
+		/* 
+		The ordering is implicit in the node sequence in the list
+		However to do a node sort, it's handy to have each node know its order
+		This order is used only within __barycentricOrdering() except for debug
+		*/
+		var i = 0
+		orderedLayer.forEach(function(node){
+			node.setOrder(i)
+			i += 1
+		});
+	}
+			
+	function __copyDict(levelDictionary){
+		/* Handy method to make a real copy of the levelDictionary */
+		return levelDictionary.map(function(nodeList){
+			return nodeList.slice();
+		});
+	}
+
+	return {
+		barycentricOrdering : barycentricOrdering
+	}
+})

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/CrossingModule.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout.js
URL: http://svn.apache.org/viewvc/commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout.js?rev=984129&view=auto
==============================================================================
--- commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout.js (added)
+++ commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout.js Tue Aug 10 17:13:04 2010
@@ -0,0 +1,401 @@
+require.def("src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout",
+[
+	"src/javascript/scxml/cgf/layout/hierarchical/NodeWrapper",
+	"src/javascript/scxml/cgf/layout/hierarchical/LayeringModule",
+	"src/javascript/scxml/cgf/layout/hierarchical/CrossingModule",
+	"src/javascript/scxml/cgf/layout/hierarchical/HorizontalPositioner",
+	"src/javascript/scxml/cgf/layout/LinkOptimizer"],
+function(NodeWrapper,LayeringModule,CrossingModule,HorizontalPositioner,LinkOptimizer){
+
+	var HEURISTICS_ENUM = {
+			LONGEST_PATH_LAYERING_TOP_DOWN : "LONGEST_PATH_LAYERING_TOP_DOWN",
+			LONGEST_PATH_LAYERING_BOTTOM_UP : "LONGEST_PATH_LAYERING_BOTTOM_UP",
+			MINIMUM_WIDTH_LAYERING : "MINIMUM_WIDTH_LAYERING"
+	}
+
+	function hierarchicalLayout(entityNodeList,wrappedNodeList,options){
+
+		options = options || {}
+		options['xOffset'] = options['xOffset'] || 30;	// Minimum X Distance; Minimum horizontal distance between any 2 tree nodes (negative values work too)
+		options['yOffset'] = options['yOffset'] || 30;	// Minimum Y Distance; Minimum vertical distance between any 2 tree nodes   
+		options['addEdgeObjHeight'] = options['addEdgeObjHeight'] || true;	// Add edge object height; Increment spacing between node layers with edge object drawing of maximum height between 2 given layers
+		options['Origin'] = options['Origin'] || false;	// Start tree at origin?
+		options['uncrossPhase1'] = options['uncrossPhase1'] || 5;	// Maximum uncrossing iterations
+		options['uncrossPhase2'] = options['uncrossPhase2'] || 15;	// Maximum uncrossing random restarts
+		options['baryPlaceMax'] = options['baryPlaceMax'] || 10;	// Maximum gridpositioning iterations
+		options['Spline optimization']  = options['Spline optimization'] || false;	// Spline optimization
+		options['Arrow curvature'] = options['Arrow curvature'] || 0	// Arrow curvature
+		options['heuristic'] = options['heuristic'] || HEURISTICS_ENUM.LONGEST_PATH_LAYERING_TOP_DOWN
+
+		var t = new Date();
+
+		// Step 1: Get all entity nodes (semantic objects) and wrap them
+		//entityNodeList, linkNodeDict = self.__getEntityLinkTuple(selection)    
+		if(entityNodeList.length == 0)
+			return
+			
+		// Build a connection map (rapid access maps to children && parents)
+		wrappedNodeList.forEach(function(wrappedNode){
+			wrappedNode.buildConnectivityMaps()
+		});
+
+		// Step 2: Build a proper layered hieararchy
+		wrappedNodeList = LayeringModule.greedyCycleRemover(wrappedNodeList)
+		var layerTime = new Date();
+		var levelDictionary;
+
+		switch(options['heuristic']){
+			case HEURISTICS_ENUM.LONGEST_PATH_LAYERING_TOP_DOWN:
+				levelDictionary = LayeringModule.longestPathLayeringTopDown(wrappedNodeList)
+				levelDictionary = LayeringModule.addDummyNodes(levelDictionary, true)
+				break;
+			case HEURISTICS_ENUM.LONGEST_PATH_LAYERING_BOTTOM_UP:
+				levelDictionary = LayeringModule.longestPathLayeringBottomUp(wrappedNodeList)
+				levelDictionary = LayeringModule.addDummyNodes(levelDictionary, false)
+				break;
+			case HEURISTICS_ENUM.MINIMUM_WIDTH_LAYERING:
+				var mwl = new LayeringModule.MinimumWidthLayering(wrappedNodeList)
+				// UBW = 1..4, c = 1..2
+				levelDictionary = mwl.execute(2, 2)
+				levelDictionary = LayeringModule.addDummyNodes(levelDictionary, false)
+				break;
+		}
+
+		console.log('Layering algorithm required', new Date() - layerTime, 'milliseconds to assign each node a layer');
+
+		//return
+		console.log( 'Added dummy nodes, dumping layers:');
+
+		//debugLevelDict(levelDictionary)
+					
+		// Step 3: Minimize crossings		
+		levelDictionary = CrossingModule.barycentricOrdering(levelDictionary, options['uncrossPhase1'], options['uncrossPhase2'])
+
+		// Step 4: Horizontal grid positioner
+		HorizontalPositioner.priorityBarycenterPositioner(levelDictionary,options['baryPlaceMax'] ) 
+
+		// Step 5: Draw nodes && edges on the canvas
+		var topLeft;
+		if(entityNodeList.length != 0)
+			topLeft = __getMaxUpperLeftCoordinate(entityNodeList)
+		else
+			topLeft = [0, 0]
+
+		//TODO: hook up linkNodeDict
+		//__drawNodes(levelDictionary, linkNodeDict, topLeft)
+		__drawNodes(levelDictionary, null, topLeft)
+						
+		//debugLevelDict(levelDictionary)
+
+		console.log( 'Hierarchical layout took', new Date() - t, 'milliseconds to compute')
+
+		function __getMaxUpperLeftCoordinate(entityNodeList){
+			/* 
+			Returns the maximum upper left coordinate of all the nodes the layout is
+			being applied to
+			This corresponds to the minumum x && y coords of all the nodes
+			*/
+			var minX = Number.MAX_VALUE
+			var minY = Number.MAX_VALUE
+			entityNodeList.forEach(function(node){
+				var bbox = node.visualObject.getBBox();
+				if(bbox.y < minY)
+					minY = bbox.y
+				if(bbox.x < minX)
+					minX = bbox.x
+			});
+			return [minX, minY]
+		}
+					
+		function __drawNodes( levelDictionary, linkNodeDict, topLeft){
+			/* 
+			Takes size of nodes into account to translate grid positions into actual
+			canvas coordinates
+			*/
+			var setSmooth		= options['Spline optimization']
+			var setCurvature = options['Arrow curvature']
+			var minOffsetY = options['yOffset']
+			var minOffsetX = options['xOffset']
+			var giveExtraSpaceForLinks = options['addEdgeObjHeight']
+
+			// Caclulate x, y offsets
+			var offsetX = 0
+			var levelInt2offsetY = {}
+			var currentLevel, levelInt;
+			for(levelInt = 0; levelInt < levelDictionary.length; levelInt++){
+				currentLevel = levelDictionary[levelInt]
+				levelInt2offsetY[levelInt] = 0
+				
+				// Calculate maximum node size on a per level basis (X is for all levels)
+				// Then add minimum seperation distance between nodes
+				currentLevel.forEach(function(node){
+					// getSize returns node width, && height of the node & child link icon
+					var size = node.getSize(giveExtraSpaceForLinks)
+					var x = size[0], y = size[1];
+					offsetX = Math.max(offsetX, x)
+					levelInt2offsetY[levelInt] = Math.max(levelInt2offsetY[levelInt], y)
+				});
+			}
+																			 
+					
+			var maxOffsetX = offsetX + minOffsetX
+			var halfOffsetX = offsetX / 2
+					
+			// Send nodes to their final destination, assign final pos to dummy edges
+			var x = topLeft[0], y = topLeft[1];
+			for(levelInt = 0; levelInt < levelDictionary.length; levelInt++){
+				currentLevel = levelDictionary[levelInt]
+				var longEdgeOffset = [halfOffsetX, levelInt2offsetY[levelInt] / 3]
+											
+				// Move each node in the level (Dummy edges save the pos but don't move)
+				currentLevel.forEach(function(node){
+					node.moveTo(x + node.getGridPosition() * maxOffsetX, y, longEdgeOffset)
+				})
+					
+				// Increment y for the next iteration
+				y += levelInt2offsetY[levelInt] + minOffsetY
+			}
+				
+			// Self-looping edges (Must move these manually into position)
+			NodeWrapper.SelfLoopList.forEach(function(selfLoopedEdge){
+				var pos = selfLoopedEdge.getEdgePosition();
+				x = pos[0]
+				y = pos[1]
+				selfLoopedEdge.moveTo(x,y)
+			})
+
+			//debugger;
+			// Re-wire the links to take into account the new node positions
+			/*
+			var selectedLinks = []
+			linkNodeDict.values().forEach(function(obj){
+				selectedLinks.push(obj)
+			})
+			optimizeLinks(this.cb, setSmooth, setCurvature, selectedLinks=selectedLinks)
+			*/
+			//LinkOptimizer.optimizeLinks(linkNodeList);
+			
+			// Route multi-layer edges
+			//__edgeRouter()
+		}
+			
+		 function __edgeRouter(){
+			/*
+			Previously, edges traversing multiple layers were represented as a chain
+			of dummy nodes. Now these nodes are used as points on a continuous spline.
+			*/
+			function getEndpoint(nodeTuple, pointList, direction, isReversedEdge){
+				/* Gets the nearest arrow endpoint. Handles edge reversal */
+
+				var ix,iy;
+				if((direction == 'start' && ! isReversedEdge)
+					 || (direction == 'end' && isReversedEdge)){
+					var endNode = nodeTuple[0]
+					if(isReversedEdge){
+						ix = -2
+						iy = -1
+					}
+					else{
+						ix = 0
+						iy = 1
+					}
+				}
+				else{
+					endNode = nodeTuple[1]
+					if(isReversedEdge){
+						ix = 0
+						iy = 1
+					}
+					else{
+						ix = -2 
+						iy = -1				
+					}
+				}
+						
+				// Is it connected to a named port!?!
+				if(endNode.isConnectedByNamedPort(edgeObject)){
+					handler = endNode.getConnectedByNamedPortHandler(nodeTuple[2]) 
+					return dc.coords(handler).slice(0,2)
+				}
+						
+				// Not a named port...
+				return list(endNode.getClosestConnector2Point( endNode, pointList[ix], pointList[iy]))	 
+			}	
+			
+			
+			//todo: improve method for spline arrows + add comments + optimize?
+			console.log( '----------------Dummy Edge Routing-----------------')
+			NodeWrapper.ID2LayerEdgeDict.keys().forEach(function(dummyEdge){
+				
+				var dummyList = NodeWrapper.ID2LayerEdgeDict[dummyEdge]
+				var dummyNode = dummyList[0]
+				var dummyChild = dummyNode.children[0]
+				var linkFlagList = dummyNode.childNodeToLinkFlagListMap[dummyChild.id]
+				
+				// Real nodes at start/end of the edge
+				var edgeSourceNode = dummyNode.parents[0]
+				edgeSourceNode = edgeSourceNode.getASGNode().visualObject
+				dummyNode = dummyList[-1]
+				var edgeTargetNode = dummyNode.children[0]
+				//print 'Dummy edge number', dummyEdge,
+				//print dummyList[0].parents.keys()[0].getName(),	edgeTargetNode.getName()
+				edgeTargetNode = edgeTargetNode.getASGNode().visualObject
+				var nodeTuple = [edgeSourceNode, edgeTargetNode, null]
+				
+				// Some edges are internally reversed to break cycles, when drawing
+				// this must be taken into account
+				var isReversedEdge = false
+				var edgesToRoute = []
+				linkFlagList.forEach(function(flag){
+					var linkNode = flag[0], isReversed = flag[1];
+					edgesToRoute.push(linkNode)
+					if(isReversed) isReversedEdge = true
+				});
+					
+				// Get all the points the edge must pass through (sorted by layer order)
+				dummyList.sort(function(a, b){ return a.getLayer() < b.getLayer()})
+				if(isReversedEdge) dummyList.reverse()
+
+				var sortedDummyRouteList = []
+				dummyList.forEach(function(node){
+					sortedDummyRouteList = 
+						sortedDummyRouteList.concat(node.getEdgePosition())
+				})
+				
+				// Set the coordinates of the edge directly 
+				// This is complicated by the fact that AToM3 treats edges as two
+				// segments that join poorly (for spline arrows)
+				edgesToRoute.forEach(function(edgeObject){
+					var dc = edgeObject.visualObject.dc
+					var linkObj = edgeObject.visualObject
+					var tag = linkObj.tag
+					
+					if(isReversedEdge){
+						inPoint = dc.coords( tag + "2ndSeg0" ).slice(0,2)
+						outPoint = dc.coords( tag + "1stSeg0" ).slice(0,2)
+					}
+					else{
+						inPoint = dc.coords( tag + "1stSeg0" ).slice(0,2)
+						outPoint = dc.coords( tag + "2ndSeg0" ).slice(0,2)
+					}
+					
+					//print 'Dummy route', sortedDummyRouteList
+					var numPoints = sortedDummyRouteList.length / 2;
+					// Add 2 extra control points for odd case (to make splines nice)
+					var center, start, end, newMid1, newMid2, centerIndex;
+					if(numPoints % 2 == 1){
+						if(numPoints == 1)
+							center = sortedDummyRouteList
+						else{
+							start = sortedDummyRouteList.slice(0,numPoints - 1)
+							end = sortedDummyRouteList.slice(0,numPoints + 1)
+							center = sortedDummyRouteList.slice(numPoints - 1,numPoints + 1)
+						}
+						
+						if(! isReversedEdge){
+							newMid1 = [center[0], center[1] - 20]
+							newMid2 = [center[0], center[1] + 20]
+						}
+						else{
+							newMid2 = [center[0], center[1] - 20]
+							newMid1 = [center[0], center[1] + 20]
+						}
+																
+						if(numPoints == 1)
+							sortedDummyRouteList = newMid1 + center + newMid2 
+						else
+							sortedDummyRouteList = start + newMid1 + center + newMid2 + end
+						centerIndex = numPoints - 1 + 2
+					}
+						
+					// Add 1 extra control point for even case (to make splines nice)
+					else{
+						start = sortedDummyRouteList.slice(0,numPoints)
+						end = sortedDummyRouteList.slice(numPoints)
+						center = [start[-2] + (end[0] - start[-2]) / 2, start[-1] + (end[1] - start[-1]) / 2]
+						sortedDummyRouteList = start + center + end					
+						centerIndex = numPoints
+					}
+						
+					// Now I know where the center is... so lets move the center object
+					// Is the edge object a hyperlink?
+					if(edgeObject.inConnections + edgeObject.outConnections.length > 2){
+						var fromObjs = []
+						edgeObject.inConnections.forEach(function(semObj){
+							fromObjs.push(semObj.visualObject)
+						})
+						var toObjs = []
+						edgeObject.outConnections.forEach(function(semObj){
+							toObjs.push(semObj.visualObject)
+						})
+						optimizerHyperLink(dc, linkObj, fromObjs, toObjs, 0, 0, 0, center )
+					} else {
+						linkObj.moveTo(center)
+					}
+					
+					// Go through the 2 segments in the link
+					nodeTuple[2] = edgeObject
+					linkObj.connections.forEach(function(connTuple){
+						var itemHandler = connTuple[0]
+						var direction = connTuple[1]
+
+						var inPoint, outPoint, segCoords;
+						if( direction ){
+							inPoint = getEndpoint(nodeTuple, sortedDummyRouteList,
+																		'start', isReversedEdge)
+
+							segCoords = inPoint + sortedDummyRouteList.slice(0,centerIndex+2)
+						}
+						else{
+							outPoint = getEndpoint(nodeTuple, sortedDummyRouteList,
+																		 'end', isReversedEdge) 
+							segCoords = sortedDummyRouteList.slice(centerIndex) + outPoint
+							segCoords = __reverseCoordList(segCoords)
+						}
+				
+						// Applies the changed coords to the canvas
+						dc.coords( [itemHandler] + segCoords )		
+						
+						// This may change the associated link drawings: 
+						// move them to the new point 
+						if( direction )
+							linkObj.updateDrawingsTo(inPoint[0], inPoint[1], itemHandler, segmentNumber=1)
+						else
+							linkObj.updateDrawingsTo(outPoint[0], outPoint[1], itemHandler, segmentNumber=2)
+					})
+				});
+			})
+		}
+			
+			
+
+		function __reverseCoordList( segCoords){
+			/* 
+			Input: list of coordinates [x0, y0, x1, y1, ..., xn, yn]
+			Output: list of coordinates reversed [xn, yn, ..., x1, y1, x0, y0]
+			*/		
+			var reversedCoords = []
+			for(var i = segCoords.length - 1; i > 0; i-=2){
+				reversedCoords = reversedCoords.concat([segCoords[i - 1], segCoords[i]])
+			}
+			return reversedCoords
+		}
+			
+
+	}
+
+	function recursivelyApplyHierarchicalLayout(graphEntity,options){
+		var nodeWrapperChildren = graphEntity.children.map(function(c){return new NodeWrapper(c,NodeWrapper.REGULAR_NODE)});
+		graphEntity.children.filter(function(c){return c.children.length})
+			.forEach(function(c){recursivelyApplyHierarchicalLayout(c,options)});
+		hierarchicalLayout(graphEntity.children,nodeWrapperChildren,options);
+	}
+
+	return {
+		recursivelyApplyHierarchicalLayout : recursivelyApplyHierarchicalLayout,
+		hierarchicalLayout : hierarchicalLayout,
+		HEURISTICS_ENUM : HEURISTICS_ENUM
+	}
+
+
+});

Propchange: commons/sandbox/gsoc/2010/scxml-js/trunk/src/javascript/scxml/cgf/layout/hierarchical/HierarchicalLayout.js
------------------------------------------------------------------------------
    svn:eol-style = native