Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

247
LINES

< > TinyBrain | #1007303 - CirclesAndLines [include]

JavaX fragment (include)

sclass BaseBase {
  S text;
  S textForRender() { ret text; }
}

sclass Base extends BaseBase {
}

sclass CirclesAndLines {
  new L<Circle> circles;
  new L<Line> lines;
  Class<? extends Arrow> arrowClass = Arrow;
  Class<? extends Circle> circleClass = Circle;
  transient Lock lock = fairLock();
  transient S defaultImageID = #1007372;
  double imgZoom = 1;
  
  // auto-visualize
  Circle circle_autoVis(S text, S visualizationText, double x, double y) {
    ret addAndReturn(circles, nu(circleClass, +x, +y, +text, img := processImage(quickVisualizeOr(visualizationText, defaultImageID))));
  }
  
  S makeVisualizationText(S text) {
    ret possibleGlobalID(text) ? "" : text;
  }

  Circle circle_autoVis(S text, double x, double y) {
    ret circle_autoVis(text, makeVisualizationText(text), x, y);
  }
  
  Circle circle(BufferedImage img, double x, double y, S text) {
    ret addAndReturn(circles, nu(circleClass, +x, +y, +text, img := processImage(img));
  }
  
  Circle circle(S text, double x, double y) {
    ret addAndReturn(circles, nu(circleClass, +x, +y, +text, img := processImage(loadImage2(#1007452))); // white
  }
  
  Circle addCircle(S imageID, double x, double y) {
    ret addCircle(imageID, x, y, "");
  }
  
  Circle addCircle(S imageID, double x, double y, S text) {
    ret addAndReturn(circles, nu(circleClass, +x, +y, +text, img := processImage(loadImage2(imageID))));
  }
  
  Arrow findArrow(Circle a, Circle b) {
    for (Line l : getWhere(lines, +a, +b))
      if (l instanceof Arrow)
        ret (Arrow) l;
    null;
  }
  
  Line addLine(Circle a, Circle b) {
    Line line = findWhere(lines, +a, +b);
    if (line == null)
      lines.add(line = nu(Line, +a, +b));
    ret line;
  }
  
  Arrow arrow(Circle a, S text, Circle b) {
    ret addArrow(a, b, text);
  }
  
  Arrow addArrow(Circle a, Circle b) {
    ret addArrow(a, b, "");
  }
  
  Arrow addArrow(Circle a, Circle b, S text) {
    ret addAndReturn(lines, nu(arrowClass, +a, +b, +text));
  }
  
  BufferedImage makeImage(int w, int h) {
    BufferedImage bg = renderTiledBackground(#1007195, w, h);
    if (!lock.tryLock()) null;
    try {
      for (Line l : lines) {
        Pt a = l.a.pt(w, h), b = l.b.pt(w, h);
        if (l << Arrow)
          drawThoughtArrow(bg, l.a.img(), a.x, a.y, l.b.img(), b.x, b.y, l.color);
        else
          drawThoughtLine(bg, l.a.img(), a.x, a.y, l.b.img(), b.x, b.y, l.color);
        S text = l.textForRender();
        if (nempty(text))
          drawThoughtLineText(bg, l.a.img(), a.x, a.y, l.b.img(), b.x, b.y, text, l.color);
      }
      for (Circle c : circles) {
        Pt p = c.pt(w, h);
        drawThoughtCircle(bg, c.img(), p.x, p.y);
        S text = c.textForRender();
        if (nempty(text))
          drawThoughtCircleText(bg, c.img(), p, text);
      }
    } finally {
      lock.unlock();
    }
    ret bg;
  }
  
  Canvas showAsFrame(int w, int h) {
    Canvas canvas = showAsFrame();
    frameInnerSize(canvas, w, h);
    centerFrame(getFrame(canvas));
    ret canvas;
  }
  
  Canvas showAsFrame() {
    ret (Canvas) swing(func {
      Canvas canvas = makeCanvas();
      showCenterFrame(canvas);
      ret canvas;
    });
  }
  
  Canvas makeCanvas() {
    fO makeImg = func(int w, int h) { makeImage(w, h) };
    final Canvas canvas = jcanvas(makeImg);
    disableImageSurfaceSelector(canvas);
    new CircleDragger(canvas, r { updateCanvas(canvas, makeImg) }, circles);
    
    componentPopupMenu(canvas, voidfunc(JPopupMenu menu) {
      Pt p = canvas.pointFromEvent(componentPopupMenu_mouseEvent.get());
      final Circle c = findCircle(canvas, p);
      if (c != null)
        addMenuItem(menu, "Delete Circle", r { deleteCircle(c); canvas.update() });
    });
    
    ret canvas;
  }
  
  Canvas show() { ret showAsFrame(); }
  Canvas show(int w, int h) { ret showAsFrame(w, h); }
  
  Circle findCircle(S text) {
    for (Circle c : circles)
      if (eqic(c.text, text))
        ret c;
    null;
  }
  
  void clear {
    lines.clear();
    circles.clear();
  }
  
  Circle findCircle(Canvas canvas, Pt p) {
    new Lowest<Circle> best;
    for (Circle c : circles)
      if (c.contains(canvas, p))
        best.put(c, pointDistance(p, c.pt(canvas)));
    ret best.get();
  }
  
  BufferedImage processImage(BufferedImage img) {
    ret scaleImage(img, imgZoom);
  }
  
  void deleteCircle(Circle c) {
    for (Line l : cloneList(lines))
      if (l.a == c || l.b == c) lines.remove(l);
    circles.remove(c);
  }
} // end class CirclesAndLines

sclass Circle extends Base {
  transient BufferedImage img;
  double x, y;
  static BufferedImage defaultImage;
  
  BufferedImage img() {
    if (img != null) ret img;
    if (defaultImage == null) defaultImage = loadImage2(#1007372);
    ret defaultImage;
  }
  
  Pt pt(ImageSurface is) {
    ret pt(is.getWidth(), is.getHeight());
  }
  
  Pt pt(int w, int h) {
    ret new Pt(iround(x*w), iround(y*h));
  }
  
  bool contains(ImageSurface is, Pt p) {
    ret pointDistance(p, pt(is)) <= thoughtCircleSize(img())/2+1;
  }
}

sclass Line extends Base {
  Circle a, b;
  Color color = Color.white;
  
  Line setColor(Color color) {
    this.color = color;
    this;
  }
}

Line > Arrow {}

sclass CircleDragger extends MouseAdapter {
  ImageSurface is;
  L<Circle> circles;
  O update;
  int dx, dy;
  Circle circle;

  *(ImageSurface *is, O *update, L<Circle> *circles) {
    if (containsInstance(is.tools, CircleDragger)) ret;
    is.tools.add(this);
    is.addMouseListener(this);
    is.addMouseMotionListener(this);
  }

  public void mousePressed(MouseEvent e) {
    if (e.getButton() == MouseEvent.BUTTON1) {
      Pt p = is.pointFromEvent(e);
      circle = findCircle(p);
      if (circle != null) {
        dx = p.x-iround(circle.x*is.getWidth());
        dy = p.y-iround(circle.y*is.getHeight());
      }
    }
  }

  public void mouseDragged(MouseEvent e) {
    if (circle != null) {
      Pt p = is.pointFromEvent(e);
      circle.x = (p.x-dx)/(double) is.getWidth();
      circle.y = (p.y-dy)/(double) is.getHeight();
      callF(update);
    }
  }

  public void mouseReleased(MouseEvent e) {
    mouseDragged(e);
    circle = null;
  }
  
  Circle findCircle(Pt p) {
    new Lowest<Circle> best;
    for (Circle c : circles)
      if (c.contains(is, p))
        best.put(c, pointDistance(p, c.pt(is)));
    ret best.get();
  }
}

Author comment

Began life as a copy of #1007298

download  show line numbers  debug dex   

Travelled to 3 computer(s): cfunsshuasjs, onxytkatvevr, tvejysmllsmz

No comments. add comment

Snippet ID: #1007303
Snippet name: CirclesAndLines [include]
Eternal ID of this version: #1007303/66
Text MD5: bd241f2e3b7d29a466161ece807b9a3c
Author: stefan
Category: javax / gui
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2017-04-06 19:18:20
Source code size: 6618 bytes / 247 lines
Pitched / IR pitched: No / No
Views / Downloads: 109 / 337
Version history: 65 change(s)
Referenced in: [show]