Changeset 2865
- Timestamp:
- 06/13/07 12:33:22 (12 years ago)
- Location:
- trunk/loci/visbio/overlays
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/loci/visbio/overlays/FreeformTool.java
r2725 r2865 101 101 protected float[][] pre, post; 102 102 103 /** Point at which mouseDown occurs */103 /** Point at which mouseDown occurs. */ 104 104 protected float downX, downY; 105 105 … … 128 128 // find closest freeform 129 129 double maxThresh = ERASE_THRESH; 130 Info info = getClosestFreeform(display, dpx, dpy,131 maxThresh);132 OverlayFreeform target = info.freeform;130 DistanceQuery distanceQuery = getClosestFreeform(display, dpx, 131 dpy, maxThresh); 132 OverlayFreeform target = distanceQuery.freeform; 133 133 134 134 // operate on closest freeform 135 135 if (target != null) { 136 // editing operations on closest freeform 136 137 freeform = target; 137 138 138 double dist = info.dist; 139 int seg = info.seg; 140 double weight = info.wt; 141 142 if ((seg == 0 && weight == 0.0) || 143 (seg == freeform.getNumNodes()-2 && weight == 1.0)) 139 double dist = distanceQuery.dist; 140 int seg = distanceQuery.seg; 141 double weight = distanceQuery.wt; 142 143 if (distanceQuery.isNearEndNode()) 144 144 { 145 145 // near an end node … … 177 177 else { 178 178 // determine projection on seg. 179 // insert a pair of nodes there, starting a tendril 179 180 float[] a = freeform.getNodeCoords(seg); 180 181 float[] b = freeform.getNodeCoords(seg + 1); … … 190 191 } 191 192 else { // no freeform was sufficiently close 193 // drawing operations on new freeform 192 194 if (!ctl) { 193 195 // record initial coordinates of freeform … … 198 200 } 199 201 202 // stuff you have to do if there's been a change 200 203 overlay.notifyListeners(new TransformEvent(overlay)); 201 204 ((OverlayWidget) overlay.getControls()).refreshListSelection(); … … 237 240 float[] tail = f.getNodeCoords(f.getNumNodes()-1); 238 241 239 double[] headDbl = {(double) head[0], (double) head[1]}; 240 double[] tailDbl = {(double) tail[0], (double) tail[1]}; 241 //double[] drag = {(double) dx, (double) dy}; 242 int[] headPxl = CursorUtil.domainToPixel(display, headDbl); 243 int[] tailPxl = CursorUtil.domainToPixel(display, tailDbl); 244 double[] headPxlDbl = new double[] {(double) headPxl[0], 245 (double) headPxl[1]}; 246 double[] tailPxlDbl = new double[] {(double) tailPxl[0], 247 (double) tailPxl[1]}; 248 double[] drag = {dpx, dpy}; 249 250 // compare pair of ints with pair of floats 251 double hdist = MathUtil.getDistance(drag, headPxlDbl); 252 double tdist = MathUtil.getDistance(drag, tailPxlDbl); 242 int[] drag = new int[]{px, py}; 243 double hdist = getPixelDistanceToClick(display, head, drag); 244 double tdist = getPixelDistanceToClick(display, tail, drag); 253 245 254 246 boolean isHead = hdist < tdist ? true : false; … … 270 262 // compute distance from last node 271 263 // DISTANCE COMPUTATION: compare floats and ints 272 float lastX = freeform.getLastNodeX(); 273 float lastY = freeform.getLastNodeY(); 274 float distX = dx - lastX; 275 float distY = dy - lastY; 276 double dist = Math.sqrt (distX*distX + distY*distY); 277 278 double[] last = new double[]{(double) lastX, (double) lastY}; 279 int[] lastPxl = CursorUtil.domainToPixel(display, last); 280 281 double dxPxl = dpx - (double) lastPxl[0]; 282 double dyPxl = dpy - (double) lastPxl[1]; 283 double distPxl = Math.sqrt (dxPxl*dxPxl + dyPxl*dyPxl); 264 float[] last = {freeform.getLastNodeX(), freeform.getLastNodeY()}; 265 double distPxl = getPixelDistanceToClick(display, last, 266 new int[]{px, py}); 284 267 285 268 if (distPxl > DRAW_THRESH) { 286 float[] s = smooth(new float[]{dx, dy}, new float[] {lastX, lastY});287 freeform.setNextNode(s [0], s[1]);269 float[] s = smooth(new float[]{dx, dy}, last); 270 freeform.setNextNode(s); 288 271 double len = freeform.getCurveLength(); 289 double[] sDbl = {(double) s[0], (double) s[1]}; 290 double delta = MathUtil.getDistance(sDbl, last); 272 double delta = MathUtil.getDistance(s, last); 291 273 freeform.setCurveLength(len + delta); 292 274 // I debated whether to call setBoundaries with every mouseDrag. 293 275 // This is an efficient 294 // method, but updating realtime for erasing requires an O(n) 276 // method, but corresponding update when erasing 277 // erasing requires an O(n) 295 278 // scan of the nodes every time a node is deleted. 296 279 freeform.setBoundaries(s[0], s[1]); … … 302 285 if (freeform == null) { 303 286 // DISTANCE COMPUTATION compare floats with floats 304 Info info= getClosestFreeform(display,287 DistanceQuery distanceQuery = getClosestFreeform(display, 305 288 dpx, dpy, ERASE_THRESH); 306 OverlayFreeform target = info.freeform;289 OverlayFreeform target = distanceQuery.freeform; 307 290 if (target != null) freeform = target; 308 291 } … … 310 293 if (freeform != null) { 311 294 // delete an end node if you're near enough 312 float[] beg = freeform.getNodeCoords (0); 313 float[] end = freeform.getNodeCoords (freeform.getNumNodes() - 1); 314 315 double[] drag = {dpx, dpy}; 316 double[] begDbl = {(double) beg[0], (double) beg[1]}; 317 double[] endDbl = {(double) end[0], (double) end[1]}; 318 int[] begPxl = CursorUtil.domainToPixel(display, begDbl); 319 int[] endPxl = CursorUtil.domainToPixel(display, endDbl); 320 double[] begPxlDbl = {(double) begPxl[0], (double) begPxl[1]}; 321 double[] endPxlDbl = {(double) endPxl[0], (double) endPxl[1]}; 322 323 // DISTANCE COMPUTATION ints and floats 324 double bdist = MathUtil.getDistance(drag, begPxlDbl); 325 double edist = MathUtil.getDistance(drag, endPxlDbl); 295 float[] beg = freeform.getNodeCoords(0); 296 float[] end = freeform.getNodeCoords(freeform.getNumNodes() - 1); 297 298 int[] dragPxl = {px, py}; 299 300 double bdist = getPixelDistanceToClick(display, beg, dragPxl); 301 double edist = getPixelDistanceToClick(display, beg, dragPxl); 326 302 327 303 boolean closerToEnd = edist < bdist ? true : false; … … 331 307 if (!closerToEnd) freeform.reverseNodes(); 332 308 if (ctl) { 333 double[] nearest = new double[2], lastDbl = new double[2]; 334 float[] last; 335 double delta; 336 int index; 337 if (closerToEnd) nearest = endDbl; 338 else nearest = begDbl; 309 float[] nearest = new float[2]; 310 if (closerToEnd) nearest = end; 311 else nearest = beg; 339 312 340 313 // adjust curve length 341 index = freeform.getNumNodes()-1; // last node in freef 342 last = freeform.getNodeCoords(index); 343 lastDbl[0] = (double) last[0]; 344 lastDbl[1] = (double) last[1]; 345 delta = MathUtil.getDistance (nearest, lastDbl); 314 int index = freeform.getNumNodes()-1; // last node in freef 315 float[] last = freeform.getNodeCoords(index); 316 double delta = MathUtil.getDistance(nearest, last); 346 317 freeform.setCurveLength(freeform.getCurveLength() - delta); 347 318 … … 556 527 } 557 528 558 /** Wraps distance info and address of a freeform object*/559 protected class Info{529 /** Wraps distance and address of a freeform object. */ 530 protected class DistanceQuery { 560 531 public double dist, wt; 561 532 public int seg; 562 533 public OverlayFreeform freeform; 563 534 564 public Info(double[] distSegWt, OverlayFreeform f) { 535 /** Constructs a DistanceQuery object. */ 536 public DistanceQuery(double[] distSegWt, OverlayFreeform f) { 565 537 this.freeform = f; 566 538 this.dist = distSegWt[0]; … … 568 540 this.wt = distSegWt[2]; 569 541 } 570 } 571 572 /** Wraps info for redrawing a curve 542 543 /** Whether the nearest node is an end node. */ 544 public boolean isNearEndNode() { 545 return (seg == 0 && wt == 0.0) || 546 (seg == freeform.getNumNodes()-2 && wt == 1.0); 547 } 548 } 549 550 /** Wraps information for redrawing a curve 573 551 * Appears like a 'tendril' on screen */ 574 pr ivateclass Tendril {552 protected class Tendril { 575 553 public int start, stop, tip; 576 554 public boolean nodal; … … 658 636 } 659 637 } 660 661 /*662 if (mode == DRAW || mode == EDIT || mode == ERASE) {663 freeform.setDrawing(true);664 freeform.setSelected(true);665 }666 667 if (mode == DRAW) {668 // create list of freeforms669 OverlayObject[] objs = overlay.getObjects();670 for (int i=0; i<objs.length; i++) {671 if (objs[i] instanceof OverlayFreeform && objs[i] != freeform) {672 otherFreefs.add(objs[i]);673 }674 }675 }676 else {677 otherFreefs.removeAllElements();678 }679 680 if (mode == CHILL && freeform != null) {681 if (freeform.getNumNodes() <= 1) overlay.removeObject(freeform);682 else {683 freeform.computeLength();684 freeform.updateBoundingBox();685 freeform.computeGridParameters();686 freeform.setDrawing(false);687 freeform = null;688 }689 }690 */691 638 } 692 639 … … 721 668 * the given point 722 669 */ 723 /* 724 private OverlayFreeform getClosestFreeform( float dx, 725 float dy, double thresh) { 726 // returns only objects at the current dimensional position 727 OverlayObject[] objects = overlay.getObjects(); 728 // Q: Hey, are all of these OverlayFreeforms? 729 // A: No, it returns OverlayObjects of all types 730 731 OverlayFreeform closestFreeform = null; 732 if (objects != null) { 733 double minDistance = Double.MAX_VALUE; 734 for (int i = 0; i < objects.length; i++) { 735 OverlayObject currentObject = objects[i]; 736 if (currentObject instanceof OverlayFreeform) { 737 OverlayFreeform currentFreeform = (OverlayFreeform) currentObject; 738 // rough check: is point within EDIT_THRESH of bounding box (fast) 739 if (currentFreeform.getDistance(dx, dy) < thresh) { 740 // fine check: actually compute minimum 741 // distance to freeform (slower) 742 double[] distSegWt = 743 // DISTANCE COMPUTATION 744 // compare float[][] with ints 745 MathUtil.getDistSegWt(currentFreeform.getNodes(), dx, dy); 746 double distance = distSegWt[0]; 747 if (distance < thresh && distance < minDistance) { 748 minDistance = distance; 749 closestFreeform = currentFreeform; 750 } 751 } // end (.. < EDIT_THRESH) 752 } // end if 753 } // end for 754 } // end if 755 return closestFreeform; 756 } 757 */ 758 759 /** Returns the closest (subject to a threshhold) OverlayFreeform object to 760 * the given point 761 */ 762 protected Info getClosestFreeform(DisplayImpl display, double dpx, 670 protected DistanceQuery getClosestFreeform(DisplayImpl display, double dpx, 763 671 double dpy, double thresh) { 764 672 // returns only objects at the current dimensional position … … 791 699 } // end for 792 700 } // end if 793 return new Info(min, closestFreeform);701 return new DistanceQuery(min, closestFreeform); 794 702 } 795 703 … … 807 715 } 808 716 809 /** Casts an array of floats to doubles */ 717 /** Gets distance in pixels between a click and a point in domain coords. */ 718 private double getPixelDistanceToClick(DisplayImpl display, float[] p, int[] 719 click) { 720 // TODO Make this work for N-D arguments (not just 2D) 721 double[] pDbl = new double[] {(double) p[0], (double) p[1]}; 722 int[] pPxl = CursorUtil.domainToPixel(display, pDbl); 723 double[] pPxlDbl = new double[] {(double) pPxl[0], 724 (double) pPxl[1]}; 725 double[] clickDbl = new double[] {(double) click[0], 726 (double) click[1]}; 727 return MathUtil.getDistance(clickDbl, pPxlDbl); 728 } 729 730 /** Casts an array of floats to doubles. */ 810 731 private double[][] floatsToPixelDoubles(DisplayImpl d, float[][] nodes) { 811 732 double[][] nodesDbl = new double[nodes.length][nodes[0].length]; … … 819 740 } 820 741 821 /** Prints node array of current freeform; for debugging */742 /** Prints node array of current freeform; for debugging. */ 822 743 private void printNodes(float[][] nodes) { 823 744 System.out.println("Printing nodes..."); … … 827 748 } 828 749 829 /** Prints node array of current freeform; for debugging */750 /** Prints node array of current freeform; for debugging. */ 830 751 private void printNodes() { 831 752 if (freeform!=null){ … … 835 756 } 836 757 837 /** Prints a message for debugging */758 /** Prints a message for debugging. */ 838 759 public void print(String methodName, String message) { 839 760 boolean toggle = true; -
trunk/loci/visbio/overlays/OverlayNodedObject.java
r2824 r2865 424 424 } 425 425 426 /** Sets coordinates of last node. */ 427 public void setLastNode(float[] c) { 428 setLastNode(c[0], c[1]); 429 } 430 426 431 /** Prints node array of current freeform; for debugging */ 427 432 private void printNodes(float[][] nodes) { … … 441 446 Arrays.fill(nodes[1], numNodes++, maxNodes, y); 442 447 // i.e., set all remaining nodes (as per maxNodes) to next node coords 448 } 449 450 /** Sets next node coordinates. */ 451 public void setNextNode(float[] c) { 452 setNextNode(c[0], c[1]); 443 453 } 444 454 -
trunk/loci/visbio/overlays/OverlayUtil.java
r2823 r2865 29 29 import java.util.Vector; 30 30 import loci.visbio.view.TransformLink; 31 import loci.visbio.util.MathUtil; 31 32 import visad.*; 32 33 import visad.util.CursorUtil; … … 516 517 int len = 2 * arcLen; 517 518 518 Vector sets = new Vector(numNodes);519 520 /*521 System.out.println("1: isHighlightNode = " + hlt);522 System.out.println("Thread.currentThread()" + Thread.currentThread());523 System.out.println("numNodes = " + numNodes);524 System.out.println("numNodeSets = " + numNodeSets);525 System.out.println("numSets = " + numSets);526 System.out.println("hlen = " + hlen);527 System.out.println("rangeSamples[0].length = " + rangeSamples[0].length);528 */529 530 519 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 531 520 // Build nodes sets 532 521 // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 533 534 for (int i=0; i<numNodes - 1; i++) { 535 float[] v = new float[]{nodes[0][i+1] - nodes[0][i], nodes[1][i+1] - 536 nodes[1][i]}; 537 538 if (v[0] == 0 && v[1] == 0) continue; 539 // nodes are colocational 540 // angle of vector perpendicular to line 541 double theta = Math.PI / 2 + Math.atan2(v[1], v[0]); 542 543 float dx = (float) (delta * Math.cos(theta)); 544 float dy = (float) (delta * Math.sin(theta)); 545 546 float[] p1 = {nodes[0][i] + dx, nodes[1][i] + dy}; 547 float[] p2 = {nodes[0][i+1] + dx, nodes[1][i+1] + dy}; 548 float[] p3 = {nodes[0][i] - dx, nodes[1][i] - dy}; 549 float[] p4 = {nodes[0][i+1] - dx, nodes[1][i+1] - dy}; 550 551 float[][] setSamples = {{p1[0], p2[0], p3[0], p4[0]}, 552 {p1[1], p2[1], p3[1], p4[1]}}; 522 523 int samples = 0; 524 UnionSet unionSet = null; 525 try { 526 unionSet = buildNodesSets(domain, nodes, delta); 527 samples = unionSet.getLength(); 528 } 529 catch (VisADException ex) { ex.printStackTrace(); } 530 531 //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 532 533 int hlen = hlt ? len : 0; 534 float[][] rangeSamples = new float[4][samples]; 535 536 // fill nodes range samples; 537 Color col = GLOW_COLOR; 538 float r = col.getRed() / 255f; 539 float g = col.getGreen() / 255f; 540 float b = col.getBlue() / 255f; 541 542 // ADJUST THIS to account for circles later 543 Arrays.fill(rangeSamples[0], r); 544 Arrays.fill(rangeSamples[1], g); 545 Arrays.fill(rangeSamples[2], b); 546 Arrays.fill(rangeSamples[3], GLOW_ALPHA); 547 548 // REMOVE this when adding circles later 549 FlatField field = null; 550 try { 551 FunctionType fieldType = new FunctionType(domain, range); 552 field = new FlatField(fieldType, unionSet); 553 field.setSamples(rangeSamples); 554 } 555 catch (VisADException exc) { exc.printStackTrace(); } 556 catch (RemoteException exc) { exc.printStackTrace(); } 557 558 return field; 559 560 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 561 // Build circle and circle samples 562 // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 563 564 /* 565 System.out.println("2: isHighlightNode = " + hlt); 566 System.out.println("Thread.currentThread()" + Thread.currentThread()); 567 */ 568 /* 569 Gridded2DSet hltSet = null; 570 if (hlt) { 571 float rad = 2 * delta; 572 573 // assemble a small circle 574 float[][] highlightSetSamples = new float[2][len]; 575 576 // top half of circle 577 for (int i=0; i<arcLen; i++) { 578 highlightSetSamples[0][i] = c[0] + rad * ARC[0][i]; 579 highlightSetSamples[1][i] = c[1] + rad * ARC[1][i]; 580 } 581 582 // bottom half of circle 583 for (int i=0; i<arcLen; i++) { 584 int ndx = arcLen + i; 585 highlightSetSamples[0][ndx] = c[0] + rad * ARC[0][i]; 586 highlightSetSamples[1][ndx] = c[1] - rad * ARC[1][i]; 587 } 588 553 589 try { 554 sets.add(new Gridded2DSet(domain, setSamples, 555 2, 2, null, null, null, false)); 556 } 557 558 catch (VisADException exc) { exc.printStackTrace(); } 559 } 560 561 int hlen = hlt ? len : 0; 562 int goodSets = sets.size(); 563 if (goodSets == 0 ) { 564 return null; 565 } 566 else { 567 float[][] rangeSamples = new float[4][hlen + 4 * goodSets]; 568 569 // fill nodes range samples; 570 Color col = GLOW_COLOR; 571 float r = col.getRed() / 255f; 572 float g = col.getGreen() / 255f; 573 float b = col.getBlue() / 255f; 574 575 Arrays.fill(rangeSamples[0], 0, 4*goodSets, r); 576 Arrays.fill(rangeSamples[1], 0, 4*goodSets, g); 577 Arrays.fill(rangeSamples[2], 0, 4*goodSets, b); 578 Arrays.fill(rangeSamples[3], 0, 4*goodSets, GLOW_ALPHA); 579 580 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 581 // Build circle and circle samples 582 // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 583 584 /* 585 System.out.println("2: isHighlightNode = " + hlt); 586 System.out.println("Thread.currentThread()" + Thread.currentThread()); 587 */ 588 Gridded2DSet hltSet = null; 589 if (hlt) { 590 float rad = 2 * delta; 591 592 // assemble a small circle 593 float[][] highlightSetSamples = new float[2][len]; 594 595 // top half of circle 596 for (int i=0; i<arcLen; i++) { 597 highlightSetSamples[0][i] = c[0] + rad * ARC[0][i]; 598 highlightSetSamples[1][i] = c[1] + rad * ARC[1][i]; 599 } 600 601 // bottom half of circle 602 for (int i=0; i<arcLen; i++) { 603 int ndx = arcLen + i; 604 highlightSetSamples[0][ndx] = c[0] + rad * ARC[0][i]; 605 highlightSetSamples[1][ndx] = c[1] - rad * ARC[1][i]; 606 } 607 608 try { 609 // build highlight set 610 hltSet = new Gridded2DSet(domain, highlightSetSamples, 611 arcLen, 2, null, null, null, false); 612 } 613 catch (VisADException ex) { ex.printStackTrace(); } 614 615 col = HLT_COLOR; 616 r = col.getRed() / 255f; 617 g = col.getGreen() / 255f; 618 b = col.getBlue() / 255f; 619 620 Arrays.fill(rangeSamples[0], 4*goodSets, 4*goodSets + hlen, r); 621 Arrays.fill(rangeSamples[1], 4*goodSets, 4*goodSets + hlen, g); 622 Arrays.fill(rangeSamples[2], 4*goodSets, 4*goodSets + hlen, b); 623 Arrays.fill(rangeSamples[3], 4*goodSets, 4*goodSets + hlen, HLT_ALPHA); 624 625 sets.add(hltSet); 626 } 590 // build highlight set 591 hltSet = new Gridded2DSet(domain, highlightSetSamples, 592 arcLen, 2, null, null, null, false); 593 } 594 catch (VisADException ex) { ex.printStackTrace(); } 595 596 col = HLT_COLOR; 597 r = col.getRed() / 255f; 598 g = col.getGreen() / 255f; 599 b = col.getBlue() / 255f; 600 601 Arrays.fill(rangeSamples[0], 4*goodSets, 4*goodSets + hlen, r); 602 Arrays.fill(rangeSamples[1], 4*goodSets, 4*goodSets + hlen, g); 603 Arrays.fill(rangeSamples[2], 4*goodSets, 4*goodSets + hlen, b); 604 Arrays.fill(rangeSamples[3], 4*goodSets, 4*goodSets + hlen, HLT_ALPHA); 605 606 sets.add(hltSet); 627 607 628 608 Gridded2DSet[] trueSets = new Gridded2DSet[sets.size()]; … … 643 623 } 644 624 */ 625 /* 645 626 fieldSet = new UnionSet (domain, trueSets); 646 627 FunctionType fieldType = new FunctionType(domain, range); … … 653 634 return field; 654 635 } 636 */ 655 637 656 638 /* … … 833 815 */ 834 816 public static float getMultiplier(DisplayImpl display) { 817 // This method may be a bit naive, obtaining the multiplier from 818 // only one measurement. 835 819 int[] p1 = {0,0}; 836 820 int[] p2 = {0, 1000}; … … 933 917 } 934 918 919 // put this in ObjectUtil or something 920 /** Connects a pair of VisAD-style 2D arrays of points */ 921 public static float[][] adjoin(float[][] a, float b[][]) { 922 int alen = a[0].length; 923 int blen = b[0].length; 924 float[][] result = new float[a.length][alen + blen]; 925 for (int j=0; j<a.length; j++) { 926 for (int i=0; i<alen; i++) { 927 result[j][i] = a[j][i]; 928 } 929 for (int i=0; i<blen; i++) { 930 result[j][i+alen] = b[j][i]; 931 } 932 } 933 return result; 934 } 935 936 /** Given a set of nodes, creates a UnionSet of Gridded2DSets to 937 * highlight the nodes. */ 938 public static UnionSet buildNodesSets(RealTupleType domain, float[][] nodes, 939 float width) 940 throws VisADException { 941 int len = nodes[0].length; 942 943 // Create two arrays to store the gridpoints: one to the right of the curve 944 // and another to the left (supposing the curve is oriented in order of 945 // increasing node indices, i.e., the first node is nodes[][0], the last 946 // is nodes[][nodes.length-1]) 947 float[][] right = new float[2][len]; // store the gridpts 948 float[][] left = new float[2][len]; 949 950 if (len <=1) return null; 951 952 for (int i=0; i<len; i++) { 953 float[] rightPt = new float[2]; 954 float[] leftPt = new float[2]; 955 956 if (i==0) { // Case 1: the first node 957 958 float[] p1 = new float[] {nodes[0][0], nodes[1][0]}; // first point 959 float[] p2 = new float[] {nodes[0][1], nodes[1][1]}; // second point 960 // get a perpendicular vector to the right of p2-p1 961 float[] vPerp = MathUtil.getRightPerpendicularVector2D(p2, p1); 962 rightPt = MathUtil.add(p1, MathUtil.scalarMultiply(vPerp, width)); 963 leftPt = MathUtil.add(p1, MathUtil.scalarMultiply(vPerp, -1f * width)); 964 } 965 else if (i == len - 1) { // Case 2: the last node 966 967 float[] p1 = new float[] {nodes[0][i-1], nodes[1][i-1]}; // penultimate 968 float[] p2 = new float[] {nodes[0][i], nodes[1][i]}; // last point 969 // get a perpendicular vector to the right of p2-p1 970 float[] vPerp = MathUtil.getRightPerpendicularVector2D(p2, p1); 971 // add a multiple of this vector to the point p2, the last node in 972 // the curve 973 rightPt = MathUtil.add(p2, MathUtil.scalarMultiply(vPerp, width)); 974 leftPt = MathUtil.add(p2, MathUtil.scalarMultiply(vPerp, -1f * width)); 975 } 976 else { // Case 3: all interior nodes 977 978 float[] p1 = {nodes[0][i-1], nodes[1][i-1]}; 979 float[] p2 = {nodes[0][i], nodes[1][i]}; 980 float[] p3 = {nodes[0][i+1], nodes[1][i+1]}; 981 982 // obtain unit vectors bisecting p2-p1 and p3-p2 983 float[] bisector = MathUtil.getRightBisectorVector2D(p1, p2, p3); 984 float[] bisectorReflected = MathUtil.scalarMultiply(bisector, -1f); 985 986 // compute angle between the p2-p1 and bisector 987 float sin = Math.abs(MathUtil.cross2D(bisector, 988 MathUtil.unit(MathUtil.vector(p2, p1)))); 989 if (sin < 0.1f) sin = 0.1f; // keep a lower bound on this for safety 990 // (the value of sin could become really small) 991 992 // compute offset distance from curve 993 float offset = width / sin; 994 995 rightPt = MathUtil.add(p2, MathUtil.scalarMultiply(bisector, offset)); 996 leftPt = MathUtil.add(p2, MathUtil.scalarMultiply(bisectorReflected, 997 offset)); 998 } // end else // TEMP 999 1000 // copy calculated values to storage arrays 1001 right[0][i] = rightPt[0]; 1002 right[1][i] = rightPt[1]; 1003 left[0][i] = leftPt[0]; 1004 left[1][i] = leftPt[1]; 1005 } // end for 1006 1007 // assemble an array of gridded sets representing the highlighting 1008 Gridded2DSet[] sets = makeGridded2DSets(domain, nodes, right, left); 1009 UnionSet fieldSets = null; 1010 fieldSets = new UnionSet(domain, sets); 1011 1012 return fieldSets; 1013 } 1014 1015 /** Makes valid Gridded2DSets from the arrays supplied. 1016 * @param nodes The nodes of the noded object 1017 * @param right The points on the right side of the noded object (supposing 1018 * node indices increase from left to right across the screen) 1019 * @param left The points on the left side of the noded object (again 1020 * supposing node indices increase from left to right across the screen) 1021 */ 1022 public static Gridded2DSet[] makeGridded2DSets(RealTupleType domain, 1023 float[][] nodes, float[][] right, float[][] left) { 1024 int len = nodes[0].length; 1025 Vector sets = new Vector(100); 1026 for (int i=0; i<len-1; i++) { 1027 float[][] setSamples = { 1028 {right[0][i], right[0][i+1], left[0][i], left[0][i+1]}, 1029 {right[1][i], right[1][i+1], left[1][i], left[1][i+1]} 1030 }; 1031 1032 try { 1033 Gridded2DSet set = new Gridded2DSet(domain, setSamples, 2, 2, null, 1034 null, null, false); 1035 sets.add(set); 1036 } 1037 catch (VisADException ex) { 1038 // If samples form an invalid set, the grid is bow-tie shaped. 1039 // "Uncross" the box just by switching the order of the two 1040 // left points 1041 setSamples = new float[][]{ 1042 {right[0][i], right[0][i+1], left[0][i+1], left[0][i]}, 1043 {right[1][i], right[1][i+1], left[1][i+1], left[1][i]} 1044 }; 1045 1046 try { 1047 Gridded2DSet set = new Gridded2DSet(domain, setSamples, 2, 2, null, 1048 null, null, false); 1049 sets.add(set); 1050 } 1051 catch (VisADException ex2) { 1052 System.out.println("OverlayUtil: error making Gridded2DSets: " + 1053 "lefth tries produced invalid sets."); 1054 ex2.printStackTrace(); 1055 } 1056 } 1057 } // end for 1058 1059 // Convert vector to array 1060 Gridded2DSet[] trueSets = new Gridded2DSet[sets.size()]; 1061 Object[] garbage = sets.toArray(trueSets); 1062 1063 return trueSets; 1064 } 1065 1066 /** Prints a VisAD style group of points. */ 1067 public static void print(float[][] points) { 1068 for (int i=0; i<points[0].length; i++) { 1069 System.out.println("[" + points[0][i] + "," + points[1][i] + "]"); 1070 } 1071 } 1072 1073 /** Prints a point. */ 1074 public static void print(float x, float y) { 1075 System.out.println("[" + x + "," + y + "]"); 1076 } 1077 1078 public static void print(float[] p) { 1079 print(p[0], p[1]); 1080 } 935 1081 }
Note: See TracChangeset
for help on using the changeset viewer.