计算线段和点之间的距离

时间:2021-03-23 17:36:00

标签: java geometry

我目前正在从头开始用 Java 开发一个塔防游戏,我正在重新设计子弹碰撞。为此,我需要计算给定点和线段之间的距离。我已经编写了一个函数来做到这一点,但它通常会在不应该提供的情况下给出与其中一个点的距离。

线段类:

public class LineSegment {
    public Vector2DK p;
    public Vector2DK q;

    /**
     * Creates a line segment between the points P and Q
     * @param p Point P
     * @param q Point Q
     */
    public LineSegment(Vector2DK p, Vector2DK q) {
        this.p = p;
        this.q = q;
    }

    /**
     * Calculates the distance to point R
     * @param r Point R
     * @return Distance
     */
    public double distanceFrom(Vector2DK r) {
        // after trying what feels like everything I might have gotten a little confused(stupid errors ahead)
        Vector2DP differenceVector = r.subtract(p).toPolar();
        Vector2DP differenceVector2 = r.subtract(q).toPolar();
        double alpha = differenceVector.getAngle() - q.subtract(p).getAngle();
        double beta = differenceVector2.getAngle() - q.subtract(p).getAngle();
        if (alpha < Math.PI / 2 && alpha > -Math.PI / 2) {
            return p.distanceTo(r);
        } else if (beta > Math.PI / 2 || beta < -Math.PI / 2) {
            return q.distanceTo(r);
        }
        return Math.abs(differenceVector.getMagnitude() * Math.sin(alpha));
    }

    public static void main(String[] args) {
        // a main method for testing 
        // I already added a case where the bullet of the tower flew right thru the enemy(but I probably got the wrong tick, so the values are probably not good for testing)
        Vector2DK linePoint0 = new Vector2DK(339.9354152826523, 374.7835775987438);
        Vector2DK linePoint1 = new Vector2DK(317.79869321314067, 388.4287303893724);

        Vector2DK point = new Vector2DK(290.0194200000002, 400.0);

        LineSegment lineSegment = new LineSegment(linePoint0, linePoint1);
        Line line = new Line(linePoint0, linePoint1);
        System.out.println(lineSegment.distanceFrom(point));
    }
}

我的两个向量类:

public class Vector2DK implements Vector2D {
    private double x;
    private double y;

    public Vector2DK(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public Vector2DK(Vector2D vector) {
        Vector2DK vector2DK = vector.toKartesian();
        x = vector2DK.x;
        y = vector2DK.y;
    }

    public void copyToSelf(Vector2DK vector) {
        x = vector.x;
        y = vector.y;
    }

    @Override
    public String toString() {
        return String.format("Vector2DK(%s, %s)", x, y);
    }

    @Override
    public Vector2DK toKartesian() {
        return new Vector2DK(x, y);
    }

    @Override
    public Vector2DP toPolar() {
        return new Vector2DP(getMagnitude(), getAngle());
    }

    @Override
    public double getAngle() {
        return Math.atan2(y, x);
    }

    @Override
    public double getMagnitude() {
        return Math.sqrt(getMagnitudeSquare());
    }

    @Override
    public double getX() {
        return x;
    }

    @Override
    public double getY() {
        return y;
    }

    @Override
    public void setAngle(double angle) {
        Vector2DP vector = toPolar();
        vector.setAngle(angle);
        copyToSelf(vector.toKartesian());
    }

    @Override
    public void setMagnitude(double magnitude) {
        Vector2DP vector = toPolar();
        vector.setAngle(magnitude);
        copyToSelf(vector.toKartesian());
    }

    @Override
    public void setX(double x) {
        this.x = x;
    }

    @Override
    public void setY(double y) {
        this.y = y;
    }

    @Override
    public double getMagnitudeSquare() {
        return x * x + y * y;
    }

    @Override
    public double distanceTo(Vector2D vector) {
        return Math.sqrt(MathFunc.square(x - vector.getX()) + MathFunc.square(y - vector.getY()));
    }

    @Override
    public void normalize() {
        double magnitude = getMagnitude();
        x /= magnitude;
        y /= magnitude;
    }

    @Override
    public void reverse() {
        x = -x;
        y = -y;
    }

    @Override
    public Vector2D add(Vector2D vector) {
        return new Vector2DK(x + vector.getX(), y + vector.getY());
    }

    @Override
    public Vector2D subtract(Vector2D vector) {
        return new Vector2DK(x - vector.getX(), y - vector.getY());
    }

    @Override
    public Vector2D scale(double value) {
        return new Vector2DK(x * value, y * value);
    }

    @Override
    public void addWith(Vector2D vector) {
        x += vector.getX();
        y += vector.getY();
    }

    @Override
    public void subtractWith(Vector2D vector) {
        x -= vector.getX();
        y -= vector.getY();
    }

    @Override
    public void scaleWith(double value) {
        x *= value;
        y *= value;
    }

    @Override
    public double dotProduct(Vector2D vector) {
        return x * vector.getX() + y * vector.getY();
    }
}

和:

public class Vector2DP implements Vector2D {
    private double magnitude;
    private double angle;

