N
N
Nikiti42015-09-16 16:55:38
JavaScript
Nikiti4, 2015-09-16 16:55:38

Implementation of rotation through a quaternion. Where is the mistake?

I'm trying to implement point rotation. The task is this: there is a molecule, for each atom there are three coordinates. This molecule has a -COH group. You need to rotate -OH at a certain angle around the CO axis. I wrote an implementation in java, everything works fine on simple coordinates, but does not work on real data. Please help me find the error. (In the main-class, data that does not work is commented out)
Main-class

public class App2
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
//        Vector carbon = new Vector(0.864, -8.606, -0.389);
//        Vector oxygen = new Vector(-0.495, -8.775, -4.434);
//        Vector hydrogen = new Vector(-0.682, -9.652, -0.809);
        
        Vector carbon = new Vector(0, 0, 0);
        Vector oxygen = new Vector(2, 2, 2);
        Vector hydrogen = new Vector(4, 1, 1);
        
        
        double angle = Math.PI/2;
        
        // Создаем вектор, вокруг которого будем вращать точку, и нормализуем его
        Vector direction = oxygen.residual(carbon);
        direction = direction.normalize();
         // На основе направляющего вектора и угла вращения создаем кватернион и нормализуем его
        Quaternion q = new Quaternion(angle, direction);
        q = q.normalize();
        // Тут вектор, который будем вращать
        Vector rotate = hydrogen.residual(carbon);
       // Вращаем
        rotate = rotate.transform(q);
        rotate = rotate.sum(carbon);
        
        System.out.println(rotate);
        
    }
    
}

Quaternion.java
public class Quaternion {
    
    double w;
    double i;
    double j;
    double k;
            
    public Quaternion(double angle, Vector vecDir) {
        this.w = Math.cos(angle/2);
        i = vecDir.x*Math.sin(angle/2);
        j = vecDir.y*Math.sin(angle/2);
        k = vecDir.z*Math.sin(angle/2);
    }
    
    public Quaternion(double w, double i, double j, double k) {
        this.w = w;
        this.i = i;
        this.j = j;
        this.k = k;
    }
    
    public Quaternion multiply(Quaternion q) {
        double nw = w*q.w - i*q.i - j*q.j - k*q.k;
        double ni = w*q.i + i*q.w + j*q.k - k*q.j;
        double nj = w*q.j - i*q.k + j*q.w + k*q.i;
        double nk = w*q.k + i*q.j - j*q.i + k*q.w;
        return new Quaternion(nw, ni, nj, nk);
    }
    
    public Quaternion multiplyToVector(Vector v) {
        Quaternion q = new Quaternion(0, v.x, v.y, v.z);
        return multiply(q);
    }
    
    public Quaternion normalize() {
        double len = Math.sqrt(w*w + i*i + j*j + k*k);
        return new Quaternion(w/len, i/len, j/len, k/len);
    }
    
    public Quaternion invert() {
        Quaternion res = new Quaternion(w, -i, -j, -k);
        return res;
    }
    
    public Vector toVector() {
        return new Vector(i, j, k);
    }
    
    
}

Vector.java
class Vector {
    
    double x;
    double y;
    double z;
    
    public Vector(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    
     // Действуем по формуле v' = qvq^(-1)
    public Vector transform(Quaternion q) {
        Quaternion r = q.multiplyToVector(this);
        r = r.multiply(q.invert().normalize());
        return r.toVector();
    }

    @Override
    public String toString() {
        return String.format("%2f %2f %2f", x, y, z);
    }
    
    public Vector normalize() {
        double len = Math.sqrt(x*x + y*y + z*z);
        return new Vector(x/len, y/len, z/len);
    }
    
    public Vector sum(Vector v) {
        return new Vector(v.x+x, v.y+y, v.z+z);
    }
    
    public Vector residual(Vector v) {
        return new Vector(x-v.x, y-v.y, z-v.z);
    }
    
}

Answer the question

In order to leave comments, you need to log in

5 answer(s)
S
Stockholm Syndrome, 2019-04-20
@khodos_dmitry

you are trying to get the data-officeId attribute, and you just have officeId
either
either way

var office_id = onMapMarks[a].getAttribute('office-id');

M
Mrrl, 2015-09-16
@Mrl

It turned out (-0.41, -7.31, -1.00). Why do you think it's wrong? The simplest independent checks show no errors.

N
Nikiti4, 2015-09-16
@Nikiti4

It was:
It became:
Together:
This, of course, is a rotation, but not by pi / 2, but by a smaller one. And the length seems to change

D
Deerenaros, 2015-09-20
@Deerenaros

Wow, what a beauty.
In general, reading the code was a bit hampered by its quality (more on that below), but it is worth noting that no mathematical errors were found (but this does not mean that there are none, it only means that they are a little more likely not). So everything basically turns as it should. It should be at least, and as for a possible error - there is a possibility that you are interpreting the results incorrectly - apparently the coordinates are entered into some editor and you can easily enter them a little incorrectly. Or maybe you did something that you yourself didn’t want - for example, you asked to turn around an axis, but you wanted to around a point - you are not very familiar with chemistry, it’s hard to say anything here. In any case, the error is most likely outside the scope of this code (and this program, it seems, too).
However, being a bit of a mathematician and quite a bit of a programmer, it is worth noting that in applied programming for mathematically capacious areas, very often everything is reduced to operations on matrices. If not all, then most - wherever possible in general. Why? First, in 99% of cases matrix forms are much, much simpler. If not for a person, then for a computer for sure - it’s better for him to detail an order of magnitude more numbers than to deal with diff. analysis =) Secondly, there are a huge number of efficient algorithms for working with matrices, both with huge ones - parallel computing, and small ones - fast arithmetic. And, finally, almost always records in matrix form are much more concise.
Here ... As for the code, on the one hand, nothing bad, but the names of the methods plunge into quiet horror. I personally don’t like Multiply, it’s a rather rare term in the literature, since it means the process itself, which no one here is interested in, but the result is a product. Moreover, we do not change the object, but create a new one. In Russian, this is like multiplication and product - they learn to multiply, but calculate the product. Something like this. And you don’t need toVector - java even knows what arguments to supply without you, and for you this is clearly superfluous information - you should implement the product of quaternions and a quaternion by a constant, java would already call the necessary method depending on the parameters supplied. And invert would not be needed.
And the neighborhood of sum and residual ... Well, this is already quite sad. If the method changes the object (not our case), then add and reduce - that is, the process, if not - sum and difference. But residual... For an hour I wondered what GMRES had to do with it, because the usual difference...
In the rest... More or less.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question