我试图在使用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();
}
}
答案 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。