source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/CompletelyInsideAreaStrategy.java@ 15586

Last change on this file since 15586 was 15586, checked in by Don-vip, 4 years ago

code cleanup

File size: 5.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.styleelement.placement;
3
4import java.awt.Rectangle;
5import java.awt.geom.Point2D;
6import java.awt.geom.Rectangle2D;
7
8import org.openstreetmap.josm.gui.MapViewState;
9import org.openstreetmap.josm.gui.draw.MapViewPath;
10import org.openstreetmap.josm.gui.draw.MapViewPositionAndRotation;
11
12/**
13 * Places the label / icon so that it is completely inside the area.
14 *
15 * @author Michael Zangl
16 * @since 11722
17 * @since 11748 moved to own file
18 */
19public class CompletelyInsideAreaStrategy implements PositionForAreaStrategy {
20 /**
21 * An instance of this class.
22 */
23 public static final CompletelyInsideAreaStrategy INSTANCE = new CompletelyInsideAreaStrategy(0, 0);
24
25 protected final double offsetX;
26 protected final double offsetY;
27
28 protected CompletelyInsideAreaStrategy(double offsetX, double offsetY) {
29 this.offsetX = offsetX;
30 this.offsetY = offsetY;
31 }
32
33 @Override
34 public MapViewPositionAndRotation findLabelPlacement(MapViewPath path, Rectangle2D nb) {
35 // Using the Centroid is Nicer for buildings like: +--------+
36 // but this needs to be fast. As most houses are | 42 |
37 // boxes anyway, the center of the bounding box +---++---+
38 // will have to do. ++
39 // Centroids are not optimal either, just imagine a U-shaped house.
40
41 Rectangle pb = path.getBounds();
42
43 // quick check to see if label box is smaller than primitive box
44 if (pb.width < nb.getWidth() || pb.height < nb.getHeight()) {
45 return null;
46 }
47
48 final double w = pb.width - nb.getWidth();
49 final double h = pb.height - nb.getHeight();
50
51 final int x2 = pb.x + (int) (w / 2.0);
52 final int y2 = pb.y + (int) (h / 2.0);
53
54 final int nbw = (int) nb.getWidth();
55 final int nbh = (int) nb.getHeight();
56
57 Rectangle centeredNBounds = new Rectangle(x2, y2, nbw, nbh);
58
59 // slower check to see if label is displayed inside primitive shape
60 if (path.contains(centeredNBounds)) {
61 return centerOf(path.getMapViewState(), centeredNBounds);
62 }
63
64 // if center position (C) is not inside osm shape, try naively some other positions as follows:
65 final int x1 = pb.x + (int) (.25 * w);
66 final int x3 = pb.x + (int) (.75 * w);
67 final int y1 = pb.y + (int) (.25 * h);
68 final int y3 = pb.y + (int) (.75 * h);
69 // +-----------+
70 // | 5 1 6 |
71 // | 4 C 2 |
72 // | 8 3 7 |
73 // +-----------+
74 Rectangle[] candidates = {
75 new Rectangle(x2, y1, nbw, nbh),
76 new Rectangle(x3, y2, nbw, nbh),
77 new Rectangle(x2, y3, nbw, nbh),
78 new Rectangle(x1, y2, nbw, nbh),
79 new Rectangle(x1, y1, nbw, nbh),
80 new Rectangle(x3, y1, nbw, nbh),
81 new Rectangle(x3, y3, nbw, nbh),
82 new Rectangle(x1, y3, nbw, nbh)
83 };
84 // Dumb algorithm to find a better placement. We could surely find a smarter one but it should
85 // solve most of building issues with only few calculations (8 at most)
86 for (int i = 0; i < candidates.length; i++) {
87 centeredNBounds = candidates[i];
88 if (path.contains(centeredNBounds)) {
89 return centerOf(path.getMapViewState(), centeredNBounds);
90 }
91 }
92
93 // none found
94 return null;
95 }
96
97 private MapViewPositionAndRotation centerOf(MapViewState mapViewState, Rectangle centeredNBounds) {
98 double x = centeredNBounds.getCenterX() + offsetX;
99 double y = centeredNBounds.getCenterY() + offsetY;
100 return new MapViewPositionAndRotation(mapViewState.getForView(x, y), 0);
101 }
102
103 @Override
104 public boolean supportsGlyphVector() {
105 return false;
106 }
107
108 @Override
109 public PositionForAreaStrategy withAddedOffset(Point2D addToOffset) {
110 if (Math.abs(addToOffset.getX()) < 1e-5 && Math.abs(addToOffset.getY()) < 1e-5) {
111 return this;
112 } else {
113 return new CompletelyInsideAreaStrategy(offsetX + addToOffset.getX(), offsetY - addToOffset.getY());
114 }
115 }
116
117 @Override
118 public String toString() {
119 return "CompletelyInsideAreaStrategy [offsetX=" + offsetX + ", offsetY=" + offsetY + "]";
120 }
121
122 @Override
123 public int hashCode() {
124 final int prime = 31;
125 int result = 1;
126 long temp;
127 temp = Double.doubleToLongBits(offsetX);
128 result = prime * result + (int) (temp ^ (temp >>> 32));
129 temp = Double.doubleToLongBits(offsetY);
130 result = prime * result + (int) (temp ^ (temp >>> 32));
131 return result;
132 }
133
134 @Override
135 public boolean equals(Object obj) {
136 if (this == obj) {
137 return true;
138 }
139 if (obj == null || getClass() != obj.getClass()) {
140 return false;
141 }
142 CompletelyInsideAreaStrategy other = (CompletelyInsideAreaStrategy) obj;
143 return Double.doubleToLongBits(offsetX) == Double.doubleToLongBits(other.offsetX)
144 && Double.doubleToLongBits(offsetY) == Double.doubleToLongBits(other.offsetY);
145 }
146}
Note: See TracBrowser for help on using the repository browser.