Java 使用SWT围绕圆弧绘制边

Java 使用SWT围绕圆弧绘制边,java,graphics,swt,Java,Graphics,Swt,我试图在使用SWT图形绘制的圆弧周围绘制一条边,曲线边本身效果很好,因为它也使用SWT绘制圆弧,但在绘制直边时,我使用一些三角来计算线条的连接位置,不幸的是,由于我猜我无法发现一个舍入错误,或者绘制弧函数的一些神秘之处,当形状的宽度(以度为单位)是奇数时,我无法让它工作。你可以看到边缘没有对齐,我已经尝试过了,并在这里包含了我的代码的可复制版本: import org.eclipse.jface.dialogs.Dialog; import org.eclipse.swt.SWT; import

我试图在使用SWT图形绘制的圆弧周围绘制一条边,曲线边本身效果很好,因为它也使用SWT绘制圆弧,但在绘制直边时,我使用一些三角来计算线条的连接位置,不幸的是,由于我猜我无法发现一个舍入错误,或者绘制弧函数的一些神秘之处,当形状的宽度(以度为单位)是奇数时,我无法让它工作。你可以看到边缘没有对齐,我已经尝试过了,并在这里包含了我的代码的可复制版本:

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

似乎是一个舍入错误

调用
getFinalLocation
时,只需将
Math.rounds
替换为
Math.floor

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

对齐看起来好多了。

您可以用它来正确绘制圆弧轮廓,而不用自己做数学运算

绘制整个轮廓:

使用GEF,您可以创建一个
饼图
(弧的轮廓),并将其转换为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();
    }
}
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,您可以创建一个
,并检索其起点(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);

        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();
    }
}
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,您只需要包括以下JAR:

org.eclipse.gef.geometry.convert.swt.Geometry2SWT<version>.jar
org.eclipse.gef.geometry<version>.jar
org.eclipse.gef.geometry.convert.swt.Geometry2SWT.jar
org.eclipse.gef.geometry.jar
您可以从以下版本的“插件”文件夹中检索它们:


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

您能为不同的零件绘制不同的线条样式,并选择打开/关闭零件吗?@Link19不是直接的,我在答案中添加了另一种方法来单独绘制零件。这似乎已经解决了问题。