1

我正在用体素制作一个椭圆体,并且我有一个实现,但它不能正常工作,在过去的几个小时里,我一直在尝试没有成功的事情。

以下是它的工作原理:

  • 它使用 Bresenham 圆算法沿 Z 轴绘制 2D 椭圆
  • 它计算一个向前和一边到另一边的圆的坐标
  • 它使用这些坐标作为 X 和 Y 的半径

这是有效的:

  • 球体是完美的
  • 椭球体是完美的
    • z > x 和 z > y
    • x == y

这是没有的:

我猜是因为我每次都从中心到前面绘制切片,但我不知道。下面是我的实现,一团糟。我很快把它清理了一下,所以在某种程度上是可以理解的。另外我正在为以后保存优化,我只想让它现在工作。

我不会展示我对圆算法本身的实现,因为我知道它可以工作,而且只会让这个问题变得更长。所以我将解释它的两个功能。

private List<Integer> getSlice(int rx, int ry)从运行 Bresenham 圆算法获得原始结果,不需要对称性。它将结果作为 x、y 结果的列表返回。

public void generateEllipse(int z, int cx, int cy, int cz, int rx, int ry)使用给定信息生成一个椭圆并使用对称性绘制坐标,这些将呈现在屏幕上。

ArrayList<Integer> s = getSlice(rz, rx);
ArrayList<Integer> s2 = getSlice(rz, ry);

int cap = Math.max(s2.size(), s.size());

while (s.size() > 1)
{
    int x = 0;
    int z = 0;
    int z2 = 0;
    int y2 = 0;

    int i = cap - 2;

    if (s.size() > i)
    {
        z = s.get(i);
        x = s.get(i + 1);

        s.remove(i + 1);
        s.remove(i);
    }

    if (s2.size() > i)
    {
        z2 = s2.get(i);
        y2 = s2.get(i + 1);

        s2.remove(i + 1);
        s2.remove(i);
    }

    if (x != 0 && y2 != 0)
        generateEllipse(z, cx, cy, cz, x, y2);

    cap = Math.max(s2.size(), s.size());

一两周前我问了一个类似的问题(是的,我遇到问题很久了:()并得到了答案,我实现了它并且它有效,但我不满意,我想避免浮点数一起看3D Ellipsoid out of distinct units

有了这个,我在四舍五入和得到不均匀的切片时遇到了问题,所以球体是不可能的。具有讽刺意味的是,现在球体是唯一可能的东西(除了从前到后的椭圆)。

编辑:

我通过添加 x > y 工作

else if (y2 < x && ry - y2 != 0)
    generateEllipse(z, cx, cy, cz, x, ry - y2);

|| r - y2 == 0到底部的第一个测试。

我不太确定为什么会这样,我现在正在弄清楚。但我仍然遇到 y > x 的问题。任何人?

编辑2:

现在我看它,它与 y = x 椭球不同,回到绘图板上。

编辑3:

昨晚我在想这个,我想我已经想通了,这不是我自己问题的答案,但我想指出我所看到的错误。我正在测试第一个列表并从最大列表的大小递减地绘制坐标。

这很糟糕,因为不能保证两个列表的长度相等,这是我试图加速算法的失败。

在图片中,你看不到,但小椭圆实际上距离大椭圆有几个街区。这是由于未绘制椭圆而引起的,这是由于列表没有数据引起的。实际的小椭圆大椭圆是因为算法绘制了两个八分圆,这两个八分圆都存储在列表中getSlice(...)

那么我该如何解决这个问题呢?我还没有实现任何东西,可能暂时不会(现在还早),但这就是我的大脑所产生的结果。同样,这不是问题的答案,只是想法。

while(!s.isEmpty())在循环外迭代并定义了两个新值:incX = s.size然后incY = s1.size测试它们的 z 值是否匹配,如果不匹配,则进行更正。我想我会得到这些值,测试最大的列表,如果它们不匹配,那么将最小列表的 inc 值减 2 并获取旧值。

我测试是!s.isEmpty()因为这两个列表将同时为空。同样绘制椭圆,我将使用任何一个 z 值,因为同样,它们都应该相等。

如果那是错误的,那么我想我找到了这份文件:http ://www.cs.sunysb.edu/vislab/wordpress/pdf/398.pdf 。

4

1 回答 1

2

感谢任何查看此内容的人(即使我没有得到任何回复:(),我设置此答案是因为问题已解决,代码如下:

    ArrayList<Integer> s = getSlice(rz, rx);
    ArrayList<Integer> s2 = getSlice(rz, ry);

    boolean yMax = Math.max(s2.size(), s.size()) == s2.size();

    int decX = s.size() - 1;
    int decY = s2.size() - 1;

    boolean done = false;

    while (!done)
    {

        int x = 0;
        int z = 0;
        int z2 = 0;
        int y = 0;

        y = s2.get(decY--);
        z2 = s2.get(decY--);

        x = s.get(decX--);
        z = s.get(decX--);

        if (z != z2)
        {
            if (yMax)
            {
                decX += 2;
                x = s.get(decX);

                s2.remove(decY + 2);
                s2.remove(decY + 1);    
            }
            else
            {
                decY += 2;
                y = s2.get(decY);

                s.remove(decX + 2);
                s.remove(decX + 1); 
            }

            z = z < z2 ? z : z2;
        }
        else
        {
            s.remove(decX + 2);
            s.remove(decX + 1);             

            s2.remove(decY + 2);
            s2.remove(decY + 1);    
        }

        if (y != 0 && x != 0)
            generateEllipse(z, cx, cy, cz, x, y);

        done = yMax ? s2.isEmpty() : s.isEmpty();
    }

现在需要做的就是优化。我仍然会阅读那篇论文,它涵盖了其他对我的程序有趣且有用的主题:)。

问题是我没有考虑每个列表的不同大小,如果一条曲线比另一条曲线不那么陡峭,它将有更多的坐标。当 rx == ry 时,Z 总是相同的。这使我能够绘制球体和前后椭圆体。

当它们不相同时,z 会发生变化,因为曲线会更快/更慢。当我在测试第一个列表时发生这种情况时,它会忽略那些,因为迭代会在到达它们之前停止。

大椭圆,小椭圆是因为它们被向后绘制而引起的,因此首先绘制了外部八分圆,恰好具有较少的总值。

在不久的将来,我将提出更详细的答案和更优雅的实现。我只是提出这个答案,让任何路人知道问题已经解决。我不想让任何人经历我试图弄清楚这一切的挫败感!令人惊讶的是,最棘手的问题是如何由最愚蠢的事情引起的。

于 2012-04-05T14:26:46.527 回答