Changeset 4954 in josm


Ignore:
Timestamp:
Feb 16, 2012 3:37:24 PM (16 months 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.