hackedteam/rcs-console

View on GitHub
src/org/un/cava/birdeye/ravis/enhancedGraphLayout/visual/edgeRenderers/EdgeDrawer.as

Summary

Maintainability
Test Coverage
/* 
* The MIT License
*
* Copyright (c) 2007 The SixDegrees Project Team
* (Jason Bellone, Juan Rodriguez, Segolene de Basquiat, Daniel Lang).
* 
* 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 org.un.cava.birdeye.ravis.enhancedGraphLayout.visual.edgeRenderers {
    
    
    import flash.display.DisplayObject;
    import flash.display.Graphics;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    
    import mx.core.UIComponent;
    
    import org.un.cava.birdeye.ravis.enhancedGraphLayout.visual.IControllableEdgeRenderer;
    import org.un.cava.birdeye.ravis.graphLayout.data.*;
    import org.un.cava.birdeye.ravis.graphLayout.layout.HierarchicalLayouter;
    import org.un.cava.birdeye.ravis.graphLayout.visual.*;
    import org.un.cava.birdeye.ravis.graphLayout.visual.edgeRenderers.*;
    import org.un.cava.birdeye.ravis.utils.Geometry;
    import org.un.cava.birdeye.ravis.utils.GraphicsWrapper;
    import org.un.cava.birdeye.ravis.utils.TypeUtil;
    
    /**
     * This edge renderer draws rectangular edge arrows.
     * Please note that for undirected graphs, the actual direction
     * of the arrow might be arbitrary.
     * */
    
    public class EdgeDrawer extends BaseEdgeRenderer implements IControllableEdgeRenderer {
        
        /* constructor does nothing and is therefore omitted
        */
        public var arrowLength:Number = 5;
        
        public var enableArrow:Boolean = true;
        public var fromType:String;
        public var toType:String;
        protected var _type:String;
        protected var labelView:UIComponent;
        
        protected var edgeClass:String;
        protected var arrowPosition:String;
        
        /* temporary fix */
        protected var color:Number;
        
        public static const BASE_EDGE_ABOVE:int = 1;
        public static const BASE_EDGE_RIGHT:int = 2;
        public static const BASE_EDGE_BELOW:int = 3;
        public static const BASE_EDGE_LEFT:int = 4;
        protected var baseEdgePosition:int;
        private var ptPos:Number = 0;
        public var layoutOrientation:uint = HierarchicalLayouter.ORIENT_LEFT_RIGHT;
        public var baseEdgeDis:Number = 30;
        public var isFixBaseEdge:Boolean = true;
        public var hitSize:Number = 6;
        
        public function EdgeDrawer() {
            super();
        }
        
        protected function drawLine(x1:Number, y1:Number, x2:Number, y2:Number):void
        {
            g.lineStyle(hitSize, this.color, 0.01);
            moveTo(x1, y1);
            lineTo(x2, y2);
            g.lineStyle(1, this.color, 1);
            moveTo(x1, y1);
            lineTo(x2, y2);
        }
        
        protected function lineTo(ptx:Number, pty:Number):void
        {
            var pos:Point = new Point(ptx, pty);
            pos = vedge.vgraph.localToGlobal(pos);
            pos = labelView.globalToLocal(pos);
            g.lineTo(pos.x, pos.y);
        }
        
        protected function moveTo(ptx:Number, pty:Number):void
        {
            var pos:Point = new Point(ptx, pty);
            pos = vedge.vgraph.localToGlobal(pos);
            pos = labelView.globalToLocal(pos);
            g.moveTo(pos.x, pos.y);
        }
        
        protected function positionComponent(component:DisplayObject, ptx:Number, pty:Number):void
        {
            var pos:Point = new Point(ptx, pty);
            pos = vedge.vgraph.localToGlobal(pos);
            pos = labelView.globalToLocal(pos);
            component.x = pos.x;
            component.y = pos.y;
        }
        
        /**
         * The draw function, i.e. the main function to be used.
         * Draws a straight line from one node of the edge to the other.
         * The colour is determined by the "disting" parameter and
         * a set of edge parameters, which are stored in an edge object.
         * 
         * @inheritDoc
         * */
        public override function draw():void {
            
            var edge:IEdge = vedge.edge;
            
            var edgeVO:Object = edge.data;
            
            var visible:String = String(edgeVO.visible);
            var fromVisible:String = String(edge.fromNode.data.visible);
            var toVisible:String = String(edge.toNode.data.visible);
            
            
            if (TypeUtil.isFalse(visible) || TypeUtil.isFalse(fromVisible) || TypeUtil.isFalse(toVisible))    
            {
                return;
            }
            
            calculateLayoutOrientation();
            baseEdgePosition = calculateBaseEdgePosition();
            redraw();    
        }
        
        protected function calculateBaseEdgePosition():int
        {
            var edge:IEdge = vedge.edge;
            var fromNode:INode = edge.node1;
            
            var numNodeAbove:int = 0;
            var numNodeRight:int = 0;
            var numNodeBelow:int = 0;
            var numNodeLeft:int = 0;
            
            var visualFromNode:IVisualNode = fromNode.vnode;
            if (!(visualFromNode && visualFromNode.view))
                return -1;
            
            var fromPt:Point = new Point(visualFromNode.view.x + visualFromNode.view.width/2, visualFromNode.view.y + visualFromNode.view.height/2);
            for each (var toNode:INode in fromNode.successors)
            {
                var visualToNode:IVisualNode = toNode.vnode;
                if (!(visualToNode && visualToNode.view))
                    continue;
                var toPt:Point = new Point(visualToNode.view.x + visualToNode.view.width/2, visualToNode.view.y + visualToNode.view.height/2)
                if (isFullyAbovePt(toPt, fromPt))
                    numNodeAbove++;
                
                if (isFullyRightOfPt(toPt, fromPt))
                    numNodeRight++;
                
                if (isFullyBelowPt(toPt, fromPt))
                    numNodeBelow++;
                
                if (isFullyLeftOfPt(toPt, fromPt))
                    numNodeLeft++;
            }
            
            var vg:IVisualGraph = edge.vedge.vgraph;
            
            switch(layoutOrientation)
            {
            case HierarchicalLayouter.ORIENT_LEFT_RIGHT:
            {
                if (numNodeLeft > numNodeRight)
                    return BASE_EDGE_LEFT;
                else
                    return BASE_EDGE_RIGHT;
            }
            case HierarchicalLayouter.ORIENT_RIGHT_LEFT:
            {
                if (numNodeRight > numNodeLeft)
                    return BASE_EDGE_RIGHT;
                else
                    return BASE_EDGE_LEFT;
            }
            case HierarchicalLayouter.ORIENT_TOP_DOWN:
            {
                if (numNodeAbove > numNodeBelow)
                    return BASE_EDGE_ABOVE;
                else
                    return BASE_EDGE_BELOW;
            }
            case HierarchicalLayouter.ORIENT_BOTTOM_UP:
            {
                if (numNodeBelow > numNodeAbove)
                    return BASE_EDGE_BELOW;
                else
                    return BASE_EDGE_ABOVE;
            }
            }
            
            var maxNum:int = Math.max(numNodeAbove, numNodeBelow, numNodeLeft, numNodeRight);
            if (maxNum == numNodeAbove)
                return BASE_EDGE_ABOVE;
            
            if (maxNum == numNodeBelow)
                return BASE_EDGE_BELOW;
            
            if (maxNum == numNodeLeft)
                return BASE_EDGE_LEFT;
            
            if (maxNum == numNodeRight)
                return BASE_EDGE_RIGHT;
            
            return -1;
        }
        
        protected function calculateLayoutOrientation():void
        {
            if (vedge.vgraph.layouter is HierarchicalLayouter)
            {
                layoutOrientation = HierarchicalLayouter(vedge.vgraph.layouter).orientation;
            }
        }
        
        protected function redraw():void {
            
            var edge:IEdge = vedge.edge;
            var edgeVO:Object = edge.data;
            var toPositionStrID:String;
            var fromPositionStrID:String
            arrowPosition = "type1";
            if (edgeVO is XML)
            {
                toPositionStrID = (edgeVO as XML).attribute("toPosition");
                fromPositionStrID = (edgeVO as XML).attribute("fromPosition");
                edgeClass = (edgeVO as XML).attribute("edgeClass");
                color = Number((edgeVO as XML).attribute("color").toString());
            }
            else
            {
                toPositionStrID = edgeVO.toPosition;
                fromPositionStrID = edgeVO.fromPosition;
                edgeClass = edgeVO.edgeClass;
                color = edgeVO.color;
            }
            /* first get the corresponding visual object */
            var fromNode:IVisualNode = vedge.edge.node1.vnode;
            var toNode:IVisualNode = vedge.edge.node2.vnode;
            
            fromType = fromNode.node.data.type;
            toType = toNode.node.data.type;
            
            var fromPt:Rectangle;
            var toPt:Rectangle;
            
            fromPt = new Rectangle(fromNode.view.x, 
                fromNode.view.y, 
                fromNode.view.width, fromNode.view.height);
            
            toPt = new Rectangle(toNode.view.x, 
                toNode.view.y,
                toNode.view.width, toNode.view.height);
            
            labelView = vedge.labelView;
            vedge.labelView["layoutOrientation"] = layoutOrientation;
            var castedComp:EdgeRenderer;
            var fromDistance:Number = 0;
            var toDistance:Number = 0
            if (labelView is EdgeRenderer)
            {
                castedComp = EdgeRenderer(labelView);
                fromDistance = castedComp.fromDistance;
                toDistance = castedComp.toDistance;
            }
            
            var g:GraphicsWrapper = new GraphicsWrapper(labelView.graphics);
            g.fuzzFactor = hitSize;
            g.clear();
            /* now we actually draw */
            /* apply the style to the drawing */
            
            if(vedge.lineStyle != null) {
                g.lineStyle(
                    Number(vedge.lineStyle.thickness),
                    Number(vedge.lineStyle.color),
                    Number(vedge.lineStyle.alpha),
                    Boolean(vedge.lineStyle.pixelHinting),
                    String(vedge.lineStyle.scaleMode),
                    String(vedge.lineStyle.caps),
                    String(vedge.lineStyle.joints),
                    Number(vedge.lineStyle.miterLimits)
                );
            }
            
            var midPt:Point = new Point();
            baseEdgePosition = calculateBaseEdgePosition();
            /* calculate the midpoint */
            
            var pt1:Point = new Point();
            var pt2:Point = new Point();
            var pt3:Point = new Point();
            var pt4:Point = new Point();
            var pt5:Point = new Point();
            var finalPt:Point = new Point();
            
            var pt41:Point = new Point();
            var pt42:Point = new Point();
            
            var tmpPt:Point = new Point();
            
            switch(baseEdgePosition)
            {
            case BASE_EDGE_ABOVE:
            {
                pt1.x = fromPt.x + fromPt.width/2;
                pt1.y = fromPt.y;
                pt2.x = pt1.x;
                if (isFixBaseEdge == false)
                {
                    baseEdgeDis = (Math.abs(fromPt.y - toPt.y)  - toPt.height)/2;
                    pt2.y = pt1.y - baseEdgeDis;
                }
                else
                {
                    pt2.y = pt1.y - (baseEdgeDis) + fromDistance;
                }
                
                
                if (isFullyAbovePt(new Point(toPt.x, toPt.y + toPt.height), pt2))
                {
                    pt4.y = toPt.y + toPt.height;
                    finalPt.y = pt4.y;
                }
                else if (isFullyBelowPt(new Point(toPt.x, toPt.y), pt2))
                {
                    pt4.y = toPt.y;
                    finalPt.y = pt4.y;
                }
                else
                {
                    pt3.y = pt2.y;
                    if (isFullyLeftOfPt(new Point(toPt.x + toPt.width , toPt.y), pt2))
                    {
                        pt3.x = toPt.x + toPt.width;
                        finalPt.x = pt3.x;
                        pt3.x += toDistance;
                    }
                    else if (isFullyRightOfPt(new Point(toPt.x, toPt.y), pt2))
                    {
                        pt3.x = toPt.x;
                        finalPt.x = pt3.x;
                        pt3.x += toDistance;
                    }
                    else
                    {
                        //Recalculate pt2
                        pt2.x = pt1.x;
                        pt2.y = Math.min(toPt.y + toPt.height, pt1.y);
                        
                        pt3.x = pt2.x;
                        pt3.y = pt2.y;
                    }
                    finalPt.y = pt3.y;
                    pt4.y = pt3.y;
                    pt4.x = pt3.x;
                    break;
                }
                
                pt4.x = toPt.x + toPt.width/2;
                finalPt.x = pt4.x;
                pt4.x += toDistance
                pt3.x = pt4.x;
                pt3.y = pt2.y;
                pt5.x = pt4.x ;
                pt5.y = pt4.y + 2*ptPos;
                pt41.y = pt42.y = pt4.y;
                pt41.x = pt4.x + ptPos;
                pt42.x = pt4.x - ptPos;
                break;
            }
                
            case BASE_EDGE_BELOW:
            {
                pt1.x = fromPt.x + fromPt.width/2;
                pt1.y = fromPt.y + fromPt.height;
                pt2.x = pt1.x;
                if (isFixBaseEdge == false)
                {
                    baseEdgeDis = (Math.abs(fromPt.y - toPt.y) - fromPt.height)/2;
                    pt2.y = pt1.y + baseEdgeDis;
                }
                else
                {
                    pt2.y = pt1.y + baseEdgeDis + fromDistance;
                }
                
                
                if (isFullyBelowPt(new Point(toPt.x, toPt.y), pt2))
                {
                    pt4.y = toPt.y;    
                    finalPt.y = pt4.y;
                }
                else if (isFullyAbovePt(new Point(toPt.x, toPt.y + toPt.height), pt2))
                {
                    pt4.y = toPt.y + toPt.height;
                    finalPt.y = pt4.y;
                }
                else
                {
                    pt3.y = pt2.y;
                    if (isFullyLeftOfPt(new Point(toPt.x + toPt.width , toPt.y), pt2))
                    {
                        pt3.x = toPt.x + toPt.width;
                        finalPt.x = pt3.x;
                        pt3.x += toDistance;
                    }
                    else if (isFullyRightOfPt(new Point(toPt.x, toPt.y), pt2))
                    {
                        pt3.x = toPt.x;
                        finalPt.x = pt3.x;
                        pt3.x += toDistance;
                    }
                    else
                    {
                        //Recalculate pt2
                        pt2.x = pt1.x;
                        pt2.y = Math.max(toPt.y, pt1.y);
                        
                        pt3.x = pt2.x;
                        pt3.y = pt2.y;
                    }
                    finalPt.y = pt3.y;
                    pt4.y = pt3.y;
                    pt4.x = pt3.x;
                    break;
                }
                pt4.x = toPt.x + toPt.width/2;
                finalPt.x = pt4.x;
                pt4.x += toDistance;
                pt3.x = pt4.x;
                pt3.y = pt2.y;
                pt5.x = pt4.x ;
                pt5.y = pt4.y - 2*ptPos;
                pt41.y = pt42.y = pt4.y;
                pt41.x = pt4.x + ptPos;
                pt42.x = pt4.x - ptPos;                        
                break;
            }
                
            case BASE_EDGE_LEFT:
            {
                pt1.x = fromPt.x;
                pt1.y = fromPt.y + fromPt.height/2;
                pt2.y = pt1.y;
                if (isFixBaseEdge == false)
                {
                    baseEdgeDis = (Math.abs(fromPt.x - toPt.x) - toPt.width)/2;
                    pt2.x = pt1.x - baseEdgeDis;
                }
                else
                {
                    pt2.x = pt1.x - baseEdgeDis + fromDistance;
                }
                
                if (isFullyLeftOfPt(new Point(toPt.x + toPt.width, toPt.y), pt2))
                {
                    pt4.x = toPt.x + toPt.width;
                    finalPt.x = pt4.x;
                    
                }
                else if (isFullyRightOfPt(new Point(toPt.x, toPt.y), pt2))
                {
                    pt4.x = toPt.x;
                    finalPt.x = pt4.x;
                }
                else
                {
                    pt3.x = pt2.x;
                    if (isFullyAbovePt(new Point(toPt.x, toPt.y + toPt.height), pt2))
                    {
                        pt3.y = toPt.y + toPt.height;
                        finalPt.y = pt3.y;
                        pt3.y += toDistance;
                    }
                    else if (isFullyBelowPt(new Point(toPt.x, toPt.y), pt2))
                    {
                        pt3.y = pt3.y = toPt.y;
                        finalPt.y = pt3.y;
                        pt3.y += toDistance;
                    }
                    else
                    {
                        //Recalculate pt2
                        pt2.y = pt1.y;
                        pt2.x = Math.min(toPt.x + toPt.width, pt1.x);
                        
                        pt3.x = pt2.x;
                        pt3.y = pt2.y;
                    }
                    finalPt.x = pt3.x;
                    pt4.y = pt3.y;
                    pt4.x = pt3.x;
                    break;
                }
                
                pt4.y = toPt.y + toPt.height/2;
                finalPt.y = pt4.y;
                pt4.y += toDistance;
                pt3.y = pt4.y;
                pt3.x = pt2.x;
                pt5.x = pt4.x + 2*ptPos;
                pt5.y = pt4.y;
                pt41.x = pt42.x = pt4.x;
                pt41.y = pt4.y + ptPos;
                pt42.y = pt4.y - ptPos;                    
                break;
            }
                
            case BASE_EDGE_RIGHT:
            {
                pt1.x = fromPt.x + fromPt.width;
                pt1.y = fromPt.y + fromPt.height/2;
                pt2.y = pt1.y;
                if (isFixBaseEdge == false)
                {
                    baseEdgeDis = (Math.abs(fromPt.x - toPt.x) - fromPt.width)/2;
                    pt2.x = pt1.x + baseEdgeDis;
                }
                else
                {
                    pt2.x = pt1.x + baseEdgeDis + fromDistance;
                }
                
                if (isFullyRightOfPt(new Point(toPt.x, toPt.y), pt2))
                {
                    pt4.x = toPt.x;
                    finalPt.x = pt4.x;
                }
                else if (isFullyLeftOfPt(new Point(toPt.x + toPt.width, toPt.y), pt2))
                {
                    pt4.x = toPt.x + toPt.width;
                    finalPt.x = pt4.x;
                }
                else
                {
                    pt3.x = pt2.x;
                    if (isFullyAbovePt(new Point(toPt.x, toPt.y + toPt.height), pt2))
                    {
                        pt3.y = toPt.y + toPt.height;
                        finalPt.y = pt3.y;
                        pt3.y += toDistance;
                    }
                    else if (isFullyBelowPt(new Point(toPt.x, toPt.y), pt2))
                    {
                        pt3.y = toPt.y;
                        finalPt.y = pt3.y;
                        pt3.y += toDistance;
                    }
                    else
                    {
                        //Recalculate pt2
                        pt2.y = pt1.y;
                        pt2.x = Math.max(toPt.x, pt1.x);
                        
                        pt3.x = pt2.x;
                        pt3.y = pt2.y;
                    }
                    finalPt.x = pt3.x;
                    pt4.y = pt3.y;
                    pt4.x = pt3.x;
                    break;
                }
                
                pt4.y = toPt.y + toPt.height/2;    
                finalPt.y = pt4.y;
                pt4.y += toDistance;
                pt3.y = pt4.y;
                pt3.x = pt2.x;
                pt5.x = pt4.x - 2*ptPos;
                pt5.y = pt4.y;    
                pt41.x = pt42.x = pt4.x;
                pt41.y = pt4.y + ptPos;
                pt42.y = pt4.y - ptPos;                
                break;
            }
            }
            
            //Caculate label position
            var dis12:Number = (pt2.x-pt1.x)*(pt2.x-pt1.x) + (pt2.y-pt1.y)*(pt2.y-pt1.y);
            var dis23:Number = (pt3.x-pt2.x)*(pt3.x-pt2.x) + (pt3.y-pt2.y)*(pt3.y-pt2.y);
            var dis34:Number = (pt4.x-pt3.x)*(pt4.x-pt3.x) + (pt4.y-pt3.y)*(pt4.y-pt3.y);
            var maxDis:Number = Math.max(dis12, dis23, dis34);
            
            if (dis12 == maxDis)
            {
                midPt.x = (pt2.x + pt1.x)/2;
                midPt.y = (pt2.y + pt1.y)/2;
            }
            else if (dis23 == maxDis)
            {
                midPt.x = (pt3.x + pt2.x)/2;
                midPt.y = (pt3.y + pt2.y)/2;
            }
            else if (dis34 == maxDis)
            {
                midPt.x = (pt3.x + pt4.x)/2;
                midPt.y = (pt3.y + pt4.y)/2;
            }
            
            drawLine(pt1.x, pt1.y, pt2.x, pt2.y);
            drawLine(pt2.x, pt2.y, pt3.x, pt3.y);
            drawLine(pt3.x, pt3.y, pt4.x, pt4.y);
            if (toDistance != 0)
            {
                drawLine(pt4.x, pt4.y, finalPt.x, finalPt.y);
            }
            
            if(arrowPosition == "type1"){
                if ((pt3.x == pt4.x) && (pt3.y == pt4.y))
                {
                    if ((pt2.x == pt3.x) && (pt2.y == pt3.y))
                    {
                        if ((pt1.x == pt2.x) && (pt1.y == pt2.y))
                        {
                            
                        }
                        else
                        {
                            drawArrow(pt1.x, pt1.y, pt2.x, pt2.y);
                        }
                    }
                    else
                    {
                        drawArrow(pt2.x, pt2.y, pt4.x, pt4.y);
                    }
                }
                else
                {
                    drawArrow(pt3.x, pt3.y, pt4.x, pt4.y);
                }                
            }
            if (arrowPosition == "type2")
            {
                tmpPt = pt4;
                pt4 = pt1;
                pt1 = tmpPt;
                
                tmpPt = pt3;
                pt3 = pt2;
                pt2 = tmpPt;
                if ((pt3.x == pt4.x) && (pt3.y == pt4.y))
                {
                    if ((pt2.x == pt3.x) && (pt2.y == pt3.y))
                    {
                        if ((pt1.x == pt2.x) && (pt1.y == pt2.y))
                        {
                            
                        }
                        else
                        {
                            drawArrow(pt1.x, pt1.y, pt2.x, pt2.y);
                        }
                    }
                    else
                        drawArrow(pt2.x, pt2.y, pt4.x, pt4.y);
                }
                else
                {
                    drawArrow(pt3.x, pt3.y, pt4.x, pt4.y);
                }                
            }
            
            
            
            if (arrowPosition == "type3")
            {
                tmpPt = pt4;
                pt4 = pt1;
                pt1 = tmpPt;
                
                tmpPt = pt3;
                pt3 = pt2;
                pt2 = tmpPt;
                if ((pt3.x == pt4.x) && (pt3.y == pt4.y))
                {
                    if ((pt2.x == pt3.x) && (pt2.y == pt3.y))
                    {
                        if ((pt1.x == pt2.x) && (pt1.y == pt2.y))
                        {
                            
                        }
                        else
                        {
                            drawArrow(pt1.x, pt1.y, pt2.x, pt2.y);
                        }
                    }
                    else
                        drawArrow(pt2.x, pt2.y, pt4.x, pt4.y);
                }
                else
                {
                    drawArrow(pt3.x, pt3.y, pt4.x, pt4.y);
                }
                
            }
            
            if(arrowPosition == "type4"){
                if ((pt3.x == pt4.x) && (pt3.y == pt4.y))
                {
                    if ((pt2.x == pt3.x) && (pt2.y == pt3.y))
                    {
                        if ((pt1.x == pt2.x) && (pt1.y == pt2.y))
                        {
                            
                        }
                        else
                        {
                            //drawArrow(pt1.x, pt1.y, pt2.x, pt2.y);
                            moveTo(pt5.x ,pt5.y);
                            lineTo(pt4.x, pt4.y);
                            moveTo(pt5.x ,pt5.y);
                            lineTo(pt41.x, pt41.y);
                            moveTo(pt5.x ,pt5.y);
                            lineTo(pt42.x, pt42.y);
                        }
                    }
                    else
                        //drawArrow(pt2.x, pt2.y, pt4.x, pt4.y);
                    {
                        moveTo(pt5.x ,pt5.y);
                        lineTo(pt4.x, pt4.y);
                        moveTo(pt5.x ,pt5.y);
                        lineTo(pt41.x, pt41.y);
                        moveTo(pt5.x ,pt5.y);
                        lineTo(pt42.x, pt42.y);                            
                    }
                }
                else
                {
                    //drawArrow(pt3.x, pt3.y, pt4.x, pt4.y);
                    moveTo(pt5.x ,pt5.y);
                    lineTo(pt4.x, pt4.y);
                    moveTo(pt5.x ,pt5.y);
                    lineTo(pt41.x, pt41.y);
                    moveTo(pt5.x ,pt5.y);
                    lineTo(pt42.x, pt42.y);            
                }                
            }
            
            var midPtFrom:Point = new Point((pt2.x + pt3.x)/2, (pt2.y + pt3.y)/2);
            var midPtTo:Point = new Point((pt3.x + pt4.x)/2, (pt3.y + pt4.y)/2);
            
            if (castedComp && castedComp.label)
                positionComponent(castedComp.label , midPt.x - (castedComp.label.width/2), midPt.y - (castedComp.label.height/2));
            if (castedComp && castedComp.fromControl && (castedComp.fromControl['isDragging'] == false))
                positionComponent(castedComp.fromControl , midPtFrom.x - (castedComp.fromControl.width/2), midPtFrom.y - (castedComp.fromControl.height/2));
            if (castedComp && castedComp.toControl && (castedComp.toControl['isDragging'] == false))
                positionComponent(castedComp.toControl , midPtTo.x - (castedComp.toControl.width/2), midPtTo.y - (castedComp.toControl.height/2));
        }
        protected function calculatePoint(fromX:Number, fromY:Number, distance:Number, angle:Number):Object{
            angle = angle * 1.745329E-002;
            var _loc3:Number = fromX + distance * Math.cos(angle);
            var _loc2:Number = fromY - distance * Math.sin(angle);
            return ({x: _loc3, y: _loc2});
        }
        
        protected function drawArrow(fromX:Number, fromY:Number, toX:Number, toY:Number):void{
            
            if (enableArrow == false)
                return;
            
            var eps:Number = 0.0000000000001;
            if (fromY == toY)
                fromY += eps;
            
            if (fromX == toX)
                fromX += eps;
            
            var dXY:Number = (fromY - toY) / (fromX - toX);
            
            var arrowOS:Number;
            if (fromX >= toX)
            {
                arrowOS = 155;
            }
            else
            {
                arrowOS = 25;
            }    
            
            var arrowLine1:Object = this.calculatePoint(toX, toY, arrowLength, 180 - Math.atan(dXY) * 5.729578E+001 - arrowOS);
            var arrowLine2:Object = this.calculatePoint(toX, toY, arrowLength, 180 - Math.atan(dXY) * 5.729578E+001 + arrowOS);           
            
            moveTo(toX, toY);
            g.beginFill(color,1);
            lineTo(arrowLine1.x, arrowLine1.y);            
            lineTo(arrowLine2.x, arrowLine2.y);
            lineTo(toX, toY);
            g.endFill(); 
            
        }
        
        //checks if obj1 is fully above obj2 (this includes the space for the arrow)
        protected function isFullyAbove(obj1:IVisualNode, obj2:IVisualNode):Boolean {
            return (obj1.view.y + obj1.view.height + arrowLength) < obj2.view.y;
        }
        
        protected function isFullyAbovePt(pt:Point, pt1:Point):Boolean {
            return (pt.y) < pt1.y;
        }
        
        //checks if obj1 is fully below obj2 (this includes the space for the arrow)
        protected function isFullyBelow(obj1:IVisualNode, obj2:IVisualNode):Boolean {
            return obj1.view.y > (obj2.view.y + obj2.view.height + arrowLength);
        }
        
        protected function isFullyBelowPt(pt:Point, pt1:Point):Boolean {
            return pt.y > (pt1.y);
        } 
        
        //checks if obj1 is fully to the right of obj2 (this includes the space for the arrow)
        protected function isFullyRightOf(obj1:IVisualNode, obj2:IVisualNode):Boolean {
            return obj1.view.x > (obj2.view.x + obj2.view.width + arrowLength);
        }
        protected function isFullyRightOfPt(pt:Point, pt1:Point):Boolean {
            return pt.x > (pt1.x);
        }    
        
        //checks if obj1 is fully to the left of obj2 (this includes the space for the arrow)
        private function isFullyLeftOf(obj1:IVisualNode, obj2:IVisualNode):Boolean {
            return (obj1.view.x + obj1.view.width + arrowLength) < obj2.view.x;
        }
        private function isFullyLeftOfPt(pt:Point, pt1:Point):Boolean {
            return (pt.x) < pt1.x;
        }  
        
        //from the right side of obj1 to the left side of obj2
        private function rightToLeft(obj1:IVisualNode, obj2:IVisualNode):void {
            moveTo(obj1.view.x + obj1.view.width, obj1.view.y + (obj1.view.height/2));
            if(edgeClass == 'type1') {
                if (baseEdgePosition == BASE_EDGE_LEFT)
                {
                    lineTo((obj1.view.x + obj1.view.width) + 20 - arrowLength , obj1.view.y + (obj1.view.height/2));
                    lineTo((obj1.view.x + obj1.view.width) + 20 - arrowLength , obj2.view.y + (obj2.view.height/2));
                    lineTo(obj2.view.x - arrowLength+1, obj2.view.y + (obj2.view.height/2));
                }
                else
                {
                    
                }
                drawArrow((obj1.view.x + obj1.view.width) + .5*(obj2.view.x - (obj1.view.x + obj1.view.width)) - arrowLength, obj2.view.y + (obj2.view.height/2), obj2.view.x, obj2.view.y + (obj2.view.height/2));
            }else if(edgeClass == 'type2'){
                lineTo((obj1.view.x + obj1.view.width) + .5*(obj2.view.x - (obj1.view.x + obj1.view.width)) - arrowLength, obj2.view.y + (obj2.view.height/2));
                lineTo(obj2.view.x - arrowLength+1, obj2.view.y + (obj2.view.height/2));
                drawArrow((obj1.view.x + obj1.view.width) + .5*(obj2.view.x - (obj1.view.x + obj1.view.width)) - arrowLength, obj2.view.y + (obj2.view.height/2), obj2.view.x, obj2.view.y + (obj2.view.height/2));
                
            }
            else {
                lineTo(obj2.view.x - arrowLength+1, obj2.view.y + (obj2.view.height/2));    
                drawArrow(obj1.view.x + obj1.view.width, obj1.view.y + (obj1.view.height/2), obj2.view.x, obj2.view.y + (obj2.view.height/2));
            }
        }
        
        //from the left side of obj1 to the right side of obj2
        private function leftToRight(obj1:IVisualNode, obj2:IVisualNode):void {
            moveTo(obj1.view.x , obj1.view.y + (obj1.view.height/2));
            if(edgeClass == 'type1'){
                if (baseEdgePosition == BASE_EDGE_RIGHT)
                {
                    lineTo((obj2.view.x + obj2.view.width) , obj1.view.y + (obj1.view.height/2));
                    lineTo((obj2.view.x + obj2.view.width) , obj2.view.y + (obj2.view.height/2));
                    lineTo((obj2.view.x + obj2.view.width) + arrowLength-1, obj2.view.y + obj2.view.height/2);
                }
                else
                {
                    
                }
                
                drawArrow((obj2.view.x + obj2.view.width) + .5*(obj1.view.x - (obj2.view.x + obj2.view.width)) + arrowLength, obj2.view.y + (obj2.view.height/2), (obj2.view.x + obj2.view.width), obj2.view.y + obj2.view.height/2);        
            }else if(edgeClass == 'type2'){
                lineTo((obj2.view.x + obj2.view.width) + .5*(obj1.view.x - (obj2.view.x + obj2.view.width)) + arrowLength, obj2.view.y + (obj2.view.height/2));
                lineTo((obj2.view.x + obj2.view.width) + arrowLength-1, obj2.view.y + obj2.view.height/2);
                
                drawArrow((obj2.view.x + obj2.view.width) + .5*(obj1.view.x - (obj2.view.x + obj2.view.width)) + arrowLength, obj2.view.y + (obj2.view.height/2), (obj2.view.x + obj2.view.width), obj2.view.y + obj2.view.height/2);        
            }
            else{
                lineTo((obj2.view.x + obj2.view.width) + arrowLength-1, obj2.view.y + obj2.view.height/2);
                drawArrow(obj1.view.x, obj1.view.y + (obj1.view.height/2), (obj2.view.x + obj2.view.width), obj2.view.y + obj2.view.height/2);
            }
            
        }
        
        //from the top of obj1 to the bottom of obj2
        private function topToBottom(obj1:IVisualNode, obj2:IVisualNode):void {
            moveTo(obj1.view.x + (obj1.view.width/2), obj1.view.y);
            if(edgeClass == 'type1'){
                if (baseEdgePosition == BASE_EDGE_BELOW)
                {
                    lineTo(obj1.view.x + (obj1.view.width/2), obj1.view.y - 20);
                    lineTo(obj2.view.x+(obj2.view.width/2), obj1.view.y - 20);
                    lineTo(obj2.view.x+(obj2.view.width/2), (obj2.view.y + obj2.view.height)+ arrowLength-1); 
                }
                else
                {
                    lineTo(obj2.view.x+(obj2.view.width/2), (obj2.view.y + obj2.view.height)+ arrowLength-1); 
                }
                drawArrow(obj2.view.x+(obj2.view.width/2), obj1.view.y + .5*((obj2.view.y + obj2.view.height) - obj1.view.y), obj2.view.x+(obj2.view.width/2), (obj2.view.y + obj2.view.height));            
            }else if(edgeClass == 'type2'){
                lineTo(obj2.view.x+(obj2.view.width/2), obj1.view.y + .5*((obj2.view.y + obj2.view.height) - obj1.view.y));
                lineTo(obj2.view.x+(obj2.view.width/2), (obj2.view.y + obj2.view.height)+ arrowLength-1);
                drawArrow(obj2.view.x+(obj2.view.width/2), obj1.view.y + .5*((obj2.view.y + obj2.view.height) - obj1.view.y), obj2.view.x+(obj2.view.width/2), (obj2.view.y + obj2.view.height));            
            }
            else{
                lineTo(obj2.view.x+(obj2.view.width/2), (obj2.view.y + obj2.view.height)+ arrowLength-1);
                drawArrow(obj1.view.x + (obj1.view.width/2), obj1.view.y, obj2.view.x+(obj2.view.width/2), (obj2.view.y + obj2.view.height));
            }
            
        }
        
        //from the bottom of obj1 to the top of obj2
        private function bottomToTop(obj1:IVisualNode, obj2:IVisualNode):void {
            moveTo(obj1.view.x + (obj1.view.width/2), obj1.view.y + obj1.view.height);
            if(edgeClass == 'type1') {
                if (baseEdgePosition == BASE_EDGE_ABOVE)
                {
                    lineTo(obj1.view.x + (obj1.view.width/2), (obj1.view.y + obj1.view.height) + 20);
                    lineTo(obj2.view.x + (obj2.view.width/2), (obj1.view.y + obj1.view.height) + 20);
                    lineTo(obj2.view.x + (obj2.view.width/2), obj2.view.y - arrowLength+1);
                }
                else
                {
                    lineTo(obj2.view.x + (obj2.view.width/2), obj2.view.y - arrowLength+1);
                }
                drawArrow(obj2.view.x + (obj2.view.width/2), (obj1.view.y + obj1.view.height) + .5*(obj2.view.y - (obj1.view.y + obj1.view.height)), obj2.view.x + (obj2.view.width/2), obj2.view.y);
            }
            else if(edgeClass == 'type2'){
                lineTo(obj1.view.x + (obj1.view.width/2), (obj1.view.y + obj1.view.height));
                lineTo(obj2.view.x + (obj2.view.width/2), (obj1.view.y + obj1.view.height) + .5*(obj2.view.y - (obj1.view.y + obj1.view.height)));
                lineTo(obj2.view.x + (obj2.view.width/2), obj2.view.y - arrowLength+1);
                
                drawArrow(obj2.view.x + (obj2.view.width/2), (obj1.view.y + obj1.view.height) + .5*(obj2.view.y - (obj1.view.y + obj1.view.height)), obj2.view.x + (obj2.view.width/2), obj2.view.y);
            }
            else {
                lineTo(obj2.view.x + (obj2.view.width/2), obj2.view.y - arrowLength+1);
                drawArrow(obj1.view.x + (obj1.view.width/2), obj1.view.y + obj1.view.height, obj2.view.x + (obj2.view.width/2), obj2.view.y);
            }
        }
        
        //from the center of _obj1 to the center of _obj2
        private function centerToCenter(obj1:IVisualNode, obj2:IVisualNode):void {
            moveTo(obj1.view.x + (obj1.view.width/2), obj1.view.y + (obj1.view.height/2));
            lineTo(obj2.view.x + (obj2.view.width/2), obj2.view.y + (obj2.view.height/2));
            drawArrow(obj1.view.x + (obj1.view.width/2), obj1.view.y + obj1.view.height, obj2.view.x + (obj2.view.width/2), obj2.view.y);
        }              
        
        public function fromControlCoordinates():Point {
            return Geometry.midPointOfLine(
                vedge.edge.node1.vnode.viewCenter,
                vedge.edge.node2.vnode.viewCenter
            );
        }
        
        public function toControlCoordinates():Point {
            return Geometry.midPointOfLine(
                vedge.edge.node1.vnode.viewCenter,
                vedge.edge.node2.vnode.viewCenter
            );
        }
    }
}