Ticket #3781: rework-multipolygons-1.patch
| File rework-multipolygons-1.patch, 23.4 KB (added by , 17 years ago) |
|---|
-
src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java
26 26 import java.util.Iterator; 27 27 import java.util.LinkedList; 28 28 import java.util.List; 29 import java.util.TreeSet; 30 import java.util.Comparator; 29 31 30 32 import javax.swing.ImageIcon; 31 33 … … 52 54 public class MapPaintVisitor extends SimplePaintVisitor { 53 55 protected boolean useRealWidth; 54 56 protected boolean zoomLevelDisplay; 55 protected int fillAreas;56 57 protected boolean drawMultipolygon; 57 58 protected boolean drawRestriction; 58 59 protected boolean leftHandTraffic; … … 73 74 protected double circum; 74 75 protected double dist; 75 76 protected Collection<String> regionalNameOrder; 76 protected Boolean selectedCall;77 77 protected Boolean useStyleCache; 78 78 private static int paintid = 0; 79 79 private static int viewid = 0; … … 139 139 * @param n The node to draw. 140 140 */ 141 141 @Override 142 public void visit(Node n) { 142 public void visit(Node n) {} 143 public void drawNode(Node n) { 143 144 /* check, if the node is visible at all */ 144 145 if((n.getEastNorth().east() > maxEN.east() ) || 145 146 (n.getEastNorth().north() > maxEN.north()) || … … 175 176 * Draw a line for all segments, according to tags. 176 177 * @param w The way to draw. 177 178 */ 178 @Override 179 public void visit(Way w) { 179 @Override 180 public void visit(Way w) {} 181 public void drawWay(Way w, int fillAreas) { 180 182 if(w.getNodesCount() < 2) 181 183 { 182 184 w.mappaintVisibleCode = viewid; … … 390 392 displaySegments(); 391 393 } 392 394 393 public Collection< Way> joinWays(Collection<Way> join, OsmPrimitive errs)395 public Collection<PolyData> joinWays(Collection<Way> join, OsmPrimitive errs) 394 396 { 395 Collection< Way> res = new LinkedList<Way>();397 Collection<PolyData> res = new LinkedList<PolyData>(); 396 398 Object[] joinArray = join.toArray(); 397 399 int left = join.size(); 398 400 while(left != 0) … … 479 481 { 480 482 w = new Way(w); 481 483 w.setNodes(n); 482 if (selected) { 483 data.addSelected(Collections.singleton(w),false /* don't notify listeners */); 484 } else { 485 data.clearSelection(w); 486 } 484 // Do not mess with the DataSet's contents here. 487 485 } 488 486 if(!w.isClosed()) 489 487 { … … 493 491 w.getDisplayName(DefaultNameFormatter.getInstance())), true); 494 492 } 495 493 } 496 res.add(w); 494 PolyData pd = new PolyData(w); 495 pd.selected = selected; 496 res.add(pd); 497 497 } /* while(left != 0) */ 498 498 499 499 return res; … … 504 504 { 505 505 if(osm instanceof Way) 506 506 { 507 Way w = (Way)osm; 507 508 if(style instanceof AreaElemStyle) 508 509 { 509 510 Way way = (Way)osm; … … 530 531 osm.mappaintDrawnCode = paintid; 531 532 } 532 533 533 @Override 534 public void visit(Relation r) { 535 534 public void visit(Relation r) {}; 535 public void paintUnselectedRelation(Relation r) { 536 536 r.mappaintVisibleCode = 0; 537 537 538 /* TODO: is it possible to do this like the nodes/ways code? */ 539 //if(profilerOmitDraw) 540 // return; 541 542 if(selectedCall) 538 if (drawMultipolygon && "multipolygon".equals(r.get("type"))) 543 539 { 544 for (RelationMember m : r.getMembers())545 {546 if (m.isNode() && !m.getMember().incomplete && !m.getMember().isDeleted() && !m.getMember().isFiltered())547 {548 drawSelectedMember(m.getMember(), styles != null ? getPrimitiveStyle(m.getMember()) : null, true, true);549 }550 }551 return;552 }553 else if (drawMultipolygon && "multipolygon".equals(r.get("type")))554 {555 540 if(drawMultipolygon(r)) 556 541 return; 557 542 } … … 564 549 { 565 550 for (RelationMember m : r.getMembers()) 566 551 { 567 if (m.isWay() && !m.getMember().incomplete && !m.getMember().isDeleted()) /* nodes drawn on second call */552 if (m.isWay() && drawable(m.getMember())) 568 553 { 569 554 drawSelectedMember(m.getMember(), styles != null ? getPrimitiveStyle(m.getMember()) 570 555 : null, true, true); … … 844 829 } 845 830 } 846 831 832 class PolyData { 833 public Polygon poly = new Polygon(); 834 public Way way; 835 public boolean selected = false; 836 private Point p = null; 837 private Collection<Polygon> inner = null; 838 PolyData(Way w) 839 { 840 way = w; 841 for (Node n : w.getNodes()) 842 { 843 p = nc.getPoint(n); 844 poly.addPoint(p.x,p.y); 845 } 846 } 847 public int contains(Polygon p) 848 { 849 int contains = p.npoints; 850 for(int i = 0; i < p.npoints; ++i) 851 { 852 if(poly.contains(p.xpoints[i],p.ypoints[i])) { 853 --contains; 854 } 855 } 856 if(contains == 0) return 1; 857 if(contains == p.npoints) return 0; 858 return 2; 859 } 860 public void addInner(Polygon p) 861 { 862 if(inner == null) { 863 inner = new ArrayList<Polygon>(); 864 } 865 inner.add(p); 866 } 867 public boolean isClosed() 868 { 869 return (poly.npoints >= 3 870 && poly.xpoints[0] == poly.xpoints[poly.npoints-1] 871 && poly.ypoints[0] == poly.ypoints[poly.npoints-1]); 872 } 873 public Polygon get() 874 { 875 if(inner != null) 876 { 877 for (Polygon pp : inner) 878 { 879 for(int i = 0; i < pp.npoints; ++i) { 880 poly.addPoint(pp.xpoints[i],pp.ypoints[i]); 881 } 882 poly.addPoint(p.x,p.y); 883 } 884 inner = null; 885 } 886 return poly; 887 } 888 } 889 void addInnerToOuters(Relation r, boolean incomplete, PolyData pdInner, LinkedList<PolyData> outerPolygons) 890 { 891 Way wInner = pdInner.way; 892 if(wInner != null && !wInner.isClosed()) 893 { 894 Point pInner = nc.getPoint(wInner.getNode(0)); 895 pdInner.poly.addPoint(pInner.x,pInner.y); 896 } 897 PolyData o = null; 898 for (PolyData pdOuter : outerPolygons) 899 { 900 Integer c = pdOuter.contains(pdInner.poly); 901 if(c >= 1) 902 { 903 if(c > 1 && pdOuter.way != null && pdOuter.way.isClosed()) 904 { 905 r.putError(tr("Intersection between ways ''{0}'' and ''{1}''.", 906 pdOuter.way.getDisplayName(DefaultNameFormatter.getInstance()), wInner.getDisplayName(DefaultNameFormatter.getInstance())), true); 907 } 908 if(o == null || o.contains(pdOuter.poly) > 0) { 909 o = pdOuter; 910 } 911 } 912 } 913 if(o == null) 914 { 915 if(!incomplete) 916 { 917 r.putError(tr("Inner way ''{0}'' is outside.", 918 wInner.getDisplayName(DefaultNameFormatter.getInstance())), true); 919 } 920 o = outerPolygons.get(0); 921 } 922 o.addInner(pdInner.poly); 923 } 924 847 925 public Boolean drawMultipolygon(Relation r) { 848 926 Collection<Way> inner = new LinkedList<Way>(); 849 927 Collection<Way> outer = new LinkedList<Way>(); … … 861 939 m.getMember().getDisplayName(DefaultNameFormatter.getInstance())), true); 862 940 } else if(m.getMember().incomplete) { 863 941 incomplete = true; 864 } else 865 { 866 if(m.isWay()) 867 { 942 } else { 943 if(m.isWay()) { 868 944 Way w = m.getWay(); 869 if(w.getNodesCount() < 2) 870 { 945 if(w.getNodesCount() < 2) { 871 946 r.putError(tr("Way ''{0}'' with less than two points.", 872 947 w.getDisplayName(DefaultNameFormatter.getInstance())), true); 873 948 } … … 875 950 inner.add(w); 876 951 } else if("outer".equals(m.getRole())) { 877 952 outer.add(w); 878 } else 879 { 953 } else { 880 954 r.putError(tr("No useful role ''{0}'' for Way ''{1}''.", 881 955 m.getRole(), w.getDisplayName(DefaultNameFormatter.getInstance())), true); 882 956 if(!m.hasRole()) { … … 911 985 { 912 986 Boolean zoomok = isZoomOk(wayStyle); 913 987 Boolean visible = false; 914 Collection<Way> join = new LinkedList<Way>(); 988 Collection<Way> outerjoin = new LinkedList<Way>(); 989 Collection<Way> innerjoin = new LinkedList<Way>(); 915 990 916 991 drawn = true; 917 992 for (Way w : outer) … … 919 994 if(w.isClosed()) { 920 995 outerclosed.add(w); 921 996 } else { 922 join.add(w);997 outerjoin.add(w); 923 998 } 924 999 } 925 if(join.size() != 0)926 {927 for(Way w : joinWays(join, incomplete ? null : r)) {928 outerclosed.add(w);929 }930 }931 932 join.clear();933 1000 for (Way w : inner) 934 1001 { 935 1002 if(w.isClosed()) { 936 1003 innerclosed.add(w); 937 1004 } else { 938 join.add(w);1005 innerjoin.add(w); 939 1006 } 940 1007 } 941 if( join.size() != 0)1008 if(outerclosed.size() == 0 && outerjoin.size() == 0) 942 1009 { 943 for(Way w : joinWays(join, incomplete ? null : r)) {944 innerclosed.add(w);945 }946 }947 948 if(outerclosed.size() == 0)949 {950 1010 r.putError(tr("No outer way for multipolygon ''{0}''.", 951 1011 r.getDisplayName(DefaultNameFormatter.getInstance())), true); 952 1012 visible = true; /* prevent killing remaining ways */ 953 1013 } 954 1014 else if(zoomok) 955 1015 { 956 class PolyData { 957 public Polygon poly = new Polygon(); 958 public Way way; 959 private Point p = null; 960 private Collection<Polygon> inner = null; 961 PolyData(Way w) 962 { 963 way = w; 964 for (Node n : w.getNodes()) 965 { 966 p = nc.getPoint(n); 967 poly.addPoint(p.x,p.y); 968 } 969 } 970 public int contains(Polygon p) 971 { 972 int contains = p.npoints; 973 for(int i = 0; i < p.npoints; ++i) 974 { 975 if(poly.contains(p.xpoints[i],p.ypoints[i])) { 976 --contains; 977 } 978 } 979 if(contains == 0) return 1; 980 if(contains == p.npoints) return 0; 981 return 2; 982 } 983 public void addInner(Polygon p) 984 { 985 if(inner == null) { 986 inner = new ArrayList<Polygon>(); 987 } 988 inner.add(p); 989 } 990 public boolean isClosed() 991 { 992 return (poly.npoints >= 3 993 && poly.xpoints[0] == poly.xpoints[poly.npoints-1] 994 && poly.ypoints[0] == poly.ypoints[poly.npoints-1]); 995 } 996 public Polygon get() 997 { 998 if(inner != null) 999 { 1000 for (Polygon pp : inner) 1001 { 1002 for(int i = 0; i < pp.npoints; ++i) { 1003 poly.addPoint(pp.xpoints[i],pp.ypoints[i]); 1004 } 1005 poly.addPoint(p.x,p.y); 1006 } 1007 inner = null; 1008 } 1009 return poly; 1010 } 1016 LinkedList<PolyData> outerPoly = new LinkedList<PolyData>(); 1017 for (Way w : outerclosed) { 1018 outerPoly.add(new PolyData(w)); 1011 1019 } 1012 LinkedList<PolyData> poly = new LinkedList<PolyData>(); 1013 for (Way w : outerclosed) 1014 { 1015 poly.add(new PolyData(w)); 1016 } 1020 outerPoly.addAll(joinWays(outerjoin, incomplete ? null : r)); 1017 1021 for (Way wInner : innerclosed) 1018 1022 { 1019 Polygon polygon = new Polygon(); 1020 1021 for (Node n : wInner.getNodes()) 1022 { 1023 Point pInner = nc.getPoint(n); 1024 polygon.addPoint(pInner.x,pInner.y); 1025 } 1026 if(!wInner.isClosed()) 1027 { 1028 Point pInner = nc.getPoint(wInner.getNode(0)); 1029 polygon.addPoint(pInner.x,pInner.y); 1030 } 1031 PolyData o = null; 1032 for (PolyData pd : poly) 1033 { 1034 Integer c = pd.contains(polygon); 1035 if(c >= 1) 1036 { 1037 if(c > 1 && pd.way.isClosed()) 1038 { 1039 r.putError(tr("Intersection between ways ''{0}'' and ''{1}''.", 1040 pd.way.getDisplayName(DefaultNameFormatter.getInstance()), wInner.getDisplayName(DefaultNameFormatter.getInstance())), true); 1041 } 1042 if(o == null || o.contains(pd.poly) > 0) { 1043 o = pd; 1044 } 1045 } 1046 } 1047 if(o == null) 1048 { 1049 if(!incomplete) 1050 { 1051 r.putError(tr("Inner way ''{0}'' is outside.", 1052 wInner.getDisplayName(DefaultNameFormatter.getInstance())), true); 1053 } 1054 o = poly.get(0); 1055 } 1056 o.addInner(polygon); 1023 PolyData pdInner = new PolyData(wInner); 1024 // incomplete is probably redundant 1025 addInnerToOuters(r, incomplete, pdInner, outerPoly); 1057 1026 } 1027 for (PolyData pdInner : joinWays(innerjoin, incomplete ? null : r)) { 1028 addInnerToOuters(r, incomplete, pdInner, outerPoly); 1029 } 1058 1030 AreaElemStyle areaStyle = (AreaElemStyle)wayStyle; 1059 for (PolyData pd : poly) 1060 { 1031 for (PolyData pd : outerPoly) { 1061 1032 Polygon p = pd.get(); 1062 if( isPolygonVisible(p))1063 {1064 drawAreaPolygon(p, (data.isSelected(pd.way) || data.isSelected(r)) ? selectedColor 1065 : areaStyle.color);1066 visible = true;1067 }1033 if(!isPolygonVisible(p)) 1034 continue; 1035 1036 boolean selected = pd.selected || data.isSelected(pd.way) || data.isSelected(r); 1037 drawAreaPolygon(p, selected ? selectedColor : areaStyle.color); 1038 visible = true; 1068 1039 } 1069 1040 } 1070 1041 if(!visible) /* nothing visible, so disable relation and all its ways */ … … 1083 1054 ElemStyle innerStyle = getPrimitiveStyle(wInner); 1084 1055 if(innerStyle == null) 1085 1056 { 1057 if (data.isSelected(wInner)) 1058 continue; 1086 1059 if(zoomok && (wInner.mappaintDrawnCode != paintid 1087 1060 || outer.size() == 0)) 1088 1061 { … … 1114 1087 ElemStyle outerStyle = getPrimitiveStyle(wOuter); 1115 1088 if(outerStyle == null) 1116 1089 { 1090 // Selected ways are drawn at the very end 1091 if (data.isSelected(wOuter)) 1092 continue; 1117 1093 if(zoomok) 1118 1094 { 1119 1095 drawWay(wOuter, ((AreaElemStyle)wayStyle).line, … … 1414 1390 } 1415 1391 } 1416 1392 1393 boolean drawable(OsmPrimitive osm) 1394 { 1395 return !osm.isDeleted() && !osm.isFiltered() && !osm.incomplete; 1396 } 1397 1417 1398 @Override 1418 1399 public void getColors() 1419 1400 { … … 1425 1406 1426 1407 DataSet data; 1427 1408 1409 <T extends OsmPrimitive> Collection<T> selectedLast(final DataSet data, Collection <T> prims) { 1410 ArrayList<T> sorted = new ArrayList<T>(prims); 1411 Collections.sort(sorted, 1412 new Comparator<T>() { 1413 public int compare(T o1, T o2) { 1414 boolean s1 = data.isSelected(o1); 1415 boolean s2 = data.isSelected(o2); 1416 if (s1 && !s2) 1417 return 1; 1418 if (!s1 && s2) 1419 return -1; 1420 return o1.compareTo(o2); 1421 } 1422 }); 1423 return sorted; 1424 } 1425 1428 1426 /* Shows areas before non-areas */ 1429 1427 @Override 1430 1428 public void visitAll(DataSet data, Boolean virtual) { … … 1433 1431 //profilerOmitDraw = Main.pref.getBoolean("mappaint.profiler.omitdraw",false); 1434 1432 1435 1433 useStyleCache = Main.pref.getBoolean("mappaint.cache",true); 1436 fillAreas = Main.pref.getInteger("mappaint.fillareas", 10000000);1434 int fillAreas = Main.pref.getInteger("mappaint.fillareas", 10000000); 1437 1435 fillAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.fillalpha", 50)))); 1438 1436 showNames = Main.pref.getInteger("mappaint.shownames", 10000000); 1439 1437 showIcons = Main.pref.getInteger("mappaint.showicons", 10000000); … … 1468 1466 maxEN = nc.getEastNorth(nc.getWidth()-1,0); 1469 1467 1470 1468 1471 selectedCall = false;1472 1469 ++paintid; 1473 1470 viewid = nc.getViewID(); 1474 1471 … … 1491 1488 // profilerN = 0; 1492 1489 for (final Relation osm : data.relations) 1493 1490 { 1494 if( !osm.isDeleted() && !osm.isFiltered() && !osm.incomplete&& osm.mappaintVisibleCode != viewid)1491 if(drawable(osm) && osm.mappaintVisibleCode != viewid) 1495 1492 { 1496 osm.visit(this);1493 paintUnselectedRelation(osm); 1497 1494 // profilerN++; 1498 1495 } 1499 1496 } … … 1506 1503 1507 1504 /*** AREAS ***/ 1508 1505 // profilerN = 0; 1509 for (final Way osm : data.ways) 1510 { 1511 if (!osm.incomplete && !osm.isDeleted() && !osm.isFiltered() 1506 for (final Way osm : selectedLast(data, data.ways)) { 1507 if (drawable(osm) 1512 1508 && osm.mappaintVisibleCode != viewid && osm.mappaintDrawnCode != paintid) 1513 1509 { 1514 1510 if(isPrimitiveArea(osm) && osm.mappaintDrawnAreaCode != paintid) 1515 1511 { 1516 osm.visit(this);1512 drawWay(osm, fillAreas); 1517 1513 // profilerN++; 1518 } else {1514 }// else { 1519 1515 noAreaWays.add(osm); 1520 }1516 //} 1521 1517 } 1522 1518 } 1523 1519 … … 1530 1526 1531 1527 /*** WAYS ***/ 1532 1528 // profilerN = 0; 1533 fillAreas = 0; 1534 for (final OsmPrimitive osm : noAreaWays) 1529 for (final Way osm : noAreaWays) 1535 1530 { 1536 osm.visit(this);1531 drawWay(osm, 0); 1537 1532 // profilerN++; 1538 1533 } 1539 1534 … … 1548 1543 { 1549 1544 /*** WAYS (filling disabled) ***/ 1550 1545 // profilerN = 0; 1551 for (final OsmPrimitive osm: data.ways)1552 if ( !osm.incomplete && !osm.isDeleted() && !osm.isFiltered() && !data.isSelected(osm)1553 && osm.mappaintVisibleCode != viewid )1546 for (final Way way : data.ways) 1547 if (drawable(way) && !data.isSelected(way) 1548 && way.mappaintVisibleCode != viewid ) 1554 1549 { 1555 osm.visit(this);1550 drawWay(way, 0); 1556 1551 // profilerN++; 1557 1552 } 1558 1553 … … 1565 1560 } 1566 1561 1567 1562 /*** SELECTED ***/ 1568 selectedCall = true;1569 1563 //profilerN = 0; 1570 1564 for (final OsmPrimitive osm : data.getSelected()) { 1571 1565 if (!osm.incomplete && !osm.isDeleted() && !(osm instanceof Node) 1572 && osm.mappaintVisibleCode != viewid && osm.mappaintDrawnCode != paintid) 1566 && osm.mappaintVisibleCode != viewid && osm.mappaintDrawnCode != paintid 1567 ) 1573 1568 { 1574 osm.visit(this); 1569 osm.visit(new AbstractVisitor() { 1570 public void visit(Way w) { 1571 drawWay(w, 0); 1572 } 1573 public void visit(Node n) { 1574 drawNode(n); 1575 } 1576 public void visit(Relation r) { 1577 /* TODO: is it possible to do this like the nodes/ways code? */ 1578 //if(profilerOmitDraw) 1579 // return; 1580 r.mappaintVisibleCode = 0; 1581 for (RelationMember m : r.getMembers()) { 1582 if (m.isNode() && drawable(m.getMember())) { 1583 drawSelectedMember(m.getMember(), styles != null ? getPrimitiveStyle(m.getMember()) : null, true, true); 1584 } 1585 } 1586 } 1587 }); 1575 1588 // profilerN++; 1576 1589 } 1577 1590 } … … 1587 1600 1588 1601 /*** NODES ***/ 1589 1602 //profilerN = 0; 1590 for (final OsmPrimitive osm : data.nodes)1603 for (final Node osm : data.nodes) 1591 1604 if (!osm.incomplete && !osm.isDeleted() && (data.isSelected(osm) || !osm.isFiltered()) 1592 1605 && osm.mappaintVisibleCode != viewid && osm.mappaintDrawnCode != paintid) 1593 1606 { 1594 osm.visit(this);1607 drawNode(osm); 1595 1608 // profilerN++; 1596 1609 } 1597 1610
