Changeset 4954 in josm for trunk/src


Ignore:
Timestamp:
2012-02-16T15:37:24+01:00 (13 years ago)
Author:
akks
Message:

Tab in draw mode allows snapping to current way point projections ant to other line segment (right-click)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/mapmode/DrawAction.java

    r4924 r4954  
    334334                WaySegment seg = Main.map.mapView.getNearestWaySegment(curMousePos, OsmPrimitive.isSelectablePredicate);
    335335                if (seg!=null) {
    336                     snapHelper.fixToSegment(seg);
     336                    snapHelper.setBaseSegment(seg);
    337337                    computeHelperLine();
    338338                    redrawIfRequired();
     
    772772
    773773
    774         double hdg = Math.toDegrees(currentBaseNode.getEastNorth()
     774        double curHdg = Math.toDegrees(currentBaseNode.getEastNorth()
    775775                .heading(currentMouseEastNorth));
     776        double baseHdg=-1;
    776777        if (previousNode != null) {
    777             angle = hdg - Math.toDegrees(previousNode.getEastNorth()
     778            baseHdg = Math.toDegrees(previousNode.getEastNorth()
    778779                    .heading(currentBaseNode.getEastNorth()));
    779             angle += angle < 0 ? 360 : 0;
    780         }
    781 
    782         snapHelper.checkAngleSnapping(currentMouseEastNorth,angle);
    783         if (!snapHelper.isActive()) {
    784             // find out the distance, in metres, between the base point and the mouse cursor
    785             LatLon mouseLatLon = mv.getProjection().eastNorth2latlon(currentMouseEastNorth);
    786             distance = currentBaseNode.getCoor().greatCircleDistance(mouseLatLon);
    787             showStatusInfo(angle, hdg, distance);
    788         } // elsewhere status ar was filled by snapHelper
     780        }
     781     
     782        snapHelper.checkAngleSnapping(currentMouseEastNorth,baseHdg, curHdg);
     783
     784        // status bar was filled by snapHelper
    789785       
    790786        // Now done in redrawIfRequired()
     
    11971193        boolean snapOn; // snapping is turned on
    11981194       
    1199         private boolean active; // snapping is activa for current mouse position
     1195        private boolean active; // snapping is active for current mouse position
    12001196        private boolean fixed; // snap angle is fixed
    1201         private boolean absoluteFix; // snap angle is absolute
     1197        private boolean absoluteFix; // snap angle is absolute 
    12021198       
    12031199        private boolean drawConstructionGeometry;
    12041200        private boolean showProjectedPoint;
    12051201        private boolean showAngle;
     1202
     1203        private boolean snapToProjections;
    12061204       
    12071205        EastNorth dir2;
     
    12091207        String labelText;
    12101208        double lastAngle;
     1209        double customBaseHeading=-1; // angle of base line, if not last segment)
     1210        private EastNorth segmentPoint1; // remembered first point of base segment
     1211        private EastNorth segmentPoint2; // remembered second point of base segment
     1212        private EastNorth projectionSource; // point that we are projecting to the line
    12111213               
    12121214        double snapAngles[];
     
    12181220        final String fixFmt="%d "+tr("FIX");
    12191221        Color snapHelperColor;
     1222        private Color highlightColor;
     1223
    12201224        private Stroke normalStroke;
    12211225        private Stroke helperStroke;
     1226        private Stroke highlightStroke;
    12221227       
    12231228        JCheckBoxMenuItem checkBox;
     
    12291234                       
    12301235            Collection<String> angles = Main.pref.getCollection("draw.anglesnap.angles",
    1231                     Arrays.asList("0","30","45","60","90","120","135","150"));
     1236                    Arrays.asList("0","30","45","60","90","120","135","150","180"));
    12321237           
    12331238            snapAngles = new double[2*angles.size()];
     
    12461251            drawConstructionGeometry = Main.pref.getBoolean("draw.anglesnap.drawConstructionGeometry", true);
    12471252            showProjectedPoint = Main.pref.getBoolean("draw.anglesnap.drawProjectedPoint", true);
     1253            snapToProjections = Main.pref.getBoolean("draw.anglesnap.projectionsnap", true);
     1254
    12481255            showAngle = Main.pref.getBoolean("draw.anglesnap.showAngle", true);
    12491256
    12501257            normalStroke = new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
    12511258            snapHelperColor = Main.pref.getColor(marktr("draw angle snap"), Color.ORANGE);
     1259
     1260            highlightColor = Main.pref.getColor(marktr("draw angle snap highlight"), new Color(Color.ORANGE.getRed(),Color.ORANGE.getGreen(),Color.ORANGE.getBlue(),128));
     1261            highlightStroke = new BasicStroke(10, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
    12521262           
    12531263            float dash1[] = { 4.0f };
     
    12871297                g2.draw(b);
    12881298            }
    1289 
     1299            if (projectionSource!=null) {
     1300                g2.setColor(snapHelperColor);
     1301                g2.setStroke(helperStroke);
     1302                b = new GeneralPath();
     1303                b.moveTo(p3.x,p3.y);
     1304                Point pp=mv.getPoint(projectionSource);
     1305                b.lineTo(pp.x,pp.y);
     1306                g2.draw(b);
     1307            }
     1308           
     1309           
     1310            if (customBaseHeading>=0) {
     1311                g2.setColor(highlightColor);
     1312                g2.setStroke(highlightStroke);
     1313                b = new GeneralPath();
     1314                Point pp1=mv.getPoint(segmentPoint1);
     1315                Point pp2=mv.getPoint(segmentPoint2);
     1316                b.moveTo(pp1.x,pp1.y);
     1317                b.lineTo(pp2.x,pp2.y);
     1318                g2.draw(b);
     1319            }
     1320           
     1321           
    12901322            g2.setColor(selectedColor);
    12911323            g2.setStroke(normalStroke);
     
    13081340        /* If mouse position is close to line at 15-30-45-... angle, remembers this direction
    13091341         */
    1310         public  void checkAngleSnapping(EastNorth currentEN, double angle) {
    1311             if (!snapOn) return;
    1312             if (!absoluteFix && previousNode==null) return;
     1342        public void checkAngleSnapping(EastNorth currentEN, double baseHeading, double curHeading) {
     1343            EastNorth p0 = currentBaseNode.getEastNorth();
     1344            EastNorth snapPoint = currentEN;
     1345            double angle = -1;
    13131346           
    1314             double nearestAngle;
    1315             if (fixed) {
    1316                 nearestAngle = lastAngle; // if direction is fixed
    1317                 active=true;
    1318             } else {
    1319                 nearestAngle = getNearestAngle(angle);
    1320                 lastAngle = nearestAngle;
    1321                 active = Math.abs(nearestAngle-180)>1e-3 && getAngleDelta(nearestAngle,angle)<snapAngleTolerance;
    1322             }
     1347            double activeBaseHeading = (customBaseHeading>=0)? customBaseHeading : baseHeading;
    13231348           
    1324             if (active) {
    1325                 double de,dn,l, phi;
    1326 
    1327                 EastNorth p0 = currentBaseNode.getEastNorth();
    1328                 e0=p0.east(); n0=p0.north();
     1349            if (snapOn && (activeBaseHeading>=0)) {
     1350                angle = curHeading - activeBaseHeading;
     1351                if (angle < 0) angle+=360;
     1352                if (angle > 360) angle=0;
    13291353               
    1330                 if (showAngle)  {
    1331                     if (fixed) {
    1332                         if (absoluteFix) labelText = "=";
    1333                                     else labelText = String.format(fixFmt, (int) nearestAngle);
    1334                     } else labelText = String.format("%d", (int) nearestAngle);
     1354                double nearestAngle;
     1355                if (fixed) {
     1356                    nearestAngle = lastAngle; // if direction is fixed use previous angle
     1357                    active = true;
    13351358                } else {
    1336                     if (fixed) {
    1337                         if (absoluteFix) labelText = "=";
    1338                         else labelText = String.format(tr("FIX"),0);
    1339                     } else labelText="";
    1340                 }
    1341                
    1342                 if (absoluteFix) {
    1343                     de=0; dn=1;
     1359                    nearestAngle = getNearestAngle(angle);
     1360                    if (getAngleDelta(nearestAngle, angle) < snapAngleTolerance) {
     1361                        active = (customBaseHeading>=0)? true : Math.abs(nearestAngle - 180) > 1e-3;
     1362                        // if angle is to previous segment, exclude 180 degrees
     1363                        lastAngle = nearestAngle;
     1364                    } else active=false;
     1365                }
     1366
     1367                if (active) {
     1368                    double de, dn, l, phi;
     1369                    e0 = p0.east();
     1370                    n0 = p0.north();
     1371                    buildLabelText(nearestAngle);
     1372
     1373                    phi = (nearestAngle + activeBaseHeading) * Math.PI / 180;
     1374                    // (pe,pn) - direction of snapping line
     1375                    pe = Math.sin(phi);
     1376                    pn = Math.cos(phi);
     1377                    double scale = 20 * Main.map.mapView.getDist100Pixel();
     1378                    dir2 = new EastNorth(e0 + scale * pe, n0 + scale * pn);
     1379                    snapPoint = getSnapPoint(currentEN);
    13441380                } else {
    1345                     EastNorth prev = previousNode.getEastNorth();
    1346                     de = e0-prev.east();
    1347                     dn = n0-prev.north();
    1348                     l=Math.hypot(de, dn);
    1349                     if (Math.abs(l)<1e-4) { noSnapNow(); return; }
    1350                     de/=l; dn/=l;
    1351                 }
    1352                
    1353                 phi=nearestAngle*Math.PI/180;
    1354                 // (pe,pn) - direction of snapping line
    1355                 pe = de*Math.cos(phi) + dn*Math.sin(phi); 
    1356                 pn = -de*Math.sin(phi) + dn*Math.cos(phi);
    1357                 double scale = 20*Main.map.mapView.getDist100Pixel();
    1358                 dir2 = new EastNorth( e0+scale*pe, n0+scale*pn);
    1359                 EastNorth snapPoint = getSnapPoint(currentEN);
    1360                
    1361                 // find out the distance, in metres, between the base point and projected point
    1362                 LatLon mouseLatLon = Main.map.mapView.getProjection().eastNorth2latlon(snapPoint);
    1363                 double distance = currentBaseNode.getCoor().greatCircleDistance(mouseLatLon);
    1364                 double hdg = Math.toDegrees(p0.heading(snapPoint));
    1365                 if (previousNode != null) {
    1366                     angle = hdg - Math.toDegrees(previousNode.getEastNorth().heading(p0));
    1367                     angle += angle < 0 ? 360 : 0;
    1368                     if (Math.abs(angle-360)<1e-4) angle=0;
    1369                 }
    1370                
    1371                 showStatusInfo(angle, hdg, distance);
    1372            } else {
    1373                 noSnapNow();
    1374            }
     1381                    noSnapNow();
     1382                }
     1383            }
     1384
     1385            // find out the distance, in metres, between the base point and projected point
     1386            LatLon mouseLatLon = Main.map.mapView.getProjection().eastNorth2latlon(snapPoint);
     1387            double distance = currentBaseNode.getCoor().greatCircleDistance(mouseLatLon);
     1388            double hdg = Math.toDegrees(p0.heading(snapPoint));
     1389            // heading of segment from current to calculated point, not to mouse position
     1390           
     1391            if (baseHeading >=0 ) { // there is previous line segment with some heading
     1392                angle = hdg - baseHeading;
     1393                if (angle < 0) angle+=360;
     1394                if (angle > 360) angle=0;
     1395            }
     1396            showStatusInfo(angle, hdg, distance);
     1397        }
     1398
     1399        private void buildLabelText(double nearestAngle) {
     1400            if (showAngle) {
     1401                if (fixed) {
     1402                    if (absoluteFix) {
     1403                        labelText = "=";
     1404                    } else {
     1405                        labelText = String.format(fixFmt, (int) nearestAngle);
     1406                    }
     1407                } else {
     1408                    labelText = String.format("%d", (int) nearestAngle);
     1409                }
     1410            } else {
     1411                if (fixed) {
     1412                    if (absoluteFix) {
     1413                        labelText = "=";
     1414                    } else {
     1415                        labelText = String.format(tr("FIX"), 0);
     1416                    }
     1417                } else {
     1418                    labelText = "";
     1419                }
     1420            }
    13751421        }
    13761422       
     
    13801426            double dn=p.north()-n0;
    13811427            double l = de*pe+dn*pn;
    1382             if (!absoluteFix && l<1e-5) {active=false; return p; } //  do not go backward!
     1428            double delta = Main.map.mapView.getDist100Pixel()/20;
     1429            if (!absoluteFix && l<delta) {active=false; return p; } //  do not go backward!
     1430           
     1431            projectionSource=null;
     1432            if (snapToProjections) {
     1433                DataSet ds = getCurrentDataSet();
     1434                Collection<Way> selectedWays = ds.getSelectedWays();
     1435                if (selectedWays.size()==1) {
     1436                    Way w = selectedWays.iterator().next();
     1437                    for (Node n: w.getNodes()) {
     1438                        EastNorth en=n.getEastNorth();
     1439                        double l1 = (en.east()-e0)*pe+(en.north()-n0)*pn;
     1440                        if (Math.abs(l1-l) < delta) {
     1441                            l=l1;
     1442                            projectionSource =  en;
     1443                            break;
     1444                        }
     1445                    }
     1446                }
     1447            }
    13831448            return projected = new EastNorth(e0+l*pe, n0+l*pn);
    13841449        }
     
    13911456        }
    13921457
    1393         public void fixToSegment(WaySegment seg) {
     1458        public void setBaseSegment(WaySegment seg) {
    13941459            if (seg==null) return;
    1395             double hdg = seg.getFirstNode().getEastNorth().heading(seg.getSecondNode().getEastNorth());
     1460            segmentPoint1=seg.getFirstNode().getEastNorth();
     1461            segmentPoint2=seg.getSecondNode().getEastNorth();
     1462           
     1463            double hdg = segmentPoint1.heading(segmentPoint2);
    13961464            hdg=Math.toDegrees(hdg);
    13971465            if (hdg<0) hdg+=360;
    1398             if (hdg>360) hdg=hdg-360;
    1399             fixed=true;
    1400             absoluteFix=true;
    1401             lastAngle=hdg;
     1466            if (hdg>360) hdg-=360;
     1467            //fixed=true;
     1468            //absoluteFix=true;
     1469            customBaseHeading=hdg;
    14021470        }
    14031471
     
    14121480            }
    14131481            checkBox.setState(snapOn);
     1482            customBaseHeading=-1;
    14141483        }
    14151484       
     
    14171486            snapOn = true;
    14181487            checkBox.setState(snapOn);
     1488            customBaseHeading=-1;
    14191489            unsetFixedMode();
    14201490        }
     
    14231493            snapOn = !snapOn;
    14241494            checkBox.setState(snapOn);
     1495            customBaseHeading=-1;
    14251496            unsetFixedMode();
    14261497        }
     
    14681539       
    14691540        MouseListener anglePopupListener = new PopupMenuLauncher( new JPopupMenu() {
    1470             { 
    1471                add(new JCheckBoxMenuItem(new AbstractAction(tr("Show helper geometry")){
     1541               JCheckBoxMenuItem helperCb = new JCheckBoxMenuItem(new AbstractAction(tr("Show helper geometry")){
    14721542                    public void actionPerformed(ActionEvent e) {
    14731543                        boolean sel=((JCheckBoxMenuItem) e.getSource()).getState();
     
    14771547                        init(); enableSnapping();
    14781548                    }
    1479                }));
     1549               });
     1550               JCheckBoxMenuItem projectionCb = new JCheckBoxMenuItem(new AbstractAction(tr("Snap to node projections")){
     1551                    public void actionPerformed(ActionEvent e) {
     1552                        boolean sel=((JCheckBoxMenuItem) e.getSource()).getState();
     1553                        Main.pref.put("draw.anglesnap.projectionsnap", sel);
     1554                        init(); enableSnapping();
     1555                    }
     1556               });
     1557            { 
     1558               helperCb.setState(Main.pref.getBoolean("draw.anglesnap.drawConstructionGeometry",true));
     1559               projectionCb.setState(Main.pref.getBoolean("draw.anglesnap.projectionsnapgvff",true));
     1560               add(helperCb);
     1561               add(projectionCb);;
    14801562               add(new AbstractAction(tr("Disable")) {
    14811563                public void actionPerformed(ActionEvent e) {
     
    14861568               add(new AbstractAction(tr("0,90,...")) {
    14871569                public void actionPerformed(ActionEvent e) {
    1488                     saveAngles("0","90");
     1570                    saveAngles("0","90","180");
    14891571                    init(); enableSnapping();
    14901572                }
     
    14921574               add(new AbstractAction(tr("0,45,90,...")) {
    14931575                public void actionPerformed(ActionEvent e) {
    1494                     saveAngles("0","45","90","135");
     1576                    saveAngles("0","45","90","135","180");
    14951577                    init(); enableSnapping();
    14961578                }
     
    14981580               add(new AbstractAction(tr("0,30,45,60,90,...")) {
    14991581                public void actionPerformed(ActionEvent e) {
    1500                     saveAngles("0","30","45","60","90","120","135","150");
     1582                    saveAngles("0","30","45","60","90","120","135","150","180");
    15011583                    init(); enableSnapping();
    15021584                }
Note: See TracChangeset for help on using the changeset viewer.