1
28 package demo.layout.module;
29
30 import y.module.LayoutModule;
31 import y.module.YModule;
32
33 import y.base.Edge;
34 import y.base.Node;
35 import y.layout.Layouter;
36 import y.layout.router.polyline.EdgeLayoutDescriptor;
37 import y.layout.router.polyline.EdgeRouter;
38 import y.layout.router.polyline.Grid;
39 import y.layout.router.polyline.PenaltySettings;
40 import y.option.ConstraintManager;
41 import y.option.OptionGroup;
42 import y.option.OptionHandler;
43 import y.option.OptionItem;
44 import y.util.DataProviderAdapter;
45 import y.view.Graph2D;
46
47
51 public class PolylineEdgeRouterModule extends LayoutModule {
52
53 private static final String POLYLINE_EDGE_ROUTER = "POLYLINE_EDGE_ROUTER";
55
56 protected static final String SECTION_LAYOUT = "LAYOUT";
58 protected static final String ITEM_SCOPE = "SCOPE";
60 protected static final String VALUE_SCOPE_ALL_EDGES = "SCOPE_ALL_EDGES";
61 protected static final String VALUE_SCOPE_SELECTED_EDGES = "SCOPE_SELECTED_EDGES";
62 protected static final String VALUE_SCOPE_EDGES_AT_SELECTED_NODES = "SCOPE_EDGES_AT_SELECTED_NODES";
63 protected static final String ITEM_OPTIMIZATION_STRATEGY = "OPTIMIZATION_STRATEGY";
64 protected static final String VALUE_STRATEGY_BALANCED = "STRATEGY_BALANCED";
65 protected static final String VALUE_STRATEGY_MINIMIZE_BENDS = "STRATEGY_MINIMIZE_BENDS";
66 protected static final String VALUE_STRATEGY_MINIMIZE_CROSSINGS = "STRATEGY_MINIMIZE_CROSSINGS";
67 protected static final String ITEM_MONOTONIC_RESTRICTION = "MONOTONIC_RESTRICTION";
68 protected static final String VALUE_MONOTONIC_NONE = "MONOTONIC_NONE";
69 protected static final String VALUE_MONOTONIC_HORIZONTAL = "MONOTONIC_HORIZONTAL";
70 protected static final String VALUE_MONOTONIC_VERTICAL = "MONOTONIC_VERTICAL";
71 protected static final String VALUE_MONOTONIC_BOTH = "MONOTONIC_BOTH";
72 protected static final String TITLE_MINIMAL_DISTANCES = "MINIMAL_DISTANCES";
73 protected static final String ITEM_MINIMAL_EDGE_TO_EDGE_DISTANCE = "MINIMAL_EDGE_TO_EDGE_DISTANCE";
74 protected static final String ITEM_MINIMAL_NODE_TO_EDGE_DISTANCE = "MINIMAL_NODE_TO_EDGE_DISTANCE";
75 protected static final String ITEM_MINIMAL_NODE_CORNER_DISTANCE = "MINIMAL_NODE_CORNER_DISTANCE";
76 protected static final String ITEM_MINIMAL_FIRST_SEGMENT_LENGTH = "MINIMAL_FIRST_SEGMENT_LENGTH";
77 protected static final String ITEM_MINIMAL_LAST_SEGMENT_LENGTH = "MINIMAL_LAST_SEGMENT_LENGTH";
78 protected static final String TITLE_GRID_SETTINGS = "GRID_SETTINGS";
79 protected static final String ITEM_GRID_ENABLED = "GRID_ENABLED";
80 protected static final String ITEM_GRID_SPACING = "GRID_SPACING";
81 protected static final String ITEM_CONSIDER_NODE_LABELS = "CONSIDER_NODE_LABELS";
82 protected static final String ITEM_CONSIDER_EDGE_LABELS = "CONSIDER_EDGE_LABELS";
83 protected static final String ITEM_ENABLE_REROUTING = "ENABLE_REROUTING";
84 protected static final String ITEM_MAXIMAL_DURATION = "MAXIMAL_DURATION";
85
86 protected static final String SECTION_POLYLINE_ROUTING = "POLYLINE_ROUTING";
88 protected static final String ITEM_ENABLE_POLYLINE_ROUTING = "ENABLE_POLYLINE_ROUTING";
90 protected static final String ITEM_PREFERRED_POLYLINE_SEGMENT_LENGTH = "PREFERRED_POLYLINE_SEGMENT_LENGTH";
91
92 private boolean isEdgesDPAddedByModule;
94 private boolean isNodesDPAddedByModule;
95
96
99 public PolylineEdgeRouterModule() {
100 super(POLYLINE_EDGE_ROUTER);
101 setPortIntersectionCalculatorEnabled(true);
102 }
103
104
108 protected OptionHandler createOptionHandler() {
109 final OptionHandler options = new OptionHandler(getModuleName());
110 final ConstraintManager optionConstraints = new ConstraintManager(options);
111 final EdgeRouter polyline = new EdgeRouter();
113 final EdgeLayoutDescriptor descriptor = polyline.getDefaultEdgeLayoutDescriptor();
114 final Grid grid = polyline.getGrid();
115
116 options.useSection(SECTION_LAYOUT);
118 byte scope = polyline.getSphereOfAction();
120 options.addEnum(ITEM_SCOPE, new String[]{
121 VALUE_SCOPE_ALL_EDGES,
122 VALUE_SCOPE_SELECTED_EDGES,
123 VALUE_SCOPE_EDGES_AT_SELECTED_NODES
124 }, scope == EdgeRouter.ROUTE_ALL_EDGES ? 0 : 1);
125 options.addEnum(ITEM_OPTIMIZATION_STRATEGY, new String[]{
126 VALUE_STRATEGY_BALANCED,
127 VALUE_STRATEGY_MINIMIZE_BENDS,
128 VALUE_STRATEGY_MINIMIZE_CROSSINGS
129 }, 0);
130 options.addEnum(ITEM_MONOTONIC_RESTRICTION, new String[]{
131 VALUE_MONOTONIC_NONE,
132 VALUE_MONOTONIC_HORIZONTAL,
133 VALUE_MONOTONIC_VERTICAL,
134 VALUE_MONOTONIC_BOTH
135 }, descriptor.getMonotonicPathRestriction());
136
137 final OptionGroup distancesGroup = new OptionGroup();
139 distancesGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, TITLE_MINIMAL_DISTANCES);
140 distancesGroup.addItem(
142 options.addDouble(ITEM_MINIMAL_EDGE_TO_EDGE_DISTANCE, descriptor.getMinimalEdgeToEdgeDistance()));
143 distancesGroup.addItem(
144 options.addDouble(ITEM_MINIMAL_NODE_TO_EDGE_DISTANCE, polyline.getMinimalNodeToEdgeDistance()));
145 distancesGroup.addItem(
146 options.addDouble(ITEM_MINIMAL_NODE_CORNER_DISTANCE, descriptor.getMinimalNodeCornerDistance()));
147 distancesGroup.addItem(
148 options.addDouble(ITEM_MINIMAL_FIRST_SEGMENT_LENGTH, descriptor.getMinimalFirstSegmentLength()));
149 distancesGroup.addItem(
150 options.addDouble(ITEM_MINIMAL_LAST_SEGMENT_LENGTH, descriptor.getMinimalLastSegmentLength()));
151
152 final OptionGroup gridGroup = new OptionGroup();
154 gridGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, TITLE_GRID_SETTINGS);
155 final OptionItem itemGridEnabled =
157 gridGroup.addItem(options.addBool(ITEM_GRID_ENABLED, grid != null));
158 final OptionItem itemGridSpacing =
159 gridGroup.addItem(options.addDouble(ITEM_GRID_SPACING, grid != null ? grid.getSpacing() : 10));
160 optionConstraints.setEnabledOnValueEquals(itemGridEnabled, Boolean.TRUE, itemGridSpacing);
162
163 options.addBool(ITEM_CONSIDER_NODE_LABELS, polyline.isConsiderNodeLabelsEnabled());
165 options.addBool(ITEM_CONSIDER_EDGE_LABELS, polyline.isConsiderEdgeLabelsEnabled());
166 options.addBool(ITEM_ENABLE_REROUTING, polyline.isReroutingEnabled());
167 options.addInt(ITEM_MAXIMAL_DURATION, 0);
168
169 options.useSection(SECTION_POLYLINE_ROUTING);
171 final OptionItem itemEnablePolylineRouting = options.addBool(ITEM_ENABLE_POLYLINE_ROUTING, true);
173 final OptionItem itemPreferredPolylineSegmentLength =
174 options.addDouble(ITEM_PREFERRED_POLYLINE_SEGMENT_LENGTH, polyline.getPreferredPolylineSegmentLength());
175 optionConstraints.setEnabledOnValueEquals(itemEnablePolylineRouting,
177 Boolean.TRUE, itemPreferredPolylineSegmentLength);
178
179 return options;
180 }
181
182
186 protected void mainrun() {
187 final EdgeRouter edgeRouter = new EdgeRouter();
188
189 final OptionHandler options = getOptionHandler();
190 configure(edgeRouter, options);
191
192 final Graph2D graph = getGraph2D();
193 prepareGraph(graph, options);
194 try {
195 launchLayouter(edgeRouter);
196 } finally {
197 restoreGraph(graph, options);
198 }
199 }
200
201
211 protected void prepareGraph(final Graph2D graph, final OptionHandler options) {
212 if (VALUE_SCOPE_SELECTED_EDGES.equals(options.getString(ITEM_SCOPE))) {
213 isEdgesDPAddedByModule = graph.getDataProvider(Layouter.SELECTED_EDGES) == null;
216 if (isEdgesDPAddedByModule) {
217 graph.addDataProvider(Layouter.SELECTED_EDGES, new DataProviderAdapter() {
218 public boolean getBool(Object dataHolder) {
219 return graph.isSelected((Edge) dataHolder);
220 }
221 });
222 }
223 } else if (VALUE_SCOPE_EDGES_AT_SELECTED_NODES.equals(options.getString(ITEM_SCOPE))) {
224 isNodesDPAddedByModule = graph.getDataProvider(Layouter.SELECTED_NODES) == null;
226 if (isNodesDPAddedByModule) {
227 graph.addDataProvider(Layouter.SELECTED_NODES, new DataProviderAdapter() {
228 public boolean getBool(Object dataHolder) {
229 return graph.isSelected((Node) dataHolder);
230 }
231 });
232 }
233 }
234 }
235
236
242 protected void restoreGraph(final Graph2D graph, final OptionHandler options) {
243 if(VALUE_SCOPE_SELECTED_EDGES.equals(options.getString(ITEM_SCOPE))) {
245 if (isEdgesDPAddedByModule) {
246 isEdgesDPAddedByModule = false;
247 graph.removeDataProvider(Layouter.SELECTED_EDGES);
248 }
249 } else if (VALUE_SCOPE_EDGES_AT_SELECTED_NODES.equals(options.getString(ITEM_SCOPE))) {
250 if (isNodesDPAddedByModule) {
251 isNodesDPAddedByModule = false;
252 graph.removeDataProvider(Layouter.SELECTED_NODES);
253 }
254 }
255 }
256
257
262 protected void configure(final EdgeRouter router, final OptionHandler options) {
263 final String scope = options.getString(ITEM_SCOPE);
264 if (VALUE_SCOPE_EDGES_AT_SELECTED_NODES.equals(scope)) {
265 router.setSphereOfAction(EdgeRouter.ROUTE_EDGES_AT_SELECTED_NODES);
266 } else if (VALUE_SCOPE_ALL_EDGES.equals(scope)) {
267 router.setSphereOfAction(EdgeRouter.ROUTE_ALL_EDGES);
268 } else {
269 router.setSphereOfAction(EdgeRouter.ROUTE_SELECTED_EDGES);
270 }
271
272 final EdgeLayoutDescriptor descriptor = router.getDefaultEdgeLayoutDescriptor();
273
274 final String strategy = options.getString(ITEM_OPTIMIZATION_STRATEGY);
275 final PenaltySettings penaltySettings = descriptor.getPenaltySettings();
276 if (strategy.equals(VALUE_STRATEGY_BALANCED)) {
277 penaltySettings.setBendPenalty(3);
278 penaltySettings.setEdgeCrossingPenalty(1);
279 } else if (strategy.equals(VALUE_STRATEGY_MINIMIZE_BENDS)) {
280 penaltySettings.setBendPenalty(3);
281 penaltySettings.setEdgeCrossingPenalty(0);
282 } else {
283 penaltySettings.setBendPenalty(3);
284 penaltySettings.setEdgeCrossingPenalty(5);
285 }
286
287 final String monotonyFlag = options.getString(ITEM_MONOTONIC_RESTRICTION);
288 if (monotonyFlag.equals(VALUE_MONOTONIC_BOTH)) {
289 descriptor.setMonotonicPathRestriction(EdgeLayoutDescriptor.MONOTONIC_BOTH);
290 } else if (monotonyFlag.equals(VALUE_MONOTONIC_HORIZONTAL)) {
291 descriptor.setMonotonicPathRestriction(EdgeLayoutDescriptor.MONOTONIC_HORIZONTAL);
292 } else if (monotonyFlag.equals(VALUE_MONOTONIC_VERTICAL)) {
293 descriptor.setMonotonicPathRestriction(EdgeLayoutDescriptor.MONOTONIC_VERTICAL);
294 } else {
295 descriptor.setMonotonicPathRestriction(EdgeLayoutDescriptor.MONOTONIC_NONE);
296 }
297
298 descriptor.setMinimalEdgeToEdgeDistance(options.getDouble(ITEM_MINIMAL_EDGE_TO_EDGE_DISTANCE));
299 router.setMinimalNodeToEdgeDistance(options.getDouble(ITEM_MINIMAL_NODE_TO_EDGE_DISTANCE));
300 descriptor.setMinimalNodeCornerDistance(options.getDouble(ITEM_MINIMAL_NODE_CORNER_DISTANCE));
301 descriptor.setMinimalFirstSegmentLength(options.getDouble(ITEM_MINIMAL_FIRST_SEGMENT_LENGTH));
302 descriptor.setMinimalLastSegmentLength(options.getDouble(ITEM_MINIMAL_LAST_SEGMENT_LENGTH));
303
304 if (options.getBool(ITEM_GRID_ENABLED)) {
305 final double gridSpacing = options.getDouble(ITEM_GRID_SPACING);
306 router.setGrid(new Grid(0, 0, gridSpacing));
307 } else {
308 router.setGrid(null);
309 }
310
311 router.setConsiderNodeLabelsEnabled(options.getBool(ITEM_CONSIDER_NODE_LABELS));
312 router.setConsiderEdgeLabelsEnabled(options.getBool(ITEM_CONSIDER_EDGE_LABELS));
313 router.setReroutingEnabled(options.getBool(ITEM_ENABLE_REROUTING));
314 router.setPolylineRoutingEnabled(options.getBool(ITEM_ENABLE_POLYLINE_ROUTING));
315 router.setPreferredPolylineSegmentLength(options.getDouble(ITEM_PREFERRED_POLYLINE_SEGMENT_LENGTH));
316
317 int maximalDuration = options.getInt(ITEM_MAXIMAL_DURATION);
318 if (maximalDuration == 0) {
319 router.setMaximumDuration(Long.MAX_VALUE);
320 } else {
321 router.setMaximumDuration(maximalDuration * 1000);
322 }
323 }
324 }
325