所以我被赋予了一个选择图片并使用java代码(主要是drawLine和drawArc方法)绘制它的任务,我决定在下面的截图链接中显示的flamel。
问题1:drawArc方法是否正确(x,y,x width,y height,startAngle,arcAngle)?我将图片放入油漆并打开网格,这样我就可以得到(x,y)坐标并计算高度和宽度。然而,当我运行程序时,弧永远不会从(x,y)坐标开始,我总是必须调整所有数字以将弧移动到它应该的位置。有没有什么办法解决这一问题?我做错了吗?
问题2:上面的截图是我到目前为止编码的结果。请注意,正如红色箭头所指出的那样,弧线的末端向内移动,而不是以倾斜结束。将该弧度与第一个屏幕截图(原始flamel)的相应区域进行比较,以更好地了解我的意思。基本上我想要一条流过的曲线。我四处寻找并发现了Cardinal Spline(Catmull-Rom),这正是我正在寻找的,但我没有找到 easy 解释它是如何工作的或者为它编写代码。代码越短越好(更容易理解)。我使用jGrasp进行编码,我发现的所有“演示”和“源代码”都有大量编译错误,我不理解,也不知道如何修复。我是一个Java新手,所以如果有人可以让我了解如何创建一个通过Java Applet中的多个点的曲线的基础知识,我将非常感激。
以下代码
import java.applet.*;
import java.awt.*;
public class Flamel extends Applet
{
public void paint (Graphics flamel)
{
//crown
flamel.drawLine(217,75,217,105);
flamel.drawLine(283,75,283,105);
flamel.drawLine(217,105,283,105);
flamel.drawArc(217,62,33,20,180,180);
flamel.drawArc(250,62,33,20,180,180);
//left wing
flamel.drawLine(203,98,147,98);
flamel.drawLine(233,133,216,133);
flamel.drawLine(204,127,181,127);
flamel.drawLine(181,127,172,118);
flamel.drawArc(204,113,22,20,199,67);
flamel.drawArc(158,93,25,25,190,90);
flamel.drawArc(145,95,20,14,154,140);
flamel.drawArc(203,65,60,67,180,90);
//right wing
flamel.drawLine(297,98,353,98);
flamel.drawLine(267,133,284,133);
flamel.drawLine(296,127,319,127);
flamel.drawLine(319,127,328,118);
flamel.drawArc(274,113,22,20,270,67);
flamel.drawArc(318,93,25,25,260,80);
flamel.drawArc(334,95,20,14,255,140);
flamel.drawArc(236,65,60,67,270,90);
//cross heads (top/bottom/left/right)
flamel.drawLine(250,128,237,151);
flamel.drawLine(250,128,263,151);
flamel.drawLine(237,151,244,159);
flamel.drawLine(263,151,257,159);
flamel.drawLine(250,421,238,398);
flamel.drawLine(250,421,263,398);
flamel.drawLine(238,398,244,393);
flamel.drawLine(263,398,257,393);
flamel.drawLine(170,220,146,233);
flamel.drawLine(170,246,146,233);
flamel.drawLine(170,220,177,227);
flamel.drawLine(170,246,177,240);
flamel.drawLine(330,220,354,233);
flamel.drawLine(330,246,354,233);
flamel.drawLine(330,220,323,227);
flamel.drawLine(330,246,323,240);
//cross body
flamel.drawLine(244,159,244,393);
flamel.drawLine(257,159,257,393);
flamel.drawLine(177,227,323,227);
flamel.drawLine(177,240,323,240);
//snake (starting upward from tail)
flamel.drawArc(252,342,10,45,270,180);
flamel.drawArc(240,296,6,33,90,180);
flamel.drawArc(225,270,35,85,90,180);
flamel.drawArc(235,218,45,45,270,90);
}
}
答案 0 :(得分:0)
不可否认,当目标是连接几十个或几百个drawLine
和drawArc
个电话时,我认为这不是一个编程练习。而且我不完全确定它是否适合作为一个问题。但我会尝试以更广泛的规范方式回答它,希望它仍然可以接受,即使我提出的解决方案不再包含对drawLine
或{的任何调用{1}} ... 子>
通常,您应该考虑绘制“复杂”几何对象的替代方法。 Graphics
类的drawArc
和drawLine
方法可能会被使用,并且可能会有应用案例,但我个人认为它们主要是作为遗留特征源于Java 1.0。
在Java中有更多现代的表示几何形状的方法。特别是,通过Shape
接口(因此名称......)。
drawArc
界面的优势在于其灵活性的提高。这个接口有很多实现。例如,Line2D
或Arc2D
,或者 - 最重要的是 - Path2D
。后者允许通过指定线端点的坐标来手动“构建”形状。它还支持三次曲线部分(样条曲线 - 不是Catmull-Rom,但是Bezier),使用Path2D#curveTo
方法(以及稍微简单的Shape
方法)。 quadTo
类还允许您使用Path2D#append
方法任意组合多个形状。
考虑到您的应用案例,还可以使用Stroke#createStrokedShape
方法创建描边形状。简单地说:如果你有Path2D
代表一条细线,那么你可以使用这种方法创建一个代表厚的Shape
。 (请注意,这与绘图具有粗笔划的细线不同!)。
这是一个绘制类似于原始绘画部分的内容的示例(红色和绿色部分仅用于指出实际绘制的内容......):
使用以下代码创建:
Shape
实际上,最难的部分是制作这些箭形末端。但是如果结果只是看起来像原始的,并且你不需要一个代表绘制元素的整个轮廓的实际形状,你可以简单地将这些头部涂在其余的部分上......
脚注:
手动摆弄坐标仍然不是我认为是一个很好的编程练习。但也许你(或正在阅读这个答案的其他人)有机会学习Java2D中的import java.applet.Applet;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.awt.geom.Path2D;
public class Flamel extends Applet
{
public void paint (Graphics gr)
{
Graphics2D g = (Graphics2D)gr;
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(Color.BLACK);
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Path2D path = new Path2D.Double();
// Create the lower, snail-like part
path.moveTo(100, 300);
path.quadTo(115, 275, 100, 260);
path.quadTo( 60, 225, 100, 200);
path.quadTo(150, 180, 150, 150);
// Append the upper part, which is a "perfect arc"
Arc2D a = new Arc2D.Double(50, 100, 100, 100, 0, 180, Arc2D.OPEN);
path.append(a, true);
BasicStroke s = new BasicStroke(14);
// Fill a stroked version of the path
g.setColor(Color.BLACK);
g.fill(s.createStrokedShape(path));
// Draw the path
g.setColor(Color.GREEN);
g.draw(path);
// Draw a stroked version of the path:
g.setColor(Color.RED);
g.draw(s.createStrokedShape(path));
}
}
类......
对于某些应用案例,通过Shape
对象表示“所有内容”可能有缺点 - 例如,盲目创建许多 Line2D
对象作为插入替换Shape
调用,这可能会产生一些开销,影响性能和内存(导致GC)。但这肯定不适用于此。