Changeset 3836 in josm
- Timestamp:
- 2011-01-31T14:18:47+01:00 (14 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 3 added
- 2 deleted
- 20 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
r3824 r3836 300 300 *--------*/ 301 301 public StyleCache mappaintStyle = null; 302 public int mappaintDrawnCode = 0;303 302 304 303 /* This should not be called from outside. Fixing the UI to add relevant … … 307 306 public void clearCached() 308 307 { 309 mappaintDrawnCode = 0;310 308 mappaintStyle = null; 311 309 } … … 808 806 public boolean isSelected() { 809 807 return dataSet != null && dataSet.isSelected(this); 808 } 809 810 public boolean isMemberOfSelected() { 811 if (referrers == null) 812 return false; 813 if (referrers instanceof OsmPrimitive) 814 return referrers instanceof Relation && ((OsmPrimitive) referrers).isSelected(); 815 for (OsmPrimitive ref : (OsmPrimitive[]) referrers) { 816 if (ref instanceof Relation && ref.isSelected()) 817 return true; 818 } 819 return false; 810 820 } 811 821 -
trunk/src/org/openstreetmap/josm/data/osm/Way.java
r3630 r3836 110 110 } 111 111 return false; 112 }113 114 /* mappaint data */115 public boolean isMappaintArea = false;116 public Integer mappaintDrawnAreaCode = 0;117 /* end of mappaint data */118 @Override public void clearCached() {119 super.clearCached();120 isMappaintArea = false;121 mappaintDrawnAreaCode = 0;122 112 } 123 113 -
trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java
r3831 r3836 3 3 4 4 import java.awt.Graphics2D; 5 import java.awt.Polygon;6 import java.awt.Rectangle;7 5 import java.awt.RenderingHints; 8 import java.awt.geom.Point2D;9 6 import java.util.ArrayList; 10 import java.util.Collection;11 7 import java.util.Collections; 12 8 import java.util.Comparator; 13 import java.util.Li nkedList;9 import java.util.List; 14 10 15 11 import org.openstreetmap.josm.Main; 16 12 import org.openstreetmap.josm.data.Bounds; 17 import org.openstreetmap.josm.data.coor.EastNorth;18 import org.openstreetmap.josm.data.coor.LatLon;19 13 import org.openstreetmap.josm.data.osm.BBox; 20 14 import org.openstreetmap.josm.data.osm.DataSet; … … 22 16 import org.openstreetmap.josm.data.osm.OsmPrimitive; 23 17 import org.openstreetmap.josm.data.osm.Relation; 24 import org.openstreetmap.josm.data.osm.RelationMember;25 18 import org.openstreetmap.josm.data.osm.Way; 26 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;27 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;28 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;29 19 import org.openstreetmap.josm.gui.NavigatableComponent; 30 20 import org.openstreetmap.josm.gui.mappaint.AreaElemStyle; 31 21 import org.openstreetmap.josm.gui.mappaint.ElemStyle; 32 22 import org.openstreetmap.josm.gui.mappaint.ElemStyles; 33 import org.openstreetmap.josm.gui.mappaint.IconElemStyle;34 23 import org.openstreetmap.josm.gui.mappaint.LineElemStyle; 35 24 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; 36 import org.openstreetmap.josm.gui.mappaint.StyleCache; 25 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle; 26 import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList; 27 import org.openstreetmap.josm.tools.Pair; 37 28 38 29 public class MapPaintVisitor implements PaintVisitor { 39 30 40 31 private Graphics2D g; 32 private boolean inactive; 41 33 private NavigatableComponent nc; 42 34 43 private boolean zoomLevelDisplay;44 private boolean drawMultipolygon;45 private boolean drawRestriction;46 private boolean leftHandTraffic;47 35 private ElemStyles styles; 48 36 private double circum; 49 private double dist;50 private static int paintid = 0;51 private EastNorth minEN;52 private EastNorth maxEN;53 37 private MapPainter painter; 54 38 private MapPaintSettings paintSettings; 55 56 private boolean inactive; 57 58 protected boolean isZoomOk(ElemStyle e) { 59 if (!zoomLevelDisplay) /* show everything if the user wishes so */ 60 return true; 61 62 if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */ 63 return (circum < 1500); 64 65 return !(circum >= e.maxScale || circum < e.minScale); 66 } 67 68 public StyleCache getPrimitiveStyle(OsmPrimitive osm, boolean nodefault) { 69 if(osm.mappaintStyle == null) 70 { 71 if(styles != null) { 72 osm.mappaintStyle = styles.get(osm); 73 if(osm instanceof Way) { 74 ((Way)osm).isMappaintArea = styles.isArea(osm); 75 } 76 } 77 if (osm.mappaintStyle.equals(StyleCache.EMPTY_STYLECACHE)) { 78 if(osm instanceof Node) 79 osm.mappaintStyle = StyleCache.SIMPLE_NODE_STYLECACHE; 80 else if (osm instanceof Way) 81 osm.mappaintStyle = StyleCache.UNTAGGED_WAY_STYLECACHE; 82 } 83 } 84 if (nodefault && osm.mappaintStyle.equals(StyleCache.UNTAGGED_WAY_STYLECACHE)) 85 return StyleCache.EMPTY_STYLECACHE; 86 return osm.mappaintStyle; 87 } 88 89 public IconElemStyle getPrimitiveNodeStyle(OsmPrimitive osm) { 90 if(osm.mappaintStyle == null && styles != null) { 91 IconElemStyle icon = styles.getIcon(osm); 92 osm.mappaintStyle = StyleCache.create(icon); 93 return icon; 94 } 95 for (ElemStyle s : osm.mappaintStyle.getStyles()) { 96 if (s instanceof IconElemStyle) 97 return (IconElemStyle) s; 98 } 99 return null; 100 } 101 102 public boolean isPrimitiveArea(Way osm) { 103 if(osm.mappaintStyle == null && styles != null) { 104 osm.mappaintStyle = styles.get(osm); 105 osm.isMappaintArea = styles.isArea(osm); 106 } 107 return osm.isMappaintArea; 108 } 109 110 public void drawNode(Node n) { 111 /* check, if the node is visible at all */ 112 EastNorth en = n.getEastNorth(); 113 if((en.east() > maxEN.east() ) || 114 (en.north() > maxEN.north()) || 115 (en.east() < minEN.east() ) || 116 (en.north() < minEN.north())) 117 return; 118 119 StyleCache sc = getPrimitiveStyle(n, false); 120 121 for (ElemStyle s : sc.getStyles()) { 122 if (isZoomOk(s)) { 123 s.paintPrimitive(n, paintSettings, painter, data.isSelected(n), false); 124 } 125 126 } 127 } 128 129 public void drawWay(Way w, int fillAreas) { 130 if(w.getNodesCount() < 2) 131 return; 132 133 if (w.hasIncompleteNodes()) 134 return; 135 136 /* check, if the way is visible at all */ 137 double minx = 10000; 138 double maxx = -10000; 139 double miny = 10000; 140 double maxy = -10000; 141 142 for (Node n : w.getNodes()) 143 { 144 if(n.getEastNorth().east() > maxx) { 145 maxx = n.getEastNorth().east(); 146 } 147 if(n.getEastNorth().north() > maxy) { 148 maxy = n.getEastNorth().north(); 149 } 150 if(n.getEastNorth().east() < minx) { 151 minx = n.getEastNorth().east(); 152 } 153 if(n.getEastNorth().north() < miny) { 154 miny = n.getEastNorth().north(); 155 } 156 } 157 158 if ((minx > maxEN.east()) || 159 (miny > maxEN.north()) || 160 (maxx < minEN.east()) || 161 (maxy < minEN.north())) 162 return; 163 164 StyleCache sc = getPrimitiveStyle(w, false); 165 for (ElemStyle s : sc.getStyles()) { 166 if(!isZoomOk(s)) 167 return; 168 if (fillAreas > dist || !(s instanceof AreaElemStyle)) { 169 s.paintPrimitive(w, paintSettings, painter, data.isSelected(w), false); 170 } 171 } 172 } 173 174 public void paintUnselectedRelation(Relation r) { 175 if (drawMultipolygon && "multipolygon".equals(r.get("type"))) 176 drawMultipolygon(r); 177 else if (drawRestriction && "restriction".equals(r.get("type"))) { 178 IconElemStyle nodeStyle = getPrimitiveNodeStyle(r); 179 if (nodeStyle != null) { 180 painter.drawRestriction(r, leftHandTraffic, nodeStyle); 181 } 182 } 183 } 184 185 public boolean drawMultipolygon(Relation r) { 186 boolean drawn = false; 187 188 Multipolygon multipolygon = new Multipolygon(nc); 189 multipolygon.load(r); 190 191 AreaElemStyle areaStyle = null; 192 LineElemStyle lineStyle = null; 193 for (ElemStyle s : getPrimitiveStyle(r, false).getStyles()) { 194 if (s instanceof AreaElemStyle) { 195 areaStyle = (AreaElemStyle) s; 196 } else if (s instanceof LineElemStyle) { 197 lineStyle = (LineElemStyle) s; 198 } 199 } 200 201 boolean disabled = r.isDisabled(); 202 // If area style was not found for relation then use style of ways 203 if(styles != null && areaStyle == null) { 204 for (Way w : multipolygon.getOuterWays()) { 205 for (ElemStyle s : styles.getArea(w).getStyles()) { 206 if (s instanceof AreaElemStyle) { 207 areaStyle = (AreaElemStyle) s; 208 } else if (s instanceof LineElemStyle) { 209 lineStyle = (LineElemStyle) s; 210 } 211 } 212 disabled = disabled || w.isDisabled(); 213 if(areaStyle != null) { 214 break; 215 } 216 } 217 } 218 219 if (areaStyle != null) { 220 boolean zoomok = isZoomOk(areaStyle); 221 boolean visible = false; 222 223 drawn = true; 224 225 if(zoomok && !disabled && !multipolygon.getOuterWays().isEmpty()) { 226 for (PolyData pd : multipolygon.getCombinedPolygons()) { 227 Polygon p = pd.get(); 228 if(!isPolygonVisible(p)) { 229 continue; 230 } 231 232 boolean selected = pd.selected || data.isSelected(r); 233 painter.drawArea(p, selected ? paintSettings.getRelationSelectedColor() 234 : areaStyle.color, painter.getAreaName(r)); 235 visible = true; 236 } 237 } 238 239 if(!visible) 240 return drawn; 241 for (Way wInner : multipolygon.getInnerWays()) { 242 StyleCache inner = getPrimitiveStyle(wInner, true); 243 AreaElemStyle innerArea = null; 244 for (ElemStyle s : inner.getStyles()) { 245 if (s instanceof AreaElemStyle) { 246 innerArea = (AreaElemStyle) s; 247 break; 248 } 249 } 250 251 if(inner.getStyles().isEmpty()) { 252 if (data.isSelected(wInner) || disabled) 253 continue; 254 if(zoomok && (wInner.mappaintDrawnCode != paintid || multipolygon.getOuterWays().isEmpty())) { 255 lineStyle.paintPrimitive(wInner, paintSettings, 256 painter, (data.isSelected(wInner) || data.isSelected(r)), false); 257 } 258 wInner.mappaintDrawnCode = paintid; 259 } 260 else { 261 if(areaStyle.equals(innerArea)) { 262 wInner.mappaintDrawnAreaCode = paintid; 263 264 if(!data.isSelected(wInner)) { 265 wInner.mappaintDrawnCode = paintid; 266 drawWay(wInner, 0); 267 } 268 } 269 } 270 } 271 for (Way wOuter : multipolygon.getOuterWays()) { 272 StyleCache outer = getPrimitiveStyle(wOuter, true); 273 boolean hasOuterArea = false; 274 for (ElemStyle s : outer.getStyles()) { 275 if (s instanceof AreaElemStyle) { 276 hasOuterArea = true; 277 break; 278 } 279 } 280 281 if (outer.getStyles().isEmpty()) { 282 // Selected ways are drawn at the very end 283 if (data.isSelected(wOuter)) 284 continue; 285 if(zoomok) { 286 lineStyle.paintPrimitive(wOuter, paintSettings, painter, 287 (data.isSelected(wOuter) || data.isSelected(r)), r.isSelected()); 288 } 289 wOuter.mappaintDrawnCode = paintid; 290 } else if (hasOuterArea) { 291 wOuter.mappaintDrawnAreaCode = paintid; 292 if(!data.isSelected(wOuter)) { 293 wOuter.mappaintDrawnCode = paintid; 294 drawWay(wOuter, 0); 295 } 296 } 297 } 298 } 299 return drawn; 300 } 301 302 protected boolean isPolygonVisible(Polygon polygon) { 303 Rectangle bounds = polygon.getBounds(); 304 if (bounds.width == 0 && bounds.height == 0) return false; 305 if (bounds.x > nc.getWidth()) return false; 306 if (bounds.y > nc.getHeight()) return false; 307 if (bounds.x + bounds.width < 0) return false; 308 if (bounds.y + bounds.height < 0) return false; 309 return true; 310 } 311 312 protected Point2D getCentroid(Polygon p) 313 { 314 double cx = 0.0, cy = 0.0, a = 0.0; 315 316 // usually requires points[0] == points[npoints] and can then use i+1 instead of j. 317 // Faked it slowly using j. If this is really gets used, this should be fixed. 318 for (int i = 0; i < p.npoints; i++) { 319 int j = i+1 == p.npoints ? 0 : i+1; 320 a += (p.xpoints[i] * p.ypoints[j]) - (p.ypoints[i] * p.xpoints[j]); 321 cx += (p.xpoints[i] + p.xpoints[j]) * (p.xpoints[i] * p.ypoints[j] - p.ypoints[i] * p.xpoints[j]); 322 cy += (p.ypoints[i] + p.ypoints[j]) * (p.xpoints[i] * p.ypoints[j] - p.ypoints[i] * p.xpoints[j]); 323 } 324 return new Point2D.Double(cx / (3.0*a), cy / (3.0*a)); 325 } 326 327 protected double getArea(Polygon p) 328 { 329 double sum = 0.0; 330 331 // usually requires points[0] == points[npoints] and can then use i+1 instead of j. 332 // Faked it slowly using j. If this is really gets used, this should be fixed. 333 for (int i = 0; i < p.npoints; i++) { 334 int j = i+1 == p.npoints ? 0 : i+1; 335 sum = sum + (p.xpoints[i] * p.ypoints[j]) - (p.ypoints[i] * p.xpoints[j]); 336 } 337 return Math.abs(sum/2.0); 338 } 339 340 DataSet data; 341 342 <T extends OsmPrimitive> Collection<T> selectedLast(final DataSet data, Collection <T> prims) { 343 ArrayList<T> sorted = new ArrayList<T>(prims); 344 Collections.sort(sorted, 345 new Comparator<T>() { 346 public int compare(T o1, T o2) { 347 boolean s1 = data.isSelected(o1); 348 boolean s2 = data.isSelected(o2); 349 if (s1 && !s2) 350 return 1; 351 if (!s1 && s2) 352 return -1; 353 return o1.compareTo(o2); 354 } 355 }); 356 return sorted; 357 } 358 359 /* Shows areas before non-areas */ 39 private DataSet data; 40 41 private class StyleCollector { 42 private List<Pair<ElemStyle, OsmPrimitive>> styleElems; 43 protected boolean memberSelected = false; 44 private Class klass; 45 46 public StyleCollector(Class<?> klass) { 47 styleElems = new ArrayList<Pair<ElemStyle, OsmPrimitive>>(); 48 this.klass = klass; 49 } 50 51 public void add(OsmPrimitive osm) { 52 StyleList sl = styles.get(osm, circum, nc); 53 for (ElemStyle s : sl) { 54 if (klass.isInstance(s)) { 55 styleElems.add(new Pair<ElemStyle, OsmPrimitive>(s, osm)); 56 } 57 } 58 } 59 60 public void drawAll() { 61 Collections.sort(styleElems, STYLE_COMPARATOR); 62 for (Pair<ElemStyle, OsmPrimitive> p : styleElems) { 63 p.a.paintPrimitive(p.b, paintSettings, painter, data.isSelected(p.b), memberSelected); 64 } 65 } 66 67 public boolean isMemberSelected() { 68 return memberSelected; 69 } 70 71 public void setMemberSelected(boolean memberSelected) { 72 this.memberSelected = memberSelected; 73 } 74 } 75 76 private final static Comparator<Pair<ElemStyle, OsmPrimitive>> STYLE_COMPARATOR = new Comparator<Pair<ElemStyle, OsmPrimitive>>() { 77 @Override 78 public int compare(Pair<ElemStyle, OsmPrimitive> p1, Pair<ElemStyle, OsmPrimitive> p2) { 79 int d1 = Float.compare(p1.a.z_index, p2.a.z_index); 80 if (d1 != 0) 81 return d1; 82 if (p1.a == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && p2.a != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE) 83 return 1; 84 if (p1.a != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && p2.a == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE) 85 return -1; 86 // newer primitives to the front 87 long id = p1.b.getUniqueId() - p2.b.getUniqueId(); 88 if (id > 0) 89 return 1; 90 if (id < 0) 91 return -1; 92 return Float.compare(p1.a.object_z_index, p2.a.object_z_index); 93 } 94 }; 95 360 96 public void visitAll(final DataSet data, boolean virtual, Bounds bounds) { 361 97 //long start = System.currentTimeMillis(); 362 98 BBox bbox = new BBox(bounds); 363 99 this.data = data; 364 ++paintid; 365 366 int fillAreas = Main.pref.getInteger("mappaint.fillareas", 10000000); 367 LatLon ll1 = nc.getLatLon(0, 0); 368 LatLon ll2 = nc.getLatLon(100, 0); 369 dist = ll1.greatCircleDistance(ll2); 370 371 zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay", false); 100 101 styles = MapPaintStyles.getStyles(); 102 372 103 circum = nc.getDist100Pixel(); 373 styles = MapPaintStyles.getStyles(); 374 drawMultipolygon = Main.pref.getBoolean("mappaint.multipolygon", true); 375 drawRestriction = Main.pref.getBoolean("mappaint.restriction", true); 376 leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false); 377 minEN = nc.getEastNorth(0, nc.getHeight() - 1); 378 maxEN = nc.getEastNorth(nc.getWidth() - 1, 0); 104 boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000); 105 boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true); 106 styles.setDrawMultipolygon(drawMultipolygon); 107 boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true); 108 boolean leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false); 379 109 380 110 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, … … 383 113 384 114 this.paintSettings = MapPaintSettings.INSTANCE; 385 this.painter = new MapPainter(paintSettings, g, inactive, nc, virtual, dist, circum); 386 387 if (fillAreas > dist && styles != null && styles.hasAreas()) { 388 Collection<Way> noAreaWays = new LinkedList<Way>(); 389 final Collection<Way> ways = data.searchWays(bbox); 390 391 /*** disabled ***/ 392 for (final Way osm : ways) { 393 if (osm.isDisabled() && osm.isDrawable() && osm.mappaintDrawnCode != paintid) { 394 drawWay(osm, 0); 395 osm.mappaintDrawnCode = paintid; 396 } 397 } 398 399 /*** RELATIONS ***/ 400 for (final Relation osm: data.searchRelations(bbox)) { 401 if (osm.isDrawable()) { 402 paintUnselectedRelation(osm); 403 } 404 } 405 406 /*** AREAS ***/ 407 for (final Way osm : selectedLast(data, ways)) { 408 if (osm.isDrawable() && osm.mappaintDrawnCode != paintid) { 409 if (isPrimitiveArea(osm)) { 410 if(osm.mappaintDrawnAreaCode != paintid) 411 drawWay(osm, fillAreas); 412 } else if(!data.isSelected(osm)) { 413 noAreaWays.add(osm); 414 } 415 } 416 } 417 418 /*** WAYS ***/ 419 for (final Way osm : noAreaWays) { 420 drawWay(osm, 0); 421 osm.mappaintDrawnCode = paintid; 422 } 423 } else { 424 drawMultipolygon = false; 425 final Collection<Way> ways = data.searchWays(bbox); 426 427 /*** WAYS (disabled) ***/ 428 for (final Way way: ways) { 429 if (way.isDisabled() && way.isDrawable() && !data.isSelected(way)) { 430 drawWay(way, 0); 431 way.mappaintDrawnCode = paintid; 432 } 433 } 434 435 /*** RELATIONS ***/ 436 for (final Relation osm: data.searchRelations(bbox)) { 437 if (osm.isDrawable()) { 438 paintUnselectedRelation(osm); 439 } 440 } 441 442 /*** WAYS (filling disabled) ***/ 443 for (final Way way: ways) { 444 if (way.isDrawable() && !data.isSelected(way)) { 445 drawWay(way, 0); 446 } 447 } 448 } 449 450 /*** SELECTED ***/ 451 for (final OsmPrimitive osm : data.getSelected()) { 452 if (osm.isUsable() && !(osm instanceof Node) && (osm instanceof Relation || osm.mappaintDrawnCode != paintid)) { 453 osm.visit(new AbstractVisitor() { 454 public void visit(Way w) { 455 drawWay(w, 0); 456 } 457 458 public void visit(Node n) { 459 // Selected nodes are painted in following part 460 } 461 462 public void visit(Relation r) { 463 for (RelationMember m : r.getMembers()) { 464 OsmPrimitive osm = m.getMember(); 465 if(osm.isDrawable()) { 466 StyleCache sc = getPrimitiveStyle(m.getMember(), false); 467 if(osm instanceof Way) 468 { 469 for (ElemStyle s : sc.getStyles()) { 470 if (!(s instanceof AreaElemStyle)) { 471 s.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true); 472 } 473 } 474 } 475 else if(osm instanceof Node) 476 { 477 for (ElemStyle s : sc.getStyles()) { 478 if (isZoomOk(s)) { 479 s.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true); 480 } 481 } 482 } 483 osm.mappaintDrawnCode = paintid; 484 } 485 } 486 } 487 }); 488 } 489 } 490 491 /*** NODES ***/ 492 for (final Node osm: data.searchNodes(bbox)) { 493 if (!osm.isIncomplete() && !osm.isDeleted() && (data.isSelected(osm) || !osm.isDisabledAndHidden()) 494 && osm.mappaintDrawnCode != paintid) { 495 drawNode(osm); 496 } 497 } 115 this.painter = new MapPainter(paintSettings, g, inactive, nc, virtual, circum, leftHandTraffic); 116 117 StyleCollector scDisabledLines = new StyleCollector(LineElemStyle.class); 118 StyleCollector scSelectedLines = new StyleCollector(LineElemStyle.class); 119 StyleCollector scSelectedAreas = new StyleCollector(AreaElemStyle.class); 120 StyleCollector scMemberLines = new StyleCollector(LineElemStyle.class); 121 scMemberLines.setMemberSelected(true); 122 StyleCollector scNormalAreas = new StyleCollector(AreaElemStyle.class); 123 StyleCollector scNormalLines = new StyleCollector(LineElemStyle.class); 124 for (final Way w : data.searchWays(bbox)) { 125 if (w.isDrawable()) { 126 if (w.isDisabled()) { 127 scDisabledLines.add(w); 128 } else if (w.isSelected()) { 129 scSelectedLines.add(w); 130 if (drawArea) { 131 scSelectedAreas.add(w); 132 } 133 } else if (w.isMemberOfSelected()) { 134 scMemberLines.add(w); 135 if (drawArea) { 136 scNormalAreas.add(w); 137 } 138 } else { 139 scNormalLines.add(w); 140 if (drawArea) { 141 scNormalAreas.add(w); 142 } 143 } 144 } 145 } 146 scDisabledLines.drawAll(); 147 scDisabledLines = null; 148 149 StyleCollector scDisabledNodes = new StyleCollector(NodeElemStyle.class); 150 StyleCollector scSelectedNodes = new StyleCollector(NodeElemStyle.class); 151 StyleCollector scMemberNodes = new StyleCollector(NodeElemStyle.class); 152 scMemberNodes.setMemberSelected(true); 153 StyleCollector scNormalNodes = new StyleCollector(NodeElemStyle.class); 154 for (final Node n: data.searchNodes(bbox)) { 155 if (n.isDrawable()) { 156 if (n.isDisabled()) { 157 scDisabledNodes.add(n); 158 } else if (n.isSelected()) { 159 scSelectedNodes.add(n); 160 } else if (n.isMemberOfSelected()) { 161 scMemberNodes.add(n); 162 } else { 163 scNormalNodes.add(n); 164 } 165 } 166 } 167 scDisabledNodes.drawAll(); 168 scDisabledNodes = null; 169 170 StyleCollector scDisabledRestrictions = new StyleCollector(NodeElemStyle.class); 171 StyleCollector scNormalRestrictions = new StyleCollector(NodeElemStyle.class); 172 StyleCollector scSelectedRestrictions = new StyleCollector(NodeElemStyle.class); 173 for (Relation r: data.searchRelations(bbox)) { 174 if (r.isDrawable()) { 175 if (r.isDisabled()) { 176 if (drawRestriction) { 177 scDisabledRestrictions.add(r); 178 } 179 } else if (r.isSelected()) { 180 if (drawMultipolygon) { 181 scSelectedAreas.add(r); 182 } 183 if (drawRestriction) { 184 scSelectedRestrictions.add(r); 185 } 186 } else { 187 if (drawMultipolygon) { 188 scNormalAreas.add(r); 189 } 190 if (drawRestriction) { 191 scNormalRestrictions.add(r); 192 } 193 } 194 } 195 } 196 scDisabledRestrictions.drawAll(); 197 scDisabledRestrictions = null; 198 199 scNormalAreas.drawAll(); 200 scSelectedAreas.drawAll(); 201 scNormalLines.drawAll(); 202 scMemberLines.drawAll(); 203 scSelectedLines.drawAll(); 204 scNormalNodes.drawAll(); 205 scNormalRestrictions.drawAll(); 206 scMemberNodes.drawAll(); 207 scSelectedRestrictions.drawAll(); 208 scSelectedNodes.drawAll(); 498 209 499 210 painter.drawVirtualNodes(data.searchWays(bbox)); 500 //System.err.println("PAINTING TOOK "+(System.currentTimeMillis() - start) );211 //System.err.println("PAINTING TOOK "+(System.currentTimeMillis() - start)+ " (at scale "+circum+")"); 501 212 } 502 213 -
trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java
r3831 r3836 26 26 import org.openstreetmap.josm.data.osm.RelationMember; 27 27 import org.openstreetmap.josm.data.osm.Way; 28 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon; 29 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData; 28 30 import org.openstreetmap.josm.gui.NavigatableComponent; 29 import org.openstreetmap.josm.gui.mappaint. IconElemStyle;31 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle; 30 32 import org.openstreetmap.josm.tools.ImageProvider; 31 33 import org.openstreetmap.josm.tools.LanguageInfo; … … 58 60 private final double circum; 59 61 62 private final boolean leftHandTraffic; 63 60 64 private final Collection<String> regionalNameOrder; 61 65 … … 66 70 public MapPainter(MapPaintSettings settings, Graphics2D g, 67 71 boolean inactive, NavigatableComponent nc, boolean virtual, 68 double dist, double circum) {69 72 double circum, boolean leftHandTraffic) 73 { 70 74 this.g = g; 71 75 this.inactive = inactive; 72 76 this.nc = nc; 73 this.useStrokes = settings.getUseStrokesDistance() > dist;74 this.showNames = settings.getShowNamesDistance() > dist;75 this.showIcons = settings.getShowIconsDistance() > dist;77 this.useStrokes = settings.getUseStrokesDistance() > circum; 78 this.showNames = settings.getShowNamesDistance() > circum; 79 this.showIcons = settings.getShowIconsDistance() > circum; 76 80 this.outlineOnly = settings.isOutlineOnly(); 77 81 … … 93 97 this.regionalNameOrder = Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(names)); 94 98 this.circum = circum; 95 } 96 97 public void drawWay(Way way, Color color, int width, float dashed[], Color dashedColor, boolean showDirection, 99 this.leftHandTraffic = leftHandTraffic; 100 } 101 102 public void drawWay(Way way, Color color, float width, float dashed[], Color dashedColor, boolean showDirection, 98 103 boolean reversedDirection, boolean showHeadArrowOnly) { 99 104 … … 154 159 } 155 160 156 private void displaySegments(GeneralPath path, GeneralPath arrows, Color color, int width, float dashed[], Color dashedColor) {161 private void displaySegments(GeneralPath path, GeneralPath arrows, Color color, float width, float dashed[], Color dashedColor) { 157 162 g.setColor(inactive ? inactiveColor : color); 158 163 if (useStrokes) { 159 if (dashed .length > 0) {164 if (dashed == null || dashed.length > 0) { 160 165 g.setStroke(new BasicStroke(width,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0, dashed,0)); 161 166 } else { … … 168 173 if(!inactive && useStrokes && dashedColor != null) { 169 174 g.setColor(dashedColor); 170 if (dashed .length > 0) {175 if (dashed == null || dashed.length > 0) { 171 176 float[] dashedOffset = new float[dashed.length]; 172 177 System.arraycopy(dashed, 1, dashedOffset, 0, dashed.length - 1); … … 319 324 } 320 325 326 public void drawArea(Relation r, Color color, String name) { 327 Multipolygon multipolygon = new Multipolygon(nc); 328 multipolygon.load(r); 329 if(!r.isDisabled() && !multipolygon.getOuterWays().isEmpty()) { 330 for (PolyData pd : multipolygon.getCombinedPolygons()) { 331 Polygon p = pd.get(); 332 if(!isPolygonVisible(p)) { 333 continue; 334 } 335 drawArea(p, color, getAreaName(r)); 336 } 337 } 338 } 339 340 private boolean isPolygonVisible(Polygon polygon) { 341 Rectangle bounds = polygon.getBounds(); 342 if (bounds.width == 0 && bounds.height == 0) return false; 343 if (bounds.x > nc.getWidth()) return false; 344 if (bounds.y > nc.getHeight()) return false; 345 if (bounds.x + bounds.width < 0) return false; 346 if (bounds.y + bounds.height < 0) return false; 347 return true; 348 } 349 321 350 public void drawRestriction(ImageIcon icon, Point pVia, double vx, double vx2, double vy, double vy2, double iconAngle, boolean selected) { 322 351 /* rotate icon with direction last node in from to */ … … 334 363 } 335 364 336 public void drawRestriction(Relation r, boolean leftHandTraffic, IconElemStyle icon) {365 public void drawRestriction(Relation r, NodeElemStyle icon) { 337 366 338 367 Way fromWay = null; -
trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java
r3825 r3836 26 26 import org.openstreetmap.josm.gui.mappaint.ElemStyles; 27 27 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; 28 import org.openstreetmap.josm.gui.mappaint.StyleCache;29 28 import org.openstreetmap.josm.gui.mappaint.xml.AreaPrototype; 30 29 … … 47 46 private final List<List<Node>> nonClosedWays = new ArrayList<List<Node>>(); 48 47 48 private final double SCALE = 1.0; // arbitrary scale - we could test every possible scale, but this should suffice 49 49 50 public MultipolygonTest() { 50 51 super(tr("Multipolygon"), … … 115 116 public void visit(Way w) { 116 117 if (styles != null && !w.isClosed()) { 117 AreaPrototype e = styles.getAreaProto(w); 118 if (e != null && ! e.closed) { 119 errors.add( new TestError(this, Severity.WARNING, tr("Area style way is not closed"), NOT_CLOSED, w)); 118 for (ElemStyle s : styles.generateStyles(w, SCALE, null, false).a) { 119 if (s instanceof AreaElemStyle) { 120 errors.add( new TestError(this, Severity.WARNING, tr("Area style way is not closed"), NOT_CLOSED, w)); 121 break; 122 } 120 123 } 121 124 } … … 143 146 List<List<Node>> outerWays = joinWays(polygon.getOuterWays()); 144 147 if (styles != null) { 145 StyleCache sc = styles.get(r);146 148 147 149 AreaElemStyle area = null; 148 for (ElemStyle s : s c.getStyles()) {150 for (ElemStyle s : styles.generateStyles(r, SCALE, null, false).a) { 149 151 if (s instanceof AreaElemStyle) { 150 152 area = (AreaElemStyle) s; … … 155 157 if (area == null) { 156 158 errors.add( new TestError(this, Severity.OTHER, tr("No style in multipolygon relation"), 157 NO_STYLE_POLYGON, r));159 NO_STYLE_POLYGON, r)); 158 160 for (Way w : polygon.getOuterWays()) { 159 161 160 for (ElemStyle s : styles.ge tArea(w).getStyles()) {162 for (ElemStyle s : styles.generateStyles(r, SCALE, null, true).a) { 161 163 if (s instanceof AreaElemStyle) { 162 164 area = (AreaElemStyle) s; … … 173 175 for (Way wInner : polygon.getInnerWays()) { 174 176 AreaElemStyle areaInner = null; 175 for (ElemStyle s : styles.ge t(wInner).getStyles()) {177 for (ElemStyle s : styles.generateStyles(wInner, SCALE, null, false).a) { 176 178 if (s instanceof AreaElemStyle) { 177 179 areaInner = (AreaElemStyle) s; … … 185 187 l.add(wInner); 186 188 errors.add( new TestError(this, Severity.WARNING, tr("Style for inner way equals multipolygon"), 187 INNER_STYLE_MISMATCH, l, Collections.singletonList(wInner)));189 INNER_STYLE_MISMATCH, l, Collections.singletonList(wInner))); 188 190 } 189 191 } 190 192 for (Way wOuter : polygon.getOuterWays()) { 191 193 AreaElemStyle areaOuter = null; 192 for (ElemStyle s : styles.ge t(wOuter).getStyles()) {194 for (ElemStyle s : styles.generateStyles(wOuter, SCALE, null, false).a) { 193 195 if (s instanceof AreaElemStyle) { 194 196 areaOuter = (AreaElemStyle) s; -
trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java
r3824 r3836 5 5 6 6 import org.openstreetmap.josm.data.osm.OsmPrimitive; 7 import org.openstreetmap.josm.data.osm.Relation; 7 8 import org.openstreetmap.josm.data.osm.Way; 8 9 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings; … … 14 15 public Color color; 15 16 16 p ublic AreaElemStyle(long minScale, long maxScale, Color color) {17 super( minScale, maxScale);17 protected AreaElemStyle(Cascade c, Color color) { 18 super(c); 18 19 this.color = color; 20 } 21 22 public static AreaElemStyle create(Cascade c) { 23 Color color = c.get("fill-color", null, Color.class); 24 if (color == null) 25 return null; 26 return new AreaElemStyle(c, color); 19 27 } 20 28 … … 25 33 String name = painter.isShowNames() ? painter.getAreaName(w) : null; 26 34 painter.drawArea(w, w.isSelected() ? paintSettings.getSelectedColor() : color, name); 27 // line.paintPrimitive(way, paintSettings, painter, selected); 35 } else if (primitive instanceof Relation) { 36 painter.drawArea((Relation) primitive, selected ? paintSettings.getRelationSelectedColor() : color, painter.getAreaName(primitive)); 28 37 } 29 38 } … … 40 49 @Override 41 50 public int hashCode() { 42 return color.hashCode();51 return 11 * super.hashCode() + color.hashCode(); 43 52 } 44 53 45 54 @Override 46 55 public String toString() { 47 return "AreaElemStyle{" + "color=" + color + '}';56 return "AreaElemStyle{" + super.toString() + "color=" + color + '}'; 48 57 } 49 58 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java
r3824 r3836 7 7 8 8 abstract public class ElemStyle { 9 // zoom range to display the feature10 public long minScale;11 public long maxScale;9 10 public float z_index; 11 public float object_z_index; 12 12 13 public ElemStyle( long minScale, long maxScale) {14 this. minScale = minScale;15 this. maxScale = maxScale;13 public ElemStyle(float z_index, float object_z_index) { 14 this.z_index = z_index; 15 this.object_z_index = object_z_index; 16 16 } 17 18 protected ElemStyle(Cascade c) { 19 z_index = c.get("z-index", 0f, Float.class); 20 object_z_index = c.get("object-z-index", 0f, Float.class); 21 } 22 23 public abstract void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member); 17 24 18 25 @Override … … 21 28 return false; 22 29 ElemStyle s = (ElemStyle) o; 23 return minScale == s.minScale && maxScale == s.maxScale;30 return z_index == s.z_index && object_z_index == s.object_z_index; 24 31 } 25 32 26 33 @Override 27 34 public int hashCode() { 28 return getClass().hashCode(); 35 int hash = 5; 36 hash = 41 * hash + Float.floatToIntBits(this.z_index); 37 hash = 41 * hash + Float.floatToIntBits(this.object_z_index); 38 return hash; 29 39 } 30 40 31 public abstract void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member); 41 @Override 42 public String toString() { 43 if (z_index != 0f || object_z_index != 0f) 44 return String.format("z_idx=%s/%s ", z_index, object_z_index); 45 return ""; 46 } 32 47 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
r3825 r3836 2 2 package org.openstreetmap.josm.gui.mappaint; 3 3 4 import static org.openstreetmap.josm.tools.Utils.equal; 5 4 import java.awt.Color; 6 5 import java.util.ArrayList; 7 6 import java.util.Collection; 8 7 import java.util.HashSet; 8 import java.util.Iterator; 9 9 import java.util.List; 10 import java.util.Map.Entry; 10 11 import java.util.Set; 11 12 … … 13 14 import org.openstreetmap.josm.data.osm.Node; 14 15 import org.openstreetmap.josm.data.osm.OsmPrimitive; 16 import org.openstreetmap.josm.data.osm.Relation; 15 17 import org.openstreetmap.josm.data.osm.Way; 16 import org.openstreetmap.josm.gui.mappaint.xml.AreaPrototype; 17 import org.openstreetmap.josm.gui.mappaint.xml.IconPrototype; 18 import org.openstreetmap.josm.gui.mappaint.xml.LinePrototype; 19 import org.openstreetmap.josm.gui.mappaint.xml.LinemodPrototype; 18 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon; 19 import org.openstreetmap.josm.gui.NavigatableComponent; 20 import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList; 20 21 import org.openstreetmap.josm.gui.mappaint.xml.XmlStyleSource; 21 22 import org.openstreetmap.josm.tools.FilteredCollection; 23 import org.openstreetmap.josm.tools.Pair; 22 24 import org.openstreetmap.josm.tools.Predicate; 25 import org.openstreetmap.josm.tools.Utils; 23 26 24 27 public class ElemStyles { 25 28 private List<XmlStyleSource> styleSources; 29 private boolean drawMultipolygon; 26 30 27 31 public ElemStyles() … … 41 45 @Override 42 46 public boolean evaluate(XmlStyleSource s) { 43 return equal(s.getPrefName(), name);47 return Utils.equal(s.getPrefName(), name); 44 48 } 45 49 46 50 }); 47 }48 49 public static class WayPrototypesRecord {50 public LinePrototype line;51 public List<LinemodPrototype> linemods;52 public AreaPrototype area;53 54 public List<ElemStyle> createStyles() {55 List<ElemStyle> ret = new ArrayList<ElemStyle>();56 if (area != null) {57 ret.add(area.createStyle());58 }59 if (line != null) {60 ret.add(line.createStyle());61 } else {62 if (area != null) {63 ret.add(LineElemStyle.createSimpleLineStyle(area.color));64 } else {65 ret.add(LineElemStyle.UNTAGGED_WAY);66 }67 }68 69 if (linemods != null) {70 for (LinemodPrototype p : linemods) {71 LineElemStyle s = p.createStyle(line.getWidth());72 if (p.over) {73 ret.add(s);74 } else {75 ret.add(0, s);76 }77 }78 }79 return ret;80 }81 }82 83 public StyleCache get(OsmPrimitive osm) {84 if (osm instanceof Node) {85 IconPrototype icon = getNode(osm);86 if (icon == null)87 return StyleCache.EMPTY_STYLECACHE;88 return StyleCache.create(icon.createStyle());89 } else {90 WayPrototypesRecord p = get(osm, false);91 return StyleCache.create(p.createStyles());92 }93 }94 95 public IconPrototype getNode(OsmPrimitive osm) {96 IconPrototype icon = null;97 for (XmlStyleSource s : getStyleSources()) {98 icon = s.getNode(osm, icon);99 }100 return icon;101 }102 103 private WayPrototypesRecord get(OsmPrimitive osm, boolean forceArea) {104 WayPrototypesRecord p = new WayPrototypesRecord();105 for (XmlStyleSource s : getStyleSources()) {106 s.get(osm, forceArea || !(osm instanceof Way) || ((Way) osm).isClosed(), p);107 }108 return p;109 }110 111 public boolean hasAreas() {112 for (XmlStyleSource s : getStyleSources()) {113 if (s.hasAreas())114 return true;115 }116 return false;117 }118 119 public boolean isArea(OsmPrimitive osm) {120 for (XmlStyleSource s : getStyleSources()) {121 if (s.isArea(osm))122 return true;123 }124 return false;125 }126 127 public StyleCache getArea(Way osm) {128 if (osm.hasKeys()) {129 /* force area mode also for unclosed ways */130 WayPrototypesRecord p = get(osm, true);131 if (p.area != null)132 return StyleCache.create(p.createStyles());133 }134 return StyleCache.EMPTY_STYLECACHE;135 }136 137 public AreaPrototype getAreaProto(Way osm) {138 if (osm.hasKeys()) {139 /* force area mode also for unclosed ways */140 WayPrototypesRecord p = get(osm, true);141 if (p.area != null)142 return p.area;143 }144 return null;145 }146 147 public IconElemStyle getIcon(OsmPrimitive osm) {148 if (!osm.hasKeys())149 return null;150 NodeElemStyle icon = getNode(osm).createStyle();151 if (icon instanceof IconElemStyle) {152 return (IconElemStyle) icon;153 }154 return null;155 51 } 156 52 … … 165 61 return names; 166 62 } 63 64 public StyleList get(OsmPrimitive osm, double scale, NavigatableComponent nc) { 65 return getStyleCacheWithRange(osm, scale, nc).a; 66 } 67 68 public Pair<StyleList, Range> getStyleCacheWithRange(OsmPrimitive osm, double scale, NavigatableComponent nc) { 69 if (osm.mappaintStyle == null) { 70 osm.mappaintStyle = StyleCache.EMPTY_STYLECACHE; 71 } else { 72 Pair<StyleList, Range> lst = osm.mappaintStyle.getWithRange(scale); 73 if (lst.a != null) 74 return lst; 75 } 76 Pair<StyleList, Range> p = getImpl(osm, scale, nc); 77 if (osm instanceof Node && p.a.isEmpty()) { 78 p.a = StyleList.SIMPLE_NODE; 79 } else if (osm instanceof Way && !Utils.exists(p.a, LineElemStyle.class)) { 80 AreaElemStyle area = Utils.find(p.a, AreaElemStyle.class); 81 LineElemStyle line = (area == null ? LineElemStyle.UNTAGGED_WAY : LineElemStyle.createSimpleLineStyle(area.color)); 82 p.a = new StyleList(p.a, line); 83 } 84 osm.mappaintStyle = osm.mappaintStyle.put(p.a, p.b); 85 return p; 86 } 87 88 private Pair<StyleList, Range> getImpl(OsmPrimitive osm, double scale, NavigatableComponent nc) { 89 if (osm instanceof Node) 90 { 91 return generateStyles(osm, scale, null, false); 92 } 93 else if (osm instanceof Way) 94 { 95 Pair<StyleList, Range> p = generateStyles(osm, scale, null, false); 96 97 boolean isOuterWayOfSomeMP = false; 98 boolean hasIndependentLineElemStyle = false; 99 Color wayColor = null; 100 101 for (OsmPrimitive referrer : osm.getReferrers()) { 102 Relation r = (Relation) referrer; 103 if (!drawMultipolygon || !"multipolygon".equals(r.get("type")) || !r.isUsable()) { 104 continue; 105 } 106 Multipolygon multipolygon = new Multipolygon(nc); 107 multipolygon.load(r); 108 109 if (multipolygon.getOuterWays().contains(osm)) { 110 if (!isOuterWayOfSomeMP) { // do this only one time 111 List<ElemStyle> tmp = new ArrayList<ElemStyle>(p.a.size()); 112 for (ElemStyle s : p.a) { 113 if (s instanceof AreaElemStyle) { 114 wayColor = ((AreaElemStyle) s).color; 115 } else { 116 tmp.add(s); 117 } 118 } 119 p.a = new StyleList(tmp); 120 isOuterWayOfSomeMP = true; 121 hasIndependentLineElemStyle = Utils.exists(p.a, LineElemStyle.class); 122 } 123 124 if (!hasIndependentLineElemStyle) { 125 Pair<StyleList, Range> mpElemStyles = getStyleCacheWithRange(r, scale, nc); 126 LineElemStyle mpLine = Utils.find(mpElemStyles.a, LineElemStyle.class); 127 if (mpLine != null) { 128 p.a = new StyleList(p.a, mpLine); 129 p.b = Range.cut(p.b, mpElemStyles.b); 130 break; 131 } else if (wayColor == null) { 132 AreaElemStyle mpArea = Utils.find(mpElemStyles.a, AreaElemStyle.class); 133 if (mpArea != null) { 134 p.b = Range.cut(p.b, mpElemStyles.b); 135 wayColor = mpArea.color; 136 } 137 } 138 } 139 } 140 } 141 if (isOuterWayOfSomeMP) { 142 if (!Utils.exists(p.a, LineElemStyle.class)) { 143 p.a = new StyleList(p.a, LineElemStyle.createSimpleLineStyle(wayColor)); 144 } 145 return p; 146 } 147 148 for (OsmPrimitive referrer : osm.getReferrers()) { 149 Relation ref = (Relation) referrer; 150 if (!drawMultipolygon || !"multipolygon".equals(ref.get("type")) || !ref.isUsable()) { 151 continue; 152 } 153 Multipolygon multipolygon = new Multipolygon(nc); 154 multipolygon.load(ref); 155 156 if (multipolygon.getInnerWays().contains(osm)) { 157 Iterator<Way> it = multipolygon.getOuterWays().iterator(); 158 p = generateStyles(osm, scale, it.hasNext() ? it.next() : null, false); 159 boolean hasIndependentElemStyle = false; 160 for (ElemStyle s : p.a) { 161 if (s instanceof LineElemStyle || s instanceof AreaElemStyle) { 162 hasIndependentElemStyle = true; 163 } 164 } 165 if (!hasIndependentElemStyle && !multipolygon.getOuterWays().isEmpty()) { 166 StyleList mpElemStyles = get(ref, scale, nc); 167 Color mpColor = null; 168 for (ElemStyle mpS : mpElemStyles) { 169 if (mpS instanceof AreaElemStyle) { 170 mpColor = ((AreaElemStyle) mpS).color; 171 break; 172 } 173 } 174 p.a = new StyleList(p.a, LineElemStyle.createSimpleLineStyle(mpColor)); 175 } 176 return p; 177 } 178 } 179 return p; 180 } 181 else if (osm instanceof Relation) 182 { 183 Pair<StyleList, Range> p = generateStyles(osm, scale, null, true); 184 if (drawMultipolygon && "multipolygon".equals(osm.get("type"))) { 185 if (!Utils.exists(p.a, AreaElemStyle.class)) { 186 // look at outer ways to find area style 187 Multipolygon multipolygon = new Multipolygon(nc); 188 multipolygon.load((Relation) osm); 189 for (Way w : multipolygon.getOuterWays()) { 190 Pair<StyleList, Range> wayStyles = generateStyles(w, scale, null, false); 191 ElemStyle area = Utils.find(wayStyles.a, AreaElemStyle.class); 192 if (area != null) { 193 p.a = new StyleList(p.a, area); 194 p.b = Range.cut(p.b, wayStyles.b); 195 break; 196 } 197 } 198 } 199 } 200 return p; 201 } 202 return null; 203 } 204 205 /** 206 * @param multipolyOuterWay support for a very old multipolygon tagging style 207 * where you add the tags both to the outer and the inner way. 208 * However, independent inner way style is also possible. 209 * @param pretendWayIsClosed For styles that require the way to be closed, 210 * we pretend it is. This is useful for generating area styles from the (segmented) 211 * outer ways of a multipolygon. 212 */ 213 public Pair<StyleList, Range> generateStyles(OsmPrimitive osm, double scale, OsmPrimitive multipolyOuterWay, boolean pretendWayIsClosed) { 214 215 List<ElemStyle> sl = new ArrayList<ElemStyle>(); 216 MultiCascade mc = new MultiCascade(); 217 218 for (XmlStyleSource s : styleSources) { 219 s.apply(mc, osm, scale, multipolyOuterWay, pretendWayIsClosed); 220 } 221 222 for (Entry<String, Cascade> e : mc.entrySet()) { 223 if ("*".equals(e.getKey())) 224 continue; 225 Cascade c = e.getValue(); 226 if (osm instanceof Way) { 227 addIfNotNull(sl, AreaElemStyle.create(c)); 228 addIfNotNull(sl, LineElemStyle.createLine(c)); 229 addIfNotNull(sl, LineElemStyle.createCasing(c)); 230 } else if (osm instanceof Node) { 231 addIfNotNull(sl, NodeElemStyle.create(c)); 232 } else if (osm instanceof Relation) { 233 if ("multipolygon".equals(osm.get("type"))) { 234 addIfNotNull(sl, AreaElemStyle.create(c)); 235 addIfNotNull(sl, LineElemStyle.createLine(c)); 236 addIfNotNull(sl, LineElemStyle.createCasing(c)); 237 } else if ("restriction".equals(osm.get("type"))) { 238 addIfNotNull(sl, NodeElemStyle.create(c)); 239 } 240 } 241 } 242 243 return new Pair<StyleList, Range>(new StyleList(sl), mc.range); 244 } 245 246 private static <T> void addIfNotNull(List<T> list, T obj) { 247 if (obj != null) { 248 list.add(obj); 249 } 250 } 251 252 public boolean isDrawMultipolygon() { 253 return drawMultipolygon; 254 } 255 256 public void setDrawMultipolygon(boolean drawMultipolygon) { 257 this.drawMultipolygon = drawMultipolygon; 258 } 167 259 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java
r3824 r3836 15 15 public class LineElemStyle extends ElemStyle { 16 16 17 public static final LineElemStyle UNTAGGED_WAY; 17 public static LineElemStyle createSimpleLineStyle(Color color) { 18 return new LineElemStyle(Cascade.EMPTY_CASCADE, -1f, 0f, color != null ? color : PaintColors.UNTAGGED.get(), null, null); 19 } 20 public static final LineElemStyle UNTAGGED_WAY = createSimpleLineStyle(null); 18 21 19 static { 20 UNTAGGED_WAY = new LineElemStyle(0, Long.MAX_VALUE, -1, 0, PaintColors.UNTAGGED.get(), new float[0], null); 21 } 22 23 public static LineElemStyle createSimpleLineStyle(Color color) { 24 return new LineElemStyle(0, Long.MAX_VALUE, -1, 0, color, new float[0], null); 25 } 26 27 private int width; 28 public int realWidth; //the real width of this line in meter 22 private float width; 23 public float realWidth; // the real width of this line in meter 29 24 public Color color; 30 25 private float[] dashed; 31 26 public Color dashedColor; 32 27 33 p ublic LineElemStyle(long minScale, long maxScale, int width, int realWidth, Color color, float[] dashed, Color dashedColor) {34 super( minScale, maxScale);28 protected LineElemStyle(Cascade c, float width, float realWidth, Color color, float[] dashed, Color dashedColor) { 29 super(c); 35 30 setWidth(width); 36 31 this.realWidth = realWidth; … … 38 33 this.dashed = dashed; 39 34 this.dashedColor = dashedColor; 35 } 36 37 public static LineElemStyle createLine(Cascade c) { 38 return createImpl(c, ""); 39 } 40 41 public static LineElemStyle createCasing(Cascade c) { 42 return createImpl(c, "casing-"); 43 } 44 45 private static LineElemStyle createImpl(Cascade c, String prefix) { 46 Float width = c.get(prefix + "width", null, Float.class); 47 if (width == null) 48 return null; 49 50 float realWidth = c.get(prefix + "real-width", 0f, Float.class); 51 Color color = c.get(prefix + "color", null, Color.class); 52 if (color == null) { 53 color = c.get(prefix + "fill-color", null, Color.class); 54 } 55 if (color == null) { 56 color = PaintColors.UNTAGGED_WAY.get(); 57 } 58 float[] dashes = c.get(prefix + "dashes", null, float[].class); 59 Color dashesBackground = c.get(prefix + "dashes-background-color", null, Color.class); 60 61 return new LineElemStyle(c, width, realWidth, color, dashes, dashesBackground); 40 62 } 41 63 … … 55 77 56 78 Color myDashedColor = dashedColor; 57 int myWidth = getWidth();79 float myWidth = getWidth(); 58 80 59 81 if (realWidth > 0 && paintSettings.isUseRealWidth() && !showDirection) { … … 67 89 if(widthTag != null) { 68 90 try { 69 realWidth = Integer.parseInt(widthTag);91 realWidth = new Float(Integer.parseInt(widthTag)); 70 92 } 71 93 catch(NumberFormatException nfe) { … … 107 129 } 108 130 109 public int getWidth() {110 if (width == -1 )131 public float getWidth() { 132 if (width == -1f) 111 133 return MapPaintSettings.INSTANCE.getDefaultSegmentWidth(); 112 134 return width; 113 135 } 114 136 115 public void setWidth( int width) {137 public void setWidth(float width) { 116 138 this.width = width; 117 139 } … … 133 155 @Override 134 156 public int hashCode() { 135 int hash = 3;136 hash = 29 * hash + this.width;137 hash = 29 * hash + this.realWidth;138 hash = 29 * hash + this.color.hashCode();139 hash = 29 * hash + Arrays.hashCode( this.dashed);140 hash = 29 * hash + ( this.dashedColor != null ? this.dashedColor.hashCode() : 0);157 int hash = super.hashCode(); 158 hash = 29 * hash + Float.floatToIntBits(width); 159 hash = 29 * hash + Float.floatToIntBits(realWidth); 160 hash = 29 * hash + color.hashCode(); 161 hash = 29 * hash + Arrays.hashCode(dashed); 162 hash = 29 * hash + (dashedColor != null ? dashedColor.hashCode() : 0); 141 163 return hash; 142 164 } … … 144 166 @Override 145 167 public String toString() { 146 return "LineElemStyle{" + "width=" + width + " realWidth=" + realWidth + " color=" + color + " dashed=" + Arrays.toString(dashed) + " dashedColor=" + dashedColor + '}';168 return "LineElemStyle{" + super.toString() + "width=" + width + " realWidth=" + realWidth + " color=" + color + " dashed=" + Arrays.toString(dashed) + " dashedColor=" + dashedColor + '}'; 147 169 } 148 170 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java
r3824 r3836 2 2 package org.openstreetmap.josm.gui.mappaint; 3 3 4 import java.awt.Color; 5 6 import javax.swing.GrayFilter; 7 import javax.swing.ImageIcon; 8 4 9 import org.openstreetmap.josm.data.osm.Node; 10 import org.openstreetmap.josm.data.osm.OsmPrimitive; 11 import org.openstreetmap.josm.data.osm.Relation; 12 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings; 5 13 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter; 14 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference; 15 import org.openstreetmap.josm.tools.Utils; 6 16 7 abstract public class NodeElemStyle extends ElemStyle { 17 /** 18 * applies for Nodes and turn restriction relations 19 */ 20 public class NodeElemStyle extends ElemStyle { 8 21 public boolean annotate; 9 22 public String annotation_key; 23 public ImageIcon icon; 24 private ImageIcon disabledIcon; 10 25 11 public NodeElemStyle(long minScale, long maxScale) { 12 super(minScale, maxScale); 26 public static final NodeElemStyle SIMPLE_NODE_ELEMSTYLE = new NodeElemStyle(Cascade.EMPTY_CASCADE, true, null, null); 27 28 protected NodeElemStyle(Cascade c, boolean annotate, String annotation_key, ImageIcon icon) { 29 super(c); 30 this.annotate = annotate; 31 this.annotation_key = annotation_key; 32 this.icon = icon; 33 } 34 35 public static NodeElemStyle create(Cascade c) { 36 IconReference iconRef = c.get("icon-image", null, IconReference.class); 37 if (iconRef == null) 38 return null; 39 40 ImageIcon icon = MapPaintStyles.getIcon(iconRef); 41 String text = c.get("text", null, String.class); 42 43 boolean annotate = text != null; 44 String annotation_key = null; 45 46 if (annotate && !"yes".equalsIgnoreCase(text)) { 47 annotation_key = text; 48 } 49 return new NodeElemStyle(c, annotate, annotation_key, icon); 50 } 51 52 @Override 53 public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings settings, MapPainter painter, boolean selected, boolean member) { 54 if (primitive instanceof Node) { 55 Node n = (Node) primitive; 56 if (icon != null && painter.isShowIcons()) { 57 painter.drawNodeIcon(n, (painter.isInactive() || n.isDisabled()) ? getDisabledIcon() : icon, 58 selected, member, getName(n, painter)); 59 } else { 60 if (n.isHighlighted()) { 61 painter.drawNode(n, settings.getHighlightColor(), settings.getSelectedNodeSize(), settings.isFillSelectedNode(), getName(n, painter)); 62 } else { 63 Color color; 64 boolean isConnection = n.isConnectionNode(); 65 66 if (painter.isInactive() || n.isDisabled()) { 67 color = settings.getInactiveColor(); 68 } else if (selected) { 69 color = settings.getSelectedColor(); 70 } else if (member) { 71 color = settings.getRelationSelectedColor(); 72 } else if (isConnection) { 73 if (n.isTagged()) { 74 color = settings.getTaggedConnectionColor(); 75 } else { 76 color = settings.getConnectionColor(); 77 } 78 } else { 79 if (n.isTagged()) { 80 color = settings.getTaggedColor(); 81 } else { 82 color = settings.getNodeColor(); 83 } 84 } 85 86 final int size = Utils.max((selected ? settings.getSelectedNodeSize() : 0), 87 (n.isTagged() ? settings.getTaggedNodeSize() : 0), 88 (isConnection ? settings.getConnectionNodeSize() : 0), 89 settings.getUnselectedNodeSize()); 90 91 final boolean fill = (selected && settings.isFillSelectedNode()) || 92 (n.isTagged() && settings.isFillTaggedNode()) || 93 (isConnection && settings.isFillConnectionNode()) || 94 settings.isFillUnselectedNode(); 95 96 painter.drawNode(n, color, size, fill, getName(n, painter)); 97 } 98 } 99 } else if (primitive instanceof Relation) { 100 painter.drawRestriction((Relation) primitive, this); 101 } 102 } 103 104 public ImageIcon getDisabledIcon() { 105 if (disabledIcon != null) 106 return disabledIcon; 107 if (icon == null) 108 return null; 109 return disabledIcon = new ImageIcon(GrayFilter.createDisabledImage(icon.getImage())); 13 110 } 14 111 … … 23 120 return null; 24 121 } 122 123 @Override 124 public int hashCode() { 125 int hash = super.hashCode(); 126 hash = 17 * hash + (annotate ? 1 : 0); 127 hash = 17 * hash + (annotation_key != null ? annotation_key.hashCode() : 0); 128 hash = 17 * hash + (icon != null ? icon.getImage().hashCode() : 0); 129 return hash; 130 } 131 132 @Override 133 public boolean equals(Object obj) { 134 if (obj == null || getClass() != obj.getClass()) 135 return false; 136 if (!super.equals(obj)) 137 return false; 138 139 final NodeElemStyle other = (NodeElemStyle) obj; 140 // we should get the same image object due to caching 141 if (icon != other.icon && (icon == null || other.icon == null || icon.getImage() != other.icon.getImage())) 142 return false; 143 if (annotate != other.annotate) 144 return false; 145 if (!Utils.equal(annotation_key, annotation_key)) 146 return false; 147 return true; 148 } 149 150 @Override 151 public String toString() { 152 return "NodeElemStyle{" + super.toString() + "annotate=" + annotate + " annotation_key=" + annotation_key + " icon=" + icon + '}'; 153 } 154 25 155 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/StyleCache.java
r3824 r3836 5 5 import java.util.Arrays; 6 6 import java.util.Collection; 7 import java.util. Collections;7 import java.util.Iterator; 8 8 import java.util.List; 9 9 10 import org.openstreetmap.josm.data.osm.OsmPrimitive;11 10 import org.openstreetmap.josm.data.osm.Storage; 12 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings; 13 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter; 14 11 import org.openstreetmap.josm.tools.Pair; 12 import org.openstreetmap.josm.tools.Utils; 13 14 /** 15 * Caches styles for a single primitive. 16 * Splits the range of possible scale values (0 < scale < +Infinity) into multiple 17 * subranges, for each scale range it keeps a list of styles. 18 * Immutable class, equals & hashCode is required (the same for StyleList, ElemStyle 19 * and its subclasses). 20 */ 15 21 public class StyleCache { 16 17 private List<ElemStyle> styles; 22 /* list of boundaries for the scale ranges */ 23 ArrayList<Double> bd; 24 /* styles for each scale range */ 25 ArrayList<StyleList> data; 18 26 19 27 private final static Storage<StyleCache> internPool = new Storage<StyleCache>(); // TODO: clean up the intern pool from time to time (after purge or layer removal) 20 28 21 public final static StyleCache EMPTY_STYLECACHE = create(); 22 public final static StyleCache SIMPLE_NODE_STYLECACHE = create(SimpleNodeElemStyle.INSTANCE); 23 public final static StyleCache UNTAGGED_WAY_STYLECACHE = create(LineElemStyle.UNTAGGED_WAY); 24 29 public final static StyleCache EMPTY_STYLECACHE = (new StyleCache()).intern(); 25 30 26 31 private StyleCache() { 27 styles = new ArrayList<ElemStyle>(); 28 } 29 30 public static StyleCache create() { 31 StyleCache sc = new StyleCache(); 32 sc.styles = new ArrayList<ElemStyle>(); 33 return sc.intern(); 34 } 35 36 public static StyleCache create(ElemStyle... styles) { 37 StyleCache sc = new StyleCache(); 38 sc.styles = Arrays.asList(styles); 39 return sc.intern(); 40 } 41 42 public static StyleCache create(Collection<ElemStyle> styles) { 43 StyleCache sc = new StyleCache(); 44 sc.styles = new ArrayList<ElemStyle>(styles); 45 return sc.intern(); 46 } 47 48 public Collection<ElemStyle> getStyles() { 49 return Collections.unmodifiableList(styles); 50 } 51 52 /** 53 * like String.intern() (reduce memory consumption) 32 bd = new ArrayList<Double>(); 33 bd.add(0.0); 34 bd.add(Double.POSITIVE_INFINITY); 35 data = new ArrayList<StyleList>(); 36 data.add(null); 37 } 38 39 private StyleCache(StyleCache s) { 40 bd = new ArrayList<Double>(s.bd); 41 data = new ArrayList<StyleList>(s.data); 42 } 43 44 /** 45 * List of Styles, immutable 46 */ 47 public static class StyleList implements Iterable<ElemStyle> 48 { 49 private List<ElemStyle> lst; 50 51 public static final StyleList SIMPLE_NODE = new StyleList(NodeElemStyle.SIMPLE_NODE_ELEMSTYLE); 52 53 public StyleList() { 54 lst = new ArrayList<ElemStyle>(); 55 } 56 57 public StyleList(ElemStyle... init) { 58 lst = new ArrayList<ElemStyle>(Arrays.asList(init)); 59 } 60 61 public StyleList(Collection<ElemStyle> sl) { 62 lst = new ArrayList<ElemStyle>(sl); 63 } 64 65 public StyleList(StyleList sl, ElemStyle s) { 66 lst = new ArrayList<ElemStyle>(sl.lst); 67 lst.add(s); 68 } 69 70 @Override 71 public Iterator<ElemStyle> iterator() { 72 return lst.iterator(); 73 } 74 75 public boolean isEmpty() { 76 return lst.isEmpty(); 77 } 78 79 public int size() { 80 return lst.size(); 81 } 82 83 @Override 84 public String toString() { 85 return lst.toString(); 86 } 87 88 @Override 89 public boolean equals(Object obj) { 90 if (obj == null || getClass() != obj.getClass()) 91 return false; 92 final StyleList other = (StyleList) obj; 93 return Utils.equal(lst, other.lst); 94 } 95 96 @Override 97 public int hashCode() { 98 return lst.hashCode(); 99 } 100 } 101 102 /** 103 * looks up styles for a certain scale value 104 */ 105 public StyleList get(double scale) { 106 if (scale <= 0) 107 throw new IllegalArgumentException(); 108 for (int i=0; i<data.size(); ++i) { 109 if (bd.get(i) < scale && scale <= bd.get(i+1)) { 110 return data.get(i); 111 } 112 } 113 throw new AssertionError(); 114 } 115 116 /** 117 * looks up styles for a certain scale value and additionally returns 118 * the scale range for the returned styles 119 */ 120 public Pair<StyleList, Range> getWithRange(double scale) { 121 if (scale <= 0) 122 throw new IllegalArgumentException(); 123 for (int i=0; i<data.size(); ++i) { 124 if (bd.get(i) < scale && scale <= bd.get(i+1)) { 125 return new Pair<StyleList, Range>(data.get(i), new Range(bd.get(i), bd.get(i+1))); 126 } 127 } 128 throw new AssertionError(); 129 } 130 131 public StyleCache put(StyleList sl, Range r) { 132 return put(sl, r.getLower(), r.getUpper()); 133 } 134 135 /** 136 * add a new styles to the cache. this is only possible, if 137 * for this scale range, there is nothing in the cache yet. 138 */ 139 public StyleCache put(StyleList sl, double lower, double upper) { 140 StyleCache s = new StyleCache(this); 141 s.putImpl(sl, lower, upper); 142 s.consistencyTest(); 143 return s.intern(); 144 } 145 146 /** 147 * ASCII-art explanation: 148 * 149 * data[i] 150 * --|-------|---------|-- 151 * bd[i-1] bd[i] bd[i+1] 152 * 153 * (--------] 154 * lower upper 155 */ 156 private void putImpl(StyleList sl, double lower, double upper) { 157 int i=0; 158 while (bd.get(i) < lower) { 159 ++i; 160 } 161 if (bd.get(i) == lower) { 162 if (upper > bd.get(i+1)) 163 throw new AssertionError("the new range must be within a single subrange"); 164 if (data.get(i) != null) 165 throw new AssertionError("the new range must be within a subrange that has no data"); 166 167 // --|-------|--------|-- 168 // i-1 i i+1 169 // (--------] 170 if (bd.get(i+1) == upper) { 171 data.set(i, sl); 172 } 173 // --|-------|--------|-- 174 // i-1 i i+1 175 // (-----] 176 else { 177 bd.add(i+1, upper); 178 data.add(i, sl); 179 } 180 return; 181 } else { 182 if (bd.get(i) < upper) 183 throw new AssertionError("the new range must be within a single subrange"); 184 if (data.get(i-1) != null) 185 throw new AssertionError(); 186 187 // --|-------|--------|-- 188 // i-1 i i+1 189 // (--] or 190 // (----] 191 bd.add(i, lower); 192 data.add(i, sl); 193 194 // --|--|----|--------|-- 195 // i-1 i i+1 i+2 196 // (--] 197 if (bd.get(i+1) > upper) { 198 bd.add(i+1, upper); 199 data.add(i+1, null); 200 } 201 return; 202 } 203 } 204 205 public void consistencyTest() { 206 if (bd.size() < 2) throw new AssertionError(); 207 if (data.size() < 1) throw new AssertionError(); 208 if (bd.size() != data.size() + 1) throw new AssertionError(); 209 if (bd.get(0) != 0) throw new AssertionError(); 210 if (bd.get(bd.size() - 1) != Double.POSITIVE_INFINITY) throw new AssertionError(); 211 for (int i=0; i<data.size() - 1; ++i) { 212 if (bd.get(i) >= bd.get(i + 1)) throw new AssertionError(); 213 } 214 } 215 216 /** 217 * Like String.intern() (reduce memory consumption). 218 * StyleCache must not be changed after it has 219 * been added to the intern pool. 54 220 */ 55 221 public StyleCache intern() { 56 222 return internPool.putUnique(this); 57 }58 59 public void paint(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member) {60 for (ElemStyle s : styles) {61 s.paintPrimitive(primitive, paintSettings, painter, selected, member);62 }63 223 } 64 224 … … 67 227 if (obj == null || getClass() != obj.getClass()) 68 228 return false; 69 return styles.equals(((StyleCache) obj).styles); 229 final StyleCache other = (StyleCache) obj; 230 return bd.equals(other.bd) && data.equals(other.data); 70 231 } 71 232 72 233 @Override 73 234 public int hashCode() { 74 return styles.hashCode(); 235 int hash = 7; 236 hash = 23 * hash + bd.hashCode(); 237 hash = 23 * hash + data.hashCode(); 238 return hash; 75 239 } 76 240 77 241 @Override 78 242 public String toString() { 79 return "SC{" + styles+ '}';243 return "SC{" + bd + ' ' + data + '}'; 80 244 } 81 245 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/xml/AreaPrototype.java
r3824 r3836 4 4 import java.awt.Color; 5 5 6 import org.openstreetmap.josm.gui.mappaint. AreaElemStyle;6 import org.openstreetmap.josm.gui.mappaint.Range; 7 7 8 8 public class AreaPrototype extends Prototype { 9 9 public Color color; 10 public boolean closed; 10 public boolean closed; // if true, it does not apply to unclosed ways 11 11 12 public AreaPrototype (AreaPrototype a, long maxScale, long minScale) {13 super( maxScale, minScale);12 public AreaPrototype (AreaPrototype a, Range range) { 13 super(range); 14 14 this.color = a.color; 15 15 this.closed = a.closed; … … 22 22 public void init() 23 23 { 24 priority = 0; 25 range = new Range(); 24 26 closed = false; 25 27 color = null; 26 priority = 0;27 }28 29 public AreaElemStyle createStyle() {30 return new AreaElemStyle(minScale, maxScale, color);31 28 } 32 29 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/xml/IconPrototype.java
r3827 r3836 2 2 package org.openstreetmap.josm.gui.mappaint.xml; 3 3 4 import org.openstreetmap.josm.gui.mappaint.IconElemStyle;5 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;6 4 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference; 7 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle; 8 import org.openstreetmap.josm.gui.mappaint.SimpleNodeElemStyle; 5 import org.openstreetmap.josm.gui.mappaint.Range; 9 6 10 7 public class IconPrototype extends Prototype { 11 8 12 9 public IconReference icon; 13 public boolean annotate;10 public Boolean annotate; 14 11 15 public IconPrototype (IconPrototype i, long maxScale, long minScale) {16 super( maxScale, minScale);12 public IconPrototype (IconPrototype i, Range range) { 13 super(range); 17 14 this.icon = i.icon; 18 15 this.annotate = i.annotate; … … 24 21 25 22 public void init() { 23 priority = 0; 24 range = new Range(); 26 25 icon = null; 27 priority = 0; 28 annotate = true; 29 } 30 31 public NodeElemStyle createStyle() { 32 if (icon == null) { 33 return SimpleNodeElemStyle.INSTANCE; 34 } else { 35 IconElemStyle i = new IconElemStyle(minScale, maxScale, MapPaintStyles.getIcon(icon)); 36 i.annotate = annotate; 37 return i; 38 } 26 annotate = null; 39 27 } 40 28 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinePrototype.java
r3824 r3836 6 6 import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings; 7 7 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors; 8 import org.openstreetmap.josm.gui.mappaint. LineElemStyle;8 import org.openstreetmap.josm.gui.mappaint.Range; 9 9 import org.openstreetmap.josm.tools.I18n; 10 10 … … 12 12 13 13 protected int width; 14 public int realWidth; //the real width of this line in meter14 public Integer realWidth; // the real width of this line in meter 15 15 public Color color; 16 16 protected float[] dashed; 17 17 public Color dashedColor; 18 18 19 public LinePrototype(LinePrototype s, long maxScale, long minScale) {20 super( maxScale, minScale);19 public LinePrototype(LinePrototype s, Range range) { 20 super(range); 21 21 this.width = s.width; 22 22 this.realWidth = s.realWidth; … … 32 32 public void init() 33 33 { 34 priority = 0; 35 range = new Range(); 34 36 width = -1; 35 realWidth = 0;36 dashed = n ew float[0];37 realWidth = null; 38 dashed = null; 37 39 dashedColor = null; 38 priority = 0;39 40 color = PaintColors.UNTAGGED.get(); 40 41 } … … 45 46 46 47 public void setDashed(float[] dashed) { 47 if (dashed .length == 0) {48 if (dashed == null || dashed.length == 0) { 48 49 this.dashed = dashed; 49 50 return; … … 75 76 this.width = width; 76 77 } 77 78 public LineElemStyle createStyle() {79 return new LineElemStyle(minScale, maxScale, width, realWidth, color, dashed, dashedColor);80 }81 78 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/xml/LinemodPrototype.java
r3824 r3836 2 2 package org.openstreetmap.josm.gui.mappaint.xml; 3 3 4 import org.openstreetmap.josm.gui.mappaint. LineElemStyle;4 import org.openstreetmap.josm.gui.mappaint.Range; 5 5 6 6 public class LinemodPrototype extends LinePrototype implements Comparable<LinemodPrototype> { … … 11 11 public WidthMode widthMode; 12 12 13 public LinemodPrototype(LinemodPrototype s, long maxScale, long minScale) {14 super(s, maxScale, minScale);13 public LinemodPrototype(LinemodPrototype s, Range range) { 14 super(s, range); 15 15 this.over = s.over; 16 16 this.widthMode = s.widthMode; … … 28 28 29 29 // get width for overlays 30 public int getWidth(int ref)30 public float getWidth(float ref) 31 31 { 32 int res;32 float res; 33 33 if(widthMode == WidthMode.ABSOLUTE) { 34 34 res = width; … … 60 60 return 0; 61 61 } 62 63 /**64 * this method cannot be used for LinemodPrototypes65 * - use createStyle(int) instead66 */67 @Override68 public LineElemStyle createStyle() {69 throw new UnsupportedOperationException();70 }71 72 public LineElemStyle createStyle(int refWidth) {73 return new LineElemStyle(minScale, maxScale, getWidth(refWidth), realWidth, color, dashed, dashedColor);74 }75 62 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/xml/Prototype.java
r3824 r3836 6 6 import org.openstreetmap.josm.data.osm.OsmPrimitive; 7 7 import org.openstreetmap.josm.data.osm.OsmUtils; 8 import org.openstreetmap.josm.gui.mappaint.Range; 8 9 9 10 abstract public class Prototype { 10 11 // zoom range to display the feature 11 public long minScale; 12 public long maxScale; 12 public Range range; 13 13 14 14 public int priority; … … 16 16 public Collection<XmlCondition> conditions = null; 17 17 18 public Prototype(long maxScale, long minScale) { 19 this.maxScale = maxScale; 20 this.minScale = minScale; 18 public Prototype(Range range) { 19 this.range = range; 21 20 } 22 21 23 22 public Prototype() { 24 }25 26 @Override27 public boolean equals(Object o) {28 return (o instanceof Prototype) && (((Prototype) o).getCode().equals(getCode()));29 }30 31 @Override32 public int hashCode() {33 return getClass().hashCode();34 23 } 35 24 -
trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSource.java
r3827 r3836 10 10 import java.util.List; 11 11 12 import org.openstreetmap.josm.Main; 12 13 import org.openstreetmap.josm.data.osm.Node; 13 14 import org.openstreetmap.josm.data.osm.OsmPrimitive; 14 15 import org.openstreetmap.josm.data.osm.OsmUtils; 16 import org.openstreetmap.josm.data.osm.Relation; 15 17 import org.openstreetmap.josm.data.osm.Way; 16 import org.openstreetmap.josm.gui.mappaint.ElemStyles.WayPrototypesRecord; 18 import org.openstreetmap.josm.gui.mappaint.Cascade; 19 import org.openstreetmap.josm.gui.mappaint.MultiCascade; 20 import org.openstreetmap.josm.gui.mappaint.Range; 17 21 import org.openstreetmap.josm.gui.preferences.SourceEntry; 22 import org.openstreetmap.josm.tools.Utils; 18 23 19 24 public class XmlStyleSource extends SourceEntry { … … 39 44 } 40 45 41 public IconPrototype getNode(OsmPrimitive primitive, IconPrototype icon) { 46 private static class WayPrototypesRecord { 47 public LinePrototype line; 48 public List<LinemodPrototype> linemods; 49 public AreaPrototype area; 50 } 51 52 private <T extends Prototype> T update(T current, T candidate, Double scale, MultiCascade mc) { 53 return requiresUpdate(current, candidate, scale, mc) ? candidate : current; 54 } 55 56 /** 57 * checks whether a certain match is better than the current match 58 * @param current can be null 59 * @param candidate the new Prototype that could be used instead 60 * @param scale ignored if null, otherwise checks if scale is within the range of candidate 61 * @param mc side effect: update the valid region for the current MultiCascade 62 */ 63 private boolean requiresUpdate(Prototype current, Prototype candidate, Double scale, MultiCascade mc) { 64 if (current == null || candidate.priority >= current.priority) { 65 if (scale == null) 66 return true; 67 68 if (candidate.range.contains(scale)) { 69 mc.range = Range.cut(mc.range, candidate.range); 70 return true; 71 } else { 72 mc.range = mc.range.reduceAround(scale, candidate.range); 73 return false; 74 } 75 } 76 return false; 77 } 78 79 private IconPrototype getNode(OsmPrimitive primitive, Double scale, MultiCascade mc) { 80 IconPrototype icon = null; 42 81 for (String key : primitive.keySet()) { 43 82 String val = primitive.get(key); 44 IconPrototype style; 45 if ((style = icons.get("n" + key + "=" + val)) != null) { 46 if (icon == null || style.priority >= icon.priority) { 47 icon = style; 48 } 49 } 50 if ((style = icons.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val))) != null) { 51 if (icon == null || style.priority >= icon.priority) { 52 icon = style; 53 } 54 } 55 if ((style = icons.get("x" + key)) != null) { 56 if (icon == null || style.priority >= icon.priority) { 57 icon = style; 58 } 83 IconPrototype p; 84 if ((p = icons.get("n" + key + "=" + val)) != null) { 85 icon = update(icon, p, scale, mc); 86 } 87 if ((p = icons.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val))) != null) { 88 icon = update(icon, p, scale, mc); 89 } 90 if ((p = icons.get("x" + key)) != null) { 91 icon = update(icon, p, scale, mc); 59 92 } 60 93 } 61 94 for (IconPrototype s : iconsList) { 62 if ((icon == null || s.priority >= icon.priority) && s.check(primitive)) { 63 icon = s; 95 if (s.check(primitive)) 96 { 97 icon = update(icon, s, scale, mc); 64 98 } 65 99 } … … 72 106 * multipolygon relations. 73 107 */ 74 p ublic void get(OsmPrimitive primitive, boolean closed, WayPrototypesRecord p) {108 private void get(OsmPrimitive primitive, boolean closed, WayPrototypesRecord p, Double scale, MultiCascade mc) { 75 109 String lineIdx = null; 76 110 HashMap<String, LinemodPrototype> overlayMap = new HashMap<String, LinemodPrototype>(); … … 81 115 LinemodPrototype styleLinemod; 82 116 String idx = "n" + key + "=" + val; 83 if ((styleArea = areas.get(idx)) != null && (p.area == null || styleArea.priority >= p.area.priority) && (closed || !styleArea.closed)) { 84 p.area = styleArea; 85 } 86 if ((styleLine = lines.get(idx)) != null && (p.line == null || styleLine.priority >= p.line.priority)) { 87 p.line = styleLine; 88 lineIdx = idx; 117 if ((styleArea = areas.get(idx)) != null && (closed || !styleArea.closed)) { 118 p.area = update(p.area, styleArea, scale, mc); 119 } 120 if ((styleLine = lines.get(idx)) != null) { 121 if (requiresUpdate(p.line, styleLine, scale, mc)) { 122 p.line = styleLine; 123 lineIdx = idx; 124 } 89 125 } 90 126 if ((styleLinemod = modifiers.get(idx)) != null) { 91 overlayMap.put(idx, styleLinemod); 127 if (requiresUpdate(null, styleLinemod, scale, mc)) { 128 overlayMap.put(idx, styleLinemod); 129 } 92 130 } 93 131 idx = "b" + key + "=" + OsmUtils.getNamedOsmBoolean(val); 94 if ((styleArea = areas.get(idx)) != null && (p.area == null || styleArea.priority >= p.area.priority) && (closed || !styleArea.closed)) { 95 p.area = styleArea; 96 } 97 if ((styleLine = lines.get(idx)) != null && (p.line == null || styleLine.priority >= p.line.priority)) { 98 p.line = styleLine; 99 lineIdx = idx; 132 if ((styleArea = areas.get(idx)) != null && (closed || !styleArea.closed)) { 133 p.area = update(p.area, styleArea, scale, mc); 134 } 135 if ((styleLine = lines.get(idx)) != null) { 136 if (requiresUpdate(p.line, styleLine, scale, mc)) { 137 p.line = styleLine; 138 lineIdx = idx; 139 } 100 140 } 101 141 if ((styleLinemod = modifiers.get(idx)) != null) { 102 overlayMap.put(idx, styleLinemod); 142 if (requiresUpdate(null, styleLinemod, scale, mc)) { 143 overlayMap.put(idx, styleLinemod); 144 } 103 145 } 104 146 idx = "x" + key; 105 if ((styleArea = areas.get(idx)) != null && (p.area == null || styleArea.priority >= p.area.priority) && (closed || !styleArea.closed)) { 106 p.area = styleArea; 107 } 108 if ((styleLine = lines.get(idx)) != null && (p.line == null || styleLine.priority >= p.line.priority)) { 109 p.line = styleLine; 110 lineIdx = idx; 147 if ((styleArea = areas.get(idx)) != null && (closed || !styleArea.closed)) { 148 p.area = update(p.area, styleArea, scale, mc); 149 } 150 if ((styleLine = lines.get(idx)) != null) { 151 if (requiresUpdate(p.line, styleLine, scale, mc)) { 152 p.line = styleLine; 153 lineIdx = idx; 154 } 111 155 } 112 156 if ((styleLinemod = modifiers.get(idx)) != null) { 113 overlayMap.put(idx, styleLinemod); 157 if (requiresUpdate(null, styleLinemod, scale, mc)) { 158 overlayMap.put(idx, styleLinemod); 159 } 114 160 } 115 161 } 116 162 for (AreaPrototype s : areasList) { 117 if (( p.area == null || s.priority >= p.area.priority) && (closed || !s.closed) && s.check(primitive)) {118 p.area = s;163 if ((closed || !s.closed) && s.check(primitive)) { 164 p.area = update(p.area, s, scale, mc); 119 165 } 120 166 } 121 167 for (LinePrototype s : linesList) { 122 if ( (p.line == null || s.priority >= p.line.priority) &&s.check(primitive)) {123 p.line = s;168 if (s.check(primitive)) { 169 p.line = update(p.line, s, scale, mc); 124 170 } 125 171 } 126 172 for (LinemodPrototype s : modifiersList) { 127 173 if (s.check(primitive)) { 128 overlayMap.put(s.getCode(), s); 174 if (requiresUpdate(null, s, scale, mc)) { 175 overlayMap.put(s.getCode(), s); 176 } 129 177 } 130 178 } 131 179 overlayMap.remove(lineIdx); // do not use overlay if linestyle is from the same rule (example: railway=tram) 132 if (!overlayMap.isEmpty() && p.line != null) {180 if (!overlayMap.isEmpty()) { 133 181 List<LinemodPrototype> tmp = new LinkedList<LinemodPrototype>(); 134 182 if (p.linemods != null) { … … 139 187 p.linemods = tmp; 140 188 } 141 }142 143 public boolean isArea(OsmPrimitive o) {144 if (o.hasKeys() && !(o instanceof Node)) {145 boolean noclosed = o instanceof Way && !((Way) o).isClosed();146 Iterator<String> iterator = o.keySet().iterator();147 while (iterator.hasNext()) {148 String key = iterator.next();149 String val = o.get(key);150 AreaPrototype s = areas.get("n" + key + "=" + val);151 if (s == null || (s.closed && noclosed)) {152 s = areas.get("b" + key + "=" + OsmUtils.getNamedOsmBoolean(val));153 }154 if (s == null || (s.closed && noclosed)) {155 s = areas.get("x" + key);156 }157 if (s != null && !(s.closed && noclosed)) {158 return true;159 }160 }161 for (AreaPrototype s : areasList) {162 if (!(s.closed && noclosed) && s.check(o)) {163 return true;164 }165 }166 }167 return false;168 }169 170 public boolean hasAreas() {171 return areas.size() > 0;172 189 } 173 190 … … 202 219 } 203 220 } 221 222 public void apply(MultiCascade mc, OsmPrimitive osm, double scale, OsmPrimitive multipolyOuterWay, boolean pretendWayIsClosed) { 223 Cascade def = mc.getCascade("default"); 224 boolean useMinMaxScale = Main.pref.getBoolean("mappaint.zoomLevelDisplay", false); 225 226 if (osm instanceof Node || (osm instanceof Relation && "restriction".equals(osm.get("type")))) { 227 IconPrototype icon = getNode(osm, (useMinMaxScale ? scale : null), mc); 228 if (icon != null) { 229 def.put("icon-image", icon.icon); 230 if (osm instanceof Node) { 231 if (icon.annotate != null) { 232 if (icon.annotate) { 233 def.put("text", "yes"); 234 } else { 235 def.remove("text"); 236 } 237 } 238 } 239 } 240 } else if (osm instanceof Way || (osm instanceof Relation && "multipolygon".equals(osm.get("type")))) { 241 WayPrototypesRecord p = new WayPrototypesRecord(); 242 get(osm, pretendWayIsClosed || !(osm instanceof Way) || ((Way) osm).isClosed(), p, (useMinMaxScale ? scale : null), mc); 243 if (p.line != null) { 244 def.put("width", new Float(p.line.getWidth())); 245 def.putOrClear("real-width", p.line.realWidth != null ? new Float(p.line.realWidth) : null); 246 def.putOrClear("color", p.line.color); 247 def.putOrClear("dashes", p.line.getDashed()); 248 def.putOrClear("dashes-background-color", p.line.dashedColor); 249 } 250 Float refWidth = def.get("width", null, Float.class); 251 if (refWidth != null && p.linemods != null) { 252 int numOver = 0, numUnder = 0; 253 254 while (mc.containsKey(String.format("over_%d", ++numOver))) {} 255 while (mc.containsKey(String.format("under_%d", ++numUnder))) {} 256 257 for (LinemodPrototype mod : p.linemods) { 258 Cascade c; 259 if (mod.over) { 260 c = mc.getCascade(String.format("over_%d", numOver)); 261 c.put("object-z-index", new Float(numOver)); 262 ++numOver; 263 } else { 264 c = mc.getCascade(String.format("under_%d", numUnder)); 265 c.put("object-z-index", new Float(-numUnder)); 266 ++numUnder; 267 } 268 c.put("width", new Float(mod.getWidth(refWidth))); 269 c.putOrClear("color", mod.color); 270 c.putOrClear("dashes", mod.getDashed()); 271 c.putOrClear("dashes-background-color", mod.dashedColor); 272 } 273 } 274 if (multipolyOuterWay != null) { 275 WayPrototypesRecord p2 = new WayPrototypesRecord(); 276 get(multipolyOuterWay, true, p2, (useMinMaxScale ? scale : null), mc); 277 if (Utils.equal(p.area, p2.area)) { 278 p.area = null; 279 } 280 } 281 if (p.area != null) { 282 def.putOrClear("fill-color", p.area.color); 283 def.remove("fill-image"); 284 } 285 } 286 } 287 204 288 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/xml/XmlStyleSourceHandler.java
r3827 r3836 8 8 import org.openstreetmap.josm.Main; 9 9 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference; 10 import org.openstreetmap.josm.gui.mappaint.Range; 10 11 import org.openstreetmap.josm.tools.ColorHelper; 11 12 import org.xml.sax.Attributes; … … 23 24 XmlCondition cond = new XmlCondition(); 24 25 Collection<XmlCondition> conditions; 25 longscaleMax;26 longscaleMin;26 double scaleMax; 27 double scaleMin; 27 28 LinePrototype line = new LinePrototype(); 28 29 LinemodPrototype linemod = new LinemodPrototype(); … … 32 33 { 33 34 conditions = null; 34 scaleMax = 1000000000;35 scaleMax = Double.POSITIVE_INFINITY; 35 36 scaleMin = 0; 36 37 line.init(); … … 102 103 dashed = new float[]{9}; 103 104 } else { 104 dashed = n ew float[0];105 dashed = null; 105 106 } 106 107 } … … 249 250 { 250 251 style.add(rule.cond, rule.conditions, 251 new LinePrototype(rule.line, rule.scaleMax, rule.scaleMin));252 new LinePrototype(rule.line, new Range(rule.scaleMin, rule.scaleMax))); 252 253 } 253 254 if(hadLineMod) 254 255 { 255 256 style.add(rule.cond, rule.conditions, 256 new LinemodPrototype(rule.linemod, rule.scaleMax, rule.scaleMin));257 new LinemodPrototype(rule.linemod, new Range(rule.scaleMin, rule.scaleMax))); 257 258 } 258 259 if(hadIcon) 259 260 { 260 261 style.add(rule.cond, rule.conditions, 261 new IconPrototype(rule.icon, rule.scaleMax, rule.scaleMin));262 new IconPrototype(rule.icon, new Range(rule.scaleMin, rule.scaleMax))); 262 263 } 263 264 if(hadArea) 264 265 { 265 266 style.add(rule.cond, rule.conditions, 266 new AreaPrototype(rule.area, rule.scaleMax, rule.scaleMin));267 new AreaPrototype(rule.area, new Range(rule.scaleMin, rule.scaleMax))); 267 268 } 268 269 inRule = false; -
trunk/src/org/openstreetmap/josm/tools/SubclassFilteredCollection.java
r3801 r3836 13 13 * @param <S> element type of the underlying collection 14 14 * @param <T> element type of filtered collection (and subclass of S). The predicate 15 * must except only objects of type T.15 * must accept only objects of type T. 16 16 */ 17 17 public class SubclassFilteredCollection<S, T extends S> extends AbstractCollection<T> { … … 50 50 S old = current; 51 51 current = null; 52 return (T) old; 52 // we are save because predicate only accepts objects of type T 53 @SuppressWarnings("unchecked") T res = (T) old; 54 return res; 53 55 } 54 56 -
trunk/src/org/openstreetmap/josm/tools/Utils.java
r3796 r3836 4 4 public class Utils { 5 5 6 public static <T> boolean exists(Iterable<? extends T> coll , Predicate<? super T> pred) {7 for (T el : coll) {8 if (pred .evaluate(el))6 public static <T> boolean exists(Iterable<? extends T> collection, Predicate<? super T> predicate) { 7 for (T item : collection) { 8 if (predicate.evaluate(item)) 9 9 return true; 10 10 } 11 11 return false; 12 } 13 14 public static <T> boolean exists(Iterable collection, Class<? extends T> klass) { 15 for (Object item : collection) { 16 if (klass.isInstance(item)) 17 return true; 18 } 19 return false; 20 } 21 22 public static <T> T find(Iterable<? extends T> collection, Predicate<? super T> predicate) { 23 for (T item : collection) { 24 if (predicate.evaluate(item)) 25 return item; 26 } 27 return null; 28 } 29 30 public static <T> T find(Iterable collection, Class<? extends T> klass) { 31 for (Object item : collection) { 32 if (klass.isInstance(item)) { 33 @SuppressWarnings("unchecked") T res = (T) item; 34 return res; 35 } 36 } 37 return null; 12 38 } 13 39 … … 28 54 } 29 55 56 public static int max(int a, int b, int c, int d) { 57 return Math.max(Math.max(a, b), Math.max(c, d)); 58 } 59 30 60 /** 31 61 * for convenience: test whether 2 objects are either both null or a.equals(b) 32 62 */ 33 63 public static <T> boolean equal(T a, T b) { 34 if (a == null && b == null)64 if (a == b) 35 65 return true; 36 66 return (a != null && a.equals(b));
Note:
See TracChangeset
for help on using the changeset viewer.