1
14 package demo.layout.module;
15
16 import y.module.LayoutModule;
17 import y.module.YModule;
18
19 import y.base.Edge;
20 import y.base.EdgeCursor;
21 import y.layout.LabelLayoutConstants;
22 import y.layout.LabelRanking;
23 import y.layout.LayoutStage;
24 import y.layout.Layouter;
25 import y.layout.grouping.FixedGroupLayoutStage;
26 import y.layout.labeling.GreedyMISLabeling;
27 import y.layout.orthogonal.EdgeLayoutDescriptor;
28 import y.layout.orthogonal.OrthogonalGroupLayouter;
29 import y.layout.orthogonal.OrthogonalLayouter;
30 import y.option.ConstraintManager;
31 import y.option.IntOptionItem;
32 import y.option.OptionHandler;
33 import y.view.EdgeLabel;
34 import y.view.EdgeRealizer;
35 import y.view.Graph2D;
36 import y.view.hierarchy.HierarchyManager;
37
38
39
50 public class OrthogonalLayoutModule extends LayoutModule
51 {
52 private static final String ORTHOGONAL = "ORTHOGONAL_LAYOUTER";
53 private static final String GROUPING = "GROUPING";
54 private static final String GROUP_POLICY = "GROUP_LAYOUT_POLICY";
55 private static final String IGNORE_GROUPS = "IGNORE_GROUPS";
56 private static final String LAYOUT_GROUPS = "LAYOUT_GROUPS";
57 private static final String FIX_GROUPS = "FIX_GROUPS";
58 private static final String GROUP_LAYOUT_QUALITY = "GROUP_LAYOUT_QUALITY";
59
60 private static final String LENGTH_REDUCTION = "LENGTH_REDUCTION";
61 private static final String STYLE = "STYLE";
62 private static final String USE_RANDOMIZATION = "USE_RANDOMIZATION";
63 private static final String USE_FACE_MAXIMIZATION = "USE_FACE_MAXIMIZATION";
64 private static final String USE_EXISTING_DRAWING_AS_SKETCH = "USE_EXISTING_DRAWING_AS_SKETCH";
65 private static final String CROSSING_POSTPROCESSING = "CROSSING_POSTPROCESSING";
66 private static final String PERCEIVED_BENDS_POSTPROCESSING = "PERCEIVED_BENDS_POSTPROCESSING";
67 private static final String ROUTE_MULTI_EDGES_IN_PARALLEL = "ROUTE_MULTI_EDGES_IN_PARALLEL";
68 private static final String GRID = "GRID";
69 private static final String NORMAL = "NORMAL";
70 private static final String NORMAL_TREE = "NORMAL_TREE";
71 private static final String UNIFORM_NODES = "UNIFORM_NODES";
72 private static final String BOX_NODES = "BOX_NODES";
73 private static final String MIXED = "MIXED";
74 private static final String FIXED_MIXED = "FIXED_MIXED";
75 private static final String FIXED_BOX_NODES = "FIXED_BOX_NODES";
76 private static final String MINIMUM_FIRST_SEGMENT_LENGTH = "MINIMUM_FIRST_SEGMENT_LENGTH";
77 private static final String MINIMUM_LAST_SEGMENT_LENGTH = "MINIMUM_LAST_SEGMENT_LENGTH";
78 private static final String MINIMUM_SEGMENT_LENGTH = "MINIMUM_SEGMENT_LENGTH";
79
80 private static final String LAYOUT = "LAYOUT";
81 private static final String EDGE_LABEL_MODEL = "EDGE_LABEL_MODEL";
82 private static final String EDGE_LABELING = "EDGE_LABELING";
83 private static final String LABELING = "LABELING";
84 private static final String GENERIC = "GENERIC";
85 private static final String NONE = "NONE";
86 private static final String INTEGRATED = "INTEGRATED";
87 private static final String FREE = "FREE";
88 private static final String SIDE_SLIDER = "SIDE_SLIDER";
89 private static final String CENTER_SLIDER = "CENTER_SLIDER";
90 private static final String AS_IS = "AS_IS";
91 private static final String BEST = "BEST";
92 private static final String CONSIDER_NODE_LABELS = "CONSIDER_NODE_LABELS";
93
94 private final String[] styleEnum = {NORMAL, NORMAL_TREE, UNIFORM_NODES, BOX_NODES, MIXED, FIXED_MIXED, FIXED_BOX_NODES};
95
96 private static final String[] edgeLabeling = {
97 NONE,
98 INTEGRATED,
99 GENERIC
100 };
101
102 private static final String[] edgeLabelModel = {
103 BEST,
104 AS_IS,
105 CENTER_SLIDER,
106 SIDE_SLIDER,
107 FREE,
108 };
109
110 public OrthogonalLayoutModule()
111 {
112 super (ORTHOGONAL,"yFiles Layout Team",
113 "Orthogonal Layouter");
114 setPortIntersectionCalculatorEnabled(true);
115 }
116
117 public OptionHandler createOptionHandler()
118 {
119 OptionHandler op = new OptionHandler(getModuleName());
120
121 ConstraintManager cm = new ConstraintManager( op );
122
123
124 op.useSection(LAYOUT);
125 op.addEnum(STYLE, styleEnum, 0);
126 op.addInt(GRID,25)
127 .setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(1));
128 op.addBool(LENGTH_REDUCTION, true);
129 op.addBool(USE_EXISTING_DRAWING_AS_SKETCH, false);
130 op.addBool(CROSSING_POSTPROCESSING, true);
131 op.addBool(PERCEIVED_BENDS_POSTPROCESSING, true);
132 op.addBool(USE_RANDOMIZATION, true);
133 op.addBool(USE_FACE_MAXIMIZATION,false);
134 op.addBool(ROUTE_MULTI_EDGES_IN_PARALLEL, false);
135 op.addDouble(MINIMUM_FIRST_SEGMENT_LENGTH, 10);
136 op.addDouble(MINIMUM_LAST_SEGMENT_LENGTH, 10);
137 op.addDouble(MINIMUM_SEGMENT_LENGTH, 10);
138 op.useSection(LABELING);
139 op.addEnum(EDGE_LABELING, edgeLabeling, 0);
140 op.addEnum(EDGE_LABEL_MODEL, edgeLabelModel, 0);
141 op.addBool(CONSIDER_NODE_LABELS, false);
142
143 cm.setEnabledOnValueEquals( EDGE_LABELING, NONE, EDGE_LABEL_MODEL, true);
144
145 ConstraintManager.Condition c = cm.createConditionValueEquals(USE_EXISTING_DRAWING_AS_SKETCH, Boolean.FALSE);
146 cm.setEnabledOnCondition(c, op.getItem(CROSSING_POSTPROCESSING));
147 cm.setEnabledOnCondition(c, op.getItem(PERCEIVED_BENDS_POSTPROCESSING));
148 cm.setEnabledOnCondition(c, op.getItem(STYLE));
149 cm.setEnabledOnCondition(c, op.getItem(USE_RANDOMIZATION));
150
151
152 op.useSection(GROUPING);
153 String[] gEnum = { LAYOUT_GROUPS, FIX_GROUPS, IGNORE_GROUPS };
154 op.addEnum(GROUP_POLICY, gEnum, 0);
155 op.addDouble(GROUP_LAYOUT_QUALITY, 1.0, 0.0, 1.0);
156
157 cm.setEnabledOnValueEquals( GROUP_POLICY, LAYOUT_GROUPS, GROUP_LAYOUT_QUALITY);
158
159 return op;
160 }
161
162 public void mainrun()
163 {
164 OptionHandler op = getOptionHandler();
165
166 OrthogonalLayouter orthogonal = new OrthogonalLayouter();
167
168
172 switch (OptionHandler.getIndex(styleEnum, op.getString(STYLE))){
173 default:
174 case 0:
175 orthogonal.setLayoutStyle(OrthogonalLayouter.NORMAL_STYLE);
176 break;
177 case 1:
178 orthogonal.setLayoutStyle(OrthogonalLayouter.NORMAL_TREE_STYLE);
179 break;
180 case 2:
181 orthogonal.setLayoutStyle(OrthogonalLayouter.UNIFORM_STYLE);
182 break;
183 case 3:
184 orthogonal.setLayoutStyle(OrthogonalLayouter.BOX_STYLE);
185 break;
186 case 4:
187 orthogonal.setLayoutStyle(OrthogonalLayouter.MIXED_STYLE);
188 break;
189 case 5:
190 orthogonal.setLayoutStyle(OrthogonalLayouter.FIXED_MIXED_STYLE);
191 break;
192 case 6:
193 orthogonal.setLayoutStyle(OrthogonalLayouter.FIXED_BOX_STYLE);
194 break;
195 }
196
197 final EdgeLayoutDescriptor layoutDescriptor = orthogonal.getEdgeLayoutDescriptor();
198 layoutDescriptor.setMinimumFirstSegmentLength(op.getDouble(MINIMUM_FIRST_SEGMENT_LENGTH));
199 layoutDescriptor.setMinimumLastSegmentLength(op.getDouble(MINIMUM_LAST_SEGMENT_LENGTH));
200 layoutDescriptor.setMinimumSegmentLength(op.getDouble(MINIMUM_SEGMENT_LENGTH));
201
202 orthogonal.setGrid(op.getInt(GRID));
203 orthogonal.setUseLengthReduction(
204 op.getBool(LENGTH_REDUCTION));
205 orthogonal.setUseCrossingPostprocessing(
206 op.getBool(CROSSING_POSTPROCESSING));
207 orthogonal.setPerceivedBendsOptimizationEnabled(
208 op.getBool(PERCEIVED_BENDS_POSTPROCESSING));
209 orthogonal.setUseRandomization(
210 op.getBool(USE_RANDOMIZATION));
211 orthogonal.setUseFaceMaximization(
212 op.getBool(USE_FACE_MAXIMIZATION));
213 orthogonal.setUseSketchDrawing(op.getBool(USE_EXISTING_DRAWING_AS_SKETCH));
214 orthogonal.setParallelEdgeLayouterEnabled(op.getBool(ROUTE_MULTI_EDGES_IN_PARALLEL));
215
216 Graph2D graph = getGraph2D();
217
218
222 boolean normalStyle = (orthogonal.getLayoutStyle() == OrthogonalLayouter.NORMAL_STYLE);
223 String el = op.getString(EDGE_LABELING);
224 orthogonal.setIntegratedEdgeLabelingEnabled(el.equals(INTEGRATED) && normalStyle);
225 orthogonal.setConsiderNodeLabelsEnabled(op.getBool(CONSIDER_NODE_LABELS) && normalStyle);
226 if (el.equals(GENERIC) || (el.equals(INTEGRATED) && normalStyle)) {
227 setupEdgeLabelModel(el, op.getString(EDGE_LABEL_MODEL));
228 } else if (!op.getBool(CONSIDER_NODE_LABELS) || !normalStyle) {
229 orthogonal.setLabelLayouterEnabled(false);
230 }
231
232 Layouter layouter = orthogonal;
233 LayoutStage preStage = null;
234
235 if(HierarchyManager.containsGroupNodes(graph) && !op.get(GROUP_POLICY).equals(IGNORE_GROUPS))
236 {
237 FixedGroupLayoutStage fgl = null;
238 if(op.get(GROUP_POLICY).equals(FIX_GROUPS))
239 {
240 fgl = new FixedGroupLayoutStage();
241 fgl.setInterEdgeRoutingStyle(FixedGroupLayoutStage.ROUTING_STYLE_ORTHOGONAL);
242 orthogonal.prependStage(fgl);
243 preStage = fgl;
244 } else {
245 OrthogonalGroupLayouter ogl = new OrthogonalGroupLayouter();
246 final EdgeLayoutDescriptor descriptor = ogl.getEdgeLayoutDescriptor();
247 descriptor.setMinimumFirstSegmentLength(op.getDouble(MINIMUM_FIRST_SEGMENT_LENGTH));
248 descriptor.setMinimumLastSegmentLength(op.getDouble(MINIMUM_LAST_SEGMENT_LENGTH));
249 descriptor.setMinimumSegmentLength(op.getDouble(MINIMUM_SEGMENT_LENGTH));
250 ogl.setIntegratedEdgeLabelingEnabled(orthogonal.isIntegratedEdgeLabelingEnabled());
251 ogl.setConsiderNodeLabelsEnabled(orthogonal.isConsiderNodeLabelsEnabled());
252 ogl.setLabelLayouterEnabled(orthogonal.isLabelLayouterEnabled());
253
254 ogl.setGrid(op.getInt(GRID));
255 ogl.setLayoutQuality(op.getDouble(GROUP_LAYOUT_QUALITY));
256 ogl.setParallelEdgeLayouterEnabled(op.getBool(ROUTE_MULTI_EDGES_IN_PARALLEL));
257 layouter = ogl;
258 }
259
260 try {
261 launchLayouter(layouter);
262 } finally {
263 if(preStage != null) {
264 orthogonal.removeStage(preStage);
265 }
266 }
267 }
268 else
269 {
270 launchLayouter(layouter);
271 }
272 if (el.equals(GENERIC)) {
273 GreedyMISLabeling la = new GreedyMISLabeling();
274 la.setPlaceNodeLabels(false);
275 la.setPlaceEdgeLabels(true);
276 la.setProfitModel(new LabelRanking());
277 la.doLayout(graph);
278 }
279 getGraph2D().updateViews();
280 }
281
282 void setupEdgeLabelModel(String edgeLabeling, String edgeLabelModel) {
283 if(edgeLabeling.equals(NONE) || edgeLabelModel.equals(AS_IS)) {
284 return; }
286
287 byte model = EdgeLabel.SIDE_SLIDER;
288 if (edgeLabelModel.equals(CENTER_SLIDER)) {
289 model = EdgeLabel.CENTER_SLIDER;
290 } else if (edgeLabelModel.equals(FREE) || edgeLabelModel.equals(BEST)) {
291 model = EdgeLabel.FREE;
292 }
293
297 Graph2D graph = getGraph2D();
298 for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
299 Edge e = ec.edge();
300 EdgeRealizer er = graph.getRealizer(e);
301 for (int i = 0; i < er.labelCount(); i++) {
302 EdgeLabel el = er.getLabel(i);
303 el.setModel(model);
304 int prefAlongEdge = el.getPreferredPlacement() & LabelLayoutConstants.PLACEMENT_ALONG_EDGE_MASK;
306 int prefOnSide = el.getPreferredPlacement() & LabelLayoutConstants.PLACEMENT_ON_SIDE_OF_EDGE_MASK;
307 if (model == EdgeLabel.CENTER_SLIDER && prefOnSide != LabelLayoutConstants.PLACE_ON_EDGE) {
308 el.setPreferredPlacement((byte) (LabelLayoutConstants.PLACE_ON_EDGE | prefAlongEdge));
309 } else if(model == EdgeLabel.SIDE_SLIDER && prefOnSide == LabelLayoutConstants.PLACE_ON_EDGE) {
310 el.setPreferredPlacement((byte) (LabelLayoutConstants.PLACE_RIGHT_OF_EDGE | prefAlongEdge));
311 }
312 }
313 }
314 }
315 }