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.layout.router.EdgeGroupRouterStage;
34  import y.layout.router.GroupNodeRouterStage;
35  import y.layout.router.OrthogonalEdgeRouter;
36  import y.layout.router.PatchRouterStage;
37  import y.layout.router.ReducedSphereOfActionStage;
38  import y.option.ConstraintManager;
39  import y.option.IntOptionItem;
40  import y.option.OptionItem;
41  import y.option.OptionGroup;
42  import y.option.OptionHandler;
43  
44  
45  /**
46   * This module represents an interactive configurator and launcher for
47   * {@link y.layout.router.OrthogonalEdgeRouter}.
48   *
49   *
50   * @see <a href="http://docs.yworks.com/yfiles/doc/api/index.html#/dguide/orthogonal_edge_router#orthogonal_edge_router" target="_blank">Section Orthogonal Edge Routing</a> in the yFiles for Java Developer's Guide
51   */
52  public class OrthogonalEdgeRouterModule extends LayoutModule {
53    //// Module 'Orthogonal Edge Router'
54    private static final String ORTHOGONAL_EDGE_ROUTER = "ORTHOGONAL_EDGE_ROUTER";
55    
56    //// Section 'Layout'
57    protected static final String SECTION_LAYOUT_OPTIONS = "LAYOUT_OPTIONS";
58    // Section 'Layout' items
59    protected static final String ITEM_SCOPE = "SCOPE";
60    protected static final String VALUE_SCOPE_ALL_EDGES = "ALL_EDGES";
61    protected static final String VALUE_SCOPE_SELECTED_EDGES = "SELECTED_EDGES";
62    protected static final String VALUE_SCOPE_AT_SELECTED_NODES = "AT_SELECTED_NODES";
63    protected static final String ITEM_MONOTONIC_RESTRICTION = "MONOTONIC_RESTRICTION";
64    protected static final String VALUE_MONOTONIC_NONE = "MONOTONIC_NONE";
65    protected static final String VALUE_MONOTONIC_HORIZONTAL = "MONOTONIC_HORIZONTAL";
66    protected static final String VALUE_MONOTONIC_VERTICAL = "MONOTONIC_VERTICAL";
67    protected static final String VALUE_MONOTONIC_BOTH = "MONOTONIC_BOTH";
68    protected static final String ITEM_ENFORCE_MONOTONIC_RESTRICTIONS = "ENFORCE_MONOTONIC_RESTRICTIONS";
69    protected static final String ITEM_MINIMUM_DISTANCE_TO_EDGE = "MINIMUM_DISTANCE_TO_EDGE";
70    protected static final String ITEM_USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE = "USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE";
71    protected static final String ITEM_CUSTOM_MINIMUM_DISTANCE_TO_NODE = "CUSTOM_MINIMUM_DISTANCE_TO_NODE";
72    protected static final String ITEM_ROUTE_ON_GRID = "ROUTE_ON_GRID";
73    protected static final String ITEM_GRID_SPACING = "GRID_SPACING";
74    protected static final String ITEM_SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH = "SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH";
75    protected static final String ITEM_CONSIDER_NODE_LABELS = "CONSIDER_NODE_LABELS";
76    
77    //// Section 'Crossing Minimization'
78    protected static final String SECTION_SECTION_CROSSING_MINIMIZATION = "CROSSING_MINIMIZATION";
79    // Section 'Crossing Minimization' items
80    protected static final String ITEM_LOCAL_CROSSING_MINIMIZATION = "LOCAL_CROSSING_MINIMIZATION";
81    protected static final String ITEM_CROSSING_COST = "CROSSING_COST";
82    protected static final String ITEM_REROUTING_ENABLED = "REROUTING_ENABLED";
83  
84    /**
85     * Creates an instance of this module.
86     */
87    public OrthogonalEdgeRouterModule() {
88      super(ORTHOGONAL_EDGE_ROUTER);
89      setPortIntersectionCalculatorEnabled(true);
90    }
91  
92    /**
93     * Creates an OptionHandler and adds the option items used by this module.
94     * @return the created <code>OptionHandler</code> providing module related options
95     */
96    protected OptionHandler createOptionHandler() {
97      final OptionHandler options = new OptionHandler(getModuleName());
98      options.clear();
99      final ConstraintManager optionConstraints = new ConstraintManager(options);
100     // Default provider
101     final OrthogonalEdgeRouter orthogonal = new OrthogonalEdgeRouter();
102 
103     // Group 'Layout'
104     final OptionGroup layoutGroup = new OptionGroup();
105     layoutGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, SECTION_LAYOUT_OPTIONS);
106     // Populate group
107     final byte sphereOfAction;
108     switch (orthogonal.getSphereOfAction()) {
109       case OrthogonalEdgeRouter.ROUTE_ALL_EDGES:
110         sphereOfAction = 0;
111         break;
112       case OrthogonalEdgeRouter.ROUTE_EDGES_AT_SELECTED_NODES:
113         sphereOfAction = 1;
114         break;
115       default:
116         sphereOfAction = 2;
117         break;
118     }
119     layoutGroup.addItem(
120         options.addEnum(ITEM_SCOPE, new String[]{
121             VALUE_SCOPE_ALL_EDGES,
122             VALUE_SCOPE_SELECTED_EDGES,
123             VALUE_SCOPE_AT_SELECTED_NODES
124         }, sphereOfAction));
125     layoutGroup.addItem(
126         options.addEnum(ITEM_MONOTONIC_RESTRICTION, new String[]{
127             VALUE_MONOTONIC_NONE,
128             VALUE_MONOTONIC_HORIZONTAL,
129             VALUE_MONOTONIC_VERTICAL,
130             VALUE_MONOTONIC_BOTH
131         }, 0));
132     layoutGroup.addItem(
133         options.addBool(ITEM_ENFORCE_MONOTONIC_RESTRICTIONS, orthogonal.isEnforceMonotonicPathRestrictions()));
134     // The value given for 'minimum distance' denotes a halo to the left and
135     // right of an edge segment.
136     final OptionItem itemMinimumDistanceEdge = layoutGroup.addItem(
137             options.addInt(ITEM_MINIMUM_DISTANCE_TO_EDGE, orthogonal.getMinimumDistance()));
138     itemMinimumDistanceEdge.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(4));
139     final OptionItem itemUseCustomMinimumDistanceNode = layoutGroup.addItem(
140         options.addBool(ITEM_USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE, !orthogonal.getCoupledDistances()));
141     final OptionItem itemCustomMinimumDistanceNode = layoutGroup.addItem(
142         options.addInt(ITEM_CUSTOM_MINIMUM_DISTANCE_TO_NODE, orthogonal.getMinimumDistanceToNode()));
143     itemCustomMinimumDistanceNode.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(2));
144     final OptionItem itemRouteOnGrid = layoutGroup.addItem(
145         options.addBool(ITEM_ROUTE_ON_GRID, orthogonal.isGridRoutingEnabled()));
146     final OptionItem itemGridSpacing = layoutGroup.addItem(
147         options.addInt(ITEM_GRID_SPACING, orthogonal.getGridSpacing()));
148     itemGridSpacing.setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(2));
149     layoutGroup.addItem(
150         options.addDouble(ITEM_SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH, orthogonal.getCenterToSpaceRatio(), 0.0, 1.0));
151     layoutGroup.addItem(
152         options.addBool(ITEM_CONSIDER_NODE_LABELS, orthogonal.isConsiderNodeLabelsEnabled()));
153 
154     // Group 'Crossing Minimization'
155     final OptionGroup sectionCrossingGroup = new OptionGroup();
156     sectionCrossingGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, SECTION_SECTION_CROSSING_MINIMIZATION);
157     // Populate group
158     sectionCrossingGroup.addItem(options.addBool(ITEM_LOCAL_CROSSING_MINIMIZATION,
159         orthogonal.isLocalCrossingMinimizationEnabled()));
160     sectionCrossingGroup.addItem(options.addDouble(ITEM_CROSSING_COST, orthogonal.getCrossingCost()));
161     sectionCrossingGroup.addItem(options.addBool(ITEM_REROUTING_ENABLED, orthogonal.isReroutingEnabled()));
162     // Enable/disable items depending on specific values
163     optionConstraints.setEnabledOnValueEquals(itemRouteOnGrid, Boolean.TRUE, itemGridSpacing);
164     optionConstraints.setEnabledOnValueEquals(itemUseCustomMinimumDistanceNode,
165         Boolean.TRUE,
166         itemCustomMinimumDistanceNode);
167     
168     return options;
169   }
170 
171   /**
172    * Main module execution routine.
173    * Launches the module's underlying algorithm on the module's graph based on user options.
174    */
175   protected void mainrun() {
176     final OrthogonalEdgeRouter orthogonal = new OrthogonalEdgeRouter();
177 
178     final OptionHandler options = getOptionHandler();
179     configure(orthogonal, options);
180 
181     launchLayouter(
182         new EdgeGroupRouterStage(
183             new GroupNodeRouterStage(
184                 new ReducedSphereOfActionStage(
185                     new PatchRouterStage(orthogonal)))));
186   }
187 
188   /**
189    * Configures the module's layout algorithm according to the given options.
190    * @param orthogonal the <code>OrthogonalEdgeRouter</code> to be configured
191    * @param options the layout options to set
192    */
193   protected void configure(final OrthogonalEdgeRouter orthogonal, final OptionHandler options) {    
194     String choice = options.getString(ITEM_SCOPE);
195     if (choice.equals(VALUE_SCOPE_AT_SELECTED_NODES)) {
196       orthogonal.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_EDGES_AT_SELECTED_NODES);
197     } else if (choice.equals(VALUE_SCOPE_SELECTED_EDGES)) {
198       orthogonal.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_SELECTED_EDGES);
199     } else {
200       orthogonal.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_ALL_EDGES);
201     }
202     
203     orthogonal.setMinimumDistance(options.getInt(ITEM_MINIMUM_DISTANCE_TO_EDGE));
204     orthogonal.setCoupledDistances(!options.getBool(ITEM_USE_CUSTOM_MINIMUM_DISTANCE_TO_NODE));
205     orthogonal.setMinimumDistanceToNode(options.getInt(ITEM_CUSTOM_MINIMUM_DISTANCE_TO_NODE));
206     orthogonal.setGridRoutingEnabled(options.getBool(ITEM_ROUTE_ON_GRID));
207     orthogonal.setGridSpacing(options.getInt(ITEM_GRID_SPACING));
208     orthogonal.setCenterToSpaceRatio(options.getDouble(ITEM_SPACE_DRIVEN_VS_CENTER_DRIVEN_SEARCH));
209     orthogonal.setLocalCrossingMinimizationEnabled(options.getBool(ITEM_LOCAL_CROSSING_MINIMIZATION));
210     
211     if (VALUE_MONOTONIC_BOTH.equals(options.getString(ITEM_MONOTONIC_RESTRICTION))) {
212       orthogonal.setMonotonicPathRestriction(OrthogonalEdgeRouter.MONOTONIC_BOTH);
213     } else if (VALUE_MONOTONIC_HORIZONTAL.equals(options.getString(ITEM_MONOTONIC_RESTRICTION))) {
214       orthogonal.setMonotonicPathRestriction(OrthogonalEdgeRouter.MONOTONIC_HORIZONTAL);
215     } else if (VALUE_MONOTONIC_VERTICAL.equals(options.getString(ITEM_MONOTONIC_RESTRICTION))) {
216       orthogonal.setMonotonicPathRestriction(OrthogonalEdgeRouter.MONOTONIC_VERTICAL);
217     } else {
218       orthogonal.setMonotonicPathRestriction(OrthogonalEdgeRouter.MONOTONIC_NONE);
219     }
220     
221     orthogonal.setEnforceMonotonicPathRestrictions(options.getBool(ITEM_ENFORCE_MONOTONIC_RESTRICTIONS));
222     orthogonal.setConsiderNodeLabelsEnabled(options.getBool(ITEM_CONSIDER_NODE_LABELS));
223     orthogonal.setCrossingCost(options.getDouble(ITEM_CROSSING_COST));
224     orthogonal.setReroutingEnabled(options.getBool(ITEM_REROUTING_ENABLED));
225   }
226 }
227