1
14 package demo.layout.module;
15
16 import y.module.LayoutModule;
17 import y.module.YModule;
18
19 import y.base.DataProvider;
20 import y.base.Edge;
21 import y.base.EdgeCursor;
22
23 import y.layout.LabelRanking;
24 import y.layout.EdgeLabelModel;
25 import y.layout.RotatedDiscreteEdgeLabelModel;
26 import y.layout.RotatedSliderEdgeLabelModel;
27 import y.layout.labeling.GreedyMISLabeling;
28 import y.layout.labeling.MISLabelingAlgorithm;
29 import y.layout.labeling.SALabeling;
30 import y.option.MappedListCellRenderer;
31 import y.option.OptionHandler;
32 import y.option.ConstraintManager;
33 import y.util.DataProviderAdapter;
34 import y.view.EdgeLabel;
35 import y.view.EdgeRealizer;
36 import y.view.Graph2D;
37 import y.view.Graph2DView;
38 import y.view.NodeLabel;
39 import y.view.YLabel;
40 import y.view.Graph2DLayoutExecutor;
41 import java.util.Map;
42
43
48 public class LabelingModule extends YModule {
49
50 private static final String ALLOW_NODE_OVERLAPS = "ALLOW_NODE_OVERLAPS";
51 private static final String INPUT = "INPUT";
52 private static final String CONSIDER_INVISIBLE_LABELS = "CONSIDER_INVISIBLE_LABELS";
53 private static final String ALLOW_EDGE_OVERLAPS = "ALLOW_EDGE_OVERLAPS";
54 private static final String DIVERSE_LABELING = "DIVERSE_LABELING";
55 private static final String QUALITY = "QUALITY";
56 private static final String USE_OPTIMIZATION = "USE_OPTIMIZATION";
57 private static final String USE_POSTPROCESSING = "USE_POSTPROCESSING";
58 private static final String CONSIDER_SELECTED_FEATURES_ONLY = "CONSIDER_SELECTED_FEATURES_ONLY";
59 private static final String SCOPE = "SCOPE";
60 private static final String PLACE_EDGE_LABELS = "PLACE_EDGE_LABELS";
61 private static final String MODEL = "MODEL";
62 private static final String EDGE_LABEL_MODEL = "EDGE_LABEL_MODEL";
63 private static final String AUTO_ROTATE = "AUTO_ROTATE";
64 private static final String UNKNOWN_MODEL_VALUE = "UNKNOWN_MODEL_VALUE";
65 private static final String PLACE_NODE_LABELS = "PLACE_NODE_LABELS";
66 private static final String OPTIMIZATION_BALANCED = "OPTIMIZATION_BALANCED";
67 private static final String OPTIMIZATION_NODE_OVERLAP = "OPTIMIZATION_NODE_OVERLAP";
68 private static final String OPTIMIZATION_LABEL_OVERLAP = "OPTIMIZATION_LABEL_OVERLAP";
69 private static final String OPTIMIZATION_EDGE_OVERLAP = "OPTIMIZATION_EDGE_OVERLAP";
70 private static final String OPTIMIZATION_NONE = "OPTIMIZATION_NONE";
71 private static final String OPTIMIZATION_STRATEGY = "OPTIMIZATION_STRATEGY";
72
73 private static final String AS_IS = "As Is";
75 private static final String BEST = "Best";
76
77 private static final String[] optimizationStrategy = {
78 OPTIMIZATION_BALANCED, OPTIMIZATION_NONE, OPTIMIZATION_EDGE_OVERLAP, OPTIMIZATION_LABEL_OVERLAP,
79 OPTIMIZATION_NODE_OVERLAP
80 };
81
82 public LabelingModule() {
83 super(DIVERSE_LABELING, "yFiles Layout Team", "Places Labels");
84 }
85
86
87 protected OptionHandler createOptionHandler() {
88 OptionHandler op = new OptionHandler(getModuleName());
89 op.useSection(SCOPE);
90 op.addBool(PLACE_NODE_LABELS, true);
91 op.addBool(PLACE_EDGE_LABELS, true);
92 op.addBool(CONSIDER_SELECTED_FEATURES_ONLY, false);
93 op.addBool(CONSIDER_INVISIBLE_LABELS, false);
94 op.useSection(QUALITY);
95 op.addBool(USE_OPTIMIZATION, false);
96 op.addEnum(OPTIMIZATION_STRATEGY, optimizationStrategy, 0);
97 op.addBool(ALLOW_NODE_OVERLAPS, false);
98 op.addBool(ALLOW_EDGE_OVERLAPS, true);
99 op.addBool(USE_POSTPROCESSING, false);
100
101 op.useSection(MODEL);
102 Map map = EdgeLabel.modelToStringMap();
103 Object asIs = AS_IS;
104 map.put(asIs, asIs);
105 Object best = BEST;
106 map.put(best, best);
107 op.addEnum(EDGE_LABEL_MODEL, map.keySet().toArray(), best, new MappedListCellRenderer(map));
108 op.addBool(AUTO_ROTATE, false);
109
110 final ConstraintManager cm = new ConstraintManager(op);
112 final Object[] nonAutoRotatableModels = {AS_IS, BEST, new Byte(EdgeLabel.FREE)};
113 final ConstraintManager.Condition condition = cm.createConditionValueIs(EDGE_LABEL_MODEL, nonAutoRotatableModels);
114 cm.setEnabledOnCondition(condition.inverse(), op.getItem(AUTO_ROTATE));
115
116 return op;
117 }
118
119 protected void init() {
120 final OptionHandler op = getOptionHandler();
121 DataProvider labelSet = new LabelSetDP(
122 getGraph2D(),
123 op.getBool(CONSIDER_SELECTED_FEATURES_ONLY),
124 op.getBool(PLACE_NODE_LABELS),
125 op.getBool(PLACE_EDGE_LABELS),
126 op.getBool(CONSIDER_INVISIBLE_LABELS));
127 getGraph2D().addDataProvider(INPUT, labelSet);
128
129 setupEdgeLabelModels(op.get(EDGE_LABEL_MODEL), labelSet, op.getBool(AUTO_ROTATE));
130 }
131
132 protected void mainrun() {
133 final OptionHandler op = getOptionHandler();
134 final MISLabelingAlgorithm al = op.getBool(USE_OPTIMIZATION) ?
135 (MISLabelingAlgorithm) new SALabeling() :
136 new GreedyMISLabeling();
137
138 al.setOptimizationStrategy((byte) op.getEnum(OPTIMIZATION_STRATEGY));
139 if (al.getOptimizationStrategy() == MISLabelingAlgorithm.OPTIMIZATION_NONE) {
140 al.setProfitModel(new LabelRanking());
141 }
142 al.setRemoveNodeOverlaps(!op.getBool(ALLOW_NODE_OVERLAPS));
143 al.setRemoveEdgeOverlaps(!op.getBool(ALLOW_EDGE_OVERLAPS));
144 al.setApplyPostprocessing(op.getBool(USE_POSTPROCESSING));
145
146 al.setSelection(INPUT);
147
148 final Graph2DLayoutExecutor layoutExecutor = new Graph2DLayoutExecutor(Graph2DLayoutExecutor.UNBUFFERED);
149 final Graph2DView view = getGraph2DView();
150 if (view == null) {
151 layoutExecutor.doLayout(getGraph2D(), al);
152 } else {
153 layoutExecutor.doLayout(view, al);
154 }
155
156 getGraph2D().removeDataProvider(INPUT);
157 getGraph2D().updateViews();
158 }
159
160 static EdgeLabelModel getEdgeLabelModel(byte modelValue) {
161 final EdgeLabelModel labelModel;
162 if(EdgeLabel.CENTERED == modelValue) {
163 labelModel = new RotatedDiscreteEdgeLabelModel(RotatedDiscreteEdgeLabelModel.CENTERED);
164 ((RotatedDiscreteEdgeLabelModel) labelModel).setAutoRotationEnabled(true);
165 } else if(EdgeLabel.TWO_POS == modelValue) {
166 labelModel = new RotatedDiscreteEdgeLabelModel(RotatedDiscreteEdgeLabelModel.TWO_POS);
167 ((RotatedDiscreteEdgeLabelModel) labelModel).setAutoRotationEnabled(true);
168 } else if(EdgeLabel.SIX_POS == modelValue) {
169 labelModel = new RotatedDiscreteEdgeLabelModel(RotatedDiscreteEdgeLabelModel.SIX_POS);
170 ((RotatedDiscreteEdgeLabelModel) labelModel).setAutoRotationEnabled(true);
171 } else if(EdgeLabel.THREE_CENTER == modelValue) {
172 labelModel = new RotatedDiscreteEdgeLabelModel(RotatedDiscreteEdgeLabelModel.THREE_CENTER);
173 ((RotatedDiscreteEdgeLabelModel) labelModel).setAutoRotationEnabled(true);
174 } else if(EdgeLabel.CENTER_SLIDER == modelValue) {
175 labelModel = new RotatedSliderEdgeLabelModel(RotatedSliderEdgeLabelModel.CENTER_SLIDER);
176 ((RotatedSliderEdgeLabelModel) labelModel).setAutoRotationEnabled(true);
177 } else if(EdgeLabel.SIDE_SLIDER == modelValue) {
178 labelModel = new RotatedSliderEdgeLabelModel(RotatedSliderEdgeLabelModel.SIDE_SLIDER);
179 ((RotatedSliderEdgeLabelModel) labelModel).setAutoRotationEnabled(true);
180 } else {
181 labelModel = null;
182 }
183 return labelModel;
184 }
185
186
189 static class LabelSetDP extends DataProviderAdapter
190 {
191 private final boolean considerOnlySelected;
192 private final Graph2D graph;
193 private final boolean nodes;
194 private final boolean edges;
195 private final boolean invisible;
196
197 LabelSetDP(Graph2D g,boolean sel,boolean n,boolean e,boolean uv)
198 {
199 considerOnlySelected = sel;
200 graph = g;
201 nodes = n;
202 edges = e;
203 invisible = uv;
204 }
205
206 public boolean getBool(Object o)
207 {
208 YLabel ylabel = (YLabel) o;
209 if (!ylabel.isVisible() && !invisible) {
210 return false;
211 }
212 if (o instanceof NodeLabel) {
213 NodeLabel l = (NodeLabel) o;
214 if (l.getModel() == NodeLabel.INTERNAL) return false;
215 }
216 if (considerOnlySelected)
217 {
218 if ((o instanceof NodeLabel) && nodes)
219 {
220 NodeLabel l = (NodeLabel) o;
221 if (graph.isSelected(l.getNode())) {
222 return true;
223 } else {
224 return false;
225 }
226 }
227 if ((o instanceof EdgeLabel) && edges) {
228 EdgeLabel l = (EdgeLabel) o;
229 if (graph.isSelected(l.getEdge())) {
230 return true;
231 } else {
232 return false;
233 }
234 }
235 return false;
236 } else {
237 if ((o instanceof NodeLabel) && nodes) return true;
238 if ((o instanceof EdgeLabel) && edges) return true;
239 return false;
240 }
241 }
242 }
243
244 void setupEdgeLabelModels(Object modelValue, DataProvider labelFilter, boolean autoRotate) {
245 if (AS_IS.equals(modelValue)) {
246 return;
247 }
248
249 final byte model;
250 EdgeLabelModel labelModel = null;
251 if (BEST.equals(modelValue)) {
252 model = EdgeLabel.FREE;
253 } else if (modelValue instanceof Byte) {
254 model = ((Byte) modelValue).byteValue();
255 if (autoRotate) {
256 labelModel = getEdgeLabelModel(model);
257 }
258 } else {
259 throw new IllegalArgumentException(UNKNOWN_MODEL_VALUE + modelValue);
260 }
261
262 final Graph2D graph = getGraph2D();
263 for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
264 Edge e = ec.edge();
265 EdgeRealizer er = graph.getRealizer(e);
266 for (int i = 0; i < er.labelCount(); i++) {
267 EdgeLabel label = er.getLabel(i);
268 if (labelFilter.getBool(label)) {
269 if (labelModel != null) {
270 label.setLabelModel(labelModel);
271 } else {
272 label.setModel(model);
273 }
274 label.setModelParameter(label.getLabelModel().getDefaultParameter());
275 }
276 }
277 }
278 }
279 }
280
281