Ticket #7423: bug7423.patch

File bug7423.patch, 3.5 KB (added by Balaitous, 12 years ago)

since r6920

  • src/org/openstreetmap/josm/actions/AlignInCircleAction.java

     
    2323import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2424import org.openstreetmap.josm.data.osm.Way;
    2525import org.openstreetmap.josm.gui.Notification;
    26 import org.openstreetmap.josm.tools.Geometry;
    2726import org.openstreetmap.josm.tools.Shortcut;
    2827
    2928/**
     
    181180
    182181        if (center == null) {
    183182            // Compute the centroid of nodes
    184             center = Geometry.getCentroid(nodes);
     183            center = getCenter(nodes);
     184            if(center == null) {
     185                new Notification(tr("Enable to compute center of circle."))
     186                    .setIcon(JOptionPane.INFORMATION_MESSAGE)
     187                    .setDuration(Notification.TIME_SHORT)
     188                    .show();
     189            }
    185190        }
    186191        // Node "center" now is central to all selected nodes.
    187192
     
    303308    }
    304309
    305310    /**
     311     * Compute center of the circle closest to different nodes.
     312     * Ensure exact center computation in case nodes are already aligned in circle.
     313     *
     314     * This is done by least square method.
     315     * Let be a_i x + b_i y + c_i = 0 equations of bisectors of each edges. Center must be intersection of all bisectors.
     316     *          [ a1  b1  ]         [ -c1 ]
     317     * With A = [ ... ... ] and Y = [ ... ]
     318     *          [ an  bn  ]         [ -cn ]
     319     * An approximation of center of circle is (At.A)^-1.At.Y
     320     * @param nodes Nodes parts of the circle (at least 3)
     321     * @return An approximation of the center, of null if there is no solution.
     322     */
     323    private EastNorth getCenter(List<Node> nodes) {
     324        /**
     325         * Equation of each bisector ax + by + c = 0
     326         */
     327        int nc = nodes.size();
     328        if(nc < 3) return null;
     329        double[] a = new double[nc];
     330        double[] b = new double[nc];
     331        double[] c = new double[nc];
     332        // Compute equation of bisector
     333        for(int i = 0; i < nc; i++) {
     334            EastNorth pt1 = nodes.get(i).getEastNorth();
     335            EastNorth pt2 = nodes.get((i+1) % nc).getEastNorth();
     336            a[i] = pt1.east() - pt2.east();
     337            b[i] = pt1.north() - pt2.north();
     338            double d = Math.sqrt(a[i]*a[i] + b[i]*b[i]);
     339            if(d == 0) return null;
     340            a[i] /= d;
     341            b[i] /= d;
     342            double xC = (pt1.east() + pt2.east()) / 2;
     343            double yC = (pt1.north() + pt2.north()) / 2;
     344            c[i] = -(a[i]*xC + b[i]*yC);
     345        }
     346        // At.A = [aij]
     347        double a11 = 0, a12 = 0, a22 = 0;
     348        // At.Y = [bi]
     349        double b1 = 0, b2 = 0;
     350        for(int i = 0; i < nc; i++) {
     351            a11 += a[i]*a[i];
     352            a12 += a[i]*b[i];
     353            a22 += b[i]*b[i];
     354            b1 -= a[i]*c[i];
     355            b2 -= b[i]*c[i];
     356        }
     357        // (At.A)^-1 = [invij]
     358        double det = a11*a22 - a12*a12;
     359        if(det == 0) return null;
     360        double inv11 = a22/det;
     361        double inv12 = -a12/det;
     362        double inv22 = a11/det;
     363        // center (xC, yC) = (At.A)^-1.At.y
     364        double xC = inv11*b1 + inv12*b2;
     365        double yC = inv12*b1 + inv22*b2;
     366        return new EastNorth(xC, yC);
     367    }
     368   
     369    /**
    306370     * Check if one or more nodes are outside of download area
    307371     * @param nodes Nodes to check
    308372     * @return true if action can be done