    public Vector2DP(double magnitude, double angle) {
        this.magnitude = magnitude;
        this.angle = angle;
    }

    public Vector2DP(Vector2DP vector) {
        Vector2DP vector2DP = vector.toPolar();
        this.magnitude = vector.magnitude;
        this.angle = vector.angle;
    }

    public void copyToSelf(Vector2DP vector) {
        magnitude = vector.magnitude;
        angle = vector.angle;
    }

    @Override
    public String toString() {
        return String.format("Vector2DP(%su, %s°)", magnitude, Math.toDegrees(angle));
    }

    @Override
    public Vector2DK toKartesian() {
        return new Vector2DK(getX(), getY());
    }

    @Override
    public Vector2DP toPolar() {
        return new Vector2DP(magnitude, angle);
    }

    @Override
    public double getAngle() {
        return angle;
    }

    @Override
    public double getMagnitude() {
        return magnitude;
    }

    @Override
    public double getX() {
        return Math.cos(angle) * magnitude;
    }

    @Override
    public double getY() {
        return Math.sin(angle) * magnitude;
    }

    @Override
    public void setAngle(double angle) {
        this.angle = angle;
    }

    @Override
    public void setMagnitude(double magnitude) {
        this.magnitude = magnitude;
    }

    @Override
    public void setX(double x) {
        Vector2DK vector = toKartesian();
        vector.setX(x);
        copyToSelf(vector.toPolar());
    }

    @Override
    public void setY(double y) {
        Vector2DK vector = toKartesian();
        vector.setY(y);
        copyToSelf(vector.toPolar());
    }

    @Override
    public double getMagnitudeSquare() {
        return magnitude * magnitude;
    }

    @Override
    public double distanceTo(Vector2D vector) {
        return subtract(vector).getAngle();
    }

    @Override
    public void normalize() {
        magnitude = 1;
    }

    @Override
    public void reverse() {
        angle += angle < Math.PI ? Math.PI : -Math.PI;
    }

    @Override
    public Vector2D add(Vector2D vector) {
        return toKartesian().add(vector).toPolar();
    }

    @Override
    public Vector2D subtract(Vector2D vector) {
        return toKartesian().add(vector).toPolar();
    }

    @Override
    public Vector2D scale(double value) {
        return new Vector2DP(magnitude * value, angle);
    }

    @Override
    public void addWith(Vector2D vector) {
        copyToSelf((Vector2DP) add(vector));
    }

    @Override
    public void subtractWith(Vector2D vector) {
        copyToSelf((Vector2DP) subtract(vector));
    }

    @Override
    public void scaleWith(double value) {
        magnitude *= value;
    }

    @Override
    public double dotProduct(Vector2D vector) {
        Vector2DP vector2DP = vector.toPolar();
        return magnitude * vector2DP.magnitude * Math.cos(angle - vector2DP.angle);
    }
}

1 个答案:

答案 0 :(得分:-1)

考虑下一个 Python 代码(希望它易于翻译)。

首先函数检查段向量和从段的开始和结束到点的向量的点积。

如果点在直线上的投影位于线段之外,点积的符号揭示了这一事实,我们将距离返回到最近的线段末端(图中点 A、B、C、D)

否则我们返回投影长度(formula from wiki)(图片上的 E 点)

enter image description here

hypot 给出向量长度(就像你的 getMagnitude

import math

def pt_seg_dist(px, py, qx, qy, rx, ry):
    qpx = qx - px
    qpy = qy - py
    rpx = rx - px
    rpy = ry - py
    if rpx * qpx + rpy * qpy <= 0:
        return math.hypot(rpx, rpy)
    rqx = rx - qx
    rqy = ry - qy
    if rqx * qpx + rqy * qpy >= 0:
        return math.hypot(rqx, rqy)
    return abs(rpx * qpy - rpy * qpx) / math.hypot(qpx, qpy)

print(pt_seg_dist(0, 0, 1, 0, 0.5, 2))
print(pt_seg_dist(0, 0, 1, 0, -2, 2))
print(pt_seg_dist(0, 0, 1, 0, 3, -2))

>>>
2.0
2.8284271247461903
2.8284271247461903
相关问题