Точка в трехмерном пространстве приближается к плоскостям в трехмерном пространстве без причины

Java, программа, у меня есть класс Point3d с координатами x, y, z и следующая средняя функция:

public static Point3d average(Point3d a, Point3d b){
    a.add(b);
    a.x/=2;
    a.y/=2;
    a.z/=2;
    return a;
}

У меня также есть этот класс для 2dPlane в трехмерном пространстве, образованном треугольником между тремя трехмерными точками:

package com.funguscow.model;

import com.funguscow.obj.Point3d;
import com.funguscow.obj.Vector3d;

public class TriPlane {

    public Point3d a, b, c;
    private Vector3d normal;
    private float d;

    public TriPlane(Point3d x, Point3d y, Point3d z){
        a = x;
        b = y;
        c = z;
        Vector3d ab = Vector3d.Vector3dPMinus(a, b);
        //System.out.println(ab.x + ", " + ab.y + ", " + ab.z);
        normal = Vector3d.crossProduct(
                Vector3d.Vector3dPMinus(a, b),
                Vector3d.Vector3dPMinus(a, c));
        d = Vector3d.dotProduct(normal, Vector3d.VectorFromPoint3d(a));
    }

    public Vector3d getNormal(){
        return normal;
    }

    public float getRelativeOnPlane(Point3d test){
        //System.out.println(normal.x + ", " + normal.y + ", " + normal.z);
        return Vector3d.dotProduct(normal, Vector3d.VectorFromPoint3d(test)) - d;
    }

}

getRelativeOnPlane должен найти, на какой стороне плоскости находится конкретная точка. Вам кажется, что это должно сработать? Какие-нибудь проблемы с этим вы видите?

В любом случае, вот большая проблема: у меня есть следующий класс для CubeCollider, расширяющий абстрактный класс Collider, который устанавливает шесть TriPlanes для проверки того, находится ли точка внутри куба или нет:

package com.funguscow.model;

import com.funguscow.obj.Point3d;
import com.funguscow.obj.Vector3d;

public class CubeCollider extends Collider{
    public Point3d a, b, c, d, e, f, g, h;

    public CubeCollider(){
        a = new Point3d(0, 0, 0);
        b = new Point3d(0, 0, 0);
        c = new Point3d(0, 0, 0);
        d = new Point3d(0, 0, 0);
        e = new Point3d(0, 0, 0);
        f = new Point3d(0, 0, 0);
        g = new Point3d(0, 0, 0);
        h = new Point3d(0, 0, 0);
    }

    public CubeCollider setCube(Cube cube){
        return setCube((float)cube.lines.get(0).start.x,
                (float)cube.lines.get(0).start.y, (float)cube.lines.get(0).start.z,
                (float)cube.lines.get(11).end.x, (float)cube.lines.get(11).end.y, (float)cube.lines.get(11).end.z);
    }

    public CubeCollider setCube(float x, float y, float z, float m, float n, float o){
        //System.out.println(x + ", " + y + ", " + z + ", " + m + ", " + n + ", " + o);
        a.x = b.x = c.x = d.x = x;
        e.x = f.x = g.x = h.x = m;
        a.y = c.y = e.y = g.y = y;
        b.y = d.y = f.y = h.y = n;
        a.z = b.z = e.z = f.z = z;
        c.z = d.z = g.z = h.z = o;
        return this;
    }

    public boolean shouldBother(Point3d p){
        Point3d center = Point3d.average(a, h);
        float dist = Vector3d.Vector3dPMinus(p, center).getMagnitude();
        if(dist > Vector3d.Vector3dPMinus(center, a).getMagnitude())return false;
        if(dist > Vector3d.Vector3dPMinus(center, d).getMagnitude())return false;
        if(dist > Vector3d.Vector3dPMinus(center, g).getMagnitude())return false;
        return true;
    }

    public boolean isInBounds(Point3d p){
        //System.out.println((a.x - b.x) + ", " + (a.y - b.y) + ", " + (a.z - b.z));
        TriPlane[] collider = new TriPlane[]{new TriPlane(a, b, c),
                new TriPlane(a, b, e),
                new TriPlane(e, f, g),
                new TriPlane(c, d, g),
                new TriPlane(a, c, e),
                new TriPlane(b, d, f)};
        Point3d center = Point3d.average(a, h);

        for(TriPlane plane : collider){
            float should = plane.getRelativeOnPlane(center);
            int sign = (should < 0) ? -1 : (should == 0) ? 0 : 1;
            float real = plane.getRelativeOnPlane(p);
            int rSign = (real < 0) ? -1 : (real == 0) ? 0 : 1;
            System.out.println("Center: " + center.x + ", " + center.y + ", " + center.z);
            System.out.println("Bound check: " + should + ", " + real);
            if(sign != rSign && real != 0 && should != 0)return false;
        }
        return true;
    }
}

Точка «центр» в функции isInBounds использует среднее значение точек a и h, но есть некоторая проблема. Отладка, такая как «Проверка границ:» из функции isInBounds, сообщает «следует» (точечный продукт вектора нормали плоскости и центра точки), приближается к нулю, пока после нескольких (дюжины) итераций проверки не становится точно 0.0. Может кто-нибудь, пожалуйста, скажите мне, почему это происходит? Если я не ошибаюсь, возврат нуля для функции getRelativePointOnPlane должен означать, что точка находится на плоскости, но точка, которую она тестирует (в центре), если я не ошибаюсь, должна быть между всеми плоскостями, а не на какой-либо из них. Моя логика относительно того, как использовать эти функции, неверна, или я ошибаюсь в кодировании, которое использовал для написания функций?

