com.synflow.cx.ui.internal.views.fsm.layout.EdgeLayout.java Source code

Java tutorial

Introduction

Here is the source code for com.synflow.cx.ui.internal.views.fsm.layout.EdgeLayout.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Synflow SAS.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Matthieu Wipliez - initial API and implementation and/or initial documentation
 *******************************************************************************/
package com.synflow.cx.ui.internal.views.fsm.layout;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.eclipse.draw2d.AbsoluteBendpoint;
import org.eclipse.draw2d.Bendpoint;
import org.eclipse.draw2d.geometry.Point;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.synflow.models.dpn.FSM;
import com.synflow.models.dpn.State;
import com.synflow.models.dpn.Transition;
import com.synflow.models.graph.Edge;

/**
 * This class implements a layout algorithm for the edges of an FSM.
 * 
 * @author Matthieu Wipliez
 * 
 */
public class EdgeLayout {

    private static final int BREADTH = 30;

    private void layoutDoubleEdges(List<State> states) {
        for (State state : states) {
            Multimap<State, Transition> map = HashMultimap.create();
            for (Edge edge : state.getOutgoing()) {
                map.put((State) edge.getTarget(), (Transition) edge);
            }

            for (State target : map.keySet()) {
                Collection<Transition> transitions = map.get(target);
                if (transitions.size() >= 2) {
                    Point l1 = state.get("location");
                    Point l2 = target.get("location");

                    int inc = BREADTH / (transitions.size() - 1);
                    int x = (l1.x + l2.x) / 2 - BREADTH / 2 + 15;
                    final int y = (l1.y + l2.y + 20) / 2;

                    for (Transition transition : transitions) {
                        List<Bendpoint> bendpoints = new ArrayList<>();
                        AbsoluteBendpoint bp;
                        bp = new AbsoluteBendpoint(x, y - 5);
                        bendpoints.add(bp);

                        bp = new AbsoluteBendpoint(x, y + 5);
                        bendpoints.add(bp);

                        setBendpoints(transition, bendpoints);
                        x += inc;
                    }
                }
            }
        }
    }

    /**
     * Lay out the edges of the given FSM based on the given box information.
     * 
     * @param fsm
     *            FSM
     * @param top
     *            top box
     */
    public void layoutEdges(FSM fsm, Box top) {
        layoutDoubleEdges(fsm.getStates());
        layoutFeedbackEdges(top, fsm.getTransitions());
    }

    private void layoutFeedbackEdges(Box top, List<Transition> transitions) {
        List<Transition> feedbackEdges = new ArrayList<>();

        // filter feedback edges
        for (Transition transition : transitions) {
            State source = transition.getSource();
            State target = transition.getTarget();

            int sourceN = source.getNumber();
            int targetN = target.getNumber();
            if (sourceN < targetN) {
                Point l1 = source.get("location");
                Point l2 = target.get("location");
                int height = Math.abs(l2.y - l1.y);
                transition.put("height", height);

                feedbackEdges.add(transition);
            }
        }

        // sort by ascending height
        Collections.sort(feedbackEdges, new Comparator<Transition>() {

            @Override
            public int compare(Transition o1, Transition o2) {
                Integer h1 = o1.get("height");
                Integer h2 = o2.get("height");
                return h1.compareTo(h2);
            }

        });

        int x = top.getStartX() - 20;
        for (Transition transition : feedbackEdges) {
            State source = transition.getSource();
            State target = transition.getTarget();

            List<Bendpoint> bendpoints = new ArrayList<>();
            Point l1 = source.get("location");
            Point l2 = target.get("location");

            int minX = Math.min(l1.x, l2.x) - 15;

            int height = transition.get("height");
            int edgeX;
            if (height > 100) {
                x -= 10;
                edgeX = x;
            } else {
                edgeX = minX;
            }

            AbsoluteBendpoint bp;
            bp = new AbsoluteBendpoint(l1.x + 15, l1.y + 60);
            bendpoints.add(bp);

            bp = new AbsoluteBendpoint(edgeX, l1.y + 60);
            bendpoints.add(bp);

            bp = new AbsoluteBendpoint(edgeX, l2.y + 15);
            bendpoints.add(bp);

            setBendpoints(transition, bendpoints);
        }
    }

    private void setBendpoints(Transition transition, List<Bendpoint> bendpoints) {
        transition.put("bendpoints", bendpoints);
    }

}