| OrganicEdgeRouterModule.java |
1 /****************************************************************************
2 * This demo file is part of yFiles for Java 2.14.
3 * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4 * 72070 Tuebingen, Germany. All rights reserved.
5 *
6 * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7 * of demo files in source code or binary form, with or without
8 * modification, is not permitted.
9 *
10 * Owners of a valid software license for a yFiles for Java version that this
11 * demo is shipped with are allowed to use the demo source code as basis
12 * for their own yFiles for Java powered applications. Use of such programs is
13 * governed by the rights and conditions as set out in the yFiles for Java
14 * license agreement.
15 *
16 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19 * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 ***************************************************************************/
28 package demo.layout.module;
29
30 import y.module.LayoutModule;
31 import y.module.YModule;
32
33 import y.base.DataProvider;
34 import y.layout.BendConverter;
35 import y.layout.CompositeLayoutStage;
36 import y.layout.LayoutStage;
37 import y.layout.SequentialLayouter;
38 import y.layout.grouping.GroupNodeHider;
39 import y.layout.organic.RemoveOverlapsLayoutStage;
40 import y.layout.router.OrganicEdgeRouter;
41 import y.option.OptionGroup;
42 import y.option.OptionHandler;
43 import y.view.Graph2D;
44 import y.view.Selections;
45
46 /**
47 * This module represents an interactive configurator and launcher for
48 * {@link y.layout.router.OrganicEdgeRouter}.
49 */
50 public class OrganicEdgeRouterModule extends LayoutModule {
51 //// Module 'Organic Edge Router'
52 protected static final String MODULE_ORGANIC_EDGE_ROUTER = "ORGANIC_EDGE_ROUTER";
53
54 //// Section 'default' items
55 protected static final String TITLE_LAYOUT_OPTIONS = "LAYOUT_OPTIONS";
56 protected static final String ITEM_SELECTION_ONLY = "SELECTION_ONLY";
57 protected static final String ITEM_MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
58 protected static final String ITEM_USE_BENDS = "USE_BENDS";
59 protected static final String ITEM_ROUTE_ONLY_NECESSARY = "ROUTE_ONLY_NECESSARY";
60 protected static final String ITEM_ALLOW_MOVING_NODES = "ALLOW_MOVING_NODES";
61
62 /**
63 * Creates an instance of this module.
64 */
65 public OrganicEdgeRouterModule() {
66 super(MODULE_ORGANIC_EDGE_ROUTER);
67 }
68
69 /**
70 * Creates an OptionHandler and adds the option items used by this module.
71 * @return the created <code>OptionHandler</code> providing module related options
72 */
73 protected OptionHandler createOptionHandler() {
74 final OptionHandler options = new OptionHandler(getModuleName());
75 // Defaults provider
76 final OrganicEdgeRouter defaults = new OrganicEdgeRouter();
77
78 // Group 'Layout'
79 final OptionGroup layoutGroup = new OptionGroup();
80 layoutGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, TITLE_LAYOUT_OPTIONS);
81 // Populate group
82 layoutGroup.addItem(options.addBool(ITEM_SELECTION_ONLY, false));
83 layoutGroup.addItem(options.addInt(ITEM_MINIMAL_NODE_DISTANCE, (int) defaults.getMinimalDistance(), 10, 300));
84 layoutGroup.addItem(options.addBool(ITEM_USE_BENDS, defaults.isUsingBends()));
85 layoutGroup.addItem(options.addBool(ITEM_ROUTE_ONLY_NECESSARY, !defaults.isRoutingAll()));
86 layoutGroup.addItem(options.addBool(ITEM_ALLOW_MOVING_NODES, false));
87
88 return options;
89 }
90
91 /**
92 * Main module execution routine.
93 * Launches the module's underlying algorithm on the module's graph based on user options.
94 */
95 protected void mainrun() {
96 final OrganicEdgeRouter organic = new OrganicEdgeRouter();
97
98 final OptionHandler options = getOptionHandler();
99 configure(organic, options);
100
101 final SequentialLayouter sequential = new SequentialLayouter();
102 if (options.getBool(ITEM_ALLOW_MOVING_NODES)) {
103 //if we are allowed to move nodes, we can improve the routing results by temporarily enlarging nodes and removing overlaps
104 //(this strategy ensures that there is enough space for the edges)
105 final CompositeLayoutStage cls = new CompositeLayoutStage();
106 cls.appendStage(organic.createNodeEnlargementStage());
107 cls.appendStage(new RemoveOverlapsLayoutStage(0));
108 sequential.appendLayouter(cls);
109
110 }
111 if (organic.isUsingBends()) {
112 //we want to keep the original bends
113 final BendConverter bendConverter = new BendConverter();
114 bendConverter.setSelectedEdgesDpKey(OrganicEdgeRouter.ROUTE_EDGE_DPKEY);
115 bendConverter.setAdoptSelectionEnabled(options.getBool(ITEM_SELECTION_ONLY));
116 bendConverter.setCoreLayouter(organic);
117 sequential.appendLayouter(bendConverter);
118 } else {
119 sequential.appendLayouter(organic);
120 }
121
122 final Graph2D graph = getGraph2D();
123 prepareGraph(graph, options);
124 try {
125 launchLayouter(new GroupNodeHider(sequential));
126 } finally {
127 restoreGraph(graph, options);
128 }
129 }
130
131 /**
132 * Prepares a <code>graph</code> depending on the given options for the
133 * module's layout algorithm.
134 * <br>
135 * Additional resources created by this method have to be freed up by calling
136 * {@link #restoreGraph(y.view.Graph2D, y.option.OptionHandler)} after
137 * layout calculation.
138 * @param graph the graph to be prepared
139 * @param options the options for the module's layout algorithm
140 */
141 protected void prepareGraph(final Graph2D graph, final OptionHandler options) {
142 // register grouping relevant DataProviders
143 if (options.getBool(ITEM_SELECTION_ONLY)) {
144 // backup existing data providers to prevent loss of user settings
145 final DataProvider selectedEdgesDP = Selections.createSelectionEdgeMap(graph);
146 backupDataProvider(graph, BendConverter.SCOPE_DPKEY);
147 graph.addDataProvider(BendConverter.SCOPE_DPKEY, selectedEdgesDP);
148 backupDataProvider(graph, OrganicEdgeRouter.ROUTE_EDGE_DPKEY);
149 graph.addDataProvider(OrganicEdgeRouter.ROUTE_EDGE_DPKEY, selectedEdgesDP);
150 }
151 }
152
153 /**
154 * Restores the given <code>graph</code> by freeing up resources created by
155 * {@link #prepareGraph(y.view.Graph2D, y.option.OptionHandler)}.
156 * @param graph the graph for which <code>prepareGraph</code> has been called
157 * @param options the options for the module's layout algorithm
158 */
159 protected void restoreGraph(final Graph2D graph, final OptionHandler options) {
160 // unregister grouping relevant DataProviders
161 if (options.getBool(ITEM_SELECTION_ONLY)) {
162 // remove the data providers set by this module by restoring the initial state
163 restoreDataProvider(graph, OrganicEdgeRouter.ROUTE_EDGE_DPKEY);
164 restoreDataProvider(graph, BendConverter.SCOPE_DPKEY);
165 }
166 }
167
168 /**
169 * Configures the module's layout algorithm according to the given options.
170 * @param organic the <code>OrganicEdgeRouter</code> to be configured
171 * @param options the layout options to set
172 */
173 protected void configure(final OrganicEdgeRouter organic, final OptionHandler options) {
174 organic.setMinimalDistance(options.getInt(ITEM_MINIMAL_NODE_DISTANCE));
175 organic.setUsingBends(options.getBool(ITEM_USE_BENDS));
176 organic.setRoutingAll(!options.getBool(ITEM_ROUTE_ONLY_NECESSARY));
177 }
178 }
179