Вот что прочитала консоль:

Center: 100.0, 100.0, 40.0
Bound check: -4000000.0, -1.2E7
Center: 100.0, 100.0, 40.0
Bound check: 4000000.0, 4800000.0
Center: 100.0, 100.0, 40.0
Bound check: 4000000.0, -4000000.0
Center: 50.0, 50.0, -10.0
Bound check: -2000000.0, -1000000.0
Center: 50.0, 50.0, -10.0
Bound check: 2000000.0, 5000000.0
Center: 50.0, 50.0, -10.0
Bound check: 2000000.0, -4000000.0
Center: 25.0, 25.0, -35.0
Bound check: -1000000.0, 5100000.0
Center: 12.5, 12.5, -47.5
Bound check: -500000.0, 8650000.0
Center: 6.25, 6.25, -53.75
Bound check: -250000.0, 1.0875E7
Center: 3.125, 3.125, -56.875
Bound check: -125000.0, 1.24125E7
Center: 1.5625, 1.5625, -58.4375
Bound check: -62500.0, 1.359375E7
Center: 0.78125, 0.78125, -59.21875
Bound check: -31250.0, 1.4590625E7
Center: 0.390625, 0.390625, -59.609375
Bound check: -15625.0, 1.5492187E7
Center: 0.1953125, 0.1953125, -59.8046875
Bound check: -7812.5, 1.6344532E7
Center: 0.09765625, 0.09765625, -59.90234375
Bound check: -3906.25, 1.7171484E7
Center: 0.048828125, 0.048828125, -59.951171875
Bound check: -1953.0, 1.7985352E7
Center: 0.0244140625, 0.0244140625, -59.9755859375
Bound check: -976.5, 1.879248E7
Center: 0.01220703125, 0.01220703125, -59.98779296875
Bound check: -488.25, 1.9596142E7
Center: 0.006103515625, 0.006103515625, -59.993896484375
Bound check: -244.25, 2.0398024E7
Center: 0.0030517578125, 0.0030517578125, -59.9969482421875
Bound check: -122.25, 2.1198986E7
Center: 0.00152587890625, 0.00152587890625, -59.99847412109375
Bound check: -61.0, 2.1999482E7
Center: 7.62939453125E-4, 7.62939453125E-4, -59.999237060546875
Bound check: -30.5, 2.2799734E7
Center: 3.814697265625E-4, 3.814697265625E-4, -59.99961853027344
Bound check: -15.25, 2.3599864E7
Center: 1.9073486328125E-4, 1.9073486328125E-4, -59.99980926513672
Bound check: -7.5, 2.439993E7
Center: 9.5367431640625E-5, 9.5367431640625E-5, -59.99990463256836
Bound check: -4.0, 2.5199964E7
Center: 4.76837158203125E-5, 4.76837158203125E-5, -59.99995231628418
Bound check: -2.0, 2.599998E7
Center: 2.384185791015625E-5, 2.384185791015625E-5, -59.99997615814209
Bound check: -1.0, 2.6799992E7
Center: 1.1920928955078125E-5, 1.1920928955078125E-5, -59.999988079071045
Bound check: -0.5, 2.7599994E7
Center: 5.9604644775390625E-6, 5.9604644775390625E-6, -59.99999403953552
Bound check: 0.0, 2.8399998E7
Center: 5.9604644775390625E-6, 5.9604644775390625E-6, -59.99999403953552
Bound check: 0.25, 2.4399998E7
Center: 5.9604644775390625E-6, 5.9604644775390625E-6, -59.99999403953552
Bound check: 0.23841858, -4000000.0
Center: 2.9802322387695312E-6, 2.9802322387695312E-6, -59.99999701976776
Bound check: 0.0, 2.92E7

person Yaakov Schectman    schedule 18.01.2015    source источник
comment
Это происходит для каждого куба или только для некоторых?   -  person rbennett485    schedule 18.01.2015
comment
И что вы подразумеваете под повторениями проверки? Может быть, вы могли бы опубликовать тестовый код, который вы используете, и результаты, поскольку у нас нет классов, необходимых для его самостоятельного тестирования.   -  person rbennett485    schedule 18.01.2015
comment
Я добавил System.out.println("Center: " + center.x + ", " + center.y + ", " + center.z);, и вот что отображается в консоли: Центр: 100.0, 100.0, 40.0 Проверка границ: -4000000.0, -1.2E7 Центр: 100.0, 100.0, 40.0 Проверка границ: 4000000.0, 4800000.0 Центр: 100.0, 100.0, 40.0 Проверка границ : 4000000.0, -4000000.0 Центр: 50.0, 50.0, -10.0 Проверка границы: -2000000.0, -1000000.0 Отсюда первое значение проверки границы продолжало приближаться к 0.0. Я не мог больше писать об этом в комментарии.   -  person Yaakov Schectman    schedule 18.01.2015


Ответы (1)


Ваш метод average изменяет значение a, чтобы сделать его таким же, как средний балл. Таким образом, ваш куб не является кубом, после того как вы назвали average — три грани повернулись в новые позиции. Итак, что бы ни происходило в цикле над collider, это неправильно.

person Dawood ibn Kareem    schedule 18.01.2015
comment
Спасибо! Я добавил Point3d c = new Point3d(a.x, a.y, a.z); и изменил a на c во всех последующих ссылках в функции усреднения. Похоже, теперь это работает. - person Yaakov Schectman; 18.01.2015