Ticket #2781: AlignInCircleAction.java.patch
File AlignInCircleAction.java.patch, 7.4 KB (added by , 16 years ago) |
---|
-
src/org/openstreetmap/josm/actions/AlignInCircleAction.java
5 5 6 6 import java.awt.event.ActionEvent; 7 7 import java.awt.event.KeyEvent; 8 import java.math.BigDecimal; 9 import java.math.MathContext; 8 10 import java.util.Collection; 9 11 import java.util.LinkedList; 10 12 … … 34 36 KeyEvent.VK_O, Shortcut.GROUP_EDIT), true); 35 37 } 36 38 37 public double determinant(double[][] mat) {38 double result = 0;39 40 if (mat.length == 1) {41 result = mat[0][0];42 return result;43 }44 45 if (mat.length == 2) {46 result = mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0];47 return result;48 }49 50 for (int i = 0; i < mat[0].length; i++) {51 double temp[][] = new double[mat.length - 1][mat[0].length - 1];52 for (int j = 1; j < mat.length; j++) {53 for (int k = 0; k < mat[0].length; k++) {54 if (k < i) {55 temp[j - 1][k] = mat[j][k];56 } else if (k > i) {57 temp[j - 1][k - 1] = mat[j][k];58 }59 }60 }61 result += mat[0][i] * Math.pow(-1, i) * determinant(temp);62 }63 return result;64 }65 66 39 public double distance(EastNorth n, EastNorth m) { 67 40 double easd, nord; 68 41 easd = n.east() - m.east(); … … 70 43 return Math.sqrt(easd * easd + nord * nord); 71 44 } 72 45 73 public EastNorth circumcenter(EastNorth i, EastNorth j, EastNorth k) {74 // move to 0,0, to eliminate numeric errors75 double ie = i.east() - i.east();76 double in = i.north() - i.north();77 double je = j.east() - i.east();78 double jn = j.north() - i.north();79 double ke = k.east() - i.east();80 double kn = k.north() - i.north();81 double[][] ma = { { ie, in, 1 }, { je, jn, 1 }, { ke, kn, 1 } };82 double[][] mbx = { { (ie * ie + in * in), in, 1 }, { (je * je + jn * jn), jn, 1 },83 { (ke * ke + kn * kn), kn, 1 } };84 double[][] mby = { { ie * ie + in * in, ie, 1 }, { je * je + jn * jn, je, 1 }, { ke * ke + kn * kn, ke, 1 } };85 double a = determinant(ma);86 double bx = determinant(mbx);87 double by = determinant(mby);88 EastNorth result = new EastNorth(bx / (2 * a) + i.east(), -by / (2 * a) + i.north());89 90 Node n = new Node(Main.proj.eastNorth2latlon(result));91 if (n.getCoor().isOutSideWorld()) {92 JOptionPane.showMessageDialog(Main.parent, tr("Some of the nodes are (almost) in the line"));93 return null;94 }95 return result;96 }97 98 46 public class PolarCoor { 99 47 double radius; 100 48 double angle; … … 138 86 boolean regular = false; 139 87 140 88 for (OsmPrimitive osm : sel) { 141 if (osm instanceof Node) 89 if (osm instanceof Node) { 142 90 nodes.add((Node) osm); 143 else if (osm instanceof Way)91 } else if (osm instanceof Way) { 144 92 ways.add((Way) osm); 93 } 145 94 } 146 95 147 96 // special case if no single nodes are selected and exactly one way is: … … 163 112 } else { 164 113 165 114 center = ((Node) nodes.toArray()[way.nodes.contains(nodes.toArray()[0]) ? 1 : 0]).getEastNorth(); 166 if (nodes.size() == 2) 115 if (nodes.size() == 2) { 167 116 radius = distance(((Node) nodes.toArray()[0]).getEastNorth(), ((Node) nodes.toArray()[1]).getEastNorth()); 117 } 168 118 } 169 119 nodes = new LinkedList<Node>(); 170 120 } 171 121 172 122 for (Node n : way.nodes) { 173 if (!nodes.contains(n)) 123 if (!nodes.contains(n)) { 174 124 nodes.add(n); 125 } 175 126 } 176 127 } 177 128 … … 180 131 return; 181 132 } 182 133 183 // Get average position of circumcircles of the triangles of all triplets of neighbour nodes184 134 if (center == null) { 185 186 135 // Compute the centroid of nodes 187 136 188 // See http://en.wikipedia.org/w/index.php?title=Centroid&oldid=294224857#Centroid_of_polygon for the equation used here 189 double area = 0; 190 double north = 0; 191 double east = 0; 137 BigDecimal area = new BigDecimal("0"); 138 BigDecimal north = new BigDecimal("0"); 139 BigDecimal east = new BigDecimal("0"); 192 140 193 // Integrate the area, east and north centroid, we'll compute the final value based on the result of integration194 for (int i =0; i<nodes.size(); i++) {141 // See http://en.wikipedia.org/w/index.php?title=Centroid&oldid=294224857#Centroid_of_polygon for the equation used here 142 for (int i = 0; i < nodes.size(); i++) { 195 143 EastNorth n0 = ((Node) nodes.toArray()[i]).getEastNorth(); 196 144 EastNorth n1 = ((Node) nodes.toArray()[(i+1) % nodes.size()]).getEastNorth(); 197 145 198 area += n0.east()*n1.north()-n1.east()*n0.north(); 199 east += (n0.east() +n1.east()) *(n0.east()*n1.north()-n1.east()*n0.north()); 200 north += (n0.north()+n1.north())*(n0.east()*n1.north()-n1.east()*n0.north()); 146 BigDecimal x0 = new BigDecimal(n0.east()); 147 BigDecimal y0 = new BigDecimal(n0.north()); 148 BigDecimal x1 = new BigDecimal(n1.east()); 149 BigDecimal y1 = new BigDecimal(n1.north()); 150 151 BigDecimal k = x0.multiply(y1, MathContext.DECIMAL128).subtract(y0.multiply(x1, MathContext.DECIMAL128)); 152 153 area = area.add(k, MathContext.DECIMAL128); 154 east = east.add(k.multiply(x0.add(x1, MathContext.DECIMAL128), MathContext.DECIMAL128)); 155 north = north.add(k.multiply(y0.add(y1, MathContext.DECIMAL128), MathContext.DECIMAL128)); 156 201 157 } 202 area /= 2;203 north /= 6*area;204 east /= 6*area;205 center = new EastNorth(east, north);206 }207 158 159 BigDecimal d = new BigDecimal("2"); 160 area = area.divide(d, MathContext.DECIMAL128); 161 d = new BigDecimal("6"); 162 north = north.divide(d.multiply(area, MathContext.DECIMAL128), MathContext.DECIMAL128); 163 east = east.divide(d.multiply(area, MathContext.DECIMAL128), MathContext.DECIMAL128); 164 165 center = new EastNorth(east.doubleValue(), north.doubleValue()); 166 167 } 208 168 // Node "center" now is central to all selected nodes. 209 169 210 170 // Now calculate the average distance to each node from the … … 225 185 double angle = Math.PI * 2 / nodes.size(); 226 186 pc = new PolarCoor(((Node) nodes.toArray()[0]).getEastNorth(), center, 0); 227 187 228 if (pc.angle > (new PolarCoor(((Node) nodes.toArray()[1]).getEastNorth(), center, 0).angle)) 188 if (pc.angle > (new PolarCoor(((Node) nodes.toArray()[1]).getEastNorth(), center, 0).angle)) { 229 189 angle *= -1; 190 } 230 191 231 192 pc.radius = radius; 232 193 for (Node n : nodes) {