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.EdgeBundleDescriptor;
34  import y.layout.EdgeBundling;
35  import y.layout.radial.RadialLayouter;
36  import y.option.ConstraintManager;
37  import y.option.OptionHandler;
38  import y.option.OptionItem;
39  
40  /**
41   * This module represents an interactive configurator and launcher for
42   * {@link y.layout.radial.RadialLayouter}.
43   * 
44   */
45  public class RadialLayoutModule extends LayoutModule {
46    private static final int MAXIMUM_SMOOTHNESS = 10;
47    private static final int MINIMUM_SMOOTHNESS = 1;
48    private static final int SMOOTHNESS_ANGLE_FACTOR = 4;
49  
50    //// Module 'Radial Layout'
51    protected static final String MODULE_RADIAL = "RADIAL";
52    
53    //// Section 'General'
54    protected static final String SECTION_GENERAL = "GENERAL";
55    // Section 'General' items
56    protected static final String ITEM_CENTER_STRATEGY = "CENTER_STRATEGY";
57    protected static final String VALUE_CENTER_DIRECTED = "CENTER_DIRECTED";
58    protected static final String VALUE_CENTER_CENTRAL = "CENTER_CENTRAL";
59    protected static final String VALUE_CENTER_WEIGHTED_CENTRAL = "CENTER_WEIGHTED_CENTRAL";
60    protected static final String VALUE_CENTER_SELECTED = "CENTER_SELECTED";
61    protected static final String ITEM_LAYERING_STRATEGY = "LAYERING_STRATEGY";
62    protected static final String VALUE_LAYERING_BFS = "LAYERING_BFS";
63    protected static final String VALUE_LAYERING_HIERARCHICAL = "LAYERING_HIERARCHICAL";
64    protected static final String ITEM_MINIMAL_LAYER_DISTANCE = "MINIMAL_LAYER_DISTANCE";
65    protected static final String ITEM_MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
66    protected static final String ITEM_MAXIMAL_CHILD_SECTOR_SIZE = "MAXIMAL_CHILD_SECTOR_SIZE";
67    protected static final String ITEM_EDGE_ROUTING_STRATEGY = "EDGE_ROUTING_STRATEGY";
68    protected static final String VALUE_EDGE_POLYLINE = "EDGE_POLYLINE";
69    protected static final String VALUE_EDGE_ARC = "EDGE_ARC";
70    protected static final String VALUE_EDGE_BUNDLES = "EDGE_BUNDLES";
71    protected static final String ITEM_EDGE_SMOOTHNESS = "EDGE_SMOOTHNESS";
72    protected static final String ITEM_CONSIDER_NODE_LABELS = "CONSIDER_NODE_LABELS";
73    protected static final String ITEM_EDGE_BUNDLING_STRENGTH = "EDGE_BUNDLING_STRENGTH";
74  
75    /**
76     * Creates an instance of this module.
77     */
78    public RadialLayoutModule() {
79      super(MODULE_RADIAL);
80    }
81  
82    /**
83     * Creates an OptionHandler and adds the option items used by this module.
84     * @return the created <code>OptionHandler</code> providing module related options
85     */
86    protected OptionHandler createOptionHandler() {
87      final OptionHandler options = new OptionHandler(getModuleName());
88      final ConstraintManager optionConstraints = new ConstraintManager(options);
89      // Defaults provider
90      final RadialLayouter defaults = new RadialLayouter();
91  
92      //// Section 'General'
93      options.useSection(SECTION_GENERAL);
94      // Populate section
95      options.addEnum(ITEM_CENTER_STRATEGY, new String[]{
96          VALUE_CENTER_DIRECTED,
97          VALUE_CENTER_CENTRAL,
98          VALUE_CENTER_WEIGHTED_CENTRAL,
99          VALUE_CENTER_SELECTED
100     }, defaults.getCenterNodesPolicy());
101     options.addEnum(ITEM_LAYERING_STRATEGY, new String[]{
102         VALUE_LAYERING_BFS,
103         VALUE_LAYERING_HIERARCHICAL
104     }, defaults.getLayeringStrategy() == RadialLayouter.LAYERING_STRATEGY_BFS ? 0 : 1);
105     options.addInt(ITEM_MINIMAL_LAYER_DISTANCE, (int) defaults.getMinimalLayerDistance(), 1, 1000);
106     options.addInt(ITEM_MINIMAL_NODE_DISTANCE, (int) defaults.getMinimalNodeToNodeDistance(), 0, 300);
107     options.addInt(ITEM_MAXIMAL_CHILD_SECTOR_SIZE, (int) (defaults.getMaximalChildSectorAngle()), 15, 360);
108     final OptionItem itemEdgeRoutingStrategy = options.addEnum(ITEM_EDGE_ROUTING_STRATEGY, new String[]{
109         VALUE_EDGE_POLYLINE,
110         VALUE_EDGE_ARC,
111         VALUE_EDGE_BUNDLES
112     }, defaults.getEdgeRoutingStrategy() == RadialLayouter.EDGE_ROUTING_STRATEGY_POLYLINE ? 0 : 1);
113     final int smoothness = (int) Math.min(MAXIMUM_SMOOTHNESS,
114         (1 + MAXIMUM_SMOOTHNESS * SMOOTHNESS_ANGLE_FACTOR - defaults.getMinimalBendAngle()) / SMOOTHNESS_ANGLE_FACTOR);
115     final OptionItem smoothnessItem =
116         options.addInt(ITEM_EDGE_SMOOTHNESS, smoothness, MINIMUM_SMOOTHNESS, MAXIMUM_SMOOTHNESS);
117     // Enable/disable items depending on specific values
118     optionConstraints.setEnabledOnCondition(
119         optionConstraints.createConditionValueEquals(itemEdgeRoutingStrategy, VALUE_EDGE_ARC), smoothnessItem);
120 
121     //// Section Bundling
122     final OptionItem itemBundlingStrength = options.addDouble(ITEM_EDGE_BUNDLING_STRENGTH, 0.99, 0.0, 1.0);
123     
124     // Enable/disable items depending on specific values
125     final ConstraintManager.Condition bundlingCondition =
126             optionConstraints.createConditionValueEquals(itemEdgeRoutingStrategy, VALUE_EDGE_BUNDLES);
127     optionConstraints.setEnabledOnCondition(bundlingCondition, itemBundlingStrength);
128     options.addBool(ITEM_CONSIDER_NODE_LABELS, defaults.isConsiderNodeLabelsEnabled());
129 
130     return options;
131   }
132 
133 
134   /**
135    * Main module execution routine.
136    * Launches the module's underlying algorithm on the module's graph based on user options.
137    */
138   protected void mainrun() {
139     final RadialLayouter radial = new RadialLayouter();
140     
141     final OptionHandler options = getOptionHandler();
142     configure(radial, options);
143 
144     launchLayouter(radial);
145   }
146 
147   /**
148    * Configures the module's layout algorithm according to the given options.
149    * @param radial the <code>RadialLayouter</code> to be configured
150    * @param options the layout options to set
151    */
152   protected void configure(final RadialLayouter radial, final OptionHandler options) {
153     radial.setMinimalNodeToNodeDistance(options.getInt(ITEM_MINIMAL_NODE_DISTANCE));
154 
155     if (options.getString(ITEM_EDGE_ROUTING_STRATEGY).equals(VALUE_EDGE_POLYLINE)) {
156       radial.setEdgeRoutingStrategy(RadialLayouter.EDGE_ROUTING_STRATEGY_POLYLINE);
157     } else if (options.getString(ITEM_EDGE_ROUTING_STRATEGY).equals(VALUE_EDGE_ARC)) {
158       radial.setEdgeRoutingStrategy(RadialLayouter.EDGE_ROUTING_STRATEGY_ARC);
159     } else if (options.getString(ITEM_EDGE_ROUTING_STRATEGY).equals(VALUE_EDGE_BUNDLES)) {
160       // Edge Bundling
161       final EdgeBundling ebc = radial.getEdgeBundling();
162       final EdgeBundleDescriptor descriptor = new EdgeBundleDescriptor();
163       descriptor.setBundled(true);
164       ebc.setDefaultBundleDescriptor(descriptor);
165       ebc.setBundlingStrength(options.getDouble(ITEM_EDGE_BUNDLING_STRENGTH));
166     }
167 
168     final double minimalBendAngle = 1 + (MAXIMUM_SMOOTHNESS - options.getInt(ITEM_EDGE_SMOOTHNESS)) * SMOOTHNESS_ANGLE_FACTOR;
169     radial.setMinimalBendAngle(minimalBendAngle);
170     
171     radial.setMinimalLayerDistance(options.getInt(ITEM_MINIMAL_LAYER_DISTANCE));
172     radial.setMaximalChildSectorAngle(options.getInt(ITEM_MAXIMAL_CHILD_SECTOR_SIZE));
173 
174     if (options.getString(ITEM_CENTER_STRATEGY).equals(VALUE_CENTER_CENTRAL)) {
175       radial.setCenterNodesPolicy(RadialLayouter.CENTER_NODES_POLICY_CENTRALITY);
176     } else if (options.getString(ITEM_CENTER_STRATEGY).equals(VALUE_CENTER_WEIGHTED_CENTRAL)) {
177       radial.setCenterNodesPolicy(RadialLayouter.CENTER_NODES_POLICY_WEIGHTED_CENTRALITY);
178     } else if (options.getString(ITEM_CENTER_STRATEGY).equals(VALUE_CENTER_SELECTED)) {
179       radial.setCenterNodesPolicy(RadialLayouter.CENTER_NODES_POLICY_SELECTED_NODES);
180     } else {
181       radial.setCenterNodesPolicy(RadialLayouter.CENTER_NODES_POLICY_DIRECTED);
182     }
183 
184     if (options.getString(ITEM_LAYERING_STRATEGY).equals(VALUE_LAYERING_HIERARCHICAL)) {
185       radial.setLayeringStrategy(RadialLayouter.LAYERING_STRATEGY_HIERARCHICAL);
186     } else {
187       radial.setLayeringStrategy(RadialLayouter.LAYERING_STRATEGY_BFS);
188     }
189 
190     radial.setConsiderNodeLabelsEnabled(options.getBool(ITEM_CONSIDER_NODE_LABELS));
191   }
192 }