Changeset 26101 in osm
- Timestamp:
- 2011-06-05T21:44:03+02:00 (14 years ago)
- Location:
- applications/editors/josm/plugins/turbopen/src/org/openstreetmap/josm/plugins/fastdraw
- Files:
-
- 1 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/turbopen/src/org/openstreetmap/josm/plugins/fastdraw/FastDrawingMode.java
r26081 r26101 15 15 import java.awt.Point; 16 16 import java.awt.event.MouseEvent; 17 import java.awt.event.MouseWheelEvent;18 17 import org.openstreetmap.josm.data.coor.LatLon; 19 18 import static org.openstreetmap.josm.tools.I18n.tr; … … 27 26 import java.awt.event.InputEvent; 28 27 import java.awt.event.KeyEvent; 29 import java.awt.event.MouseWheelListener;30 28 import java.io.IOException; 31 29 import java.util.*; 32 30 import javax.swing.JOptionPane; 33 import javax.swing.plaf.basic.BasicArrowButton;34 31 35 32 import org.openstreetmap.josm.Main; 36 import org.openstreetmap.josm.actions.SimplifyWayAction;37 33 import org.openstreetmap.josm.actions.mapmode.MapMode; 38 34 import org.openstreetmap.josm.command.AddCommand; … … 40 36 import org.openstreetmap.josm.command.SequenceCommand; 41 37 import org.openstreetmap.josm.data.Bounds; 42 import org.openstreetmap.josm.data.osm.BBox;43 38 import org.openstreetmap.josm.data.osm.Node; 44 39 import org.openstreetmap.josm.data.osm.OsmPrimitive; … … 49 44 import org.openstreetmap.josm.gui.layer.MapViewPaintable; 50 45 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 51 import org.openstreetmap.josm.tools.Geometry;52 46 import org.openstreetmap.josm.tools.ImageProvider; 53 47 import org.openstreetmap.josm.tools.Shortcut; … … 59 53 private static final String DRAWINGMODE_MESSAGE= 60 54 "Click or Click&drag to continue, Ctrl-Click to add fixed node, Shift-Click to start new line"; 55 56 private static final Color COLOR_FIXED = Color.green; 57 private static final Color COLOR_NORMAL = Color.white; 58 private static final Color COLOR_DELETE = Color.red; 59 private static final Color COLOR_SELECTEDFRAGMENT = Color.red; 60 private static final Color COLOR_EDITEDFRAGMENT = Color.orange; 61 61 62 62 private double maxDist; … … 68 68 private double startingEps; 69 69 70 private DrawnPolyLine line; 70 71 private MapView mv; 71 private ArrayList<LatLon> points = new ArrayList<LatLon>(100);72 private ArrayList<LatLon> simplePoints = new ArrayList<LatLon>(100);73 72 private String statusText; 74 73 private boolean drawing; … … 77 76 private boolean oldCtrl; 78 77 private boolean oldShift; 79 Set<LatLon> used; 80 Set<LatLon> fixed = new HashSet<LatLon>(); 81 private double eps=startingEps; 78 private double eps; 82 79 private final Stroke strokeForSimplified; 83 80 private final Stroke strokeForOriginal; … … 89 86 private final Cursor cursorNode; 90 87 private boolean nearpoint; 88 private LatLon highlighted; 89 private int nearestIdx; 90 private Stroke strokeForDelete; 91 91 92 92 … … 96 96 tr("Mode: {0}", tr("Fast drawing mode")), 97 97 KeyEvent.VK_T, Shortcut.GROUP_EDIT), mapFrame, Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 98 line=new DrawnPolyLine(); 98 99 strokeForOriginal = new BasicStroke(); 100 strokeForDelete = new BasicStroke(3); 99 101 strokeForSimplified = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL,5f, 100 102 new float[]{5.f,5f},0f); … … 107 109 } 108 110 111 // <editor-fold defaultstate="collapsed" desc="Event listeners"> 112 109 113 @Override 110 114 public void enterMode() { … … 113 117 loadPrefs(); 114 118 mv = Main.map.mapView; 115 119 line.setMv(mv); 120 116 121 if (getCurrentDataSet() == null) return; 117 122 … … 144 149 savePrefs(); 145 150 Main.map.mapView.setCursor(cursorDraw); 146 Main.map.mapView.repaint();151 repaint(); 147 152 } 148 153 … … 161 166 @Override 162 167 public void paint(Graphics2D g, MapView mv, Bounds bbox) { 163 if (points.size() == 0) return; 164 List<LatLon> pts=points; 165 if (simplePoints!=null && simplePoints.size()>0) { 168 LinkedList<LatLon> pts=line.getPoints(); 169 if (pts.isEmpty()) return; 170 171 if (line.wasSimplified()) { 166 172 // we are drawing simplified version, that exists 167 pts=simplePoints;168 173 g.setStroke(strokeForSimplified); 169 174 } else { … … 172 177 173 178 Point p1, p2; 174 LatLon pp2; 175 p1 = getPoint(pts.get(0)); 176 g.setColor(C olor.green);179 LatLon pp1, pp2; 180 p1 = line.getPoint(pts.get(0)); 181 g.setColor(COLOR_FIXED); 177 182 g.fillOval(p1.x - 3, p1.y - 3, 7, 7); 183 Color lineColor=COLOR_NORMAL; 178 184 if (pts.size() > 1) { 185 Iterator<LatLon> it1,it2; 186 it1=pts.listIterator(0); 187 it2=pts.listIterator(1); 179 188 for (int i = 0; i < pts.size() - 1; i++) { 180 g.setColor(Color.red); 181 p1 = getPoint(pts.get(i)); 182 pp2 = pts.get(i + 1); 183 p2 = getPoint(pts.get(i + 1)); 184 189 pp1 = it1.next(); 190 p1 = line.getPoint(pp1); 191 pp2 = it2.next(); 192 p2 = line.getPoint(pp2); 193 if (highlighted==pp1) {lineColor=COLOR_SELECTEDFRAGMENT;} 194 if (line.isLastPoint(i)) { lineColor=COLOR_EDITEDFRAGMENT; } 195 g.setColor(lineColor); 185 196 g.drawLine(p1.x, p1.y, p2.x, p2.y); 186 if (fixed.contains(pp2)) { 187 g.setColor(Color.green); 197 // g.fillOval(p2.x - 5, p2.y - 5, 11, 11); 198 if (line.isFixed(pp2)) { 199 lineColor=COLOR_NORMAL; 200 g.setColor(COLOR_FIXED); 188 201 g.fillOval(p2.x - 3, p2.y - 3, 7, 7); 189 202 } else { 190 203 g.fillRect(p2.x - 1, p2.y - 1, 3, 3); 191 204 } 205 if (shift && !line.wasSimplified() && nearestIdx==i+1 ) { 206 // highlight node to delete 207 g.setStroke(strokeForDelete); 208 g.setColor(COLOR_DELETE); 209 g.drawLine(p2.x - 5, p2.y - 5,p2.x + 5, p2.y + 5); 210 g.drawLine(p2.x - 5, p2.y + 5,p2.x + 5, p2.y - 5); 211 g.setStroke(strokeForOriginal); 212 } 213 if (ctrl && !line.wasSimplified() && nearestIdx==i+1 ) { 214 // highlight node to delete 215 g.setStroke(strokeForDelete); 216 g.setColor( line.isFixed(pp2) ? COLOR_NORMAL: COLOR_FIXED); 217 g.drawOval(p2.x - 5, p2.y - 5, 11, 11); 218 g.setStroke(strokeForOriginal); 219 } 192 220 } 193 221 } … … 206 234 updateCursor(); 207 235 // updateStatusLine(); 208 Main.map.mapView.repaint();236 repaint(); 209 237 } 210 238 … … 214 242 if (e.getButton() != MouseEvent.BUTTON1) return; 215 243 216 int idx = findClosestPoint(e.getX(),e.getY(),maxDist); 244 245 int idx=line.findClosestPoint(e.getPoint(),maxDist); 217 246 if (idx==0) { 247 line.closeLine(); 218 248 // the way should become closed 219 points.add(points.get(idx));220 249 drawing=false; 221 250 ready=true; … … 224 253 } 225 254 226 if (shift) newDrawing(); 227 if (ready) { 228 setStatusLine(tr(SIMPLIFYMODE_MESSAGE)); 255 if (ctrl && shift) newDrawing(); 256 if (!ctrl && shift) { 257 if (idx>=0) {line.deleteNode(idx); nearestIdx=-1;} 258 else line.tryToDeleteSegment(e.getPoint()); 229 259 return; 230 260 } 261 if (idx>=0) { 262 if (ctrl) { 263 // toggle fixed point 264 line.toggleFixed(idx); 265 } 266 return; 267 } 268 269 if (ready) { setStatusLine(tr(SIMPLIFYMODE_MESSAGE)); return; } 270 drawing = true; 231 271 232 272 LatLon p = getLatLon(e); 233 273 Node nd1 = getNearestNode(e.getPoint(), maxDist); 234 235 274 if (nd1!=null) { 236 275 // found node, make it fixed point of the line 237 276 //System.out.println("node "+nd1); 238 277 p=nd1.getCoor(); 239 fixed.add(p);278 line.fixPoint(p); 240 279 } 241 280 242 drawing = true; 243 points.add(p); 244 if (ctrl) fixed.add(p); 245 simplePoints=null; 281 line.addLast(p); 282 if (ctrl) line.fixPoint(p); 283 line.clearSimplifiedVersion(); 246 284 247 285 setStatusLine(tr("Please move the mouse to draw new way")); 248 Main.map.mapView.repaint(); 249 250 } 251 252 253 286 repaint(); 287 288 } 289 254 290 @Override 255 291 public void mouseReleased(MouseEvent e) { … … 259 295 if (!ready) setStatusLine(tr(DRAWINGMODE_MESSAGE) 260 296 + tr(SIMPLIFYMODE_MESSAGE)); 261 Main.map.mapView.repaint();297 repaint(); 262 298 } 263 299 … … 274 310 if (nearpoint!=nearpoint2) {nearpoint=nearpoint2;updateCursor();} 275 311 276 if (!drawing) return; 277 if (ready) { 278 setStatusLine(tr(SIMPLIFYMODE_MESSAGE)); 279 } 280 281 Point lastP = getPoint(points.get(points.size() - 1)); 282 312 nearestIdx=line.findClosestPoint(e.getPoint(),maxDist); 313 314 if (!drawing) { 315 if (shift) { 316 // find line fragment to highlight 317 LatLon h2=line.findBigSegment(e.getPoint()); 318 if (highlighted!=h2) { 319 highlighted=h2; 320 repaint(); 321 } 322 } 323 return; 324 } 325 if (ready) setStatusLine(tr(SIMPLIFYMODE_MESSAGE)); 326 327 // do not draw points close to existing points - we do not want self-intersections 328 if (nearestIdx>=0) { return; } 329 330 Point lastP = line.getLastPoint(); // last point of line fragment being edited 331 283 332 if (nearpoint){ 284 333 if ( Math.hypot(e.getX() - lastP.x, e.getY() - lastP.y) > 1e-2) { 285 points.add(nd1.getCoor()); 286 fixed.add(nd1.getCoor()); 287 Main.map.mapView.repaint(); 334 line.addFixed(nd1.getCoor()); // snap to node coords 335 repaint(); 288 336 } 289 337 } else { 290 338 if (Math.hypot(e.getX() - lastP.x, e.getY() - lastP.y) > minPixelsBetweenPoints) { 291 points.add(getLatLon(e));292 Main.map.mapView.repaint();339 line.addLast(getLatLon(e)); // free mouse-drawing 340 repaint(); 293 341 } 294 342 } … … 297 345 } 298 346 299 @Override 300 protected void updateStatusLine() { 301 Main.map.statusLine.setHelpText(statusText); 302 Main.map.statusLine.repaint(); 303 304 } 305 306 LatLon getLatLon(MouseEvent e) { 307 return mv.getLatLon(e.getX(), e.getY()); 308 } 309 310 Point getPoint(LatLon p) { 311 return mv.getPoint(p); 312 } 313 314 public void newDrawing() { 315 points.clear(); 316 used=null; 317 fixed.clear(); 318 eps=startingEps; 319 ready=false; 320 simplePoints=null; 321 } 322 323 public void back() { 324 if (points.size() == 0) { 325 return; 326 } 327 points.remove(points.size() - 1); 328 Main.map.mapView.repaint(); 347 private void doKeyEvent(KeyEvent e) { 348 /// System.out.println(e); 349 if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { 350 if (line.wasSimplified()) { 351 line.clearSimplifiedVersion(); 352 repaint(); 353 eps=startingEps; 354 } 355 back(); 356 } 357 if (e.getKeyCode() == KeyEvent.VK_ENTER) { 358 // first Enter = simplify, second = save the way 359 if (!line.wasSimplified()) { 360 line.simplify(eps); 361 setStatusLine(tr(SIMPLIFYMODE_MESSAGE)); 362 } else saveAsWay(); 363 } 364 if (e.getKeyCode() == KeyEvent.VK_DOWN) { 365 // more details 366 e.consume(); 367 changeEpsilon(epsilonMult); 368 } 369 if (e.getKeyCode() == KeyEvent.VK_UP) { 370 // less details 371 e.consume(); 372 changeEpsilon(1/epsilonMult); 373 } 374 if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { 375 // less details 376 e.consume(); 377 line.moveToTheEnd(); 378 } 379 380 329 381 } 330 382 … … 339 391 } 340 392 341 private void doKeyEvent(KeyEvent e) { 342 /// System.out.println(e); 343 if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE) { 344 if (simplePoints!=null) { 345 simplePoints=null; 346 Main.map.mapView.repaint(); 347 eps=startingEps; 348 } 349 back(); 350 } 351 if (e.getKeyCode() == KeyEvent.VK_ENTER) { 352 // first Enter = simplify, second = save the way 353 if (simplePoints==null) { 354 simplify(eps); 355 setStatusLine(tr(SIMPLIFYMODE_MESSAGE)); 356 } else saveAsWay(); 357 } 358 if (e.getKeyCode() == KeyEvent.VK_DOWN) { 359 // more details 360 e.consume(); 361 changeEpsilon(epsilonMult); 362 } 363 if (e.getKeyCode() == KeyEvent.VK_UP) { 364 // less details 365 e.consume(); 366 changeEpsilon(1/epsilonMult); 367 } 368 } 369 370 371 void changeEpsilon(double k) { 372 //System.out.println(tr("Eps={0}", eps)); 373 eps*=k; 374 setStatusLine(tr("Eps={0}", eps)); 375 simplify(eps); 376 Main.map.mapView.repaint(); 377 } 378 379 /** 380 * Simplified drawn line, not touching the nodes includes in "fixed" set. 381 */ 382 private void simplify(double epsilon) { 383 //System.out.println("Simplify polyline..."); 384 int n = points.size(); 385 if (n < 3) return; 386 used = new HashSet<LatLon>(n); 387 int start = 0; 388 for (int i = 0; i < n; i++) { 389 LatLon p = points.get(i); 390 if (fixed.contains(p) || i == n - 1) { 391 if (start < 0) { 392 start = i; 393 } else { 394 douglasPeucker(start, i, epsilon, 0); 395 } 396 } 397 } 398 simplePoints = new ArrayList<LatLon>(n); 399 simplePoints.addAll(points); 400 simplePoints.retainAll(used); 401 Main.map.mapView.repaint(); 402 used = null; 403 } 404 405 /** 406 * Simplification of the line specified by "points" field. 407 * Remainin points are included to "used" set. 408 * @param start - starting index 409 * @param end - ending index 410 * @param epsilon - min point-to line distance in pixels (tolerance) 411 * @param depth - recursion level 412 */ 413 private void douglasPeucker(int start, int end, double epsilon, int depth) { 414 if (depth > 500) return; 415 if (end - start < 1) return; // incorrect invocation 416 LatLon first = points.get(start); 417 LatLon last = points.get(end); 418 Point firstp = getPoint(first); 419 Point lastp = getPoint(last); 420 used.add(first); 421 used.add(last); 422 423 if (end - start < 2) return; 424 425 int farthest_node = -1; 426 double farthest_dist = 0; 427 428 ArrayList<double[]> new_nodes = new ArrayList<double[]>(); 429 430 double d = 0; 431 432 for (int i = start + 1; i < end; i++) { 433 d = pointLineDistance(getPoint(points.get(i)), firstp, lastp); 434 if (d > farthest_dist) { 435 farthest_dist = d; 436 farthest_node = i; 437 } 438 } 439 440 if (farthest_dist > epsilon) { 441 douglasPeucker(start, farthest_node, epsilon, depth + 1); 442 douglasPeucker(farthest_node, end, epsilon, depth + 1); 443 } 444 } 445 446 /** Modfified funclion from LakeWalker 447 * Gets distance from point p1 to line p2-p3 448 */ 449 public double pointLineDistance(Point p1, Point p2, Point p3) { 450 double x0 = p1.x; double y0 = p1.y; 451 double x1 = p2.x; double y1 = p2.y; 452 double x2 = p3.x; double y2 = p3.y; 453 if (x2 == x1 && y2 == y1) { 454 return Math.hypot(x1 - x0, y1 - y0); 455 } else { 456 return Math.abs((x2-x1)*(y1-y0)-(x1-x0)*(y2-y1))/Math.hypot(x2 - x1,y2 - y1); 457 } 458 } 459 393 @Override 394 protected void updateStatusLine() { 395 Main.map.statusLine.setHelpText(statusText); 396 Main.map.statusLine.repaint(); 397 } 398 // </editor-fold> 399 400 // <editor-fold defaultstate="collapsed" desc="Different action helper methods"> 401 public void newDrawing() { 402 eps=startingEps; 403 ready=false; 404 line.clear(); 405 } 460 406 private void saveAsWay() { 461 List<LatLon> pts=points; 462 if (simplePoints!=null && simplePoints.size()>0) { 463 // we are drawig simplified version, that exists 464 pts=simplePoints; 465 } 466 407 List<LatLon> pts=line.getPoints(); 467 408 int n = pts.size(); 468 409 if (n == 0) return; … … 476 417 for (LatLon p : pts) { 477 418 Node nd=null; 478 if ( fixed.contains(p)) {419 if (line.isFixed(p)) { 479 420 // there may be a node with same ccoords! 480 nd = Main.map.mapView.getNearestNode(getPoint(p), OsmPrimitive.isUsablePredicate); 421 nd = Main.map.mapView.getNearestNode(line.getPoint(p), OsmPrimitive.isUsablePredicate); 481 422 } 482 423 if (nd==null) { … … 505 446 } 506 447 507 private int findClosestPoint(double x, double y, double d) { 508 int n=points.size(); 509 int idx=-1; 510 double dist,minD=1e10; 511 for (int i=0;i<n;i++) { 512 dist = Math.sqrt(getPoint(points.get(i)).distanceSq(x,y)); 513 if (dist<d && dist<minD) { 514 idx=i; 515 minD=dist; 516 }; 517 } 518 return idx; 519 } 520 448 private void repaint() { 449 Main.map.mapView.repaint(); 450 } 451 452 public void back() { 453 line.undo(); 454 repaint(); 455 } 456 457 void changeEpsilon(double k) { 458 //System.out.println(tr("Eps={0}", eps)); 459 eps*=k; 460 setStatusLine(tr("Eps={0}", eps)); 461 line.simplify(eps); 462 repaint(); 463 } 464 521 465 private void setStatusLine(String tr) { 522 466 statusText=tr; … … 548 492 minPixelsBetweenPoints = Main.pref.getDouble("fastdraw.mindelta", 20); 549 493 startingEps = Main.pref.getDouble("fastdraw.startingEps", 20); 494 eps=startingEps; 550 495 } 551 496 … … 570 515 571 516 } 572 517 // </editor-fold> 518 519 // <editor-fold defaultstate="collapsed" desc="Helper functions"> 520 573 521 private Node getNearestNode(Point point, double maxDist) { 574 522 Node nd = Main.map.mapView.getNearestNode(point, OsmPrimitive.isUsablePredicate); 575 if (nd!=null && getPoint(nd.getCoor()).distance(point)<=maxDist) return nd; 523 if (nd!=null && line.getPoint(nd.getCoor()).distance(point)<=maxDist) return nd; 576 524 else return null; 577 525 } 578 526 527 LatLon getLatLon(MouseEvent e) { 528 return mv.getLatLon(e.getX(), e.getY()); 529 } 530 // </editor-fold> 531 579 532 }
Note:
See TracChangeset
for help on using the changeset viewer.