svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.labeling.app / org.gvsig.labeling.app.mainplugin / src / main / java / org / gvsig / labeling / label / GeneralLabelingStrategy.java @ 44534
History | View | Annotate | Download (29.2 KB)
1 | 40911 | jldominguez | package org.gvsig.labeling.label; |
---|---|---|---|
2 | |||
3 | import java.awt.Graphics2D; |
||
4 | import java.awt.geom.Point2D; |
||
5 | import java.awt.image.BufferedImage; |
||
6 | import java.util.ArrayList; |
||
7 | import java.util.Iterator; |
||
8 | 41227 | jldominguez | import java.util.List; |
9 | 40911 | jldominguez | import java.util.TreeMap; |
10 | import java.util.TreeSet; |
||
11 | 43510 | jjdelcerro | import org.cresques.cts.ICoordTrans; |
12 | 40911 | jldominguez | |
13 | 42980 | fdiaz | import org.slf4j.Logger; |
14 | import org.slf4j.LoggerFactory; |
||
15 | |||
16 | 40911 | jldominguez | import org.gvsig.compat.print.PrintAttributes; |
17 | import org.gvsig.fmap.dal.exception.DataException; |
||
18 | import org.gvsig.fmap.dal.exception.ReadException; |
||
19 | import org.gvsig.fmap.dal.feature.Feature; |
||
20 | import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor; |
||
21 | import org.gvsig.fmap.dal.feature.FeatureSet; |
||
22 | import org.gvsig.fmap.geom.Geometry; |
||
23 | import org.gvsig.fmap.geom.Geometry.SUBTYPES; |
||
24 | import org.gvsig.fmap.geom.Geometry.TYPES; |
||
25 | import org.gvsig.fmap.geom.GeometryException; |
||
26 | import org.gvsig.fmap.geom.GeometryLocator; |
||
27 | import org.gvsig.fmap.geom.GeometryManager; |
||
28 | 41227 | jldominguez | import org.gvsig.fmap.geom.aggregate.MultiPrimitive; |
29 | 42555 | fdiaz | import org.gvsig.fmap.geom.operation.GeometryOperationException; |
30 | import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException; |
||
31 | 40911 | jldominguez | import org.gvsig.fmap.geom.primitive.Envelope; |
32 | import org.gvsig.fmap.geom.primitive.Point; |
||
33 | import org.gvsig.fmap.geom.type.GeometryType; |
||
34 | import org.gvsig.fmap.mapcontext.ViewPort; |
||
35 | import org.gvsig.fmap.mapcontext.layers.FLayer; |
||
36 | import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect; |
||
37 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelClass; |
||
38 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingMethod; |
||
39 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelingStrategy; |
||
40 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.IPlacementConstraints; |
||
41 | import org.gvsig.fmap.mapcontext.rendering.legend.styling.IZoomConstraints; |
||
42 | import org.gvsig.fmap.mapcontext.rendering.symbols.CartographicSupport; |
||
43 | import org.gvsig.i18n.Messages; |
||
44 | import org.gvsig.labeling.lang.LabelClassUtils; |
||
45 | import org.gvsig.labeling.placements.ILabelPlacement; |
||
46 | import org.gvsig.labeling.placements.LinePlacementConstraints; |
||
47 | import org.gvsig.labeling.placements.MultiShapePlacementConstraints; |
||
48 | import org.gvsig.labeling.placements.PlacementManager; |
||
49 | import org.gvsig.labeling.placements.PointPlacementConstraints; |
||
50 | import org.gvsig.labeling.placements.PolygonPlacementConstraints; |
||
51 | import org.gvsig.labeling.placements.RemoveDuplicatesComparator; |
||
52 | import org.gvsig.labeling.symbol.SmartTextSymbol; |
||
53 | import org.gvsig.labeling.symbol.SymbolUtils; |
||
54 | import org.gvsig.symbology.SymbologyLocator; |
||
55 | import org.gvsig.symbology.fmap.mapcontext.rendering.legend.styling.LabelLocationMetrics; |
||
56 | import org.gvsig.tools.ToolsLocator; |
||
57 | import org.gvsig.tools.dispose.DisposableIterator; |
||
58 | import org.gvsig.tools.dynobject.DynStruct; |
||
59 | import org.gvsig.tools.persistence.PersistenceManager; |
||
60 | import org.gvsig.tools.persistence.PersistentState; |
||
61 | import org.gvsig.tools.persistence.exception.PersistenceException; |
||
62 | import org.gvsig.tools.task.Cancellable; |
||
63 | 42555 | fdiaz | |
64 | 44534 | omartinez | public class GeneralLabelingStrategy implements IGeneralLabelingStrategy { |
65 | 41789 | fdiaz | |
66 | private static final Logger logger = LoggerFactory |
||
67 | .getLogger(GeneralLabelingStrategy.class); |
||
68 | |||
69 | public static final String GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME = "GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME"; |
||
70 | |||
71 | public static PointPlacementConstraints DefaultPointPlacementConstraints = new PointPlacementConstraints(); |
||
72 | public static LinePlacementConstraints DefaultLinePlacementConstraints = new LinePlacementConstraints(); |
||
73 | public static PolygonPlacementConstraints DefaultPolygonPlacementConstraints = new PolygonPlacementConstraints(); |
||
74 | |||
75 | 40911 | jldominguez | private static String[] NO_TEXT = { Messages.getText("text_field") }; |
76 | 41789 | fdiaz | |
77 | private static MultiShapePlacementConstraints DefaultMultiShapePlacementConstratints = new MultiShapePlacementConstraints(); |
||
78 | |||
79 | 40911 | jldominguez | private ILabelingMethod method;
|
80 | private IPlacementConstraints placementConstraints;
|
||
81 | private IZoomConstraints zoomConstraints;
|
||
82 | 41789 | fdiaz | |
83 | 40911 | jldominguez | private boolean allowOverlapping; |
84 | 41789 | fdiaz | |
85 | 40911 | jldominguez | protected FLyrVect layer;
|
86 | |||
87 | 41789 | fdiaz | // private long parseTime;
|
88 | 40911 | jldominguez | private int unit; |
89 | private int referenceSystem; |
||
90 | // private double sizeAfter;
|
||
91 | 41789 | fdiaz | private boolean printMode = false; /* |
92 | * indicate whether output is for a
|
||
93 | * print product (PDF, PS, ...)
|
||
94 | */
|
||
95 | |||
96 | 42980 | fdiaz | private List<Geometry> drawnGeometryLabels; |
97 | |||
98 | 40911 | jldominguez | public GeneralLabelingStrategy() {
|
99 | 41789 | fdiaz | method = SymbologyLocator.getSymbologyManager() |
100 | .createDefaultLabelingMethod(); |
||
101 | 40911 | jldominguez | } |
102 | |||
103 | public void setLayer(FLayer layer) { |
||
104 | FLyrVect l = (FLyrVect) layer; |
||
105 | this.layer = l;
|
||
106 | } |
||
107 | |||
108 | public ILabelingMethod getLabelingMethod() {
|
||
109 | return method;
|
||
110 | } |
||
111 | |||
112 | public void setLabelingMethod(ILabelingMethod method) { |
||
113 | this.method = method;
|
||
114 | } |
||
115 | |||
116 | 41789 | fdiaz | private class GeometryItem { |
117 | 40911 | jldominguez | public Geometry geom = null; |
118 | public int weigh = 0; |
||
119 | public double savedPerimeter; |
||
120 | |||
121 | 41789 | fdiaz | public GeometryItem(Geometry geom, int weigh) { |
122 | 40911 | jldominguez | this.geom = geom;
|
123 | this.weigh = weigh;
|
||
124 | this.savedPerimeter = 0; |
||
125 | } |
||
126 | } |
||
127 | 41789 | fdiaz | |
128 | 42980 | fdiaz | public void draw(BufferedImage mapImage, Graphics2D mapGraphics, double scale, ViewPort viewPort, |
129 | Cancellable cancel, double dpi) throws ReadException { |
||
130 | 40911 | jldominguez | |
131 | 42980 | fdiaz | drawnGeometryLabels = new ArrayList<Geometry>(1000); |
132 | 41789 | fdiaz | |
133 | 42980 | fdiaz | int x = (int) viewPort.getOffset().getX(); |
134 | int y = (int) viewPort.getOffset().getY(); |
||
135 | 40911 | jldominguez | |
136 | 42980 | fdiaz | // offsets for page generation (PDF, PS, direct printing)
|
137 | int print_offset_x = x;
|
||
138 | int print_offset_y = y;
|
||
139 | if (printMode) {
|
||
140 | // for printing, we never offset the labels themselves
|
||
141 | x = 0;
|
||
142 | y = 0;
|
||
143 | printMode = false;
|
||
144 | } |
||
145 | 41789 | fdiaz | |
146 | 42980 | fdiaz | TreeMap<String[], GeometryItem> labelsToPlace = null; |
147 | 40911 | jldominguez | |
148 | 42980 | fdiaz | String[] usedFields = getUsedFields(); |
149 | 40911 | jldominguez | |
150 | 42980 | fdiaz | int notPlacedCount = 0; |
151 | int placedCount = 0; |
||
152 | 40911 | jldominguez | |
153 | 42980 | fdiaz | /*
|
154 | * Get the label placement solvers according the user's settings
|
||
155 | */
|
||
156 | ILabelPlacement placement = PlacementManager.getPlacement(getPlacementConstraints(), layer.getShapeType()); |
||
157 | 40911 | jldominguez | |
158 | 42980 | fdiaz | BufferedImage targetBI;
|
159 | Graphics2D targetGr;
|
||
160 | 40911 | jldominguez | |
161 | 42980 | fdiaz | /*
|
162 | * get an ordered set of the LabelClasses up on the label priority
|
||
163 | */
|
||
164 | ILabelClass[] lcs = method.getLabelClasses();
|
||
165 | TreeSet<ILabelClass> ts = new TreeSet<ILabelClass>(new LabelClassComparatorByPriority()); |
||
166 | 40911 | jldominguez | |
167 | 42980 | fdiaz | for (int i = 0; i < lcs.length; i++) |
168 | ts.add(lcs[i]); |
||
169 | 40911 | jldominguez | |
170 | 42980 | fdiaz | if (ts.size() == 0) |
171 | return;
|
||
172 | 41789 | fdiaz | |
173 | 42980 | fdiaz | /*
|
174 | * now we have an ordered set, it is only need to give a pass for each
|
||
175 | * label class to render by priorities.
|
||
176 | *
|
||
177 | * If no priorities were defined, the following loop only executes once
|
||
178 | */
|
||
179 | for (ILabelClass lc : ts) {
|
||
180 | 41789 | fdiaz | |
181 | 42980 | fdiaz | if (!lc.isVisible(scale)) {
|
182 | /*
|
||
183 | * Avoid non-visible labels
|
||
184 | */
|
||
185 | continue;
|
||
186 | } |
||
187 | 40911 | jldominguez | |
188 | 42980 | fdiaz | FeatureSet fset = null;
|
189 | DisposableIterator diter = null;
|
||
190 | try {
|
||
191 | 40911 | jldominguez | |
192 | 42980 | fdiaz | try {
|
193 | fset = method.getFeatureIteratorByLabelClass(layer, lc, viewPort, usedFields); |
||
194 | } catch (DataException e) {
|
||
195 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
196 | } |
||
197 | 40911 | jldominguez | |
198 | 42980 | fdiaz | // duplicates treatment stuff
|
199 | /* handle the duplicates mode */
|
||
200 | int duplicateMode = getDuplicateLabelsMode();
|
||
201 | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
||
202 | // we need to register the labels already placed
|
||
203 | 40911 | jldominguez | |
204 | 42980 | fdiaz | labelsToPlace = new TreeMap<String[], GeometryItem>(new RemoveDuplicatesComparator()); |
205 | } |
||
206 | 40911 | jldominguez | |
207 | 42980 | fdiaz | boolean bLabelsReallocatable = !isAllowingOverlap();
|
208 | 41790 | fdiaz | |
209 | 42980 | fdiaz | BufferedImage overlapDetectImage = null; |
210 | Graphics2D overlapDetectGraphics = null; |
||
211 | if (bLabelsReallocatable) {
|
||
212 | int width = viewPort.getImageWidth() + print_offset_x;
|
||
213 | 41790 | fdiaz | |
214 | 42980 | fdiaz | if (width < 0) { |
215 | width = 1;
|
||
216 | } |
||
217 | int height = viewPort.getImageHeight() + print_offset_y;
|
||
218 | if (height < 0) { |
||
219 | height = 1;
|
||
220 | } |
||
221 | if (mapImage != null) |
||
222 | overlapDetectImage = |
||
223 | new BufferedImage(mapImage.getWidth() + print_offset_x, mapImage.getHeight() |
||
224 | + print_offset_y, BufferedImage.TYPE_INT_ARGB);
|
||
225 | else
|
||
226 | overlapDetectImage = |
||
227 | new BufferedImage(viewPort.getImageWidth() + print_offset_x, viewPort.getImageHeight() |
||
228 | + print_offset_y, BufferedImage.TYPE_INT_ARGB);
|
||
229 | 40911 | jldominguez | |
230 | 42980 | fdiaz | overlapDetectGraphics = overlapDetectImage.createGraphics(); |
231 | overlapDetectGraphics.setRenderingHints(mapGraphics.getRenderingHints()); |
||
232 | } |
||
233 | if (bLabelsReallocatable) {
|
||
234 | targetBI = overlapDetectImage; |
||
235 | targetGr = overlapDetectGraphics; |
||
236 | targetGr.translate(-x, -y); |
||
237 | } else {
|
||
238 | targetBI = mapImage; |
||
239 | targetGr = mapGraphics; |
||
240 | } |
||
241 | 40911 | jldominguez | |
242 | 42980 | fdiaz | try {
|
243 | diter = fset.fastIterator(); |
||
244 | } catch (DataException e) {
|
||
245 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
246 | } |
||
247 | Feature featu = null;
|
||
248 | Geometry geome = null;
|
||
249 | 40911 | jldominguez | |
250 | 42980 | fdiaz | while (!cancel.isCanceled() && diter.hasNext()) {
|
251 | 40911 | jldominguez | |
252 | 43313 | fdiaz | featu = ((Feature) diter.next()).getCopy(); |
253 | 42980 | fdiaz | geome = featu.getDefaultGeometry(); |
254 | if (geome == null || geome.getType() == Geometry.TYPES.NULL) { |
||
255 | continue;
|
||
256 | } |
||
257 | 43510 | jjdelcerro | ICoordTrans ct = layer.getCoordTrans(); |
258 | if( ct!=null ) { |
||
259 | geome.reProject(ct); |
||
260 | } |
||
261 | 42980 | fdiaz | if (!setupLabel(featu, lc, cancel, usedFields, viewPort, dpi, duplicateMode)) {
|
262 | continue;
|
||
263 | } |
||
264 | 41789 | fdiaz | |
265 | 42980 | fdiaz | String[] texts = lc.getTexts(); |
266 | 41789 | fdiaz | |
267 | 42980 | fdiaz | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
268 | // check if this text (so label) is already present in
|
||
269 | // the map
|
||
270 | 41789 | fdiaz | |
271 | 42980 | fdiaz | GeometryItem item = labelsToPlace.get(texts); |
272 | if (item == null) { |
||
273 | item = new GeometryItem(geome, 0); |
||
274 | labelsToPlace.put(texts, item); |
||
275 | } |
||
276 | if (item.geom != null) { |
||
277 | 41789 | fdiaz | |
278 | 42980 | fdiaz | notPlacedCount++; |
279 | if (geome.getType() != Geometry.TYPES.POINT) {
|
||
280 | 41789 | fdiaz | |
281 | 42980 | fdiaz | Envelope auxBox = geome.getEnvelope(); |
282 | double perimeterAux = 2 * (auxBox.getLength(0) + auxBox.getLength(1)); |
||
283 | if (perimeterAux > item.savedPerimeter) {
|
||
284 | item.geom = geome; // FConverter.jts_to_igeometry(jtsGeom);
|
||
285 | item.savedPerimeter = perimeterAux; |
||
286 | } |
||
287 | } else {
|
||
288 | int weigh = item.weigh;
|
||
289 | 41789 | fdiaz | |
290 | 42980 | fdiaz | try {
|
291 | Point pointFromLabel = item.geom.centroid();
|
||
292 | Point pointGeome = geome.centroid();
|
||
293 | item.geom = |
||
294 | GeometryLocator.getGeometryManager().createPoint( |
||
295 | (pointFromLabel.getX() * weigh + pointGeome.getX()) / (weigh + 1),
|
||
296 | (pointFromLabel.getY() * weigh + pointGeome.getY()) / (weigh + 1),
|
||
297 | Geometry.SUBTYPES.GEOM2D); |
||
298 | } catch (Exception ex) { |
||
299 | throw new ReadException(layer.getFeatureStore().getProviderName(), ex); |
||
300 | } |
||
301 | 40911 | jldominguez | |
302 | 42980 | fdiaz | } |
303 | } else {
|
||
304 | item.geom = geome; |
||
305 | } |
||
306 | item.weigh++; |
||
307 | } else {
|
||
308 | // Check if size is a pixel
|
||
309 | if (isOnePoint(viewPort, geome)) {
|
||
310 | continue;
|
||
311 | } |
||
312 | 41789 | fdiaz | |
313 | 42980 | fdiaz | List<Geometry> geome_parts = new ArrayList<Geometry>(); |
314 | if (duplicateMode == IPlacementConstraints.ONE_LABEL_PER_FEATURE_PART) {
|
||
315 | geome_parts = getGeometryParts(geome); |
||
316 | } else {
|
||
317 | geome_parts.add(geome); |
||
318 | } |
||
319 | 41789 | fdiaz | |
320 | 42980 | fdiaz | try {
|
321 | int n = geome_parts.size();
|
||
322 | for (int k = 0; k < n; k++) { |
||
323 | drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, geome_parts.get(k), |
||
324 | cancel, dpi, bLabelsReallocatable); |
||
325 | } |
||
326 | } catch (GeometryException e) {
|
||
327 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
328 | } |
||
329 | 41789 | fdiaz | |
330 | 42980 | fdiaz | placedCount++; |
331 | } |
||
332 | } |
||
333 | 41789 | fdiaz | |
334 | 42980 | fdiaz | // ======= End iteration in feature set ====================
|
335 | 40911 | jldominguez | |
336 | 42980 | fdiaz | if (duplicateMode == IPlacementConstraints.REMOVE_DUPLICATE_LABELS) {
|
337 | Iterator<String[]> textsIt = labelsToPlace.keySet().iterator(); |
||
338 | while (!cancel.isCanceled() && textsIt.hasNext()) {
|
||
339 | notPlacedCount++; |
||
340 | String[] texts = textsIt.next(); |
||
341 | 40911 | jldominguez | |
342 | 42980 | fdiaz | GeometryItem item = labelsToPlace.get(texts); |
343 | if (item != null) { |
||
344 | lc.setTexts(texts); |
||
345 | // Check if size is a pixel
|
||
346 | if (isOnePoint(viewPort, item.geom)) {
|
||
347 | continue;
|
||
348 | } |
||
349 | 40911 | jldominguez | |
350 | 42980 | fdiaz | try {
|
351 | drawLabelInGeom(targetBI, targetGr, lc, placement, viewPort, item.geom, cancel, dpi, |
||
352 | bLabelsReallocatable); |
||
353 | } catch (GeometryException e) {
|
||
354 | throw new ReadException(layer.getFeatureStore().getProviderName(), e); |
||
355 | } |
||
356 | } |
||
357 | } |
||
358 | } |
||
359 | 41790 | fdiaz | |
360 | 42980 | fdiaz | if (bLabelsReallocatable) {
|
361 | targetGr.translate(x, y); |
||
362 | if (mapImage != null) { |
||
363 | mapGraphics.drawImage(overlapDetectImage, null, null); |
||
364 | } else {
|
||
365 | mapGraphics.drawImage(overlapDetectImage, null, null); |
||
366 | } |
||
367 | } |
||
368 | 40911 | jldominguez | |
369 | 42980 | fdiaz | } finally {
|
370 | if (diter != null) { |
||
371 | diter.dispose(); |
||
372 | } |
||
373 | if (fset != null) { |
||
374 | fset.dispose(); |
||
375 | } |
||
376 | } |
||
377 | } // big iteration
|
||
378 | 41789 | fdiaz | |
379 | 42980 | fdiaz | } |
380 | |||
381 | 41227 | jldominguez | private List<Geometry> getGeometryParts(Geometry ge) { |
382 | |||
383 | 41789 | fdiaz | List<Geometry> resp = new ArrayList<Geometry>(); |
384 | if (ge != null) { |
||
385 | if (ge instanceof MultiPrimitive) { |
||
386 | MultiPrimitive mp = (MultiPrimitive) ge; |
||
387 | int n = mp.getPrimitivesNumber();
|
||
388 | for (int i = 0; i < n; i++) { |
||
389 | resp.add(mp.getPrimitiveAt(i)); |
||
390 | } |
||
391 | } else {
|
||
392 | resp.add(ge); |
||
393 | } |
||
394 | } |
||
395 | return resp;
|
||
396 | } |
||
397 | 40911 | jldominguez | |
398 | 41789 | fdiaz | private void drawLabelInGeom(BufferedImage targetBI, Graphics2D targetGr, |
399 | ILabelClass lc, ILabelPlacement placement, ViewPort viewPort, |
||
400 | Geometry geom, Cancellable cancel, double dpi,
|
||
401 | boolean bLabelsReallocatable) throws GeometryException { |
||
402 | |||
403 | 40911 | jldominguez | lc.toCartographicSize(viewPort, dpi, null);
|
404 | ArrayList<LabelLocationMetrics> llm = null; |
||
405 | 41789 | fdiaz | llm = placement.guess(lc, geom, getPlacementConstraints(), 0, cancel,
|
406 | viewPort); |
||
407 | 40911 | jldominguez | |
408 | setReferenceSystem(lc.getReferenceSystem()); |
||
409 | setUnit(lc.getUnit()); |
||
410 | |||
411 | /*
|
||
412 | 41789 | fdiaz | * search if there is room left by the previous and with more priority
|
413 | * labels, then check the current level
|
||
414 | 40911 | jldominguez | */
|
415 | 41789 | fdiaz | lookupAndPlaceLabel(targetBI, targetGr, llm, placement, lc, geom, |
416 | viewPort, cancel, bLabelsReallocatable); |
||
417 | 40911 | jldominguez | |
418 | } |
||
419 | |||
420 | private int getDuplicateLabelsMode() { |
||
421 | if (getPlacementConstraints() == null) { |
||
422 | return IPlacementConstraints.DefaultDuplicateLabelsMode;
|
||
423 | } |
||
424 | return getPlacementConstraints().getDuplicateLabelsMode();
|
||
425 | } |
||
426 | |||
427 | private boolean lookupAndPlaceLabel(BufferedImage bi, Graphics2D g, |
||
428 | ArrayList<LabelLocationMetrics> llm, ILabelPlacement placement,
|
||
429 | 41789 | fdiaz | ILabelClass lc, Geometry geom, ViewPort viewPort, |
430 | 40911 | jldominguez | Cancellable cancel, boolean bLabelsReallocatable)
|
431 | 41789 | fdiaz | throws GeometryException {
|
432 | |||
433 | 42980 | fdiaz | GeometryManager gm = GeometryLocator.getGeometryManager(); |
434 | 40911 | jldominguez | int i;
|
435 | for (i = 0; !cancel.isCanceled() && i < llm.size(); i++) { |
||
436 | LabelLocationMetrics labelMetrics = llm.get(i); |
||
437 | |||
438 | IPlacementConstraints pc = getPlacementConstraints(); |
||
439 | 41789 | fdiaz | if (pc instanceof MultiShapePlacementConstraints) { |
440 | MultiShapePlacementConstraints mpc = (MultiShapePlacementConstraints) pc; |
||
441 | |||
442 | 40911 | jldominguez | GeometryType geom_gt = null;
|
443 | 41789 | fdiaz | |
444 | 40911 | jldominguez | geom_gt = gm.getGeometryType(geom.getType(), SUBTYPES.GEOM2D); |
445 | |||
446 | 41789 | fdiaz | if (geom_gt.getType() == TYPES.POINT
|
447 | || geom_gt.getType() == TYPES.MULTIPOINT) { |
||
448 | 40911 | jldominguez | pc = mpc.getPointConstraints(); |
449 | } else {
|
||
450 | 41789 | fdiaz | if (geom_gt.isTypeOf(TYPES.CURVE)
|
451 | || geom_gt.getType() == TYPES.MULTICURVE) { |
||
452 | 40911 | jldominguez | pc = mpc.getLineConstraints(); |
453 | } else {
|
||
454 | 41789 | fdiaz | if (geom_gt.isTypeOf(TYPES.SURFACE)
|
455 | || geom_gt.getType() == TYPES.MULTISURFACE) { |
||
456 | 40911 | jldominguez | pc = mpc.getPolygonConstraints(); |
457 | } |
||
458 | } |
||
459 | } |
||
460 | } |
||
461 | |||
462 | /*
|
||
463 | * Ver comentario en el metodo drawLabelInGeom
|
||
464 | */
|
||
465 | if (bLabelsReallocatable) {
|
||
466 | 41789 | fdiaz | |
467 | 40911 | jldominguez | Geometry aux_geom = null;
|
468 | aux_geom = lc.getShape(labelMetrics); |
||
469 | 41789 | fdiaz | |
470 | 40911 | jldominguez | if (!isOverlapping(bi, aux_geom)) {
|
471 | |||
472 | 41789 | fdiaz | if (!pc.isFollowingLine()) {
|
473 | 40911 | jldominguez | lc.draw(g, labelMetrics, geom); |
474 | } else {
|
||
475 | 41789 | fdiaz | |
476 | 41131 | jldominguez | ILabelClass smsLc = new SmartTextSymbolLabelClass();
|
477 | 41789 | fdiaz | SmartTextSymbol sms = new SmartTextSymbol(
|
478 | lc.getTextSymbol(), pc); |
||
479 | 40911 | jldominguez | |
480 | 41789 | fdiaz | double sizeBefore = lc.getTextSymbol().getFont()
|
481 | .getSize(); |
||
482 | double sizeAfter = SymbolUtils.getCartographicLength(
|
||
483 | this, sizeBefore, viewPort, viewPort.getDPI());
|
||
484 | 40911 | jldominguez | sms.setFontSize(sizeAfter); |
485 | |||
486 | smsLc.setTextSymbol(sms); |
||
487 | geom.transform(viewPort.getAffineTransform()); |
||
488 | smsLc.draw(g, null, geom);
|
||
489 | sms.setFontSize(sizeBefore); |
||
490 | |||
491 | } |
||
492 | return true; |
||
493 | } |
||
494 | } else {
|
||
495 | 41789 | fdiaz | if (!pc.isFollowingLine()) {
|
496 | 40911 | jldominguez | lc.draw(g, labelMetrics, null);
|
497 | 41789 | fdiaz | } else {
|
498 | ILabelClass smsLc = new SmartTextSymbolLabelClass();
|
||
499 | SmartTextSymbol sms = new SmartTextSymbol(
|
||
500 | lc.getTextSymbol(), pc); |
||
501 | 40911 | jldominguez | |
502 | double sizeBefore = lc.getTextSymbol().getFont().getSize();
|
||
503 | double sizeAfter = SymbolUtils.getCartographicLength(this, |
||
504 | 41789 | fdiaz | sizeBefore, viewPort, viewPort.getDPI()); |
505 | 40911 | jldominguez | sms.setFontSize(sizeAfter); |
506 | |||
507 | smsLc.setTextSymbol(sms); |
||
508 | geom.transform(viewPort.getAffineTransform()); |
||
509 | smsLc.draw(g, null, geom);
|
||
510 | |||
511 | sms.setFontSize(sizeBefore); |
||
512 | } |
||
513 | return true; |
||
514 | } |
||
515 | } |
||
516 | return false; |
||
517 | } |
||
518 | |||
519 | /**
|
||
520 | 41789 | fdiaz | * Divide una cadena de caracteres por el caracter dos puntos siempre que no
|
521 | * est? entre comillas.
|
||
522 | 40911 | jldominguez | *
|
523 | * @param str
|
||
524 | * Cadena de caracteres
|
||
525 | *
|
||
526 | * @return String[]
|
||
527 | *
|
||
528 | */
|
||
529 | 41789 | fdiaz | private String[] divideExpression(String str) { |
530 | 40911 | jldominguez | ArrayList<String> r = new ArrayList<String>(); |
531 | boolean inQuotationMarks = false; |
||
532 | int lastIndex = 0; |
||
533 | 41789 | fdiaz | for (int i = 0; i < str.length(); i++) { |
534 | 42171 | jbadia | String currentChar = str.substring(i, i + 1); |
535 | if (currentChar.compareTo("\"") == 0 ) { |
||
536 | 40911 | jldominguez | inQuotationMarks = !inQuotationMarks; |
537 | 42171 | jbadia | // Si es el cierre de las comillas
|
538 | if(!inQuotationMarks){
|
||
539 | r.add(str.substring(lastIndex, i + 1).replace("\"", "'")); |
||
540 | lastIndex = i + 1;
|
||
541 | } |
||
542 | 40911 | jldominguez | } |
543 | 42171 | jbadia | if (currentChar.compareTo(":") == 0 |
544 | 41789 | fdiaz | && !inQuotationMarks) { |
545 | if (lastIndex < i) {
|
||
546 | 40911 | jldominguez | r.add(str.substring(lastIndex, i)); |
547 | } |
||
548 | 41789 | fdiaz | lastIndex = i + 1;
|
549 | 40911 | jldominguez | } |
550 | } |
||
551 | 41789 | fdiaz | if (lastIndex < str.length() - 1) { |
552 | 40911 | jldominguez | r.add(str.substring(lastIndex)); |
553 | } |
||
554 | String[] result = new String[r.size()]; |
||
555 | r.toArray(result); |
||
556 | return result;
|
||
557 | } |
||
558 | |||
559 | /**
|
||
560 | * Compute the texts to show in the label and store them in LabelClass.
|
||
561 | */
|
||
562 | @SuppressWarnings("unchecked") |
||
563 | private boolean setupLabel(Feature featu, ILabelClass lc, |
||
564 | Cancellable cancel, String[] usedFields, ViewPort viewPort, |
||
565 | 41789 | fdiaz | double dpi, int duplicateMode) { |
566 | 40911 | jldominguez | |
567 | String expr = lc.getStringLabelExpression();
|
||
568 | |||
569 | long pt1 = System.currentTimeMillis(); |
||
570 | String[] texts = NO_TEXT; |
||
571 | 41421 | jjdelcerro | List<String> preTexts = new ArrayList<String>(); |
572 | 40911 | jldominguez | try {
|
573 | if (expr != null) { |
||
574 | |||
575 | if (expr.equals("")) { |
||
576 | expr = texts[0];
|
||
577 | } |
||
578 | |||
579 | String[] multiexpr = divideExpression(expr); |
||
580 | 41789 | fdiaz | for (int i = 0; i < multiexpr.length; i++) { |
581 | |||
582 | 40911 | jldominguez | expr = multiexpr[i]; |
583 | 41789 | fdiaz | Object res = LabelClassUtils.evaluate(expr,
|
584 | featu.getEvaluatorData()); |
||
585 | 40911 | jldominguez | if (res != null) { |
586 | preTexts.add(res.toString()); |
||
587 | } else {
|
||
588 | 41421 | jjdelcerro | preTexts.add("");
|
589 | 40911 | jldominguez | } |
590 | } |
||
591 | texts = new String[preTexts.size()]; |
||
592 | preTexts.toArray(texts); |
||
593 | 41789 | fdiaz | // parseTime += System.currentTimeMillis()-pt1;
|
594 | 40911 | jldominguez | } |
595 | lc.setTexts(texts); |
||
596 | |||
597 | } catch (Exception e) { |
||
598 | 41421 | jjdelcerro | logger.warn("While setting up label", e);
|
599 | 40911 | jldominguez | return false; |
600 | } |
||
601 | return true; |
||
602 | } |
||
603 | 41789 | fdiaz | |
604 | 42980 | fdiaz | private boolean isOverlapping(BufferedImage bi, Geometry lblgeom) { |
605 | 41789 | fdiaz | |
606 | 42980 | fdiaz | for (Iterator iterator = drawnGeometryLabels.iterator(); iterator.hasNext();) { |
607 | Geometry drawnGeometry = (Geometry) iterator.next(); |
||
608 | try {
|
||
609 | if (drawnGeometry.intersects(lblgeom)) {
|
||
610 | 42555 | fdiaz | return true; |
611 | } |
||
612 | 42980 | fdiaz | } catch (GeometryOperationNotSupportedException | GeometryOperationException e) {
|
613 | logger.warn("Can't check overlapping geometry");
|
||
614 | 42555 | fdiaz | } |
615 | } |
||
616 | 42980 | fdiaz | drawnGeometryLabels.add(lblgeom); |
617 | return false; |
||
618 | 40911 | jldominguez | |
619 | 42980 | fdiaz | } |
620 | |||
621 | 40911 | jldominguez | private boolean isOnePoint(ViewPort viewPort, Geometry geom) { |
622 | 41789 | fdiaz | |
623 | 40911 | jldominguez | boolean onePoint = false; |
624 | int shapeType = geom.getType();
|
||
625 | 41789 | fdiaz | |
626 | 40911 | jldominguez | if (shapeType != TYPES.POINT && shapeType != TYPES.MULTIPOINT) {
|
627 | |||
628 | Envelope env = geom.getEnvelope(); |
||
629 | double dist1Pixel = viewPort.getDist1pixel();
|
||
630 | 41789 | fdiaz | onePoint = (env.getLength(0) <= dist1Pixel && env.getLength(1) <= dist1Pixel); |
631 | 40911 | jldominguez | } |
632 | return onePoint;
|
||
633 | } |
||
634 | |||
635 | public boolean isAllowingOverlap() { |
||
636 | return allowOverlapping;
|
||
637 | } |
||
638 | |||
639 | public void setAllowOverlapping(boolean allowOverlapping) { |
||
640 | this.allowOverlapping = allowOverlapping;
|
||
641 | } |
||
642 | |||
643 | public IPlacementConstraints getPlacementConstraints() {
|
||
644 | if (placementConstraints != null) |
||
645 | return placementConstraints;
|
||
646 | |||
647 | GeometryType gt = null;
|
||
648 | 41789 | fdiaz | |
649 | 40911 | jldominguez | try {
|
650 | gt = layer.getGeometryType(); |
||
651 | // force 2d for comparison
|
||
652 | gt = GeometryLocator.getGeometryManager().getGeometryType( |
||
653 | gt.getType(), SUBTYPES.GEOM2D); |
||
654 | } catch (Exception e) { |
||
655 | logger.error("While getting placements constraints.", e);
|
||
656 | return null; |
||
657 | } |
||
658 | 41789 | fdiaz | |
659 | if (gt.isTypeOf(TYPES.POINT) || gt.isTypeOf(TYPES.MULTIPOINT)) {
|
||
660 | 40911 | jldominguez | return DefaultPointPlacementConstraints;
|
661 | } else {
|
||
662 | 41789 | fdiaz | if (gt.isTypeOf(TYPES.CURVE) || gt.isTypeOf(TYPES.MULTICURVE)) {
|
663 | 40911 | jldominguez | return DefaultLinePlacementConstraints;
|
664 | } else {
|
||
665 | if (gt.isTypeOf(TYPES.SURFACE)
|
||
666 | || gt.isTypeOf(TYPES.MULTISURFACE)) { |
||
667 | return DefaultPolygonPlacementConstraints;
|
||
668 | } else {
|
||
669 | 41789 | fdiaz | if (gt.isTypeOf(TYPES.AGGREGATE)
|
670 | || gt.isTypeOf(TYPES.GEOMETRY)) { |
||
671 | DefaultMultiShapePlacementConstratints |
||
672 | .setPointConstraints(DefaultPointPlacementConstraints); |
||
673 | DefaultMultiShapePlacementConstratints |
||
674 | .setLineConstraints(DefaultLinePlacementConstraints); |
||
675 | DefaultMultiShapePlacementConstratints |
||
676 | .setPolygonConstraints(DefaultPolygonPlacementConstraints); |
||
677 | 40911 | jldominguez | return DefaultMultiShapePlacementConstratints;
|
678 | } |
||
679 | } |
||
680 | } |
||
681 | } |
||
682 | return null; |
||
683 | } |
||
684 | |||
685 | public void setPlacementConstraints(IPlacementConstraints constraints) { |
||
686 | this.placementConstraints = constraints;
|
||
687 | } |
||
688 | |||
689 | public IZoomConstraints getZoomConstraints() {
|
||
690 | return zoomConstraints;
|
||
691 | } |
||
692 | |||
693 | public void setZoomConstraints(IZoomConstraints constraints) { |
||
694 | this.zoomConstraints = constraints;
|
||
695 | } |
||
696 | |||
697 | 41789 | fdiaz | public void print(Graphics2D g, double scale, ViewPort viewPort, |
698 | 40911 | jldominguez | Cancellable cancel, PrintAttributes properties) |
699 | throws ReadException {
|
||
700 | 41789 | fdiaz | |
701 | 40911 | jldominguez | double dpi = 100; |
702 | int pq = properties.getPrintQuality();
|
||
703 | 41789 | fdiaz | if (pq == PrintAttributes.PRINT_QUALITY_NORMAL) {
|
704 | 40911 | jldominguez | dpi = 300;
|
705 | 41789 | fdiaz | } else if (pq == PrintAttributes.PRINT_QUALITY_HIGH) { |
706 | 40911 | jldominguez | dpi = 600;
|
707 | 41789 | fdiaz | } else if (pq == PrintAttributes.PRINT_QUALITY_DRAFT) { |
708 | 40911 | jldominguez | dpi = 72;
|
709 | } |
||
710 | |||
711 | 41789 | fdiaz | viewPort.setOffset(new Point2D.Double(0, 0)); |
712 | |||
713 | 40911 | jldominguez | /* signal printing output */
|
714 | printMode = true;
|
||
715 | |||
716 | 41789 | fdiaz | draw(null, g, scale, viewPort, cancel, dpi);
|
717 | 40911 | jldominguez | } |
718 | |||
719 | public String[] getUsedFields() { |
||
720 | |||
721 | /*
|
||
722 | 41789 | fdiaz | * TODO Solve the problem with the [ and ]. Currently SQLJEP evaluator
|
723 | * cannot tell which fields are being used. Options: allow [] and remove
|
||
724 | * them or maybe while parsing the SQLJEP evaluator can inform with
|
||
725 | * events like "I have found a field"
|
||
726 | 40911 | jldominguez | */
|
727 | 41789 | fdiaz | |
728 | 40911 | jldominguez | FeatureAttributeDescriptor[] atts = null; |
729 | try {
|
||
730 | 41789 | fdiaz | atts = layer.getFeatureStore().getDefaultFeatureType() |
731 | .getAttributeDescriptors(); |
||
732 | 40911 | jldominguez | } catch (DataException e) {
|
733 | logger.error("While getting atributes.", e);
|
||
734 | } |
||
735 | 41789 | fdiaz | |
736 | 40911 | jldominguez | int n = atts.length;
|
737 | String[] resp = new String[n]; |
||
738 | 41789 | fdiaz | for (int i = 0; i < n; i++) { |
739 | 40911 | jldominguez | resp[i] = atts[i].getName(); |
740 | } |
||
741 | return resp;
|
||
742 | |||
743 | } |
||
744 | |||
745 | public boolean shouldDrawLabels(double scale) { |
||
746 | double minScaleView = -1; |
||
747 | double maxScaleView = -1; |
||
748 | |||
749 | if (zoomConstraints != null) { |
||
750 | minScaleView = zoomConstraints.getMinScale(); |
||
751 | maxScaleView = zoomConstraints.getMaxScale(); |
||
752 | } |
||
753 | |||
754 | if (minScaleView == -1 && maxScaleView == -1) { |
||
755 | // parameters not set, so the layer decides.
|
||
756 | return layer.isWithinScale(scale);
|
||
757 | } |
||
758 | |||
759 | if (minScaleView >= scale) {
|
||
760 | return (maxScaleView != -1) ? maxScaleView <= scale : true; |
||
761 | } |
||
762 | |||
763 | return false; |
||
764 | } |
||
765 | |||
766 | public void setUnit(int unitIndex) { |
||
767 | unit = unitIndex; |
||
768 | |||
769 | } |
||
770 | |||
771 | public int getUnit() { |
||
772 | return unit;
|
||
773 | } |
||
774 | |||
775 | public int getReferenceSystem() { |
||
776 | return referenceSystem;
|
||
777 | } |
||
778 | |||
779 | public void setReferenceSystem(int referenceSystem) { |
||
780 | this.referenceSystem = referenceSystem;
|
||
781 | } |
||
782 | 41789 | fdiaz | |
783 | 40911 | jldominguez | public static void registerPersistent() { |
784 | 41789 | fdiaz | |
785 | PersistenceManager manager = ToolsLocator.getPersistenceManager(); |
||
786 | if (manager.getDefinition(GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME) == null) { |
||
787 | DynStruct definition = manager.addDefinition( |
||
788 | GeneralLabelingStrategy.class, |
||
789 | GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME, |
||
790 | GENERAL_LABEL_STRATEGY_PERSISTENCE_NAME |
||
791 | + " Persistence definition", null, null); |
||
792 | definition.addDynFieldObject("labelingMethod")
|
||
793 | .setClassOfValue(ILabelingMethod.class).setMandatory(true);
|
||
794 | definition.addDynFieldObject("placementConstraints")
|
||
795 | .setClassOfValue(IPlacementConstraints.class) |
||
796 | .setMandatory(false);
|
||
797 | definition.addDynFieldObject("zoomConstraints")
|
||
798 | .setClassOfValue(IZoomConstraints.class) |
||
799 | .setMandatory(false);
|
||
800 | |||
801 | definition.addDynFieldBoolean("allowOverlapping")
|
||
802 | .setMandatory(true);
|
||
803 | definition.addDynFieldInt("unit").setMandatory(true); |
||
804 | definition.addDynFieldInt("referenceSystem").setMandatory(true); |
||
805 | } |
||
806 | 40911 | jldominguez | } |
807 | 41789 | fdiaz | |
808 | public void loadFromState(PersistentState state) |
||
809 | throws PersistenceException {
|
||
810 | |||
811 | 40911 | jldominguez | method = (ILabelingMethod) state.get("labelingMethod");
|
812 | 41789 | fdiaz | |
813 | 40911 | jldominguez | if (state.hasValue("placementConstraints")) { |
814 | 41789 | fdiaz | placementConstraints = (IPlacementConstraints) state |
815 | .get("placementConstraints");
|
||
816 | 40911 | jldominguez | } |
817 | 41789 | fdiaz | |
818 | 40911 | jldominguez | if (state.hasValue("zoomConstraints")) { |
819 | zoomConstraints = (IZoomConstraints) state.get("zoomConstraints");
|
||
820 | } |
||
821 | |||
822 | this.allowOverlapping = state.getBoolean("allowOverlapping"); |
||
823 | this.unit = state.getInt("unit"); |
||
824 | this.referenceSystem = state.getInt("referenceSystem"); |
||
825 | } |
||
826 | |||
827 | public void saveToState(PersistentState state) throws PersistenceException { |
||
828 | 41789 | fdiaz | |
829 | 40911 | jldominguez | state.set("labelingMethod", method);
|
830 | 41789 | fdiaz | |
831 | 40911 | jldominguez | if (placementConstraints != null) { |
832 | state.set("placementConstraints", placementConstraints);
|
||
833 | } |
||
834 | |||
835 | if (zoomConstraints != null) { |
||
836 | state.set("zoomConstraints", zoomConstraints);
|
||
837 | } |
||
838 | |||
839 | state.set("allowOverlapping", allowOverlapping);
|
||
840 | state.set("unit", unit);
|
||
841 | state.set("referenceSystem", referenceSystem);
|
||
842 | |||
843 | } |
||
844 | |||
845 | public double toCartographicSize(ViewPort vp, double dpi, Geometry geom) { |
||
846 | /*
|
||
847 | * This method is not used but we must implement CartographicSupport
|
||
848 | */
|
||
849 | return 0; |
||
850 | } |
||
851 | |||
852 | public void setCartographicSize(double cartographicSize, Geometry geom) { |
||
853 | /*
|
||
854 | * This method is not used but we must implement CartographicSupport
|
||
855 | */
|
||
856 | } |
||
857 | |||
858 | public double getCartographicSize(ViewPort vp, double dpi, Geometry geom) { |
||
859 | /*
|
||
860 | * This method is not used but we must implement CartographicSupport
|
||
861 | */
|
||
862 | return 0; |
||
863 | } |
||
864 | 41789 | fdiaz | |
865 | 40911 | jldominguez | public Object clone() throws CloneNotSupportedException { |
866 | return LabelClassUtils.clone(this); |
||
867 | } |
||
868 | |||
869 | } |