Changeset 2865


Ignore:
Timestamp:
06/13/07 12:33:22 (12 years ago)
Author:
sorber
Message:

Improved highlighting of freeforms and polylines. Began refactoring FreeformTool and OverlayNodedObject.

Location:
trunk/loci/visbio/overlays
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/visbio/overlays/FreeformTool.java

    r2725 r2865  
    101101  protected float[][] pre, post; 
    102102 
    103   /** Point at which mouseDown occurs */ 
     103  /** Point at which mouseDown occurs. */ 
    104104  protected float downX, downY; 
    105105 
     
    128128    // find closest freeform 
    129129    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; 
    133133 
    134134    // operate on closest freeform 
    135135    if (target != null) { 
     136      // editing operations on closest freeform 
    136137      freeform = target; 
    137138 
    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()) 
    144144      { 
    145145        // near an end node 
     
    177177          else { 
    178178            // determine projection on seg. 
     179            // insert a pair of nodes there, starting a tendril 
    179180            float[] a = freeform.getNodeCoords(seg); 
    180181            float[] b = freeform.getNodeCoords(seg + 1); 
     
    190191    } 
    191192    else { // no freeform was sufficiently close 
     193      // drawing operations on new freeform 
    192194      if (!ctl) { 
    193195        // record initial coordinates of freeform 
     
    198200    } 
    199201 
     202    // stuff you have to do if there's been a change 
    200203    overlay.notifyListeners(new TransformEvent(overlay)); 
    201204    ((OverlayWidget) overlay.getControls()).refreshListSelection(); 
     
    237240        float[] tail = f.getNodeCoords(f.getNumNodes()-1); 
    238241 
    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); 
    253245 
    254246        boolean isHead = hdist < tdist ? true : false; 
     
    270262        // compute distance from last node 
    271263        // 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}); 
    284267 
    285268        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); 
    288271          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); 
    291273          freeform.setCurveLength(len + delta); 
    292274          // I debated whether to call setBoundaries with every mouseDrag. 
    293275          // 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) 
    295278          // scan of the nodes every time a node is deleted. 
    296279          freeform.setBoundaries(s[0], s[1]); 
     
    302285      if (freeform == null) { 
    303286        // DISTANCE COMPUTATION compare floats with floats 
    304         Info info = getClosestFreeform(display, 
     287        DistanceQuery distanceQuery = getClosestFreeform(display, 
    305288            dpx, dpy, ERASE_THRESH); 
    306         OverlayFreeform target = info.freeform; 
     289        OverlayFreeform target = distanceQuery.freeform; 
    307290        if (target != null) freeform = target; 
    308291      } 
     
    310293      if (freeform != null) { 
    311294        // 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);  
    326302 
    327303        boolean closerToEnd = edist < bdist ? true : false; 
     
    331307          if (!closerToEnd) freeform.reverseNodes(); 
    332308          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; 
    339312 
    340313            // 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); 
    346317            freeform.setCurveLength(freeform.getCurveLength() - delta); 
    347318 
     
    556527  } 
    557528 
    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 { 
    560531    public double dist, wt; 
    561532    public int seg; 
    562533    public OverlayFreeform freeform; 
    563534 
    564     public Info(double[] distSegWt, OverlayFreeform f) { 
     535    /** Constructs a DistanceQuery object. */ 
     536    public DistanceQuery(double[] distSegWt, OverlayFreeform f) { 
    565537      this.freeform = f; 
    566538      this.dist = distSegWt[0]; 
     
    568540      this.wt = distSegWt[2]; 
    569541    } 
    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 
    573551   *  Appears like a 'tendril' on screen */ 
    574   private class Tendril { 
     552  protected class Tendril { 
    575553    public int start, stop, tip; 
    576554    public boolean nodal; 
     
    658636      } 
    659637    } 
    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 freeforms 
    669       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     */ 
    691638  } 
    692639 
     
    721668   *  the given point 
    722669   */ 
    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, 
    763671      double dpy, double thresh) { 
    764672    // returns only objects at the current dimensional position 
     
    791699      } // end for 
    792700    } // end if 
    793     return new Info(min, closestFreeform); 
     701    return new DistanceQuery(min, closestFreeform); 
    794702  } 
    795703 
     
    807715  } 
    808716 
    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. */ 
    810731  private double[][] floatsToPixelDoubles(DisplayImpl d, float[][] nodes) { 
    811732    double[][] nodesDbl = new double[nodes.length][nodes[0].length]; 
     
    819740  } 
    820741 
    821   /** Prints node array of current freeform; for debugging */ 
     742  /** Prints node array of current freeform; for debugging. */ 
    822743  private void printNodes(float[][] nodes) { 
    823744    System.out.println("Printing nodes..."); 
     
    827748  } 
    828749 
    829   /** Prints node array of current freeform; for debugging */ 
     750  /** Prints node array of current freeform; for debugging. */ 
    830751  private void printNodes() { 
    831752    if (freeform!=null){ 
     
    835756  } 
    836757 
    837   /** Prints a message for debugging */ 
     758  /** Prints a message for debugging. */ 
    838759  public void print(String methodName, String message) { 
    839760    boolean toggle = true; 
  • trunk/loci/visbio/overlays/OverlayNodedObject.java

    r2824 r2865  
    424424  } 
    425425 
     426  /** Sets coordinates of last node. */ 
     427  public void setLastNode(float[] c) { 
     428    setLastNode(c[0], c[1]); 
     429  } 
     430 
    426431  /** Prints node array of current freeform; for debugging */ 
    427432  private void printNodes(float[][] nodes) { 
     
    441446    Arrays.fill(nodes[1], numNodes++, maxNodes, y); 
    442447    // 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]); 
    443453  } 
    444454 
  • trunk/loci/visbio/overlays/OverlayUtil.java

    r2823 r2865  
    2929import java.util.Vector; 
    3030import loci.visbio.view.TransformLink; 
     31import loci.visbio.util.MathUtil; 
    3132import visad.*; 
    3233import visad.util.CursorUtil; 
     
    516517    int len = 2 * arcLen; 
    517518 
    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  
    530519    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    531520    // Build nodes sets 
    532521    // ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 
    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 
    553589      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); 
    627607 
    628608      Gridded2DSet[] trueSets = new Gridded2DSet[sets.size()]; 
     
    643623        } 
    644624        */ 
     625    /* 
    645626        fieldSet = new UnionSet (domain, trueSets); 
    646627        FunctionType fieldType = new FunctionType(domain, range); 
     
    653634      return field; 
    654635    } 
     636    */ 
    655637 
    656638    /* 
     
    833815   */ 
    834816  public static float getMultiplier(DisplayImpl display) { 
     817    // This method may be a bit naive, obtaining the multiplier from 
     818    // only one measurement. 
    835819    int[] p1 = {0,0}; 
    836820    int[] p2 = {0, 1000}; 
     
    933917  } 
    934918 
     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  } 
    9351081} 
Note: See TracChangeset for help on using the changeset viewer.