Search code examples
javavector3dplanedot-product

Point in 3d space approaching Planes in 3d space without reason


Java, program, I have a Point3d class w/ x,y,z coords, and the following average function:

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

I also have this class for a 2dPlane in 3d space formed by a triangle between 3 3d points:

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 is to find which side of the plane a particular point is on. Does it look like it should work to you? Any issues with it you can see?

Anyway, here's the big problem, I have the following class for a CubeCollider, extending the abstract class Collider, that sets up six TriPlanes to check whether a point is within the cube or not:

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

The point 'center' in the function isInBounds uses the average of the points a and h, but there's some issue. The debug like "Bound check: " from the isInBounds function reports 'should'(the dot product of the plane's normal vector and the point center), approaches zero, until, after a few(dozen) iterations of the check, it becomes exactly 0.0. Can someone please tell me why this happens? If I'm not mistaken, returning zero for function getRelativePointOnPlane should mean that the point is on the plane, but the point it's testing(center), if I'm not mistaken, should be between all of the planes, and not on any of them. Is my logic as to how to use these functions wrong, or am I mistaken in the coding I used to write the functions?

Here's what the console read:

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

Solution

  • Your average method changes the value of a, to make it the same as the average point. So your cube isn't a cube, after you've called average - three of the faces have rotated into new positions. So whatever happens in the loop over collider is wrong.