使用 SWT 围绕圆弧绘制边
Drawing an edge around an arc using SWT
我正在尝试围绕使用 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);
对齐看起来好多了。
您可以使用 Eclipse GEF 来正确绘制圆弧轮廓,而不是自己计算。
绘制整体轮廓:
使用 GEF,您可以创建 Pie
(这是弧形的轮廓)并将其转换为 SWT PathData
,您可以完全使用 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,您只需要包含以下 jars:
org.eclipse.gef.geometry.convert.swt.Geometry2SWT<version>.jar
org.eclipse.gef.geometry<version>.jar
您可以从此处的构建中的 "plugin" 文件夹中检索它们:https://www.eclipse.org/gef/downloads/index.php。
选择最新版本并单击更新站点link下载完整的 zip。
我正在尝试围绕使用 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);
对齐看起来好多了。
您可以使用 Eclipse GEF 来正确绘制圆弧轮廓,而不是自己计算。
绘制整体轮廓:
使用 GEF,您可以创建 Pie
(这是弧形的轮廓)并将其转换为 SWT PathData
,您可以完全使用 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,您只需要包含以下 jars:
org.eclipse.gef.geometry.convert.swt.Geometry2SWT<version>.jar
org.eclipse.gef.geometry<version>.jar
您可以从此处的构建中的 "plugin" 文件夹中检索它们:https://www.eclipse.org/gef/downloads/index.php。
选择最新版本并单击更新站点link下载完整的 zip。