使用SWT在圆弧上绘制边缘

时间:2019-09-09 12:08:34

标签: java graphics swt

我试图在使用SWT图形绘制的圆弧上绘制一条边,弯曲的边缘本身也非常好,因为它也使用了SWT绘制圆弧,但是在绘制直线边缘时,我会使用一些Trig来工作不幸的是,由于我猜测无法发现的舍入误差,或者绘制弧函数有些神秘,当形状的宽度(以度为单位)时,我无法使它起作用)是一个奇数。您可以看到边缘没有对齐,我已经尝试过,并在此处包含了可复制的代码版本:

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;

public class ArcDialog extends Dialog {

    private Color blue;

    public ArcDialog(final Shell parentShell) {
    super(parentShell);
    }

    @Override
    protected void configureShell(final Shell shell) {

    blue = new Color(shell.getDisplay(), new RGB(0, 100, 255));
    super.configureShell(shell);
    shell.setSize(new Point(450, 550));
    shell.setText("Arc Edges"); //$NON-NLS-1$
    }

    @Override
    public Control createDialogArea(final Composite comp) {

    final Composite content = (Composite) super.createDialogArea(comp);
    final Composite parent = new Composite(content, SWT.NONE);

    final GridLayout gridLayout2 = new GridLayout(6, false);
    parent.setLayout(gridLayout2);
    parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    new Label(parent, SWT.NONE).setText("Direction");

    Spinner direction = new Spinner(parent, SWT.NONE);

    direction.setMaximum(360);
    direction.setMinimum(0);
    direction.setIncrement(1);
    direction.setSelection(0);

    new Label(parent, SWT.NONE).setText("Width");

    Spinner width = new Spinner(parent, SWT.NONE);
    width.setMaximum(270);
    width.setMinimum(5);
    width.setSelection(65);
    width.setIncrement(1);

    new Label(parent, SWT.NONE).setText("Length");

    Spinner length = new Spinner(parent, SWT.NONE);
    length.setMaximum(200);
    length.setMinimum(10);
    length.setIncrement(1);
    length.setSelection(150);

    final Canvas c = new Canvas(parent, SWT.BORDER);
    c.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 6, 0));
    c.addPaintListener(e -> {
        e.gc.setAntialias(SWT.ON);
        drawArc(e.gc, (double) direction.getSelection(), new Point(c.getSize().x / 2, c.getSize().y / 2),
            length.getSelection(), width.getSelection());
        drawArcEdges(e.gc, (double) direction.getSelection(), new Point(c.getSize().x / 2, c.getSize().y / 2),
            length.getSelection(), width.getSelection());
    });

    length.addListener(SWT.Selection, event -> c.redraw());
    width.addListener(SWT.Selection, event -> c.redraw());
    direction.addListener(SWT.Selection, event -> c.redraw());

    return content;
    }

    protected void drawArc(final GC gc, final Double b, final Point screenLocation, final int length,
        final double arcWidth) {

    if (length > 0) {

        gc.setBackground(blue);
        gc.fillArc(screenLocation.x - length, screenLocation.y - length, length * 2, length * 2,
            (int) Math.round(90 - (b - (arcWidth / 2))), (int) Math.round(-arcWidth));

    }
    }

    protected void drawArcEdges(final GC gc, final Double b, final Point screenLocation, final int length,
        final double arcWidth) {

    if (length > 0) {
        Point edge = getFinalLocation(screenLocation, (double) Math.round((b - (arcWidth / 2))), length);
        gc.setLineStyle(SWT.LINE_DASH);

        gc.drawLine(screenLocation.x, screenLocation.y, edge.x, edge.y);
        edge = getFinalLocation(screenLocation, (double) Math.round(b + (arcWidth / 2)), length);

        gc.drawLine(screenLocation.x, screenLocation.y, edge.x, edge.y);

        gc.drawArc(screenLocation.x - length, screenLocation.y - length, length * 2, length * 2,
            (int) Math.round(90 - (b - (arcWidth / 2))), (int) Math.round(-arcWidth));

    }
    }

    protected Point getFinalLocation(final Point start, final Double angle, final int length) {

    final int newX = (int) Math.floor((start.x + (length * Math.sin(Math.toRadians(angle))) + 0.5));
    final int newY = (int) Math.floor(((start.y - (length * Math.cos(Math.toRadians(angle)))) + 0.5));
    return new Point(newX, newY);
    }

    public static void main(final String[] args) {
    new Display();

    final ArcDialog fml = new ArcDialog(new Shell());
    fml.open();
    }
}

enter image description here

2 个答案:

答案 0 :(得分:3)

似乎是舍入错误。

致电getFinalLocation时,只需将Math.rounds替换为Math.floor

Point edge = getFinalLocation(screenLocation, Math.floor(b - (arcWidth / 2)), length);
...
edge = getFinalLocation(screenLocation, Math.floor(b + (arcWidth / 2)), length);

对齐看起来好很多。

答案 1 :(得分:3)

您可以使用Eclipse GEF来正确绘制圆弧轮廓,而不必自己做数学运算。

绘制整个轮廓:

使用GEF,您可以创建Pie(这是圆弧的轮廓)并将其转换为可以完全用PathData绘制的SWT gc.drawPath

drawArcEdges然后变为:

protected void drawArcEdges(final GC gc, final Double b, final Point screenLocation, final int length,
                            final double arcWidth) {

    if (length > 0) {
        gc.setLineStyle(SWT.LINE_DASH);

        Pie pie = new Pie(screenLocation.x - length, screenLocation.y - length, length * 2, length * 2,
                Angle.fromDeg((int) Math.round(90 - (b - (-arcWidth / 2)))), Angle.fromDeg((int) Math.round(arcWidth)));

        PathData arcSwtPathData = Geometry2SWT.toSWTPathData(pie.toPath());
        Path arcSwtPath = new Path(gc.getDevice(), arcSwtPathData);

        gc.drawPath(arcSwtPath);

        arcSwtPath.dispose();
    }
}

要在不同部分绘制轮廓:

使用GEF,您可以创建Arc并检索其起点(X1,Y1)和终点(X2,Y2)。

使用这些点,然后可以用gc分别绘制直线和圆弧。

drawArcEdges然后变为:

protected void drawArcEdges(final GC gc, final Double b, final Point screenLocation, final int length,
                            final double arcWidth) {

    if (length > 0) {
        gc.setLineStyle(SWT.LINE_DASH);

        Arc arc = new Arc(screenLocation.x - length, screenLocation.y - length, length * 2, length * 2,
                Angle.fromDeg((int) Math.round(90 - (b - (-arcWidth / 2)))), Angle.fromDeg((int) Math.round(arcWidth)));

        gc.drawLine(screenLocation.x, screenLocation.y, (int)arc.getX1(), (int)arc.getY1());
        gc.drawLine(screenLocation.x, screenLocation.y, (int)arc.getX2(), (int)arc.getY2());

        gc.drawArc(screenLocation.x - length, screenLocation.y - length, length * 2, length * 2,
                (int) Math.round(90 - (b - (arcWidth / 2))), (int) Math.round(-arcWidth));
    }
}

要使用GEF:

要使用GEF,您只需要包括以下jar:

org.eclipse.gef.geometry.convert.swt.Geometry2SWT<version>.jar
org.eclipse.gef.geometry<version>.jar

您可以从https://www.eclipse.org/gef/downloads/index.php此处的版本中的“插件”文件夹中检索它们。

选择最新版本,然后单击更新站点链接以下载完整的zip。