【问题标题】:Arcs and Curves in Java AppletJava Applet 中的弧线和曲线
【发布时间】:2015-05-25 17:57:41
【问题描述】:

所以我被分配了选择一张图片并使用java代码(主要是drawLine和drawArc方法)绘制它的任务,我决定使用下面屏幕截图链接中显示的flamel。

问题 1:drawArc 方法的 (x, y, x width, y height, startAngle, arcAngle) 正确吗?我将图片放入绘画并打开网格,这样我可以获得(x,y)坐标并计算高度和宽度。但是,当我运行程序时,圆弧永远不会从 (x,y) 坐标开始,我总是必须调整所有数字才能将圆弧移动到应有的位置。有没有什么办法解决这一问题?我是不是做错了什么?

问题 2:上面的屏幕截图是我迄今为止编码的结果。请注意,如红色箭头所示,该弧的末端向内移动,而不是倾斜结束。将该弧与第一个屏幕截图(原始火焰)的相应区域进行比较,以更好地了解我的意思。基本上我想要一条流过的曲线。我四处搜索并找到了 Cardinal Spline (Catmull-Rom),这正是我正在寻找的,但我没有找到关于它如何工作的简单解释或示例代码.代码越短越好(更容易理解)。我使用 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);

  }
  }

【问题讨论】:

    标签: java applet curve


    【解决方案1】:

    诚然,当目标是连接数十个或数百个 drawLinedrawArc 调用时,我不认为这是一个编程练习的意义。而且我不完全确定它是否适合在这里作为一个问题。但我会尝试以更广泛、更规范的方式回答它,希望它仍然可以接受,即使我提出的解决方案将不再包含对drawLinedrawArc任何 调用...


    一般来说,您应该考虑绘制“复杂”几何对象的替代方法。 Graphics类的drawLinedrawArc方法可能会用到,也可能有应用案例,但我个人认为主要是Java 1.0时代的遗留特性。

    在 Java 中有更现代的方式来表示几何形状。特别是通过Shape 接口(因此得名...)。

    Shape 接口的优势在于它增加了灵活性。这个接口有很多实现。例如,Line2D,或Arc2D,或者——最重要的是——Path2D。后者允许通过指定线端点的坐标来手动“构建”形状。它还使用Path2D#curveTo 方法(以及更简单的quadTo 方法)支持三次曲线部分(样条-不是Catmull-Rom,而是Bezier)。 Path2D 类还允许您使用Path2D#append 方法任意组合多个形状。

    考虑到您的应用案例,还可以使用Stroke#createStrokedShape 方法创建stroked 形状。简单地说:当你有一个代表单个细线的Shape,那么你可以使用这个方法来创建一个代表Shape。 (请注意,这与仅用粗笔画细线不同!)。

    这是一个示例,它绘制了类似于您原画部分的东西(红色和绿色部分只是为了指出那里实际绘制的内容......):

    使用此代码创建:

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

    实际上,最难的部分是创建这些箭头形末端。但是,如果结果只是为了看起来像原来的样子,并且您不需要代表绘制元素的整个轮廓的实际形状,您可以简单地将这些头部绘制在其余部分上......


    脚注:

    • 手动调整坐标仍然不是我认为的良好编程练习。但也许您(或正在阅读此答案的其他人)有机会了解 Java2D 中的 Shape 类...

    • 对于某些应用案例,通过 Shape 对象表示“一切”可能有缺点 - 例如,当盲目地创建 许多 Line2D 对象作为 @987654354 的替代品时@ 调用,这可能会带来一些开销,影响性能和内存(导致 GC)。但这肯定不适用于这里。

    【讨论】:

    • 是的,你是对的,drawArc/drawLine 命令已经过时了,但我们主要使用它们是因为我们从一开始就学习 Java(我不确定这是否是一个好的教学方法,但它就是这样)。你提到的 Line2D/Arc2D/Path2D 对我来说都是全新的,但我想我可以设法学习它。至于摆弄坐标 - 你是对的,这不是一个好的编程练习,我们没有被教导这样做,但我似乎无法弄清楚如何让它工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多