Найти дельта-угол, который будет использоваться для поворота данного объекта с положением, начальным поворотом и целевой точкой для «лицом к» - PullRequest
3 голосов
/ 29 октября 2010

Я кодирую алгоритм флокирования в Java, но я застрял в определенной точке (используя библиотеки Ardor3D, в 2D плоскости).

По сути, мне нужно найти разницу углов, чтобы добавить к текущему вращению. Если вы можете получить только то, как он должен указывать с полярными координатами с 0 градусами на севере, а не с разницей, не беспокойтесь - у меня есть метод, который возвращает разность углов с учетом изменения угла наклона и отрицательных углов.

alt text

На данный момент у меня есть следующий код, который явно не будет работать, поскольку алгоритм не имеет ссылки на начальный поворот:

  long tpf = currUpdateTimeMS - lastUpdateTimeMS;

  Vector2 pos = new Vector2();
  rt.getPosition(pos);

  double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal());
  rt.setRotation(rot);

  pos.addLocal(
   Math.cos((rot - MathUtils.HALF_PI)) * (tpf / 10f),
   Math.sin((rot - MathUtils.HALF_PI)) * (tpf / 10f)
  );
  rt.setPosition(pos);

  super.updateLogic();

Обновлен код (не работает, с первого ответа):

    long tpf = currUpdateTimeMS - lastUpdateTimeMS;
    //rt.setRotation(rt.getRotation() + ((tpf / (ROT_SPEED / 2f)) % 360));

    Vector2 avgpos = app.getAvgBoidPos(new Vector2());
    Vector2 pos = rt.getPosition(new Vector2());
    avgpos.subtractLocal(pos);

    double angleRads = rt.getRotation() * FastMath.DEG_TO_RAD;
    double rot = MathUtils.acos((
        (avgpos.getX() * MathUtils.sin(angleRads)
    ) +
        (avgpos.getY() * MathUtils.cos(angleRads)
    )) / ((Math.pow(avgpos.getX(), 2) + Math.pow(avgpos.getY(), 2)) * 0.5));

    double adegdiff = rot * FastMath.RAD_TO_DEG;

    rt.setRotation(rt.getRotation() - adegdiff);
    double newrot = rt.getRotation();

    pos.addLocal(
        Math.cos((newrot - MathUtils.HALF_PI)) * (tpf / 10f),
        Math.sin((newrot - MathUtils.HALF_PI)) * (tpf / 10f)
    );
    rt.setPosition(pos);

    super.updateLogic();

Другая модификация, основанная на другом ответе:

    long tpf = currUpdateTimeMS - lastUpdateTimeMS;
    //rt.setRotation(rt.getRotation() + ((tpf / (ROT_SPEED / 2f)) % 360));

    Vector2 avgpos = app.getAvgBoidPos(new Vector2());
    Vector2 pos = rt.getPosition(new Vector2());
    avgpos.subtractLocal(pos);

    double rot = pos.angleBetween(
        app.getAvgBoidPos(new Vector2()).normalizeLocal()
    ) - (rt.getRotation() * MathUtils.DEG_TO_RAD);

    rt.setRotation(rt.getRotation() - (rot * MathUtils.RAD_TO_DEG));
    double newrot = rt.getRotation();

    pos.addLocal(
        Math.cos((newrot - MathUtils.HALF_PI)) * (tpf / 10f),
        Math.sin((newrot - MathUtils.HALF_PI)) * (tpf / 10f)
    );
    rt.setPosition(pos);

    super.updateLogic();

Я не очень хорошо разбираюсь в задачах по математике, поэтому будет полезен код, а не формулы:)

Входы

  • Текущая позиция организации
  • Текущее вращение объекта (с полярной ориентацией) в градусах

выход

  • Градусы или радианы, чтобы добавить или вычесть текущее вращение
  • ... или градусы или радианы, выраженные как полярно-ориентированный угол

Заранее спасибо, если можете помочь:)

Chris

Ответы [ 4 ]

2 голосов
/ 29 октября 2010

Вы можете использовать точечное произведение, чтобы определить косинус угла (в радианах) между текущей ориентацией и точкой, к которой вы хотите обратиться. Предположим, что агент, выполняющий просмотр, находится в начале координат и ориентирован в некотором направлении, заданном углом & theta; относительно оси Y (то есть 0 градусов "вверх" или "север"). Вы хотите найти разность углов & theta; ' между этим направлением и лицом к точке (х, у). Это дается:

&theta;' = cos<sup>-1</sup>[(x*sin(&theta;) + y*cos(&theta;)) / sqrt(x<sup>2</sup> + y<sup>2</sup>)]

Вычитание & theta; ' от & theta; будет ориентировать агента на цель.

Если агент не в источнике, просто вычтите положение агента из объекта для просмотра, чтобы привести его в форму выше.

1 голос
/ 27 ноября 2010

Немного не по теме, но вы могли бы также найти интересный код частиц и странствий в нашем пакете эффектов (ardor3d-эффекты).

Их можно найти в пылу свн, или здесь:

http://ardorlabs.trac.cvsdude.com/Ardor3Dv1/browser/trunk/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/

0 голосов
/ 29 октября 2010

Если я правильно понимаю эти функции, это может сработать:

Vector2 pos = new Vector2(); 
rt.getPosition(pos); 

double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal()) - rt.getRotation();

PS Забыл упомянуть: это rot предназначено для разности углов.Поверните объект на столько, и он должен указывать на цель.

РЕДАКТИРОВАТЬ:
Спасибо, код действительно помогает (я неправильно истолковал angleBetween).Позвольте мне повторить попытку:

Вот вектор от сущности к точке (извините, если я неправильно понял синтаксис, я не знаю java):

Vector2 pos = new Vector2(); 
rt.getPosition(pos); 

Vector2 direction = app.getAvgBoidPos(new Vector2());
direction.subtractLocal(pos);

Теперь мынормализуйте его, чтобы получить единичный вектор, указывающий на точку, и возьмите разность углов:

double rot = rt.getRotation().angleBetween(direction.normalizeLocal())
0 голосов
/ 29 октября 2010

Вот реализация того, как найти угол между двумя векторами с общим началом. это было взломано вместе на основе алгоритма, описанного там: http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors

public class DeltaDoodle {

    private double delta(ColumnVector v1,ColumnVector v2) throws Exception{
        double sp=scalarProduct(v1,v2);
        double magV1=magnitude(v1);
        double magV2=magnitude(v2);
        return Math.acos(sp/(magV1*magV2)) * (180/Math.PI);
    }

    private double scalarProduct(ColumnVector a, ColumnVector b) {
        return (a.x*b.x) + (a.y*b.y);
    }
    private double magnitude(ColumnVector a){
        return Math.sqrt((a.x*a.x) + (a.y*a.y));
    }

    public static void main(String[] args) {
        DeltaDoodle v=new DeltaDoodle();
        try {
            System.out.println("angle: " + v.delta(new ColumnVector(5, 5), new ColumnVector(1,1)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

public class ColumnVector {
    public final double x, y;

    public ColumnVector(double x1, double x2) {
        this.x = x1;
        this.y = x2;
    }
}

надеюсь, что это помогает ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...