 Timestamp:
 06/26/07 17:38:20 (13 years ago)
 Location:
 trunk/loci/visbio/overlays
 Files:

 13 added
 3 deleted
 5 edited
Legend:
 Unmodified
 Added
 Removed

trunk/loci/visbio/overlays/FreeformExtension.java
r2903 r2909 37 37 * 38 38 * The section of the freeform represented by a freeform extension is actually a 39 * loop, not a single line, like a giant 'loopie' on your shoelace. 39 * loop, but it's thin (both sides overlap exactly) so it appears like a single 40 * line. 40 41 * The loop has two parts, between start and tip and between tip and stop. 41 42 * If an edit is completed, half of the freeform extension is deleted along … … 169 170 } 170 171 171 /** Computes distance between drag and tip of extension. **/172 /** Computes distance between mouse drag and tip of extension. **/ 172 173 public double computeDragDist(DisplayImpl display, int px, int py) { 173 174 // coords of this mouseDrag event … … 181 182 return dragDist; 182 183 } 183 184 184 185 185 /** Extends the tip of the freeform extension by "one" node. */ 
trunk/loci/visbio/overlays/FreeformTool.java
r2903 r2909 260 260 } 261 261 262 // if close, connect freeforms together 262 263 if (minDist < DRAW_THRESH) { 263 264 connectFreeforms(freeform, … … 467 468 OverlayFreeform currentFreeform = (OverlayFreeform) currentObject; 468 469 // performance opportunity: 469 // I removed the check on the bounding box470 // check distance to bounding box first. 470 471 // Should the getDistance method return a distance in 471 472 // pixel coordinates? … … 525 526 } 526 527 527 //  Inner Class es528 //  Inner Class  528 529 529 530 /** 
trunk/loci/visbio/overlays/OverlayNodedObject.java
r2904 r2909 343 343 } 344 344 345 /** Returns the node array */345 /** Returns a copy of the node array */ 346 346 public float[][] getNodes() { 347 347 synchronized(nodesSync) { … … 354 354 } 355 355 356 /** Returns the number of real nodes in the array */356 /** Returns the number of real nodes in the array. */ 357 357 public int getNumNodes() { synchronized(nodesSync) { return numNodes; } } 358 358 359 /** Returns total number of nodes in array */359 /** Returns total number of nodes in array. */ 360 360 public int getMaxNodes() { synchronized(nodesSync) { return maxNodes; } } 361 361 … … 387 387 } 388 388 389 /** Sets the node array to that providedfor loading from saved */389 /** Sets the node array to that providedfor loading from saved. */ 390 390 public void setNodes(float[][] nodes) { 391 391 synchronized (nodesSync) { … … 398 398 } 399 399 400 /** Updates the coordinates of the bounding box of a noded object */ 400 /** 401 * Updates the coordinates of the bounding box of a noded object by 402 * checking the entire node array. 403 */ 401 404 public void updateBoundingBox() { 402 405 if (numNodes == 0) return; … … 418 421 } 419 422 420 /** Gets length of curve */423 /** Gets length of curve. */ 421 424 public double getCurveLength() { return curveLength; } 422 425 … … 430 433 } 431 434 432 /** Sets length of curve */435 /** Sets length of curve. */ 433 436 public void setCurveLength(double len) { curveLength = len; } 434 437 435 /** Computes length of curve */438 /** Computes length of curve. */ 436 439 public void computeLength() { 437 440 boolean notFull = false; … … 454 457 //  OverlayNodedObject API Methods: node array mutators  455 458 // note: call updateBoundingBox() after a series of changes to the node array 456 457 459 458 460 /** Sets coordinates of an existing node */ … … 538 540 if (index >= 0 && index < numNodes) { 539 541 // if array is full, make some more room. 540 if (numNodes >= maxNodes) { // numNodes should never exceed maxNodes but.. 542 if (numNodes >= maxNodes) { 543 // numNodes should never exceed maxNodes but I threw the > in anyway. 541 544 maxNodes *= 2; 542 545 resizeNodeArray(maxNodes); … … 622 625 synchronized (nodesSync) { 623 626 if (index >=0 && index < numNodes) { 624 // builtin truncation 625 //System.out.println("OverlayObject.deleteNode(" + index +") called. " + 626 // "numNodes = " + numNodes + ", maxNodes = " + maxNodes); 627 // This method includes builtin truncation: it doesn't bother to 628 // copy the extra nodes in the node array. 629 630 // Check if this delete operation will result in two colocational nodes 631 // becoming adjacent in the node array. If so, also delete one of 632 // these nodes. 627 633 int offset; 628 634 if (index > 0 && index < numNodes  1 && 629 635 MathUtil.areSame(getNodeCoords(index1), getNodeCoords(index+1))) 630 // colocational nodes exist631 636 offset = 1; 632 637 else offset = 0; … … 670 675 * the child objects. 671 676 */ 677 // TODO  combine this with 'split' method in polyline tool. 672 678 private OverlayFreeform[] slice(int seg, double weight) 673 679 { 
trunk/loci/visbio/overlays/OverlayUtil.java
r2904 r2909 155 155 float y1 = obj.getY(); 156 156 float y2 = obj.getY2(); 157 157 158 // compute corners of arrow tail 159 // (this paragraph copied straight from OverlayArrow) 158 160 double xx = x2  x1; 159 161 double yy = y2  y1; … … 174 176 // arrow lengths: 175 177 double a, b, c; 176 a = Math.sqrt(qx * qx + qy * qy); 177 b = dist; 178 c = Math.sqrt(a * a + b * b); 178 a = Math.sqrt(qx * qx + qy * qy); // 1/2 width of tail 179 b = dist; // length from tail to tip 180 c = Math.sqrt(a * a + b * b); // length of side/hypotenuse 179 181 180 182 double d = GLOW_WIDTH * getMultiplier(link); … … 300 302 float y2 = obj.getY2(); 301 303 302 /*303 // method for doing math in pixel coordinates part 1 of 2304 float[] p1 = domainToPixel(link, new float[]{obj.getX(), obj.getY()});305 float[] p2 = domainToPixel(link, new float[]{obj.getX2(), obj.getY2()});306 307 float x1 = p1[0];308 float x2 = p2[0];309 float y1 = p1[1];310 float y2 = p2[1];311 */312 304 313 305 float delta = GLOW_WIDTH * getMultiplier(link); … … 333 325 {c1[1], c2[1], c3[1], c4[1]}}; 334 326 335 /*336 // method for doing math in pixel coordinates part 2 of 2337 float[][] setSamplesPxl = {{c1[0], c2[0], c3[0], c4[0]},338 {c1[1], c2[1], c3[1], c4[1]}};339 340 float[][] setSamples = pixelToDomain(link, setSamplesPxl);341 */342 327 343 328 // construct range samples; … … 388 373 float yy2 = y1  size  delta; 389 374 390 float dx = 0.0001f; // TEMP391 375 // construct a cross shape, or if the marker is really small compared 376 // to the desired width (delta) of the selection layer, a box instead 392 377 SampledSet domainSet = null; 393 378 int samplesLength = 4; … … 410 395 // using a UnionSet for nowcouldn't get a single 411 396 // Gridded2D set to appear as a cross 397 398 // left branch 412 399 float[][] setSamples1 = { 413 400 {xx1, x1delta, xx1, x1  delta}, … … 415 402 }; 416 403 404 // vertical part 417 405 float[][] setSamples2 = { 418 406 {x1  delta, x1 + delta, x1  delta, x1 + delta}, … … 420 408 }; 421 409 410 // right branch 422 411 float[][] setSamples3 = { 423 412 {x1 + delta, xx2, x1 + delta, xx2}, … … 440 429 441 430 /* 431 float dx = 0.0001; 432 // here's the code for creating a crossshaped Gridded2DSet, 433 // which doesn't quite work 442 434 setSamples = new float[][]{ 443 435 {xx1, x1  delta, x1  delta + dx, x1 + delta  dx, x1 + delta, xx2, … … 447 439 };*/ 448 440 449 // Run this example by curtis:450 441 // Start with this: 451 442 /* … … 501 492 OverlayNodedObject ono = (OverlayNodedObject) obj; 502 493 494 // This method builds a UnionSet of Gridded2DSets to highlight an Overlay 495 // Freeform or OverlayPolyline, plus (sometimes) a translucent circle over 496 // one of the nodes of the freeform or polyline to indicate that the mouse 497 // pointer is nearby. It constructs a separate Gridded2DSet for 498 // each segment of the freeform or polyline, and an additional Gridded2DSet 499 // for the circle. 500 503 501 float delta = GLOW_WIDTH * getMultiplier(link); 504 502 float[][] nodes = ono.getNodes(); 505 // OverlayNodedObject.printThread("OU.getNodedLayer()");506 503 int numNodes = ono.getNumNodes(); 507 504 boolean hlt = ono.isHighlightNode(); … … 523 520 samples = sets.size() * 4; 524 521 525 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@526 527 522 int hlen = hlt ? len : 0; 528 523 float[][] rangeSamples = new float[4][samples+hlen]; … … 892 887 int len = nodes[0].length; 893 888 894 // Create two arrays to store the gridpoints: one to the right of the curve895 // and another to the left (supposing the curve is oriented in order of896 // in creasing node indices, i.e., the first node is nodes[][0], the last897 // is nodes[][nodes.length1])889 // Create two arrays to store the gridpoints: one to the 'right' 890 // of the curve and another to the 'left' (supposing the curve is oriented 891 // in order of increasing node indices, i.e., the first node is nodes[][0], 892 // the last is nodes[][nodes.length1]). 898 893 float[][] right = new float[2][len]; // store the gridpts 899 894 float[][] left = new float[2][len]; … … 901 896 if (len <=1) return null; 902 897 898 // The senses of left and right remain the same except when the curve 899 // doubles back on itself, i.e., when two consecutive segments form an 900 // angle of 180 degrees. Then the flag 'orientationChanged' switches. 903 901 boolean orientationChanged = false; // if this is true, right and left 904 902 // must be switched 903 904 905 // This loop computes the points to use in the Gridded2DSets. The sets 906 // are constructed separately since each sets corner points are shared 907 // by two other sets (the front points of one set are the rear points of the 908 // next, etc.) 905 909 for (int i=0; i<len; i++) { 910 // Each iteration of this loop computes a new pair of points 911 // rigthPt and leftPt. The points are computed differently 912 // depending on whether the index i points to 913 // 1) the first node 914 // 2) the last node 915 // 3) some interior node 906 916 float[] rightPt = new float[2]; 907 917 float[] leftPt = new float[2]; 908 918 909 919 // System.out.println("index = " + i); 910 if (i==0) { // Case 1: the first node 920 if (i==0) { 921 // Case 1: the first node 922 // Just compute points a distance 'width' from the first node, 923 // in the direction perpendicular to the first segment 911 924 912 925 float[] p1 = new float[] {nodes[0][0], nodes[1][0]}; // first node … … 923 936 // System.out.print("left pt: "); print(leftPt); 924 937 } 925 else if (i == len  1) { // Case 2: the last node 926 938 else if (i == len  1) { 939 // Case 2: the last node 940 // Just compute points a distance 'width' from the last node, 941 // in the direction perpendicular to the last segment 942 927 943 float[] p1 = new float[] {nodes[0][i1], nodes[1][i1]}; // penultimate 928 944 // node 929 945 float[] p2 = new float[] {nodes[0][i], nodes[1][i]}; // last node 930 946 931 boolean anti = false; 947 // Test if the last segment doubles back on the second to last segment 948 boolean anti = false; // for 'antiparallel' 932 949 if (len >= 3) { 933 // test if antiparallel934 950 float[] p0 = new float[] {nodes[0][i2], nodes[1][i2]}; // 3rd 2 last 935 951 float[] v1 = MathUtil.unit(MathUtil.vector(p1, p0)); … … 944 960 if (anti) vPerp = 945 961 MathUtil.getRightPerpendicularVector2D(p1, p2); 946 // reversed p1 and p2 above!962 // p1 and p2 above have been switched above to obtain a reflection 947 963 else vPerp = MathUtil.getRightPerpendicularVector2D(p2, p1); 948 964 … … 963 979 // System.out.println("orientation changed = " + orientationChanged); 964 980 } 965 else { // Case 3: all interior nodes 981 else { 982 // Case 3: all interior nodes 983 // Compute points a perpendicular distance 'width' away from the curve 984 // as in cases 1 and 2. This time, however, the points lie on the 985 // the line bisecting the angle formed by adjacent segments. 966 986 967 987 float[] p1 = {nodes[0][i1], nodes[1][i1]}; … … 974 994 // System.out.print("p3: "); print(p3); 975 995 996 // Test if the line doubles back on itself 976 997 // check if p2p3 and p3p2 are antiparallel 977 // have to correct the strategy in this case978 998 float[] v1 = MathUtil.unit(MathUtil.vector(p2, p1)); 979 999 float[] v2 = MathUtil.unit(MathUtil.vector(p3, p2)); … … 996 1016 float sin = Math.abs(MathUtil.cross2D(bisector, 997 1017 MathUtil.unit(MathUtil.vector(p2, p1)))); 998 if (sin < 0.1f) sin = 0.1f; // keep a lower bound on this for safety999 // (the value of sin could become really small)1018 if (sin < 0.1f) sin = 0.1f; // keep a lower bound on this value to 1019 // prevent 1/sin from becoming too large 1000 1020 1001 1021 // compute offset distance from curve 1002 1022 float offset = width / sin; 1003 1023 1004 float[] a = MathUtil.add(p2, MathUtil.scalarMultiply(bisector, offset)); 1005 float[] b = MathUtil.add(p2, MathUtil.scalarMultiply(bisectorReflected, 1024 float[] a = MathUtil.add(p2, MathUtil.scalarMultiply(bisector, 1006 1025 offset)); 1026 float[] b = MathUtil.add(p2, 1027 MathUtil.scalarMultiply(bisectorReflected, offset)); 1028 1007 1029 rightPt = orientationChanged ? b : a; 1008 1030 leftPt = orientationChanged ? a : b; … … 1048 1070 Vector sets = new Vector(100); 1049 1071 for (int i=0; i<len1; i++) { 1072 // This loop constructs Gridded2D sets, one for each segment of a noded 1073 // object (implied here by the arrays right and left). 1074 // For each segment (between indices 'i' and 'i+1'), 1075 // try to construct a trapezoidal set: 1050 1076 float[][] setSamples = { 1051 1077 {right[0][i], right[0][i+1], left[0][i], left[0][i+1]}, … … 1059 1085 } 1060 1086 catch (VisADException ex) { 1061 // If samples form an invalid set, the grid is bowtie shaped. 1087 // If samples form an invalid set, the grid is most likely 1088 // bowtie shaped. 1062 1089 // "Uncross" the box just by switching the order of the two 1063 // left points 1090 // left points. 1091 1092 // System.out.println("formed 1 invalid set"); 1064 1093 setSamples = new float[][]{ 1065 1094 {right[0][i], right[0][i+1], left[0][i+1], left[0][i]}, … … 1073 1102 } 1074 1103 catch (VisADException ex2) { 1075 // make a plain rectangular set, disregarding left and right 1076 // arrays 1104 // If the uncrossed samples still form an invalid set, give up 1105 // trying to make a trapezoidal set. 1106 // Make a plain rectangular set, disregarding left and right 1107 // arrays. Instead use the node array and calculate the corners of the 1108 // set using perpendiculars to the line segment under consideration. 1109 // System.out.println("formed 2 invalid sets"); 1077 1110 float[] p1 = {nodes[0][i], nodes[1][i]}; 1078 1111 float[] p2 = {nodes[0][i+1], nodes[1][i+1]}; … … 1125 1158 } 1126 1159 1127 /** Casts an array of floats to doubles. */ 1160 /** 1161 * Casts and converts an array of floats in domain coordinates to doubles in 1162 * pixel coordinates. 1163 */ 1128 1164 public static double[][] floatsToPixelDoubles(DisplayImpl d, float[][] nodes) { 1129 1165 double[][] nodesDbl = new double[nodes.length][nodes[0].length]; … … 1140 1176 public static void print(float[][] points) { 1141 1177 for (int i=0; i<points[0].length; i++) { 1142 System.out.println("[" + points[0][i] + "," + points[1][i] + "]");1178 print(points[0][i], points[1][i]); 1143 1179 } 1144 1180 } … … 1149 1185 } 1150 1186 1187 /** Prints a point. */ 1151 1188 public static void print(float[] p) { 1152 1189 print(p[0], p[1]); 
trunk/loci/visbio/overlays/PolylineTool.java
r2904 r2909 388 388 } 389 389 390 // TODO  combine this method with the similar one for freeforms,390 // TODO  replace this method with the similar one for freeforms, 391 391 // currently located in OverlayNodedObject.java 392 // Determine some way of combining the two. 392 393 /** Splits an overlay polyline in two */ 393 394 private void split (OverlayPolyline line, int selectedNode) { … … 427 428 } 428 429 429 /** Gets distance to the node specified, handling awkward casts. */ 430 /** 431 * Gets distance to the node specified in pixel coordinates, handling 432 * awkward casts. 433 */ 430 434 private double getDistanceToNode(int ndx, int px, int py, 431 435 DisplayImpl display) { … … 477 481 * in the objects array, item 1 the index of the nearest node in the nearest 478 482 * polyline */ 483 // TODO can this make use of or be replaced by the OverlayNodedObject instance 484 // method with the same name? 479 485 private int[] getNearestNode(DisplayImpl display, 480 486 OverlayObject[] objects, int px, int py, double threshold) {
Note: See TracChangeset
for help on using the changeset viewer.