Changeset 1846


Ignore:
Timestamp:
11/22/06 14:00:17 (14 years ago)
Author:
sorber
Message:

Freeforms can now be connected end-to-end

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

Legend:

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

    r1829 r1846  
    2727import loci.visbio.util.MathUtil; 
    2828import java.awt.event.InputEvent; 
     29import java.util.Vector; 
    2930 
    3031/** FreeformTool is the tool for creating freeform objects. */ 
     
    5455  protected OverlayFreeform freeform;  
    5556   
     57  /** Other freeforms on the canvas */ 
     58  protected Vector otherFreefs; 
     59   
    5660  /** Tendril wraps info about an edit to a curve */ 
    5761  protected Tendril tendril; 
     
    6569  public FreeformTool(OverlayTransform overlay) { 
    6670    super(overlay, "Freeform", "Freeform", "freeform.png"); 
     71    tendril = null; 
     72    otherFreefs = new Vector(); 
    6773    setMode(CHILL); 
    68     tendril = null; 
    6974  } 
    7075 
     
    8691        // test for not terminal node 
    8792        if (!(seg == 0 && weight == 0.0) && !(seg == freeform.getNumNodes()-2 && weight == 1.0)) { 
    88           erase(freeform, x, y, dist, seg, weight); 
     93          slice(freeform, x, y, dist, seg, weight); 
    8994        } 
    9095      } else { 
     
    9499          // project click onto curve and insert a new node there,  
    95100          // unless nearest point on curve is a node itself 
    96           if (weight == 0.0) { 
    97             // nearest point on seg is the start node 
    98             float[] a = freeform.getNodeCoords(seg); // determine projection on seg. 
    99             freeform.insertNode (seg+1, a[0], a[1]); 
    100             tendril = new Tendril (seg, seg+1, true); 
    101             splitNodes (seg-1, seg+2); 
    102           } else if (weight == 1.0) { 
     101          // because of the way getDistSegWt() works, weight can never be 0.0 except if seg = 0. 
     102          if (weight == 1.0) { 
    103103            // nearest point on  seg is the end node 
    104104            float[] a = freeform.getNodeCoords(seg+1); // determine projection on seg. 
     
    133133  } // end mouseDown 
    134134 
    135   /** Erases or slices a freeform */ 
    136   private void erase(OverlayFreeform freef, float x, float y, double dist, int seg, double weight) { 
    137     //TODO: don't need to check all of exterior cases 
     135  /** Slices a freeform in two */ 
     136  private void slice(OverlayFreeform freef, float x, float y, double dist, int seg, double weight) { 
    138137    int f1Start, f2Start, f1Stop, f2Stop; 
    139138    OverlayFreeform f1, f2; 
    140     boolean doNothing = false; 
    141139 
    142140    f1Start = 0; 
     
    145143    f2Stop = freef.getNumNodes() - 1; 
    146144         
    147     boolean splitFreeform = false;    
    148     if (weight == 0.0) {  
    149       // case: beginning node 
    150       freef.deleteNode(0); 
    151       //print("erase", "weight == 0: click occurred nearest start node"); 
    152     } else if (weight == 1.0) { 
    153       // case end node of segment 
    154       if (seg == freef.getNumNodes() - 2) { 
    155         freef.deleteNode(seg + 1); 
    156         //print("erase", "weight == 1: click occurred nearest end node"); 
    157       } else { 
    158         //print("erase", "weight == 1: click occurred nearest node " + (seg + 1)); 
    159         splitFreeform = true; 
    160         // reassign this guy 
    161         f2Start = seg + 2;  
    162       } 
    163     } else { 
    164       // interior segment 
    165       //print("erase", "0 < weight < 1: seg = " + seg); 
    166       splitFreeform = true; 
    167     } 
     145    if (weight == 0.0) f1Stop = seg - 1; 
     146    else if (weight == 1.0) f2Start = seg + 2;  
    168147     
    169     if (splitFreeform) { 
    170       //TODO debug weird 'elementAt()' exception that pops up.  Wrong number of object. 
    171       float[][] oldNodes = freef.getNodes(); 
    172       float[][] f1Nodes = new float[2][f1Stop+1]; 
    173       float[][] f2Nodes = new float[2][f2Stop-f2Start + 1]; 
    174  
    175       for (int i = 0; i<2; i++) { 
    176         System.arraycopy(oldNodes[i], 0, f1Nodes[i], 0, f1Stop+1); 
    177         System.arraycopy(oldNodes[i], f2Start, f2Nodes[i], 0, f2Stop-f2Start+1); 
    178       } 
    179       f1 = new OverlayFreeform(overlay, f1Nodes); 
    180       f2 = new OverlayFreeform(overlay, f2Nodes); 
    181        
    182       //System.out.println("printing nodes of original freeform"); 
    183       //printNodes(freef.getNodes()); 
    184       //System.out.println("printing nodes of new sub freeforms"); 
    185       //printNodes(f1.getNodes()); 
    186       //printNodes(f2.getNodes()); 
    187       configureOverlay(f1); 
    188       configureOverlay(f2); 
    189       overlay.addObject(f1); 
    190       overlay.addObject(f2); 
    191       f1.setSelected(false); 
    192       f2.setSelected(false); 
    193       f1.setDrawing(false); 
    194       f2.setDrawing(false); 
    195        
    196       overlay.removeObject(freef); 
    197     } 
    198   } 
    199  
    200   /** Wraps info for redrawing a curve.  Appears like a 'tendril' on screen */ 
     148    float[][] oldNodes = freef.getNodes(); 
     149    float[][] f1Nodes = new float[2][f1Stop+1]; 
     150    float[][] f2Nodes = new float[2][f2Stop-f2Start+1]; 
     151 
     152    for (int i = 0; i<2; i++) { 
     153      System.arraycopy(oldNodes[i], 0, f1Nodes[i], 0, f1Stop+1); 
     154      System.arraycopy(oldNodes[i], f2Start, f2Nodes[i], 0, f2Stop-f2Start+1); 
     155    } 
     156    f1 = new OverlayFreeform(overlay, f1Nodes); 
     157    f2 = new OverlayFreeform(overlay, f2Nodes); 
     158     
     159    configureOverlay(f1); 
     160    configureOverlay(f2); 
     161    overlay.addObject(f1); 
     162    overlay.addObject(f2); 
     163    f1.setSelected(false); 
     164    f2.setSelected(false); 
     165    f1.setDrawing(false); 
     166    f2.setDrawing(false); 
     167     
     168    //TODO element at exception caused by this 
     169    overlay.removeObject(freef); 
     170  } 
     171 
     172  /** Wraps info for redrawing a curve 
     173   *  Appears like a 'tendril' on screen */ 
    201174  private class Tendril { 
    202175    public int start, stop, tip; 
     
    259232      freeform.setDrawing(true); 
    260233      freeform.setSelected(true); 
    261     } else if (mode == CHILL && freeform != null) { 
     234    } 
     235 
     236    if (mode == DRAW) { 
     237      // create list of freeforms 
     238      OverlayObject[] objs = overlay.getObjects(); 
     239      for (int i=0; i<objs.length; i++) { 
     240        if (objs[i] instanceof OverlayFreeform && objs[i] != freeform) otherFreefs.add(objs[i]); 
     241      } 
     242    } else { 
     243      otherFreefs.removeAllElements(); 
     244    } 
     245 
     246    if (mode == CHILL && freeform != null) { 
    262247      freeform.computeLength(); 
    263248      freeform.updateBoundingBox(); 
     
    274259 
    275260    if (mode == DRAW) { 
    276       float lastX = freeform.getLastNodeX(); 
    277       float lastY = freeform.getLastNodeY(); 
    278       float dx = x - lastX;  
    279       float dy = y - lastY;  
    280       // compute distance 
    281       double dist = Math.sqrt (dx*dx + dy*dy); 
    282      
    283       if (dist > DRAW_THRESH) { 
    284         freeform.setNextNode(x, y); 
    285         double len = freeform.getCurveLength(); 
    286         freeform.setCurveLength(len + dist); 
    287         freeform.setBoundaries(x,y); // I debated whether to update this realtime.  This is an efficient method,  
    288         // buy updating realtime for erasing requires an O(n) operation every time a node is deleted. 
    289       } 
    290       // mode remains DRAW 
     261      // compute distance to endpoints of nearby freeforms 
     262      int index = -1; 
     263      boolean closerToHead = false; 
     264      double minDist = Double.MAX_VALUE; 
     265 
     266      for (int i=0; i<otherFreefs.size(); i++) { 
     267        OverlayFreeform f = (OverlayFreeform) otherFreefs.get(i); 
     268        float[] head = f.getNodeCoords(0); 
     269        float[] tail = f.getNodeCoords(f.getNumNodes()-1); 
     270 
     271        double[] headd = {(double) head[0], (double) head[1]}; 
     272        double[] taild = {(double) tail[0], (double) tail[1]}; 
     273        double[] drag = {(double) x, (double) y}; 
     274 
     275        double hdist = MathUtil.getDistance(drag, headd); 
     276        double tdist = MathUtil.getDistance(drag, taild); 
     277 
     278        boolean isHead = hdist < tdist ? true : false; 
     279        double dist = isHead ? hdist : tdist; 
     280 
     281        if (dist < minDist) { 
     282          minDist = dist; 
     283          index = i; 
     284          closerToHead = isHead; 
     285        } 
     286      } 
     287 
     288      if (minDist < DRAW_THRESH) { 
     289        connectFreeforms (freeform, (OverlayFreeform) otherFreefs.get(index), closerToHead); 
     290        setMode(CHILL); 
     291      } else {  
     292        // compute distance from last node 
     293        float lastX = freeform.getLastNodeX(); 
     294        float lastY = freeform.getLastNodeY(); 
     295        float dx = x - lastX;  
     296        float dy = y - lastY;  
     297        double dist = Math.sqrt (dx*dx + dy*dy); 
     298       
     299        if (dist > DRAW_THRESH) { 
     300          freeform.setNextNode(x, y); 
     301          double len = freeform.getCurveLength(); 
     302          freeform.setCurveLength(len + dist); 
     303          freeform.setBoundaries(x,y); // I debated whether to update this realtime.  This is an efficient method,  
     304          // buy updating realtime for erasing requires an O(n) operation every time a node is deleted. 
     305        } 
     306        // mode remains DRAW 
     307      } 
    291308    } else if (mode == ERASE) { 
    292309      if (freeform == null) { 
     
    453470  //-- Additional methods 
    454471 
     472  /** Connects a pair of freeforms 
     473   *  @param f1 the freeform being drawn 
     474   *  @param f2 the freeform to be appended to f2 
     475   *  @param head whether the tail of f1 should be connected to the head (or if not, the tail) 
     476   *  of f2 
     477   */ 
     478  private void connectFreeforms (OverlayFreeform f1, OverlayFreeform f2, boolean head) { 
     479    if (!head) f2.reverseNodes(); 
     480    float[][] newNodes = new float[2][f1.getNumNodes()+f2.getNumNodes()]; 
     481 
     482    for (int i=0; i<2; i++) { 
     483      System.arraycopy(f1.getNodes()[i], 0, newNodes[i], 0, f1.getNumNodes()); 
     484      System.arraycopy(f2.getNodes()[i], 0, newNodes[i], f1.getNumNodes(), f2.getNumNodes()); 
     485    } 
     486 
     487    OverlayFreeform f3 = new OverlayFreeform (overlay, newNodes); 
     488    overlay.removeObject(f1); 
     489    overlay.removeObject(f2); 
     490    configureOverlay(f3); 
     491    overlay.addObject(f3); 
     492  } 
     493 
    455494  /** Returns the closest (subject to a threshhold) OverlayFreeform object to  
    456495   *  the given point  
  • trunk/loci/visbio/overlays/OverlayFreeform.java

    r1829 r1846  
    164164 
    165165  /** Gets a short string representation of this freeform. */ 
    166   public String toString() { return "Freeform"; } 
     166  public String toString() { return getStatistics(); } 
    167167 
    168168} 
  • trunk/loci/visbio/overlays/OverlayObject.java

    r1829 r1846  
    118118  /** True iff this overlay supports the filled parameter. */ 
    119119  public boolean canBeFilled() { return false; } 
     120   
     121  /** True iff this overlay can be resized using X1, X2, Y1, Y2 entry boxes */ 
     122  public boolean areBoundsEditable() { return !hasNodes; } 
     123  // currently, only noded objects can't be resized this way.  (Actually could perform some rad scaling on all nodes) 
    120124 
    121125  /** True iff this overlay returns text to render. */ 
  • trunk/loci/visbio/overlays/OverlayWidget.java

    r1390 r1846  
    494494    } 
    495495    boolean enableXY1 = false, enableXY2 = false; 
     496    boolean editXY1 = false, editXY2 = false; 
    496497    String xval1 = "", yval1 = "", xval2 = "", yval2 = ""; 
    497498    String words = ""; 
     
    511512        enableXY1 = obj.hasEndpoint(); 
    512513        enableXY2 = obj.hasEndpoint2(); 
     514        editXY1 = obj.areBoundsEditable(); 
     515        editXY2 = obj.areBoundsEditable(); 
    513516        if (enableXY1) xval1 = "" + obj.getX(); 
    514517        if (enableXY1) yval1 = "" + obj.getY(); 
     
    542545    x2.setEnabled(enableXY2); 
    543546    y2.setEnabled(enableXY2); 
     547    x1.setEditable(editXY1); 
     548    y1.setEditable(editXY1); 
     549    x2.setEditable(editXY2); 
     550    y2.setEditable(editXY2); 
    544551    x1.setText(xval1); 
    545552    y1.setText(yval1); 
Note: See TracChangeset for help on using the changeset viewer.