Changeset 2332


Ignore:
Timestamp:
02/23/07 17:04:29 (13 years ago)
Author:
sorber
Message:

During drawing, polyline start/end nodes become highlighted when mouse is near.

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

Legend:

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

    r2284 r2332  
    2424package loci.visbio.overlays; 
    2525 
     26import java.awt.Color; 
    2627import java.rmi.RemoteException; 
    2728import java.util.Arrays; 
    2829import loci.visbio.util.MathUtil; 
     30import loci.visbio.util.DisplayUtil; 
    2931import visad.*; 
    3032 
     
    3537 
    3638public abstract class OverlayNodedObject extends OverlayObject { 
     39 
     40  // -- Constants -- 
     41   
     42  /** Computed (X, Y) pairs for top 1/2 of a unit circle. */ 
     43  protected static final float[][] ARC = arc(); 
     44 
     45  /** Computes the top 1/2 of a unit circle. */ 
     46  private static float[][] arc() { 
     47    int res = 16; // resolution for 1/8 of circle 
     48    float[][] arc = new float[2][4 * res]; 
     49    for (int i=0; i<res; i++) { 
     50      float t = 0.5f * (i + 0.5f) / res; 
     51      float x = (float) Math.sqrt(t); 
     52      float y = (float) Math.sqrt(1 - t); 
     53 
     54      arc[0][i] = -y; 
     55      arc[1][i] = x; 
     56 
     57      int i1 = 2 * res - i - 1; 
     58      arc[0][i1] = -x; 
     59      arc[1][i1] = y; 
     60 
     61      int i2 = 2 * res + i; 
     62      arc[0][i2] = x; 
     63      arc[1][i2] = y; 
     64 
     65      int i3 = 4 * res - i - 1; 
     66      arc[0][i3] = y; 
     67      arc[1][i3] = x; 
     68    } 
     69    return arc; 
     70  } 
     71 
     72  /** Highlighting color. */ 
     73  protected static final Color HLT = Color.YELLOW; 
     74 
     75  /** Alpha value for highlighting */ 
     76  protected static float HLT_ALPHA = 0.5f; 
    3777   
    3878  // -- Fields -- 
     
    5090  protected double curveLength; 
    5191 
     92  /** Whether the head node should be highlighted */ 
     93  protected boolean highlightHead; 
     94 
     95  /** Whether the tail node should be highlighted */ 
     96  protected boolean highlightTail; 
     97 
     98  /** Whether there is a higlighted node */ 
     99  protected boolean highlightNode; 
     100 
     101  /** Index of the highlighted node */ 
     102  protected int highlightIndex; 
     103 
     104  /** The active display, used by the getData method */ 
     105  protected DisplayImpl display; 
     106 
    52107  // -- Constructors -- 
    53108 
    54109  /** Constructs an uninitialized noded object. */ 
    55   public OverlayNodedObject(OverlayTransform overlay) { super(overlay); } 
     110  public OverlayNodedObject(OverlayTransform overlay) {  
     111    super(overlay);  
     112    setHighlightHead(false); 
     113    setHighlightTail(false); 
     114    turnOffHighlighting(); 
     115  } 
    56116 
    57117  /** Constructs a noded object. */ 
     
    71131    computeGridParameters(); 
    72132    computeLength(); 
     133    setHighlightHead(false); 
     134    setHighlightTail(false); 
     135    turnOffHighlighting(); 
    73136  } 
    74137 
     
    83146    computeGridParameters(); 
    84147    computeLength(); 
     148    setHighlightHead(false); 
     149    setHighlightTail(false); 
     150    turnOffHighlighting(); 
    85151  } 
    86152 
     
    92158    TupleType range = overlay.getRangeType(); 
    93159 
    94     float[][] setSamples = nodes; 
    95     float r = color.getRed() / 255f; 
    96     float g = color.getGreen() / 255f; 
    97     float b = color.getBlue() / 255f; 
    98  
     160    boolean circleFilled = false; // can't set to true right now w/o 
     161    // Manifold dimension mismatch occuring, since nodes are of  
     162    // manifold dimension 1. 
     163 
     164    float scale; 
     165    if (display != null) scale = getScalingValue(display); 
     166    else scale = 1f; 
     167 
     168    int arcLen = ARC[0].length; 
     169    int len = 2 * arcLen; 
     170    float rad = 10.0f * scale; // 10.0 pixels wide per active display 
     171 
     172    float[][] highlightSetSamples = new float[2][0]; 
     173 
     174    if (isHighlightNode()) { 
     175      highlightSetSamples = new float[2][circleFilled ? len : len + 1]; 
     176      float[] c = getNodeCoords(getHighlightedNodeIndex()); 
     177 
     178      // top half of circle 
     179      for (int i=0; i<arcLen; i++) { 
     180        highlightSetSamples[0][i] = c[0] + rad * ARC[0][i]; 
     181        highlightSetSamples[1][i] = c[1] + rad * ARC[1][i]; 
     182      } 
     183 
     184      // bottom half of circle 
     185      for (int i=0; i<arcLen; i++) { 
     186        int ndx = circleFilled? arcLen + i : len - i - 1; 
     187        highlightSetSamples[0][ndx] = c[0] + rad * ARC[0][i]; 
     188        highlightSetSamples[1][ndx] = c[1] - rad * ARC[1][i]; 
     189      } 
     190    }  
     191     
    99192    FlatField field = null; 
     193    FlatField highlightField = null; 
    100194    try { 
    101       SampledSet fieldSet = new Gridded2DSet(domain, 
    102         setSamples, setSamples[0].length, null, null, null, false); 
    103       if (filled) { 
     195      //highlight  
     196      SampledSet highlightSet = null; 
     197      if (isHighlightNode()) { 
     198        if (circleFilled) { 
     199          highlightSet = new Gridded2DSet(domain, highlightSetSamples, 
     200            arcLen, 2, null, null, null, false); 
     201        } 
     202        else { 
     203          highlightSetSamples[0][len] = highlightSetSamples[0][0]; 
     204          highlightSetSamples[1][len] = highlightSetSamples[1][0]; 
     205          highlightSet = new Gridded2DSet(domain, highlightSetSamples, 
     206              highlightSetSamples[0].length, null, null, null, false); 
     207        } 
     208      } 
     209 
     210     // nodes 
     211      SampledSet nodesSet = new Gridded2DSet(domain, 
     212        nodes, maxNodes, null, null, null, false); 
     213       
     214      // I've written !isDrawing() to prevent a manifold dimension mismatch 
     215      // that occurs when drawing filled polylines 
     216      if (filled && !isDrawing()) {   
    104217        Irregular2DSet roiSet = 
    105           DelaunayCustom.fillCheck((Gridded2DSet) fieldSet, false); 
    106         if (roiSet != null) fieldSet = roiSet; 
    107       } 
    108  
    109       int len = fieldSet.getSamples(false)[0].length; 
    110       float[][] rangeSamples = new float[4][len]; 
    111       Arrays.fill(rangeSamples[0], r); 
    112       Arrays.fill(rangeSamples[1], g); 
    113       Arrays.fill(rangeSamples[2], b); 
    114       Arrays.fill(rangeSamples[3], 1.0f); 
     218          DelaunayCustom.fillCheck((Gridded2DSet) nodesSet, false); 
     219        if (roiSet != null)  nodesSet = roiSet; 
     220      } 
     221 
     222      int hlen = 0; 
     223      int totalSamples = nodesSet.getLength(); 
     224      if (highlightSet != null) { 
     225        hlen = highlightSet.getLength();  
     226        totalSamples += hlen;  
     227      } 
     228 
     229      float r = color.getRed() / 255f; 
     230      float g = color.getGreen() / 255f; 
     231      float b = color.getBlue() / 255f; 
     232 
     233      float hltR = HLT.getRed() / 255f; 
     234      float hltG = HLT.getGreen() / 255f; 
     235      float hltB = HLT.getBlue() / 255f; 
     236      float hltA = HLT_ALPHA; 
     237 
     238      float[][] rangeSamples = new float[4][totalSamples]; 
     239      Arrays.fill(rangeSamples[0], 0, hlen, hltR); 
     240      Arrays.fill(rangeSamples[1], 0, hlen, hltG); 
     241      Arrays.fill(rangeSamples[2], 0, hlen, hltB); 
     242      Arrays.fill(rangeSamples[3], 0, hlen, hltA); 
     243 
     244      Arrays.fill(rangeSamples[0], hlen, totalSamples, r); 
     245      Arrays.fill(rangeSamples[1], hlen, totalSamples, g); 
     246      Arrays.fill(rangeSamples[2], hlen, totalSamples, b); 
     247      Arrays.fill(rangeSamples[3], hlen, totalSamples, 1.0f); 
     248       
     249      // select which sets to include in union set 
     250      SampledSet[] sets; 
     251      if (isHighlightNode()) sets = new SampledSet[]{highlightSet, nodesSet};   
     252      else sets = new SampledSet[]{nodesSet}; 
     253       
     254      UnionSet fieldSet = new UnionSet(domain, sets); 
    115255 
    116256      FunctionType fieldType = new FunctionType(domain, range); 
     
    120260    catch (VisADException exc) { exc.printStackTrace(); } 
    121261    catch (RemoteException exc) { exc.printStackTrace(); } 
    122     return field; 
     262    return field; // return field; 
    123263  } 
    124264 
     
    156296  public boolean hasEndpoint2() { return true; } 
    157297 
     298  /** True iff the head node is highlighted. */ 
     299  public boolean isHighlightHead() { return highlightHead; } 
     300  // TODO get rid of this ACS 
     301 
     302  /** True iff the tail node is highlighted. */ 
     303  public boolean isHighlightTail() { return highlightTail; } 
     304  // TODO get rid of this ACS 
     305 
     306  /** True iff there is a highlighted node. */ 
     307  public boolean isHighlightNode() { return highlightNode; } 
     308 
     309  /** Returns index of highlighted node. */  
     310  public int getHighlightedNodeIndex() { return highlightIndex; } 
     311 
    158312  /** True iff this overlay supports the filled parameter. */ 
    159313  public boolean canBeFilled() { return true; } 
     
    185339  // -- Object API methods -- 
    186340 
     341  /** Makes this object aware of active display.  
     342   *  The display is required to convert back and forth from pixel 
     343   *  to domain coordinates 
     344   */ 
     345  public void setActiveDisplay (DisplayImpl d) { display = d; } 
     346   
     347  /** Toggle highlight head of polyline. */ 
     348  public void setHighlightHead(boolean b) { highlightHead = b; } 
     349 
     350  /** Toggle highlight tail of polyline. */ 
     351  public void setHighlightTail(boolean b) { highlightTail = b; } 
     352 
     353  /** Highlight a node. */  
     354  public void setHighlightNode(int i) { 
     355    highlightNode = true; 
     356    highlightIndex = i; 
     357  } 
     358 
     359  /** Turn off node highlighting */ 
     360  public void turnOffHighlighting() { highlightNode = false; } 
     361 
    187362  /** Returns coordinates of node at given index in the node array */ 
    188363  public float[] getNodeCoords (int index) { 
     
    219394  /** Changes coordinates of the overlay's first endpoint. */ 
    220395  public void setCoords(float x1, float y1) { 
    221     this.x1 = x1;  
    222     this.y1 = y1; 
    223  
    224396    // different from super: 
    225397    float dx = x1-this.x1; 
     
    229401      nodes[1][i] = nodes[1][i]+dy; 
    230402    } 
     403 
     404    // same as super 
     405    this.x1 = x1; 
     406    this.y1 = y1; 
     407 
    231408    computeGridParameters(); 
    232409  } 
     
    293470  } 
    294471 
     472  /** Sets coordinates of last node. */ 
     473  public void setLastNode(float x, float y) { 
     474    setNodeCoords(numNodes-1, x, y); 
     475    if (numNodes < maxNodes) { 
     476      Arrays.fill(nodes[0], numNodes, maxNodes, x); 
     477      Arrays.fill(nodes[1], numNodes, maxNodes, y); 
     478    } 
     479  } 
     480     
    295481  /** Prints node array of current freeform; for debugging */ 
    296482  private void printNodes(float[][] nodes) { 
     
    303489  /** Sets next node coordinates. */ 
    304490  public void setNextNode(float x, float y) { 
    305     //System.out.println("OverlayObject.setNextNode(...) called. " + 
    306     //  "numNodes = " + numNodes + ", maxNodes = " + maxNodes); 
    307     //printNodes(getNodes()); 
    308491    if (numNodes >= maxNodes) { 
    309492      maxNodes *= 2; 
     
    431614  } 
    432615 
    433  
     616  /** Returns a domain/pixel scaling value */ 
     617  protected float getScalingValue(DisplayImpl d) { 
     618    double[] oDom = DisplayUtil.pixelToDomain(d, 0, 0); 
     619    double[] pDom = DisplayUtil.pixelToDomain(d, 1, 0); 
     620    double scl = MathUtil.getDistance(oDom, pDom);  
     621    return (float) scl; 
     622  } 
    434623} 
  • trunk/loci/visbio/overlays/OverlayPolyline.java

    r2284 r2332  
    3232public class OverlayPolyline extends OverlayNodedObject { 
    3333 
     34  // -- Fields -- 
     35   
    3436  // -- Constructors -- 
    3537 
     
    4951  } 
    5052 
     53  // -- Internal OverlayObject API methods -- 
     54 
     55  // -- Object API methods -- 
     56   
     57   
    5158  // -- OverlayObject API methods -- 
    52  
    53   // -- Internal OverlayObject API methods -- 
    54  
    55   // -- Object API methods -- 
    56  
    5759  /** Gets a short string representation of this freeform. */ 
    5860  public String toString() { return "Polyline"; } 
  • trunk/loci/visbio/overlays/OverlayTool.java

    r2246 r2332  
    103103 
    104104  /** 
     105   * Instructs this tool to respond to mouse movement. 
     106   * @param e DisplayEvent corresponding to this mouse movement. 
     107   * @param px X coordinate of mouse movement in pixel coordinate system. 
     108   * @param py Y coordinate of mouse movement in pixel coordinate system. 
     109   * @param dx X coordinate of mouse movement in data coordinate system. 
     110   * @param dy Y coordinate of mouse movement in data coordinate system. 
     111   * @param pos Dimensional position of mouse movement. 
     112   * @param mods Modifiers of mouse movement. 
     113   */ 
     114  public void mouseMoved(DisplayEvent e, int px, int py, 
     115    float dx, float dy, int[] pos, int mods) 
     116  { 
     117  } 
     118 
     119  /** 
    105120   * Instructs this tool to respond to a key press. 
    106121   * @param code Key code of pressed key. 
  • trunk/loci/visbio/overlays/OverlayTransform.java

    r2246 r2332  
    690690 
    691691    if (id == DisplayEvent.TRANSFORM_DONE) updatePosition(display); 
     692    else if (id == DisplayEvent.MOUSE_MOVED) { 
     693      if (tool != null) { 
     694        int px = e.getX(), py = e.getY(); 
     695        double[] coords = DisplayUtil.pixelToDomain(display, px, py); 
     696        tool.mouseMoved(e, px, py, 
     697          (float) coords[0], (float) coords[1], pos, e.getModifiers()); 
     698      } 
     699    } 
    692700    else if (id == DisplayEvent.MOUSE_PRESSED_RIGHT) { 
    693701      mouseDownRight = true; 
  • trunk/loci/visbio/overlays/OverlayWidget.java

    r2190 r2332  
    154154      new OvalTool(overlay), 
    155155      new BoxTool(overlay), 
    156       new ArrowTool(overlay) 
     156      new ArrowTool(overlay), 
     157      new PolylineTool(overlay), 
    157158    }; 
    158159    tools = new Vector(toolList.length); 
  • trunk/loci/visbio/overlays/PolylineTool.java

    r2284 r2332  
    2727import loci.visbio.data.TransformEvent; 
    2828import loci.visbio.util.DisplayUtil; 
     29import loci.visbio.util.MathUtil; 
    2930import visad.DisplayEvent; 
    3031import visad.DisplayImpl; 
     
    3536  // -- Constants -- 
    3637 
     38 
     39 
    3740  // -- Fields -- 
    3841 
     
    4043  protected OverlayPolyline line; 
    4144 
     45  /** Whether the active node of the polyline is anchored. */ 
     46  protected boolean anchored; 
     47 
     48  /** Whether the mouse is currently near the last node of  
     49   *  the active polyline. */ 
     50  protected boolean nearTail; 
     51 
     52  /** Whether the mouse is currently near the first node of  
     53   *  the active polyline. */ 
     54  protected boolean nearHead; 
     55 
     56  /** Whether the mouse has moved sufficiently far from the  
     57   *  last node placed. */ 
     58  protected boolean departed; 
     59 
    4260  // -- Constructor -- 
    4361 
    44   /** Constructs a freeform creation tool. */ 
     62  /** Constructs a creation tool. */ 
    4563  public PolylineTool(OverlayTransform overlay) { 
    4664    super(overlay, "Polyline", "Polyline", "polyline.png"); 
     65    line = null; 
     66    anchored = false; 
     67    nearTail = false; 
     68    nearHead = false; 
     69    departed = false; 
    4770  } 
    4871 
     
    5982    double dpx = (double) px; 
    6083    double dpy = (double) py; 
     84 
     85    // -- action! 
     86    deselectAll();  
    6187    
     88    if (line == null) { 
     89      line =  new OverlayPolyline(overlay, dx, dy, dx, dy); 
     90      configureOverlay(line); 
     91      overlay.addObject(line, pos); 
     92    } 
     93    else { 
     94      line.setActiveDisplay (display); 
     95 
     96      if (nearTail) { 
     97        if (!anchored) line.deleteNode(line.getNumNodes()-1); 
     98        releaseLine(); 
     99        System.out.println("nearTail, ending line"); // TEMP 
     100      } 
     101      else if (nearHead) { 
     102        if (anchored) System.out.println("puzzling case is here"); 
     103        else { 
     104          float[] c = line.getNodeCoords(0); 
     105          line.setLastNode(c[0], c[1]); 
     106          releaseLine();  
     107          System.out.println("nearHead, ending line"); // TEMP 
     108        } 
     109      } 
     110      else { 
     111        nearTail = true; 
     112        if (anchored) { 
     113          line.setNextNode(dx, dy); 
     114        } 
     115        else {  
     116          line.setNodeCoords(line.getNumNodes() - 1, dx, dy); 
     117        } 
     118        line.computeLength(); 
     119      } 
     120    } 
     121 
     122    anchored = true; 
     123    departed = false; 
     124 
    62125    overlay.notifyListeners(new TransformEvent(overlay)); 
    63126  } // end mouseDown 
     
    65128  /** Instructs this tool to respond to a mouse drag. */ 
    66129  public void mouseDrag(DisplayEvent e, int px, int py, 
    67     float dx, float dy, int[] pos, int mods) 
    68   { 
    69     boolean shift = (mods & InputEvent.SHIFT_MASK) != 0; 
    70     boolean ctl = (mods & InputEvent.CTRL_MASK) != 0; 
    71  
    72     DisplayImpl display = (DisplayImpl) e.getDisplay(); 
    73  
    74     double dpx = (double) px; 
    75     double dpy = (double) py; 
    76      
    77     overlay.notifyListeners(new TransformEvent(overlay)); 
    78   } // end mouseDrag 
     130    float dx, float dy, int[] pos, int mods) { 
     131  }  
    79132 
    80133  /** Instructs this tool to respond to a mouse release. */ 
    81134  public void mouseUp(DisplayEvent e, int px, int py,  
    82135      float dx, float dy, int[] pos, int mods) { 
     136  } 
     137 
     138  /** Instructs this tool to respond to a mouse movement. */ 
     139  public void mouseMoved(DisplayEvent e, int px, int py,  
     140      float dx, float dy, int[] pos, int mods) { 
     141    DisplayImpl display = (DisplayImpl) e.getDisplay(); 
     142    if (line != null) { 
     143      line.setActiveDisplay(display); 
     144 
     145      nearTail = false; 
     146      nearHead = false; 
     147 
     148      if (anchored) { 
     149        line.setNextNode(dx, dy); 
     150        anchored = false; 
     151        nearTail = true; 
     152      } 
     153      else { 
     154        line.setLastNode(dx, dy); 
     155      } 
     156 
     157      // determine whether to highlight head or tail nodes 
     158      double[] movePxl = {(double) px, (double) py};  
     159      float[] prevDom = line.getNodeCoords(line.getNumNodes() - 2); 
     160      double[] prevDomDbl = {(double) prevDom[0], (double) prevDom[1]};  
     161      int[] prevPxlInt = DisplayUtil.domainToPixel(display, prevDomDbl); 
     162      double[] prevPxl = {(double) prevPxlInt[0], (double) prevPxlInt[1]}; 
     163      double tailDist = MathUtil.getDistance(movePxl, prevPxl); 
     164 
     165      float[] headDom = line.getNodeCoords(0); 
     166      double[] headDomDbl = {(double) headDom[0], (double) headDom[1]}; 
     167      int[] headPxlInt = DisplayUtil.domainToPixel(display, headDomDbl); 
     168      double[] headPxl = {(double) headPxlInt[0], (double) headPxlInt[1]}; 
     169      double headDist = MathUtil.getDistance(movePxl, headPxl); 
     170 
     171      if (tailDist > 10.0) departed = true; 
     172 
     173      if (headDist < 2.0) { 
     174        line.setHighlightNode(0); 
     175        System.out.println("near head"); // TEMP 
     176        nearHead = true; 
     177      } 
     178      else if (departed && tailDist < 2.0) { 
     179        line.setHighlightNode(line.getNumNodes() - 2); 
     180        System.out.println("near tail");// TEMP 
     181        nearTail = true; 
     182      } 
     183      else { 
     184        line.turnOffHighlighting(); 
     185      } 
     186 
    83187      overlay.notifyListeners(new TransformEvent(overlay)); 
     188    } 
    84189  } 
    85190 
    86191  // -- Helper methods --  
     192   
     193  /** Ends drawing of the current line */ 
     194  private void releaseLine() { 
     195    if (line != null) { 
     196      line.turnOffHighlighting(); 
     197      line.updateBoundingBox(); 
     198      line.computeGridParameters(); 
     199      line.computeLength(); 
     200      line.setDrawing(false); 
     201      line.setSelected(true); 
     202      line = null; 
     203    } 
     204  } 
    87205 
    88206  /** Casts an array of floats to doubles */ 
Note: See TracChangeset for help on using the changeset viewer.