0

I want to draw a line with an arrow. The line can have any angle. How to achieve it in SWT?

I found similar post but its in AWT. I want to convert it into SWT. But facing problem to convert the following method in to SWT. Especially in the following line:

at.concatenate(AffineTransform.getRotateInstance(angle));

Here is the method from this post

void drawArrow(Graphics g1, int x1, int y1, int x2, int y2) {
  Graphics2D g = (Graphics2D) g1.create();
  double dx = x2 - x1, dy = y2 - y1;
  double angle = Math.atan2(dy, dx);
  int len = (int) Math.sqrt(dx*dx + dy*dy);
  AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
  at.concatenate(AffineTransform.getRotateInstance(angle));
  g.transform(at);

  // Draw horizontal arrow starting in (0, 0)
  g.drawLine(0, 0, len, 0);
  g.fillPolygon(new int[] {len, len-ARR_SIZE, len-ARR_SIZE, len}, new int[] {0, -ARR_SIZE, ARR_SIZE, 0}, 4);
}
Community
  • 1
  • 1
mantiq
  • 129
  • 7

2 Answers2

1

Here, the arrow direction is calculated from the direction of the line. I've also added an offset for the line so that it doesn't go through the arrow. This is more visible with higher stroke widths.

public static void drawArrow(GC gc, int x1, int y1, int x2, int y2, double arrowLength, double arrowAngle) {
    double theta = Math.atan2(y2 - y1, x2 - x1);
    double offset = (arrowLength - 2) * Math.cos(arrowAngle);

    gc.drawLine(x1, y1, (int)(x2 - offset * Math.cos(theta)), (int)(y2 - offset * Math.sin(theta)));

    Path path = new Path(gc.getDevice());
    path.moveTo((float)(x2 - arrowLength * Math.cos(theta - arrowAngle)), (float)(y2 - arrowLength * Math.sin(theta - arrowAngle)));
    path.lineTo((float)x2, (float)y2);
    path.lineTo((float)(x2 - arrowLength * Math.cos(theta + arrowAngle)), (float)(y2 - arrowLength * Math.sin(theta + arrowAngle)));
    path.close();

    gc.fillPath(path);

    path.dispose();
}

...

gc.setLineWidth(1);
gc.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
drawArrow(gc, x1, y1, x2, y2, 8, Math.toRadians(40));
fgb
  • 18,439
  • 2
  • 38
  • 52
0

The answer given here translated to SWT looks like this:

static Path createArrowForLine( Device device, Point fromPoint, double rotationDeg, double length, double wingsAngleDeg ) {
  double ax = fromPoint.x;
  double ay = fromPoint.y;
  double radB = Math.toRadians( -rotationDeg + wingsAngleDeg );
  double radC = Math.toRadians( -rotationDeg - wingsAngleDeg );
  Path resultPath = new Path( device );
  resultPath.moveTo( ( float )( length * Math.cos( radB ) + ax ), ( float )( length * Math.sin( radB ) + ay ) );
  resultPath.lineTo( ( float )ax, ( float )ay );
  resultPath.lineTo( ( float )( length * Math.cos( radC ) + ax ), ( float )( length * Math.sin( radC ) + ay ) );
  return resultPath;
}

The SWT Path API uses floats rather than doubles, hence the casts.

To draw an arrow on a canvas using the above method, you would use this code:

Canvas canvas = new Canvas( parent, SWT.NONE );
shell.addPaintListener( new PaintListener() {
  @Override
  public void paintControl( PaintEvent event ) {
    event.gc.setBackground( event.display.getSystemColor( SWT.COLOR_RED ) );
    Path path = createArrowForLine( event.display, new Point( 100, 100 ), 180, 100, 45 );
    event.gc.fillPath( path );
    path.dispose();
  }
} );
Community
  • 1
  • 1
Rüdiger Herrmann
  • 20,512
  • 11
  • 62
  • 79
  • I need to rotate the transform dynamically so that the arrow triangle is correctly drawn on the line . I need to convert the accepted answer from the link in my question into SWT. – mantiq Dec 08 '15 at 18:31
  • With the `rotationDeg` argument, the arrow can be rotated. Isn't that what you are looking for? – Rüdiger Herrmann Dec 09 '15 at 14:12
  • No, the method should take coordinates of 2 points fromPoint and toPoint . the out put is a directed line with arrow. The accepted answer of the link as described in my question does that . – mantiq Dec 10 '15 at 12:31
  • 1
    please note that the `Path` class **extends** `Resource` and must therefore be disposed. using this method inside a `PaintListener`will quickly allocate a lot of handles. – benez Apr 09 '16 at 20:32