mantiq
mantiq

Reputation: 129

How to draw a line with arrow in SWT on Canvas

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);
}

Upvotes: 0

Views: 1336

Answers (2)

Rüdiger Herrmann
Rüdiger Herrmann

Reputation: 20985

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();
  }
} );

Upvotes: 0

fgb
fgb

Reputation: 18559

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));

Upvotes: 1

Related Questions