问:
How to load Ant properties from property files on the command line?
I have two property files [one.properties and two.properties]. I want to dynamically load the property files into my Ant project from the command line.

My build file name is build.xml.

Command line:

```<code>> ant build [How do I pass the property file names here?]
</code>```

答:
Making a build condition such that if Required System parameters are provided for build then only allowing for the next target else build gets fail.

```<code> Pass CMD: ant -DclientName=Name1 -Dtarget.profile.evn=dev
 Fail CMD: ant
</code>```

<project name="MyProject" default="myTarget" basedir=".">
    <target name="checkParams">
        <condition property="isReqParamsProvided">
            <and>
                <isset property="clientName" />
                <length string="${clientName}" when="greater" length="0" />
                <isset property="target.profile.evn" />
                <length string="${target.profile.evn}" when="greater" length="0" />
            </and>
        </condition>
        <echo>Runtime Sytem Properties:</echo>
        <echo>client              = ${clientName}</echo>
        <echo>target.profile.evn  = ${target.profile.evn}</echo>
        <echo>isReqParamsProvided = ${isReqParamsProvided}</echo>
        <echo>Java/JVM version: ${ant.java.version}</echo>
    </target>

    <target name="failOn_InSufficentParams" depends="checkParams" unless="isReqParamsProvided">
        <fail>Invalid params for provided for Build.</fail>
    </target>

    <target name="myTarget" depends="failOn_InSufficentParams">
        <echo>Build Success.</echo>
    </target>
</project>
```

@see also: Replace all tokens form file

Body:
I have two property files [one.properties and two.properties]. I want to dynamically load the property files into my Ant project from the command line.

My build file name is build.xml.

Command line:

> ant build [How do I pass the property file names here?]

Body:
Making a build condition such that if Required System parameters are provided for build then only allowing for the next target else build gets fail.

 Pass CMD: ant -DclientName=Name1 -Dtarget.profile.evn=dev
 Fail CMD: ant

<project name="MyProject" default="myTarget" basedir=".">
    <target name="checkParams">
        <condition property="isReqParamsProvided">
            <and>
                <isset property="clientName" /> <!-- if provide read latest else read form property tag -->
                <length string="${clientName}" when="greater" length="0" />
                <isset property="target.profile.evn" /> <!-- mvn clean install -Pdev -->
                <length string="${target.profile.evn}" when="greater" length="0" />
            </and>
        </condition>
        <echo>Runtime Sytem Properties:</echo>
        <echo>client              = ${clientName}</echo>
        <echo>target.profile.evn  = ${target.profile.evn}</echo>
        <echo>isReqParamsProvided = ${isReqParamsProvided}</echo>
        <echo>Java/JVM version: ${ant.java.version}</echo>
    </target>

    <target name="failOn_InSufficentParams" depends="checkParams" unless="isReqParamsProvided">
        <fail>Invalid params for provided for Build.</fail>
    </target>

    <target name="myTarget" depends="failOn_InSufficentParams">
        <echo>Build Success.</echo>
    </target>
</project>

@see also: Replace all tokens form file


来源: stackexchange

问:
java streams: easiest way to find adjacent value match
How would it be possible to convert this iterative block of code to streams?</p>

```<code>Integer prev = -1;
boolean adjacentPair = false;

for(Integer num : numberList) {
    if (num.equals(prev)) {
        adjacentNumberSame = true;
        break;
    }
    prev = num;
}
return adjacentNumberSame
</code>```

答:
This is one (not so great) way to do it:

IntStream.range(1, numberList.size())
         .anyMatch(i -> numberList.get(i).equals(numberList.get(i-1)));
```

<p>If your <code>numberList</code> is an <code>ArrayList</code> or something similar its complexity is acceptable. If not, you'd better use <code>iterator</code>. Like so:</p>

<pre class="lang-java prettyprint-override"><code>var Iter = list.stream().iterator();
var res = list.stream()
              .skip(1)
              .map(v -> v.equals(Iter.next()) )
              .anyMatch(v -> v)
              ;
</code>```

More elegant ways require some third-party libraries with a zip function. With zip it can look like:

var res = zip(
              list.stream().skip(1),
              list.stream(),
              (a, b) -> a.equals(b)
          ).anyMatch(x->x);
```

<p>Or you can write your own <code>zip</code>. Something like this:</p>

<pre class="lang-java prettyprint-override"><code>public static <A,B,C> Stream<C> zip(Stream<A> listA, Stream<B> listB, BiFunction<A,B,C> zipper){
    var iB = listB.iterator();
    return listA.filter( a -> iB.hasNext())
                .map( a -> zipper.apply(a, iB.next()) );
}
</code>```

PS. I would not recommend reduce as it used in @vbezhenar's answer. Because it will not shortcircuit, as you can see here https://repl.it/repls/DisastrousWideRevisioncontrol (look for exception)

ContentLicense: CC BY-SA 4.0

Body:
How would it be possible to convert this iterative block of code to streams?

Integer prev = -1;
boolean adjacentPair = false;

for(Integer num : numberList) {
    if (num.equals(prev)) {
        adjacentNumberSame = true;
        break;
    }
    prev = num;
}
return adjacentNumberSame

Body:
This is one (not so great) way to do it:

IntStream.range(1, numberList.size())
         .anyMatch(i -> numberList.get(i).equals(numberList.get(i-1)));

If your numberList is an ArrayList or something similar its complexity is acceptable. If not, you'd better use iterator. Like so:

var Iter = list.stream().iterator();
var res = list.stream()
              .skip(1)
              .map(v -> v.equals(Iter.next()) )
              .anyMatch(v -> v)
              ;

More elegant ways require some third-party libraries with a zip function. With zip it can look like:

var res = zip(
              list.stream().skip(1),
              list.stream(),
              (a, b) -> a.equals(b)
          ).anyMatch(x->x);

Or you can write your own zip. Something like this:

public static <A,B,C> Stream<C> zip(Stream<A> listA, Stream<B> listB, BiFunction<A,B,C> zipper){
    var iB = listB.iterator();
    return listA.filter( a -> iB.hasNext())
                .map( a -> zipper.apply(a, iB.next()) );
}

PS. I would not recommend reduce as it used in @vbezhenar's answer. Because it will not shortcircuit, as you can see here https://repl.it/repls/DisastrousWideRevisioncontrol (look for exception)


问:
Multidimensional arrays in VB.NET 2010
Is there any way to create a multidinensional array that contains arrays of different lengths (similar to nesting arrays of different lengths in python).

Because if I were to declare a variable Dim accounts(2,2) As Integer all 1D arrays at each dimension have the same length. Is there any way to create an array so that this is not the case?

e.g The above code would create an array like this:
[[0,0],[0,0]]
but would it be possible to create this:
[[0,0],[0,0,0]]

Apologies for the poor explanation but I cannot think of any better ways to explain.

答: See Collection and Array Initializers in Visual Basic 2010.</p>

ContentLicense: CC BY-SA 2.5

Title: Multidimensional arrays in VB.NET 2010

ContentLicense: CC BY-SA 3.0


问:
implementing a 3rd person camera using lwjgl
I've tried implementing a 3rd person camera multiply times, but i just can't seem to get it to work. The movement and the zoom work fine, but the rotation just causes me a lot of troubles:

When changing the pitch of the camera (i.e. from how high you are looking at the player), the camera always rotates around the world x axis at the position of the player and not the camera x axis

When changing the angle around the player, the camera always rotates around the world z axis at the position of the player and not the camera z axis

When rotating the camera in any direction, it slowly moves in said direction, not staying at the fixed offset from the player position

I've already tried changing the matrix multiplication order, but that doesn't help and I've also tried using a look at matrix, but that wouldn't work at all, creating all sorts of other issues. I know, that using a math library would make this a lot easier, but that's not my goal. I want to at least try to understand the math behind this and understand my mistake.

My Matrix4f class:

```<code>
import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.Iterator;

import com.engine.toolbox.ArrayUtils;
import com.engine.toolbox.BufferUtils;
import com.engine.toolbox.math.vectors.Vector3f;
import com.engine.toolbox.math.vectors.Vector4f;

public class Matrix4f extends Matrix{

    public float m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44;

    public Matrix4f(float m11, float m12, float m13, float m14,
                    float m21, float m22, float m23, float m24,
                    float m31, float m32, float m33, float m34,
                    float m41, float m42, float m43, float m44) {
        super(new Float[] { m11, m12, m13, m14,
                            m21, m22, m23, m24,
                            m31, m32, m33, m34,
                            m41, m42, m43, m44});
        this.m11 = m11;
        this.m12 = m12;
        this.m13 = m13;
        this.m14 = m14;
        this.m21 = m21;
        this.m22 = m22;
        this.m23 = m23;
        this.m24 = m24;
        this.m31 = m31;
        this.m32 = m32;
        this.m33 = m33;
        this.m34 = m34;
        this.m41 = m41;
        this.m42 = m42;
        this.m43 = m43;
        this.m44 = m44;

    }

    @Override
    public Iterator<Float> iterator() {
        return Arrays.asList(this.toRawTypes()).iterator();
    }

    public Matrix4f invert() {
        Matrix4f matrixOfMinors =   new Matrix4f(   new Matrix3f(   m22, m23, m24,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m21, m23, m24,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m21, m22, m24,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m21, m22, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m32, m33, m34).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m31, m33, m34).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m31, m32, m34).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m31, m32, m33).getDeterminant());
        matrixOfMinors.m12 = -m12;
        matrixOfMinors.m14 = -m14;

        matrixOfMinors.m21 = -m21;
        matrixOfMinors.m23 = -m23;

        matrixOfMinors.m32 = -m32;
        matrixOfMinors.m34 = -m34;

        matrixOfMinors.m41 = -m41;
        matrixOfMinors.m43 = -m43;

        float temp = 0;

        temp = matrixOfMinors.m12;
        matrixOfMinors.m12 = matrixOfMinors.m21;
        matrixOfMinors.m21 = temp;

        temp = matrixOfMinors.m13;
        matrixOfMinors.m13= matrixOfMinors.m31;
        matrixOfMinors.m31 = temp;

        temp = matrixOfMinors.m23;
        matrixOfMinors.m23 = matrixOfMinors.m32;
        matrixOfMinors.m32 = temp;

        temp = matrixOfMinors.m14;
        matrixOfMinors.m14 = matrixOfMinors.m41;
        matrixOfMinors.m41 = temp;

        temp = matrixOfMinors.m24;
        matrixOfMinors.m24 = matrixOfMinors.m42;
        matrixOfMinors.m42 = temp;

        temp = matrixOfMinors.m34;
        matrixOfMinors.m34 = matrixOfMinors.m43;
        matrixOfMinors.m43 = temp;

        float d = this.getDeterminant();
        return new Matrix4f(matrixOfMinors.m11/d, matrixOfMinors.m12/d, matrixOfMinors.m13/d, matrixOfMinors.m14/d,
                            matrixOfMinors.m21/d, matrixOfMinors.m22/d, matrixOfMinors.m23/d, matrixOfMinors.m24/d,
                            matrixOfMinors.m31/d, matrixOfMinors.m32/d, matrixOfMinors.m33/d, matrixOfMinors.m34/d,
                            matrixOfMinors.m41/d, matrixOfMinors.m42/d, matrixOfMinors.m43/d, matrixOfMinors.m44/d);
    }

    public float getDeterminant() {
        return  m11*(new Matrix3f(  m22, m23, m24,
                                    m32, m33, m34,
                                    m42, m43, m44).getDeterminant()) -
                m12*(new Matrix3f(  m21, m23, m24,
                                    m31, m33, m34,
                                    m41, m43, m44).getDeterminant()) +
                m13*(new Matrix3f(  m21, m22, m24,
                                    m31, m32, m34,
                                    m41, m42, m44).getDeterminant()) -
                m14*(new Matrix3f(  m21, m22, m23,
                                    m31, m32, m33,
                                    m41, m42, m43).getDeterminant());
    }

    public static Matrix4f identity() {
        return new Matrix4f(1, 0, 0, 0,
                            0, 1, 0, 0,
                            0, 0, 1, 0,
                            0, 0, 0, 1);
    }

    public static Matrix4f perspective(float aspectRatio, float viewAngle, float nearPlane, float farPlane) {
        return new Matrix4f((float) (1/(aspectRatio*Math.tan((viewAngle/2)))),  0,                                      0,                                          0,
                            0,                                                  (float) (1/(Math.tan((viewAngle/2)))),  0,                                          0,
                            0,                                                  0,                                      -(farPlane+nearPlane)/(farPlane-nearPlane), (2*farPlane*nearPlane)/(farPlane-nearPlane),
                            0,                                                  0,                                      -1,                                         1);
    }

    public static Matrix4f translation(Vector3f translation) {
        Matrix4f result = Matrix4f.identity();
        result.m14 = translation.x;
        result.m24 = translation.y;
        result.m34 = translation.z;
        return result;
    }

    public static Matrix4f scale(Vector3f scale) {
        Matrix4f result = Matrix4f.identity();
        result.m11 = scale.x;
        result.m22 = scale.y;
        result.m33 = scale.z;
        return result;
    }

    public Matrix4f minus(Matrix4f m) {
        return new Matrix4f(m11-m.m11, m12-m.m12, m13-m.m13, m14-m.m14,
                            m21-m.m21, m22-m.m22, m13-m.m23, m24-m.m24,
                            m31-m.m31, m32-m.m32, m13-m.m33, m34-m.m34,
                            m41-m.m41, m42-m.m42, m13-m.m43, m44-m.m44);
    }

    public Matrix4f plus(Matrix4f m) {
        return new Matrix4f(m11+m.m11, m12+m.m12, m13+m.m13, m14+m.m14,
                            m21+m.m21, m22+m.m22, m13+m.m23, m24+m.m24,
                            m31+m.m31, m32+m.m32, m13+m.m33, m34+m.m34,
                            m41+m.m41, m42+m.m42, m13+m.m43, m44+m.m44);
    }

    public Matrix4f multiply(Matrix4f m) {
        Vector4f r1 = new Vector4f(m11, m12, m13, m14);
        Vector4f r2 = new Vector4f(m21, m22, m23, m24);
        Vector4f r3 = new Vector4f(m31, m32, m33, m34);
        Vector4f r4 = new Vector4f(m41, m42, m43, m44);

        Vector4f c1 = new Vector4f(m.m11, m.m21, m.m31, m.m41);
        Vector4f c2 = new Vector4f(m.m12, m.m22, m.m32, m.m42);
        Vector4f c3 = new Vector4f(m.m13, m.m23, m.m33, m.m43);
        Vector4f c4 = new Vector4f(m.m14, m.m24, m.m34, m.m44);

        return new Matrix4f(r1.dot(c1), r1.dot(c2), r1.dot(c3), r1.dot(c4),
                            r2.dot(c1), r2.dot(c2), r2.dot(c3), r2.dot(c4),
                            r3.dot(c1), r3.dot(c2), r3.dot(c3), r3.dot(c4),
                            r4.dot(c1), r4.dot(c2), r4.dot(c3), r4.dot(c4));
    }

    public Vector4f multiply(Vector4f v) {
        return new Vector4f(m11*v.x+m12*v.y+m13*v.z+m14*v.w,
                            m21*v.x+m22*v.y+m23*v.z+m24*v.w,
                            m31*v.x+m32*v.y+m33*v.z+m34*v.w,
                            m41*v.x+m42*v.y+m43*v.z+m44*v.w);
    }

    public static Matrix4f lookAt(Vector3f eye, Vector3f target, Vector3f up) {

        Vector3f direction = eye.minus(target).normalize();
        Vector3f right = direction.cross(up).normalize();
        Vector3f camUp = right.cross(direction);

        direction = direction.negate();

        Matrix4f viewMatrix = new Matrix4f(
                right.x, right.y, right.z, -right.dot(eye),
                camUp.x, camUp.y, camUp.z, -camUp.dot(eye),
                direction.x, direction.y, direction.z, -direction.dot(eye),
                0, 0, 0, 1);

        return viewMatrix;
    }

    public String toString() {
        return  "" +    this.m11 + " " + this.m12 + " " + this.m13 + " " + this.m14 + "\n" +
                        this.m21 + " " + this.m22 + " " + this.m23 + " " + this.m24 + "\n" +
                        this.m31 + " " + this.m32 + " " + this.m33 + " " + this.m34 + "\n" +
                        this.m41 + " " + this.m42 + " " + this.m43 + " " + this.m44 + "\n";
    }

    public FloatBuffer toFloatBuffer() {
        return BufferUtils.createFloatBuffer(ArrayUtils.toFloatArray(this.toRawTypes()));
    }
}
</code>```

And my camera class:

```<code>
import com.engine.componentsystem.Component;
import com.engine.eventsystem.eventtypes.engineevents.UpdateEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MouseMovedEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MousePressedEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MouseReleasedEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MouseScrolledEvent;
import com.engine.toolbox.math.matrix.Matrix4f;
import com.engine.toolbox.math.quaternion.Quaternion;
import com.engine.toolbox.math.vectors.Vector3f;

public class CameraComponent extends Component{

    private boolean right = false, left = false;
    private float mouseX = 0, mouseY = 0, oldMouseX, oldMouseY;

    private float distanceFromTarget = -5, angleAroundTarget;

    private Vector3f position = new Vector3f(0.0f), rotation = new Vector3f(0.0f), target;

    public CameraComponent() {}

    public Vector3f getPosition() {
        return position;
    }

    public Vector3f getRotation() {
        return rotation;
    }

    public Vector3f getTarget() {
        return target;
    }

    private float calculateHorizontalDistance() {
        return (float) (this.distanceFromTarget*Math.cos(Math.toRadians(this.rotation.x)));
    }

    private float calculateVerticalDistance() {
        return (float) (this.distanceFromTarget*Math.sin(Math.toRadians(this.rotation.x)));
    }

    public Matrix4f getViewMatrix() {
        Matrix4f result = Matrix4f.identity();
        Matrix4f rotationM = Quaternion.fromEuler(rotation).toMatrix();
        Matrix4f translation = Matrix4f.translation(position.negate());
        Matrix4f origin = Matrix4f.translation(target);
        Matrix4f Iorigin = Matrix4f.translation(target.negate());

        System.out.println("target: " + target);
        System.out.println("position: " + position);
        System.out.println("rotation: " + rotation);

        result = result.multiply(translation);
        result = result.multiply(origin);
        result = result.multiply(rotationM);
        result = result.multiply(Iorigin);
        return result;
    }

    @Override
    public void onAttach() {
        this.target = ((PositionComponent) parent.getComponent(PositionComponent.class)).getPosition();
    }

    @Override
    public boolean onMouseScrolled(MouseScrolledEvent event) {
        this.distanceFromTarget += event.getyOffset()*0.7f;
        return false;
    }

    @Override
    public boolean onMousePressed(MousePressedEvent event) {
        if(event.getButton() == 0 && event.getMods() == 1) {
            left = true;
        }
        if(event.getButton() == 1 && event.getMods() == 1) {
            right = true;
        }
        return false;
    }

    @Override
    public boolean onMouseReleased(MouseReleasedEvent event) {
        if(event.getButton() == 0) {
            left = false;
        }
        if(event.getButton() == 1) {
            right = false;
        }
        return false;
    }

    @Override
    public boolean onMouseMoved(MouseMovedEvent event) {
        oldMouseX = mouseX;
        oldMouseY = mouseY;
        mouseX = event.getX();
        mouseY = event.getY();
        if(left) {
            this.angleAroundTarget -= (mouseX-oldMouseX)*0.01f;
        }
        if(right) {
            this.rotation.x -= (mouseY-oldMouseY)*0.01f;
        }
        return false;
    }

    @Override
    public void onUpdate(UpdateEvent event) {
        this.target = ((PositionComponent) parent.getComponent(PositionComponent.class)).getPosition();
        float horizantalDistance = calculateHorizontalDistance();
        float verticalDistance = calculateVerticalDistance();
        float theta = ((RotationComponent) parent.getComponent(RotationComponent.class)).getRotation().y + angleAroundTarget;

        float xOffset = (float) (horizantalDistance*Math.sin(Math.toRadians(theta)));
        float zOffset = (float) (horizantalDistance*Math.cos(Math.toRadians(theta)));

        this.position.x = target.x - xOffset;
        this.position.y = target.y + verticalDistance;
        this.position.z = target.z - zOffset;

        this.rotation.y = (float) (Math.toRadians(180.0f) - theta);
    }

}
</code>```

答:
So I managed to fix my problem, by

Changing to Matrix multiplication order to rotate first and move then (I also added new functions to the Matrix4f class to make this easier)

```<code>result = result.rotate((float) -this.rotation.x, new Vector3f(1f, 0f, 0f));
result = result.rotate((float) this.rotation.y, new Vector3f(0f, 1f, 0f));
result = result.translate(position.negate());
</code>```

Fixing the mistake a made in the quaternion class which was breaking the rotation (i forgot the turn the degrees into radians)

```<code>roll = (float) Math.toRadians(roll);
pitch = (float) Math.toRadians(pitch);
yaw = (float) Math.toRadians(yaw);
</code>```

The improved Camera class (I added float smoothing to remove all the jerkiness from the motions):

```<code>package com.assec.engine.componentsystem.components;

import com.assec.engine.componentsystem.Component;
import com.assec.engine.eventsystem.engineevents.UpdateEvent;
import com.assec.engine.eventsystem.mouseevents.MouseMovedEvent;
import com.assec.engine.eventsystem.mouseevents.MousePressedEvent;
import com.assec.engine.eventsystem.mouseevents.MouseReleasedEvent;
import com.assec.engine.eventsystem.mouseevents.MouseScrolledEvent;
import com.assec.engine.toolbox.math.SmoothFloat;
import com.assec.engine.toolbox.math.matrix.Matrix4f;
import com.assec.engine.toolbox.math.vectors.Vector3f;

public class CameraComponent extends Component{

    private boolean right = false, left = false;
    private float mouseX = 0.0f, mouseY = 0.0f, oldMouseX, oldMouseY;

    private SmoothFloat distanceFromTarget = new SmoothFloat(-10.0f, 5.0f);
    private SmoothFloat angleAroundTarget = new SmoothFloat(0.0f, 10.0f);

    private SmoothFloat pitch = new SmoothFloat(0.0f, 10.0f);

    private Vector3f position = new Vector3f(0.0f), rotation = new Vector3f(0.0f), target;

    public CameraComponent() {}

    public Vector3f getPosition() {
        return position;
    }

    public Vector3f getRotation() {
        return rotation;
    }

    public Vector3f getTarget() {
        return target;
    }

    private float calculateHorizontalDistance() {
        return (float) (this.distanceFromTarget.getActual()*Math.cos(Math.toRadians(this.rotation.x)));
    }

    private float calculateVerticalDistance() {
        return (float) (this.distanceFromTarget.getActual()*Math.sin(Math.toRadians(this.rotation.x)));
    }

    public Matrix4f getViewMatrix() {
        Matrix4f result = Matrix4f.identity();

        this.target = new Vector3f(0.0f);

        this.rotation.x = pitch.getActual();
        this.rotation.x%= 360;

        float horizontalDistance = calculateHorizontalDistance();
        float verticalDistance = calculateVerticalDistance();
        float theta = angleAroundTarget.getActual();

        float xOffset = (float) (horizontalDistance*Math.sin(Math.toRadians(theta)));
        float zOffset = (float) (horizontalDistance*Math.cos(Math.toRadians(theta)));

        this.position.x = target.x - xOffset;
        this.position.y = target.y + verticalDistance;
        this.position.z = target.z - zOffset;

        this.rotation.y = 360.0f - theta;
        this.rotation.y%= 360;

        result = result.rotate((float) -this.rotation.x, new Vector3f(1f, 0f, 0f));
        result = result.rotate((float) this.rotation.y, new Vector3f(0f, 1f, 0f));
        result = result.translate(position.negate());

        return result;
    }

    @Override
    public void onAttach() {
        this.target = ((PositionComponent) parent.getComponent(PositionComponent.class)).getPosition();
        this.target = new Vector3f(0.0f);
    }

    @Override
    public boolean onMouseScrolled(MouseScrolledEvent event) {
        this.distanceFromTarget.increaseTarget(-event.getyOffset()*0.7f);
        return false;
    }

    @Override
    public boolean onMousePressed(MousePressedEvent event) {
        if(event.getButton() == 0 && event.getMods() == 1) {
            left = true;
        }
        if(event.getButton() == 1 && event.getMods() == 1) {
            right = true;
        }
        return false;
    }

    @Override
    public boolean onMouseReleased(MouseReleasedEvent event) {
        if(event.getButton() == 0) {
            left = false;
        }
        if(event.getButton() == 1) {
            right = false;
        }
        return false;
    }

    @Override
    public boolean onMouseMoved(MouseMovedEvent event) {
        oldMouseX = mouseX;
        oldMouseY = mouseY;
        mouseX = (float) event.getX();
        mouseY = (float) event.getY();
        if(left) {
            this.angleAroundTarget.increaseTarget(-(mouseX-oldMouseX)*0.1f);
        }
        if(right) {
            this.pitch.increaseTarget(-(mouseY-oldMouseY)*0.1f);
        }
        return false;
    }

    @Override
    public void onUpdate(UpdateEvent event) {
        this.angleAroundTarget.update(0.01f);
        this.distanceFromTarget.update(0.01f);
        this.pitch.update(0.01f);
    }

}

</code>```

The improved Matrix4f class:

```<code>package com.assec.engine.toolbox.math.matrix;

import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.Iterator;

import com.assec.engine.toolbox.ArrayUtils;
import com.assec.engine.toolbox.BufferUtils;
import com.assec.engine.toolbox.math.quaternion.Quaternion;
import com.assec.engine.toolbox.math.vectors.Vector3f;
import com.assec.engine.toolbox.math.vectors.Vector4f;

public class Matrix4f extends Matrix{

    public float m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44;

    public Matrix4f(float m11, float m12, float m13, float m14,
                    float m21, float m22, float m23, float m24,
                    float m31, float m32, float m33, float m34,
                    float m41, float m42, float m43, float m44) {
        super(new Float[] { m11, m12, m13, m14,
                            m21, m22, m23, m24,
                            m31, m32, m33, m34,
                            m41, m42, m43, m44});
        this.m11 = m11;
        this.m12 = m12;
        this.m13 = m13;
        this.m14 = m14;
        this.m21 = m21;
        this.m22 = m22;
        this.m23 = m23;
        this.m24 = m24;
        this.m31 = m31;
        this.m32 = m32;
        this.m33 = m33;
        this.m34 = m34;
        this.m41 = m41;
        this.m42 = m42;
        this.m43 = m43;
        this.m44 = m44;

    }

    @Override
    public Iterator<Float> iterator() {
        return Arrays.asList(this.toRawTypes()).iterator();
    }

    public Matrix4f invert() {
        Matrix4f matrixOfMinors =   new Matrix4f(   new Matrix3f(   m22, m23, m24,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m21, m23, m24,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m21, m22, m24,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m21, m22, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m32, m33, m34).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m31, m33, m34).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m31, m32, m34).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m31, m32, m33).getDeterminant());
        matrixOfMinors.m12 = -m12;
        matrixOfMinors.m14 = -m14;

        matrixOfMinors.m21 = -m21;
        matrixOfMinors.m23 = -m23;

        matrixOfMinors.m32 = -m32;
        matrixOfMinors.m34 = -m34;

        matrixOfMinors.m41 = -m41;
        matrixOfMinors.m43 = -m43;

        float temp = 0;

        temp = matrixOfMinors.m12;
        matrixOfMinors.m12 = matrixOfMinors.m21;
        matrixOfMinors.m21 = temp;

        temp = matrixOfMinors.m13;
        matrixOfMinors.m13= matrixOfMinors.m31;
        matrixOfMinors.m31 = temp;

        temp = matrixOfMinors.m23;
        matrixOfMinors.m23 = matrixOfMinors.m32;
        matrixOfMinors.m32 = temp;

        temp = matrixOfMinors.m14;
        matrixOfMinors.m14 = matrixOfMinors.m41;
        matrixOfMinors.m41 = temp;

        temp = matrixOfMinors.m24;
        matrixOfMinors.m24 = matrixOfMinors.m42;
        matrixOfMinors.m42 = temp;

        temp = matrixOfMinors.m34;
        matrixOfMinors.m34 = matrixOfMinors.m43;
        matrixOfMinors.m43 = temp;

        float d = this.getDeterminant();
        return new Matrix4f(matrixOfMinors.m11/d, matrixOfMinors.m12/d, matrixOfMinors.m13/d, matrixOfMinors.m14/d,
                            matrixOfMinors.m21/d, matrixOfMinors.m22/d, matrixOfMinors.m23/d, matrixOfMinors.m24/d,
                            matrixOfMinors.m31/d, matrixOfMinors.m32/d, matrixOfMinors.m33/d, matrixOfMinors.m34/d,
                            matrixOfMinors.m41/d, matrixOfMinors.m42/d, matrixOfMinors.m43/d, matrixOfMinors.m44/d);
    }

    public float getDeterminant() {
        return  m11*(new Matrix3f(  m22, m23, m24,
                                    m32, m33, m34,
                                    m42, m43, m44).getDeterminant()) -
                m12*(new Matrix3f(  m21, m23, m24,
                                    m31, m33, m34,
                                    m41, m43, m44).getDeterminant()) +
                m13*(new Matrix3f(  m21, m22, m24,
                                    m31, m32, m34,
                                    m41, m42, m44).getDeterminant()) -
                m14*(new Matrix3f(  m21, m22, m23,
                                    m31, m32, m33,
                                    m41, m42, m43).getDeterminant());
    }

    public static Matrix4f identity() {
        return new Matrix4f(1, 0, 0, 0,
                            0, 1, 0, 0,
                            0, 0, 1, 0,
                            0, 0, 0, 1);
    }

    public static Matrix4f perspective(float aspectRatio, float viewAngle, float nearPlane, float farPlane) {
        return new Matrix4f((float) (1/(aspectRatio*Math.tan((viewAngle/2)))),  0,                                      0,                                          0,
                            0,                                                  (float) (1/(Math.tan((viewAngle/2)))),  0,                                          0,
                            0,                                                  0,                                      -((farPlane+nearPlane)/(farPlane-nearPlane)), -(2*farPlane*nearPlane)/(farPlane-nearPlane),
                            0,                                                  0,                                      -1,                                         1);
    }

    public static Matrix4f translation(Vector3f translation) {
        Matrix4f result = Matrix4f.identity();
        result.m14 = translation.x;
        result.m24 = translation.y;
        result.m34 = translation.z;
        return result;
    }

    public static Matrix4f scale(Vector3f scale) {
        Matrix4f result = Matrix4f.identity();
        result.m11 = scale.x;
        result.m22 = scale.y;
        result.m33 = scale.z;
        return result;
    }

    public Matrix4f minus(Matrix4f m) {
        return new Matrix4f(m11-m.m11, m12-m.m12, m13-m.m13, m14-m.m14,
                            m21-m.m21, m22-m.m22, m13-m.m23, m24-m.m24,
                            m31-m.m31, m32-m.m32, m13-m.m33, m34-m.m34,
                            m41-m.m41, m42-m.m42, m13-m.m43, m44-m.m44);
    }

    public Matrix4f plus(Matrix4f m) {
        return new Matrix4f(m11+m.m11, m12+m.m12, m13+m.m13, m14+m.m14,
                            m21+m.m21, m22+m.m22, m13+m.m23, m24+m.m24,
                            m31+m.m31, m32+m.m32, m13+m.m33, m34+m.m34,
                            m41+m.m41, m42+m.m42, m13+m.m43, m44+m.m44);
    }

    public Matrix4f multiply(Matrix4f m) {
        Vector4f r1 = new Vector4f(m11, m12, m13, m14);
        Vector4f r2 = new Vector4f(m21, m22, m23, m24);
        Vector4f r3 = new Vector4f(m31, m32, m33, m34);
        Vector4f r4 = new Vector4f(m41, m42, m43, m44);

        Vector4f c1 = new Vector4f(m.m11, m.m21, m.m31, m.m41);
        Vector4f c2 = new Vector4f(m.m12, m.m22, m.m32, m.m42);
        Vector4f c3 = new Vector4f(m.m13, m.m23, m.m33, m.m43);
        Vector4f c4 = new Vector4f(m.m14, m.m24, m.m34, m.m44);

        return new Matrix4f(r1.dot(c1), r1.dot(c2), r1.dot(c3), r1.dot(c4),
                            r2.dot(c1), r2.dot(c2), r2.dot(c3), r2.dot(c4),
                            r3.dot(c1), r3.dot(c2), r3.dot(c3), r3.dot(c4),
                            r4.dot(c1), r4.dot(c2), r4.dot(c3), r4.dot(c4));
    }

    public Vector4f multiply(Vector4f v) {
        return new Vector4f(m11*v.x+m12*v.y+m13*v.z+m14*v.w,
                            m21*v.x+m22*v.y+m23*v.z+m24*v.w,
                            m31*v.x+m32*v.y+m33*v.z+m34*v.w,
                            m41*v.x+m42*v.y+m43*v.z+m44*v.w);
    }

    public Matrix4f rotate(float angle, Vector3f axis) {
        Matrix4f rotation = Quaternion.fromEuler(axis.normalized().scaled(angle)).toMatrix();
        return this.multiply(rotation);
    }

    public Matrix4f translate(Vector3f translation) {
        Matrix4f translate = Matrix4f.translation(translation);
        return this.multiply(translate);
    }

    public static Matrix4f lookAt(Vector3f eye, Vector3f target, Vector3f up) {

        Vector3f direction = eye.minus(target).normalized();
        Vector3f right = direction.cross(up).normalized();
        Vector3f camUp = right.cross(direction);

        direction = direction.negate();

        Matrix4f viewMatrix = new Matrix4f(
                right.x, right.y, right.z, -right.dot(eye),
                camUp.x, camUp.y, camUp.z, -camUp.dot(eye),
                direction.x, direction.y, direction.z, -direction.dot(eye),
                0.0f, 0.0f, 0.0f, 1.0f);
        return viewMatrix;
    }

    public String toString() {
        return  "" +    this.m11 + " " + this.m12 + " " + this.m13 + " " + this.m14 + "\n" +
                        this.m21 + " " + this.m22 + " " + this.m23 + " " + this.m24 + "\n" +
                        this.m31 + " " + this.m32 + " " + this.m33 + " " + this.m34 + "\n" +
                        this.m41 + " " + this.m42 + " " + this.m43 + " " + this.m44 + "\n";
    }

    public FloatBuffer toFloatBuffer() {
        return BufferUtils.createFloatBuffer(ArrayUtils.toFloatArray(this.toRawTypes()));
    }
}

</code>```

Body:
I've tried implementing a 3rd person camera multiply times, but i just can't seem to get it to work. The movement and the zoom work fine, but the rotation just causes me a lot of troubles:

When changing the pitch of the camera (i.e. from how high you are looking at the player), the camera always rotates around the world x axis at the position of the player and not the camera x axis

When changing the angle around the player, the camera always rotates around the world z axis at the position of the player and not the camera z axis

When rotating the camera in any direction, it slowly moves in said direction, not staying at the fixed offset from the player position

I've already tried changing the matrix multiplication order, but that doesn't help and I've also tried using a look at matrix, but that wouldn't work at all, creating all sorts of other issues. I know, that using a math library would make this a lot easier, but that's not my goal. I want to at least try to understand the math behind this and understand my mistake.

My Matrix4f class:

import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.Iterator;

import com.engine.toolbox.ArrayUtils;
import com.engine.toolbox.BufferUtils;
import com.engine.toolbox.math.vectors.Vector3f;
import com.engine.toolbox.math.vectors.Vector4f;

public class Matrix4f extends Matrix{

    public float m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44;

    public Matrix4f(float m11, float m12, float m13, float m14,
                    float m21, float m22, float m23, float m24,
                    float m31, float m32, float m33, float m34,
                    float m41, float m42, float m43, float m44) {
        super(new Float[] { m11, m12, m13, m14,
                            m21, m22, m23, m24,
                            m31, m32, m33, m34,
                            m41, m42, m43, m44});
        this.m11 = m11;
        this.m12 = m12;
        this.m13 = m13;
        this.m14 = m14;
        this.m21 = m21;
        this.m22 = m22;
        this.m23 = m23;
        this.m24 = m24;
        this.m31 = m31;
        this.m32 = m32;
        this.m33 = m33;
        this.m34 = m34;
        this.m41 = m41;
        this.m42 = m42;
        this.m43 = m43;
        this.m44 = m44;

    }

    @Override
    public Iterator<Float> iterator() {
        return Arrays.asList(this.toRawTypes()).iterator();
    }

    public Matrix4f invert() {
        Matrix4f matrixOfMinors =   new Matrix4f(   new Matrix3f(   m22, m23, m24,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m21, m23, m24,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m21, m22, m24,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m21, m22, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m32, m33, m34).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m31, m33, m34).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m31, m32, m34).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m31, m32, m33).getDeterminant());
        matrixOfMinors.m12 = -m12;
        matrixOfMinors.m14 = -m14;

        matrixOfMinors.m21 = -m21;
        matrixOfMinors.m23 = -m23;

        matrixOfMinors.m32 = -m32;
        matrixOfMinors.m34 = -m34;

        matrixOfMinors.m41 = -m41;
        matrixOfMinors.m43 = -m43;

        float temp = 0;

        temp = matrixOfMinors.m12;
        matrixOfMinors.m12 = matrixOfMinors.m21;
        matrixOfMinors.m21 = temp;

        temp = matrixOfMinors.m13;
        matrixOfMinors.m13= matrixOfMinors.m31;
        matrixOfMinors.m31 = temp;

        temp = matrixOfMinors.m23;
        matrixOfMinors.m23 = matrixOfMinors.m32;
        matrixOfMinors.m32 = temp;

        temp = matrixOfMinors.m14;
        matrixOfMinors.m14 = matrixOfMinors.m41;
        matrixOfMinors.m41 = temp;

        temp = matrixOfMinors.m24;
        matrixOfMinors.m24 = matrixOfMinors.m42;
        matrixOfMinors.m42 = temp;

        temp = matrixOfMinors.m34;
        matrixOfMinors.m34 = matrixOfMinors.m43;
        matrixOfMinors.m43 = temp;

        float d = this.getDeterminant();
        return new Matrix4f(matrixOfMinors.m11/d, matrixOfMinors.m12/d, matrixOfMinors.m13/d, matrixOfMinors.m14/d,
                            matrixOfMinors.m21/d, matrixOfMinors.m22/d, matrixOfMinors.m23/d, matrixOfMinors.m24/d,
                            matrixOfMinors.m31/d, matrixOfMinors.m32/d, matrixOfMinors.m33/d, matrixOfMinors.m34/d,
                            matrixOfMinors.m41/d, matrixOfMinors.m42/d, matrixOfMinors.m43/d, matrixOfMinors.m44/d);
    }

    public float getDeterminant() {
        return  m11*(new Matrix3f(  m22, m23, m24,
                                    m32, m33, m34,
                                    m42, m43, m44).getDeterminant()) -
                m12*(new Matrix3f(  m21, m23, m24,
                                    m31, m33, m34,
                                    m41, m43, m44).getDeterminant()) +
                m13*(new Matrix3f(  m21, m22, m24,
                                    m31, m32, m34,
                                    m41, m42, m44).getDeterminant()) -
                m14*(new Matrix3f(  m21, m22, m23,
                                    m31, m32, m33,
                                    m41, m42, m43).getDeterminant());
    }

    public static Matrix4f identity() {
        return new Matrix4f(1, 0, 0, 0,
                            0, 1, 0, 0,
                            0, 0, 1, 0,
                            0, 0, 0, 1);
    }

    public static Matrix4f perspective(float aspectRatio, float viewAngle, float nearPlane, float farPlane) {
        return new Matrix4f((float) (1/(aspectRatio*Math.tan((viewAngle/2)))),  0,                                      0,                                          0,
                            0,                                                  (float) (1/(Math.tan((viewAngle/2)))),  0,                                          0,
                            0,                                                  0,                                      -(farPlane+nearPlane)/(farPlane-nearPlane), (2*farPlane*nearPlane)/(farPlane-nearPlane),
                            0,                                                  0,                                      -1,                                         1);
    }

    public static Matrix4f translation(Vector3f translation) {
        Matrix4f result = Matrix4f.identity();
        result.m14 = translation.x;
        result.m24 = translation.y;
        result.m34 = translation.z;
        return result;
    }

    public static Matrix4f scale(Vector3f scale) {
        Matrix4f result = Matrix4f.identity();
        result.m11 = scale.x;
        result.m22 = scale.y;
        result.m33 = scale.z;
        return result;
    }

    public Matrix4f minus(Matrix4f m) {
        return new Matrix4f(m11-m.m11, m12-m.m12, m13-m.m13, m14-m.m14,
                            m21-m.m21, m22-m.m22, m13-m.m23, m24-m.m24,
                            m31-m.m31, m32-m.m32, m13-m.m33, m34-m.m34,
                            m41-m.m41, m42-m.m42, m13-m.m43, m44-m.m44);
    }

    public Matrix4f plus(Matrix4f m) {
        return new Matrix4f(m11+m.m11, m12+m.m12, m13+m.m13, m14+m.m14,
                            m21+m.m21, m22+m.m22, m13+m.m23, m24+m.m24,
                            m31+m.m31, m32+m.m32, m13+m.m33, m34+m.m34,
                            m41+m.m41, m42+m.m42, m13+m.m43, m44+m.m44);
    }

    public Matrix4f multiply(Matrix4f m) {
        Vector4f r1 = new Vector4f(m11, m12, m13, m14);
        Vector4f r2 = new Vector4f(m21, m22, m23, m24);
        Vector4f r3 = new Vector4f(m31, m32, m33, m34);
        Vector4f r4 = new Vector4f(m41, m42, m43, m44);

        Vector4f c1 = new Vector4f(m.m11, m.m21, m.m31, m.m41);
        Vector4f c2 = new Vector4f(m.m12, m.m22, m.m32, m.m42);
        Vector4f c3 = new Vector4f(m.m13, m.m23, m.m33, m.m43);
        Vector4f c4 = new Vector4f(m.m14, m.m24, m.m34, m.m44);

        return new Matrix4f(r1.dot(c1), r1.dot(c2), r1.dot(c3), r1.dot(c4),
                            r2.dot(c1), r2.dot(c2), r2.dot(c3), r2.dot(c4),
                            r3.dot(c1), r3.dot(c2), r3.dot(c3), r3.dot(c4),
                            r4.dot(c1), r4.dot(c2), r4.dot(c3), r4.dot(c4));
    }

    public Vector4f multiply(Vector4f v) {
        return new Vector4f(m11*v.x+m12*v.y+m13*v.z+m14*v.w,
                            m21*v.x+m22*v.y+m23*v.z+m24*v.w,
                            m31*v.x+m32*v.y+m33*v.z+m34*v.w,
                            m41*v.x+m42*v.y+m43*v.z+m44*v.w);
    }

    public static Matrix4f lookAt(Vector3f eye, Vector3f target, Vector3f up) {

        Vector3f direction = eye.minus(target).normalize();
        Vector3f right = direction.cross(up).normalize();
        Vector3f camUp = right.cross(direction);

        direction = direction.negate();

        Matrix4f viewMatrix = new Matrix4f(
                right.x, right.y, right.z, -right.dot(eye),
                camUp.x, camUp.y, camUp.z, -camUp.dot(eye),
                direction.x, direction.y, direction.z, -direction.dot(eye),
                0, 0, 0, 1);

        return viewMatrix;
    }

    public String toString() {
        return  "" +    this.m11 + " " + this.m12 + " " + this.m13 + " " + this.m14 + "\n" +
                        this.m21 + " " + this.m22 + " " + this.m23 + " " + this.m24 + "\n" +
                        this.m31 + " " + this.m32 + " " + this.m33 + " " + this.m34 + "\n" +
                        this.m41 + " " + this.m42 + " " + this.m43 + " " + this.m44 + "\n";
    }

    public FloatBuffer toFloatBuffer() {
        return BufferUtils.createFloatBuffer(ArrayUtils.toFloatArray(this.toRawTypes()));
    }
}

And my camera class:

import com.engine.componentsystem.Component;
import com.engine.eventsystem.eventtypes.engineevents.UpdateEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MouseMovedEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MousePressedEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MouseReleasedEvent;
import com.engine.eventsystem.eventtypes.mouseevents.MouseScrolledEvent;
import com.engine.toolbox.math.matrix.Matrix4f;
import com.engine.toolbox.math.quaternion.Quaternion;
import com.engine.toolbox.math.vectors.Vector3f;

public class CameraComponent extends Component{

    private boolean right = false, left = false;
    private float mouseX = 0, mouseY = 0, oldMouseX, oldMouseY;

    private float distanceFromTarget = -5, angleAroundTarget;

    private Vector3f position = new Vector3f(0.0f), rotation = new Vector3f(0.0f), target;

    public CameraComponent() {}

    public Vector3f getPosition() {
        return position;
    }

    public Vector3f getRotation() {
        return rotation;
    }

    public Vector3f getTarget() {
        return target;
    }

    private float calculateHorizontalDistance() {
        return (float) (this.distanceFromTarget*Math.cos(Math.toRadians(this.rotation.x)));
    }

    private float calculateVerticalDistance() {
        return (float) (this.distanceFromTarget*Math.sin(Math.toRadians(this.rotation.x)));
    }

    public Matrix4f getViewMatrix() {
        Matrix4f result = Matrix4f.identity();
        Matrix4f rotationM = Quaternion.fromEuler(rotation).toMatrix();
        Matrix4f translation = Matrix4f.translation(position.negate());
        Matrix4f origin = Matrix4f.translation(target);
        Matrix4f Iorigin = Matrix4f.translation(target.negate());

        System.out.println("target: " + target);
        System.out.println("position: " + position);
        System.out.println("rotation: " + rotation);

        result = result.multiply(translation);
        result = result.multiply(origin);
        result = result.multiply(rotationM);
        result = result.multiply(Iorigin);
        return result;
    }

    @Override
    public void onAttach() {
        this.target = ((PositionComponent) parent.getComponent(PositionComponent.class)).getPosition();
    }

    @Override
    public boolean onMouseScrolled(MouseScrolledEvent event) {
        this.distanceFromTarget += event.getyOffset()*0.7f;
        return false;
    }

    @Override
    public boolean onMousePressed(MousePressedEvent event) {
        if(event.getButton() == 0 && event.getMods() == 1) {
            left = true;
        }
        if(event.getButton() == 1 && event.getMods() == 1) {
            right = true;
        }
        return false;
    }

    @Override
    public boolean onMouseReleased(MouseReleasedEvent event) {
        if(event.getButton() == 0) {
            left = false;
        }
        if(event.getButton() == 1) {
            right = false;
        }
        return false;
    }

    @Override
    public boolean onMouseMoved(MouseMovedEvent event) {
        oldMouseX = mouseX;
        oldMouseY = mouseY;
        mouseX = event.getX();
        mouseY = event.getY();
        if(left) {
            this.angleAroundTarget -= (mouseX-oldMouseX)*0.01f;
        }
        if(right) {
            this.rotation.x -= (mouseY-oldMouseY)*0.01f;
        }
        return false;
    }

    @Override
    public void onUpdate(UpdateEvent event) {
        this.target = ((PositionComponent) parent.getComponent(PositionComponent.class)).getPosition();
        float horizantalDistance = calculateHorizontalDistance();
        float verticalDistance = calculateVerticalDistance();
        float theta = ((RotationComponent) parent.getComponent(RotationComponent.class)).getRotation().y + angleAroundTarget;

        float xOffset = (float) (horizantalDistance*Math.sin(Math.toRadians(theta)));
        float zOffset = (float) (horizantalDistance*Math.cos(Math.toRadians(theta)));

        this.position.x = target.x - xOffset;
        this.position.y = target.y + verticalDistance;
        this.position.z = target.z - zOffset;

        this.rotation.y = (float) (Math.toRadians(180.0f) - theta);
    }

}

Body:
So I managed to fix my problem, by

Changing to Matrix multiplication order to rotate first and move then (I also added new functions to the Matrix4f class to make this easier)

result = result.rotate((float) -this.rotation.x, new Vector3f(1f, 0f, 0f));
result = result.rotate((float) this.rotation.y, new Vector3f(0f, 1f, 0f));
result = result.translate(position.negate());

Fixing the mistake a made in the quaternion class which was breaking the rotation (i forgot the turn the degrees into radians)

roll = (float) Math.toRadians(roll);
pitch = (float) Math.toRadians(pitch);
yaw = (float) Math.toRadians(yaw);

The improved Camera class (I added float smoothing to remove all the jerkiness from the motions):

package com.assec.engine.componentsystem.components;

import com.assec.engine.componentsystem.Component;
import com.assec.engine.eventsystem.engineevents.UpdateEvent;
import com.assec.engine.eventsystem.mouseevents.MouseMovedEvent;
import com.assec.engine.eventsystem.mouseevents.MousePressedEvent;
import com.assec.engine.eventsystem.mouseevents.MouseReleasedEvent;
import com.assec.engine.eventsystem.mouseevents.MouseScrolledEvent;
import com.assec.engine.toolbox.math.SmoothFloat;
import com.assec.engine.toolbox.math.matrix.Matrix4f;
import com.assec.engine.toolbox.math.vectors.Vector3f;

public class CameraComponent extends Component{

    private boolean right = false, left = false;
    private float mouseX = 0.0f, mouseY = 0.0f, oldMouseX, oldMouseY;

    private SmoothFloat distanceFromTarget = new SmoothFloat(-10.0f, 5.0f);
    private SmoothFloat angleAroundTarget = new SmoothFloat(0.0f, 10.0f);

    private SmoothFloat pitch = new SmoothFloat(0.0f, 10.0f);

    private Vector3f position = new Vector3f(0.0f), rotation = new Vector3f(0.0f), target;

    public CameraComponent() {}

    public Vector3f getPosition() {
        return position;
    }

    public Vector3f getRotation() {
        return rotation;
    }

    public Vector3f getTarget() {
        return target;
    }

    private float calculateHorizontalDistance() {
        return (float) (this.distanceFromTarget.getActual()*Math.cos(Math.toRadians(this.rotation.x)));
    }

    private float calculateVerticalDistance() {
        return (float) (this.distanceFromTarget.getActual()*Math.sin(Math.toRadians(this.rotation.x)));
    }

    public Matrix4f getViewMatrix() {
        Matrix4f result = Matrix4f.identity();

        this.target = new Vector3f(0.0f);

        this.rotation.x = pitch.getActual();
        this.rotation.x%= 360;

        float horizontalDistance = calculateHorizontalDistance();
        float verticalDistance = calculateVerticalDistance();
        float theta = angleAroundTarget.getActual();

        float xOffset = (float) (horizontalDistance*Math.sin(Math.toRadians(theta)));
        float zOffset = (float) (horizontalDistance*Math.cos(Math.toRadians(theta)));

        this.position.x = target.x - xOffset;
        this.position.y = target.y + verticalDistance;
        this.position.z = target.z - zOffset;

        this.rotation.y = 360.0f - theta;
        this.rotation.y%= 360;

        result = result.rotate((float) -this.rotation.x, new Vector3f(1f, 0f, 0f));
        result = result.rotate((float) this.rotation.y, new Vector3f(0f, 1f, 0f));
        result = result.translate(position.negate());

        return result;
    }

    @Override
    public void onAttach() {
        this.target = ((PositionComponent) parent.getComponent(PositionComponent.class)).getPosition();
        this.target = new Vector3f(0.0f);
    }

    @Override
    public boolean onMouseScrolled(MouseScrolledEvent event) {
        this.distanceFromTarget.increaseTarget(-event.getyOffset()*0.7f);
        return false;
    }

    @Override
    public boolean onMousePressed(MousePressedEvent event) {
        if(event.getButton() == 0 && event.getMods() == 1) {
            left = true;
        }
        if(event.getButton() == 1 && event.getMods() == 1) {
            right = true;
        }
        return false;
    }

    @Override
    public boolean onMouseReleased(MouseReleasedEvent event) {
        if(event.getButton() == 0) {
            left = false;
        }
        if(event.getButton() == 1) {
            right = false;
        }
        return false;
    }

    @Override
    public boolean onMouseMoved(MouseMovedEvent event) {
        oldMouseX = mouseX;
        oldMouseY = mouseY;
        mouseX = (float) event.getX();
        mouseY = (float) event.getY();
        if(left) {
            this.angleAroundTarget.increaseTarget(-(mouseX-oldMouseX)*0.1f);
        }
        if(right) {
            this.pitch.increaseTarget(-(mouseY-oldMouseY)*0.1f);
        }
        return false;
    }

    @Override
    public void onUpdate(UpdateEvent event) {
        this.angleAroundTarget.update(0.01f);
        this.distanceFromTarget.update(0.01f);
        this.pitch.update(0.01f);
    }

}

The improved Matrix4f class:

package com.assec.engine.toolbox.math.matrix;

import java.nio.FloatBuffer;
import java.util.Arrays;
import java.util.Iterator;

import com.assec.engine.toolbox.ArrayUtils;
import com.assec.engine.toolbox.BufferUtils;
import com.assec.engine.toolbox.math.quaternion.Quaternion;
import com.assec.engine.toolbox.math.vectors.Vector3f;
import com.assec.engine.toolbox.math.vectors.Vector4f;

public class Matrix4f extends Matrix{

    public float m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44;

    public Matrix4f(float m11, float m12, float m13, float m14,
                    float m21, float m22, float m23, float m24,
                    float m31, float m32, float m33, float m34,
                    float m41, float m42, float m43, float m44) {
        super(new Float[] { m11, m12, m13, m14,
                            m21, m22, m23, m24,
                            m31, m32, m33, m34,
                            m41, m42, m43, m44});
        this.m11 = m11;
        this.m12 = m12;
        this.m13 = m13;
        this.m14 = m14;
        this.m21 = m21;
        this.m22 = m22;
        this.m23 = m23;
        this.m24 = m24;
        this.m31 = m31;
        this.m32 = m32;
        this.m33 = m33;
        this.m34 = m34;
        this.m41 = m41;
        this.m42 = m42;
        this.m43 = m43;
        this.m44 = m44;

    }

    @Override
    public Iterator<Float> iterator() {
        return Arrays.asList(this.toRawTypes()).iterator();
    }

    public Matrix4f invert() {
        Matrix4f matrixOfMinors =   new Matrix4f(   new Matrix3f(   m22, m23, m24,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m21, m23, m24,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m21, m22, m24,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m21, m22, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m32, m33, m34,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m31, m33, m34,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m31, m32, m34,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m31, m32, m33,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m42, m43, m44).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m41, m43, m44).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m41, m42, m44).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m41, m42, m43).getDeterminant(),
                                                    new Matrix3f(   m12, m13, m14,
                                                                    m22, m23, m24,
                                                                    m32, m33, m34).getDeterminant(), new Matrix3f(  m11, m13, m14,
                                                                                m21, m23, m24,
                                                                                m31, m33, m34).getDeterminant(), new Matrix3f(  m11, m12, m14,
                                                                                m21, m22, m24,
                                                                                m31, m32, m34).getDeterminant(), new Matrix3f(  m11, m12, m23,
                                                                                m21, m22, m23,
                                                                                m31, m32, m33).getDeterminant());
        matrixOfMinors.m12 = -m12;
        matrixOfMinors.m14 = -m14;

        matrixOfMinors.m21 = -m21;
        matrixOfMinors.m23 = -m23;

        matrixOfMinors.m32 = -m32;
        matrixOfMinors.m34 = -m34;

        matrixOfMinors.m41 = -m41;
        matrixOfMinors.m43 = -m43;

        float temp = 0;

        temp = matrixOfMinors.m12;
        matrixOfMinors.m12 = matrixOfMinors.m21;
        matrixOfMinors.m21 = temp;

        temp = matrixOfMinors.m13;
        matrixOfMinors.m13= matrixOfMinors.m31;
        matrixOfMinors.m31 = temp;

        temp = matrixOfMinors.m23;
        matrixOfMinors.m23 = matrixOfMinors.m32;
        matrixOfMinors.m32 = temp;

        temp = matrixOfMinors.m14;
        matrixOfMinors.m14 = matrixOfMinors.m41;
        matrixOfMinors.m41 = temp;

        temp = matrixOfMinors.m24;
        matrixOfMinors.m24 = matrixOfMinors.m42;
        matrixOfMinors.m42 = temp;

        temp = matrixOfMinors.m34;
        matrixOfMinors.m34 = matrixOfMinors.m43;
        matrixOfMinors.m43 = temp;

        float d = this.getDeterminant();
        return new Matrix4f(matrixOfMinors.m11/d, matrixOfMinors.m12/d, matrixOfMinors.m13/d, matrixOfMinors.m14/d,
                            matrixOfMinors.m21/d, matrixOfMinors.m22/d, matrixOfMinors.m23/d, matrixOfMinors.m24/d,
                            matrixOfMinors.m31/d, matrixOfMinors.m32/d, matrixOfMinors.m33/d, matrixOfMinors.m34/d,
                            matrixOfMinors.m41/d, matrixOfMinors.m42/d, matrixOfMinors.m43/d, matrixOfMinors.m44/d);
    }

    public float getDeterminant() {
        return  m11*(new Matrix3f(  m22, m23, m24,
                                    m32, m33, m34,
                                    m42, m43, m44).getDeterminant()) -
                m12*(new Matrix3f(  m21, m23, m24,
                                    m31, m33, m34,
                                    m41, m43, m44).getDeterminant()) +
                m13*(new Matrix3f(  m21, m22, m24,
                                    m31, m32, m34,
                                    m41, m42, m44).getDeterminant()) -
                m14*(new Matrix3f(  m21, m22, m23,
                                    m31, m32, m33,
                                    m41, m42, m43).getDeterminant());
    }

    public static Matrix4f identity() {
        return new Matrix4f(1, 0, 0, 0,
                            0, 1, 0, 0,
                            0, 0, 1, 0,
                            0, 0, 0, 1);
    }

    public static Matrix4f perspective(float aspectRatio, float viewAngle, float nearPlane, float farPlane) {
        return new Matrix4f((float) (1/(aspectRatio*Math.tan((viewAngle/2)))),  0,                                      0,                                          0,
                            0,                                                  (float) (1/(Math.tan((viewAngle/2)))),  0,                                          0,
                            0,                                                  0,                                      -((farPlane+nearPlane)/(farPlane-nearPlane)), -(2*farPlane*nearPlane)/(farPlane-nearPlane),
                            0,                                                  0,                                      -1,                                         1);
    }

    public static Matrix4f translation(Vector3f translation) {
        Matrix4f result = Matrix4f.identity();
        result.m14 = translation.x;
        result.m24 = translation.y;
        result.m34 = translation.z;
        return result;
    }

    public static Matrix4f scale(Vector3f scale) {
        Matrix4f result = Matrix4f.identity();
        result.m11 = scale.x;
        result.m22 = scale.y;
        result.m33 = scale.z;
        return result;
    }

    public Matrix4f minus(Matrix4f m) {
        return new Matrix4f(m11-m.m11, m12-m.m12, m13-m.m13, m14-m.m14,
                            m21-m.m21, m22-m.m22, m13-m.m23, m24-m.m24,
                            m31-m.m31, m32-m.m32, m13-m.m33, m34-m.m34,
                            m41-m.m41, m42-m.m42, m13-m.m43, m44-m.m44);
    }

    public Matrix4f plus(Matrix4f m) {
        return new Matrix4f(m11+m.m11, m12+m.m12, m13+m.m13, m14+m.m14,
                            m21+m.m21, m22+m.m22, m13+m.m23, m24+m.m24,
                            m31+m.m31, m32+m.m32, m13+m.m33, m34+m.m34,
                            m41+m.m41, m42+m.m42, m13+m.m43, m44+m.m44);
    }

    public Matrix4f multiply(Matrix4f m) {
        Vector4f r1 = new Vector4f(m11, m12, m13, m14);
        Vector4f r2 = new Vector4f(m21, m22, m23, m24);
        Vector4f r3 = new Vector4f(m31, m32, m33, m34);
        Vector4f r4 = new Vector4f(m41, m42, m43, m44);

        Vector4f c1 = new Vector4f(m.m11, m.m21, m.m31, m.m41);
        Vector4f c2 = new Vector4f(m.m12, m.m22, m.m32, m.m42);
        Vector4f c3 = new Vector4f(m.m13, m.m23, m.m33, m.m43);
        Vector4f c4 = new Vector4f(m.m14, m.m24, m.m34, m.m44);

        return new Matrix4f(r1.dot(c1), r1.dot(c2), r1.dot(c3), r1.dot(c4),
                            r2.dot(c1), r2.dot(c2), r2.dot(c3), r2.dot(c4),
                            r3.dot(c1), r3.dot(c2), r3.dot(c3), r3.dot(c4),
                            r4.dot(c1), r4.dot(c2), r4.dot(c3), r4.dot(c4));
    }

    public Vector4f multiply(Vector4f v) {
        return new Vector4f(m11*v.x+m12*v.y+m13*v.z+m14*v.w,
                            m21*v.x+m22*v.y+m23*v.z+m24*v.w,
                            m31*v.x+m32*v.y+m33*v.z+m34*v.w,
                            m41*v.x+m42*v.y+m43*v.z+m44*v.w);
    }

    public Matrix4f rotate(float angle, Vector3f axis) {
        Matrix4f rotation = Quaternion.fromEuler(axis.normalized().scaled(angle)).toMatrix();
        return this.multiply(rotation);
    }

    public Matrix4f translate(Vector3f translation) {
        Matrix4f translate = Matrix4f.translation(translation);
        return this.multiply(translate);
    }

    public static Matrix4f lookAt(Vector3f eye, Vector3f target, Vector3f up) {

        Vector3f direction = eye.minus(target).normalized();
        Vector3f right = direction.cross(up).normalized();
        Vector3f camUp = right.cross(direction);

        direction = direction.negate();

        Matrix4f viewMatrix = new Matrix4f(
                right.x, right.y, right.z, -right.dot(eye),
                camUp.x, camUp.y, camUp.z, -camUp.dot(eye),
                direction.x, direction.y, direction.z, -direction.dot(eye),
                0.0f, 0.0f, 0.0f, 1.0f);
        return viewMatrix;
    }

    public String toString() {
        return  "" +    this.m11 + " " + this.m12 + " " + this.m13 + " " + this.m14 + "\n" +
                        this.m21 + " " + this.m22 + " " + this.m23 + " " + this.m24 + "\n" +
                        this.m31 + " " + this.m32 + " " + this.m33 + " " + this.m34 + "\n" +
                        this.m41 + " " + this.m42 + " " + this.m43 + " " + this.m44 + "\n";
    }

    public FloatBuffer toFloatBuffer() {
        return BufferUtils.createFloatBuffer(ArrayUtils.toFloatArray(this.toRawTypes()));
    }
}


问:
If I assign a procedure to an object property, can it reference other properties of the object?
Best shown with a simple example, question is the ShowMessage at the bottom:

```<code>type
  TFrmSelfRef = class(TForm)
    BtnTest: TButton;
    procedure BtnTestClick(Sender: TObject);
  private
  public
    procedure ExternalCaller;
  end;

type
   TProcType = procedure of Object;

type
   TSomeObj = class
   private
      FIdentifier: Integer;
      FCaller    : TProcType;
   public
      property Caller     : TProcType read FCaller write FCaller;
      property Identifier : integer read FIdentifier write FIdentifier;
   end;

[snip]

procedure TFrmSelfRef.BtnTestClick(Sender: TObject);
var
   lSomeObj: TSomeObj;
begin
   lSomeObj := TSomeObj.Create;
   lSomeObj.Identifier := 200;
   lSomeObj.Caller := ExternalCaller;
   lSomeObj.Caller;
   lSomeObj.Free;
end;

procedure TFrmSelfRef.ExternalCaller;
begin
   ShowMessage('Can I access lSomeObj.Identifier (value:200) here?');
end;
</code>```

Reason: I already have a TSomeObj instance containing all the information Caller would require, but the ExternalCaller references other objects/units that I do not want to link (the unit containing) TSomeObj to.

答:
Peter's comment shows a possibility. It needs some forwarding trickery:</p>

```<code>type
  TSomeObj = class;

  TFrmSelfRef = class(TForm)
    BtnTest: TButton;
    procedure BtnTestClick(Sender: TObject);
  private
  public
    procedure ExternalCaller(ASomeObj: TSomeObj);
  end;

  TProcType = procedure(Sender: TSomeObj) of Object;

  TSomeObj = class
  private
    FIdentifier: Integer;
    FCaller    : TProcType;
  public
    property Caller     : TProcType read FCaller write FCaller;
    property Identifier : integer read FIdentifier write FIdentifier;
  end;

[snip]

procedure TFrmSelfRef.BtnTestClick(Sender: TObject);
var
  lSomeObj: TSomeObj;
begin
  lSomeObj := TSomeObj.Create;
  lSomeObj.Identifier := 200;
  lSomeObj.Caller := ExternalCaller;
  lSomeObj.Caller(lSomeObj);
end;

procedure TFrmSelfRef.ExternalCaller(ASomeObj: TSomeObj);
begin
  ShowMessage('I can access TSomeObj here! Identifier property value: ' + IntToStr(ASomeObj.Identifier));
end;
</code>```

Body:
Best shown with a simple example, question is the ShowMessage at the bottom:

type
  TFrmSelfRef = class(TForm)
    BtnTest: TButton;
    procedure BtnTestClick(Sender: TObject);
  private
  public
    procedure ExternalCaller;
  end;

type
   TProcType = procedure of Object;

type
   TSomeObj = class
   private
      FIdentifier: Integer;
      FCaller    : TProcType;
   public
      property Caller     : TProcType read FCaller write FCaller;
      property Identifier : integer read FIdentifier write FIdentifier;
   end;

[snip]

procedure TFrmSelfRef.BtnTestClick(Sender: TObject);
var
   lSomeObj: TSomeObj;
begin
   lSomeObj := TSomeObj.Create;
   lSomeObj.Identifier := 200;
   lSomeObj.Caller := ExternalCaller;
   lSomeObj.Caller;
   lSomeObj.Free;
end;

procedure TFrmSelfRef.ExternalCaller;
begin
   ShowMessage('Can I access lSomeObj.Identifier (value:200) here?');
end;

Reason: I already have a TSomeObj instance containing all the information Caller would require, but the ExternalCaller references other objects/units that I do not want to link (the unit containing) TSomeObj to.

Body:
Peter's comment shows a possibility. It needs some forwarding trickery:

type
  TSomeObj = class;

  TFrmSelfRef = class(TForm)
    BtnTest: TButton;
    procedure BtnTestClick(Sender: TObject);
  private
  public
    procedure ExternalCaller(ASomeObj: TSomeObj);
  end;

  TProcType = procedure(Sender: TSomeObj) of Object;

  TSomeObj = class
  private
    FIdentifier: Integer;
    FCaller    : TProcType;
  public
    property Caller     : TProcType read FCaller write FCaller;
    property Identifier : integer read FIdentifier write FIdentifier;
  end;

[snip]

procedure TFrmSelfRef.BtnTestClick(Sender: TObject);
var
  lSomeObj: TSomeObj;
begin
  lSomeObj := TSomeObj.Create;
  lSomeObj.Identifier := 200;
  lSomeObj.Caller := ExternalCaller;
  lSomeObj.Caller(lSomeObj);
end;

procedure TFrmSelfRef.ExternalCaller(ASomeObj: TSomeObj);
begin
  ShowMessage('I can access TSomeObj here! Identifier property value: ' + IntToStr(ASomeObj.Identifier));
end;


问:
JavaScript map object not saving object keys?
So I'm trying to add an entry to a map object with the key being an object but it doesn't seem to work.

```<code>let myMap = new Map();
myMap.set({type : 'sum', val : 10},1);
console.log(myMap.get({type:'sum',val:10})); <---- this returns undefined
</code>```

why is it returning undefined instead of 1?

答:
Even if your two objects used as a key looks equals (because they have the same attributes), they aren't (according to === which is more or less the operation used - see here for more details).

It will work if you do the following:

```<code>let myMap = new Map();
var obj = {type : 'sum', val : 10};
myMap.set(obj,1);
console.log(myMap.get(obj));
</code>```

Body:
So I'm trying to add an entry to a map object with the key being an object but it doesn't seem to work.

let myMap = new Map();
myMap.set({type : 'sum', val : 10},1);
console.log(myMap.get({type:'sum',val:10})); <---- this returns undefined

why is it returning undefined instead of 1?

Body:
Even if your two objects used as a key looks equals (because they have the same attributes), they aren't (according to === which is more or less the operation used - see here for more details).

It will work if you do the following:

let myMap = new Map();
var obj = {type : 'sum', val : 10};
myMap.set(obj,1);
console.log(myMap.get(obj));


问:
Using Returned Value in Later Function
Let's say I wanted to call a function to do some calculation, but I also wanted to use that calculated value in a later function. When I return the value of the first function can I not just send it to my next function? Here is an example of what I am talking about:

```<code>def add(x,y):
  addition = x + y
  return addition

def square(a):
  result = a * a
  return result

sum = add(1,4)
product = square(addition)
</code>```

If I call the add function, it'll return 5 as the addition result. But I want to use that number 5 in the next function, can I just send it to the next function as shown? In the main program I am working on it does not work like this.

Edit: This is a sample of the code I am actually working on which will give a better idea of what the problem is. The problem is when I send the mean to the calculateStdDev function.

```<code>#import libraries to be used
import time
import StatisticsCalculations

#global variables
mean = 0
stdDev = 0

#get file from user
fileChoice = input("Enter the .csv file name: ")
inputFile = open(fileChoice)

headers = inputFile.readline().strip('ï»¿\n').split(',') #create headers for columns and strips unnecessary characters

#create a list with header-number of lists in it
dataColumns = []
for i in headers:
  dataColumns.append([]) #fills inital list with as many empty lists as there are columns

#counts how many rows there are and adds a column of data into each empty list
rowCount = 0
for row in inputFile:
  rowCount = rowCount + 1
  comps = row.strip().split(',') #components of data
  for j in range(len(comps)):
    dataColumns[j].append(float(comps[j])) #appends the jth entry into the jth column, separating data into categories

k = 0
for entry in dataColumns:
  print("{:>11}".format(headers[k]),"|", "{:>10.2f}".format(StatisticsCalculations.findMax(dataColumns[k])),"|",
    "{:>10.2f}".format(StatisticsCalculations.findMin(dataColumns[k])),"|","{:>10.2f}".format(StatisticsCalculations.calculateMean(dataColumns[k], rowCount)),"|","{:>10.2f}".format()) #format each data entry to be right aligned and be correctly spaced in its column
#prining break line for each row
  k = k + 1 #counting until dataColumns is exhausted

inputFile.close()
</code>```

And the StatisticsCalculations module:

```<code>import math

def calculateMean(data, rowCount):
  sumForMean = 0
  for entry in data:
    sumForMean = sumForMean + entry
    mean = sumForMean/rowCount

  return mean

def calculateStdDev(data, mean, rowCount, entry):
  stdDevSum = 0
  for x in data:
    stdDevSum = float(stdDevSum) + ((float(entry[x]) - mean)** 2) #getting sum of squared difference to be used in std dev formula
  stdDev = math.sqrt(stdDevSum / rowCount) #using the stdDevSum for the remaining parts of std dev formula

  return stdDev

def findMin(data):
  lowestNum = 1000
  for component in data:
    if component < lowestNum:
      lowestNum = component

  return lowestNum

def findMax(data):
  highestNum = -1
  for number in data:
    if number > highestNum:
      highestNum = number

  return highestNum
</code>```

答:
First of all, sum is a reserved word, you shouldn't use it as a variable.

You can do it this way:

def add(x,y):
  addition = x + y
  return addition

def square(a):
  result = a * a
  return result

s = add(1, 4)
product = square(s)
```

<p>Or directly:</p>

<pre class="lang-py prettyprint-override"><code>product = square(add(1, 4))
</code>```

Title: Using Returned Value in Later Function

Body:
Let's say I wanted to call a function to do some calculation, but I also wanted to use that calculated value in a later function. When I return the value of the first function can I not just send it to my next function? Here is an example of what I am talking about:

def add(x,y):
  addition = x + y
  return addition

def square(a):
  result = a * a
  return result

sum = add(1,4)
product = square(addition)

If I call the add function, it'll return 5 as the addition result. But I want to use that number 5 in the next function, can I just send it to the next function as shown? In the main program I am working on it does not work like this.

Edit: This is a sample of the code I am actually working on which will give a better idea of what the problem is. The problem is when I send the mean to the calculateStdDev function.

#import libraries to be used
import time
import StatisticsCalculations

#global variables
mean = 0
stdDev = 0

#get file from user
fileChoice = input("Enter the .csv file name: ")
inputFile = open(fileChoice)

headers = inputFile.readline().strip('ï»¿\n').split(',') #create headers for columns and strips unnecessary characters

#create a list with header-number of lists in it
dataColumns = []
for i in headers:
  dataColumns.append([]) #fills inital list with as many empty lists as there are columns

#counts how many rows there are and adds a column of data into each empty list
rowCount = 0
for row in inputFile:
  rowCount = rowCount + 1
  comps = row.strip().split(',') #components of data
  for j in range(len(comps)):
    dataColumns[j].append(float(comps[j])) #appends the jth entry into the jth column, separating data into categories

k = 0
for entry in dataColumns:
  print("{:>11}".format(headers[k]),"|", "{:>10.2f}".format(StatisticsCalculations.findMax(dataColumns[k])),"|",
    "{:>10.2f}".format(StatisticsCalculations.findMin(dataColumns[k])),"|","{:>10.2f}".format(StatisticsCalculations.calculateMean(dataColumns[k], rowCount)),"|","{:>10.2f}".format()) #format each data entry to be right aligned and be correctly spaced in its column
#prining break line for each row
  k = k + 1 #counting until dataColumns is exhausted

inputFile.close()

And the StatisticsCalculations module:

import math

def calculateMean(data, rowCount):
  sumForMean = 0
  for entry in data:
    sumForMean = sumForMean + entry
    mean = sumForMean/rowCount

  return mean

def calculateStdDev(data, mean, rowCount, entry):
  stdDevSum = 0
  for x in data:
    stdDevSum = float(stdDevSum) + ((float(entry[x]) - mean)** 2) #getting sum of squared difference to be used in std dev formula
  stdDev = math.sqrt(stdDevSum / rowCount) #using the stdDevSum for the remaining parts of std dev formula

  return stdDev

def findMin(data):
  lowestNum = 1000
  for component in data:
    if component < lowestNum:
      lowestNum = component

  return lowestNum

def findMax(data):
  highestNum = -1
  for number in data:
    if number > highestNum:
      highestNum = number

  return highestNum

Body:
First of all, sum is a reserved word, you shouldn't use it as a variable.

You can do it this way:

def add(x,y):
  addition = x + y
  return addition

def square(a):
  result = a * a
  return result

s = add(1, 4)
product = square(s)

Or directly:

product = square(add(1, 4))


问:
Strange date error between Development and Production environment
I have a strange date error that I can't solve for days and ask for your help.

I have developed in Java/Spring/Vaadin/Hibernate an app that creates a sport training every day by a user.
The problem is that the training date is not displayed correctly in browser.
For example, I create now a new training:

```<code>training.setTrainingdate(LocalDate.now());
</code>```

On localhost shows right but online from Amazon AWS Tomcat shows it wrong date (one day before).
The MySql database is common for both cases = Amazon RDS Mysql.
My Time zone is UTC +1 (Europe/Vienna)

2020-02-17

but in the browser when I get the trainig from aws is show

2020-02-16

What I've already checked:

- On AWS-RDS-MySQL Server:

```<code>SELECT now();
</code>```

2020-02-17 12:55:50

and

```<code>SELECT * FROM `mydatabase`.training;
</code>```

2020-02-17

- Elastic Beanstalk on SSH:

```<code>date
</code>```

Mon Feb 17 11:55:50 UTC 2020

Log files

/var/log/tomcat8/catalina.out

/var/log/tomcat8/httpd/access_log

/var/log/tomcat8/httpd/error_log

2020-02-17 11:55:50.985

No matter what time I try the difference stay  one day.

Different devices and different browser same problem.

Do you have an Ideea what can be?
Thank you very much!

EDIT:

```<code>TimeZone.getDefault())
</code>```

On Production Server:

sun.util.calendar.ZoneInfo[id="Universal",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]

On localhost:

sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]

答:
RESOLVED

Solution:

I add a version to maven mysql-connector-java dependency:

```<code><dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
</dependency>
</code>```

I add to spring applications.properties:

```<code>spring.datasource.driver-class-name=com.mysql.jdbc.Driver
</code>```

and add/change in the tail of spring.datasource.url to:

```<code>?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
</code>```

PS
Many thanks to all who try to help! Specially thanks to @Leif Åstrand and @PeMa

Body:
I have a strange date error that I can't solve for days and ask for your help.

I have developed in Java/Spring/Vaadin/Hibernate an app that creates a sport training every day by a user.
The problem is that the training date is not displayed correctly in browser.
For example, I create now a new training:

training.setTrainingdate(LocalDate.now());

On localhost shows right but online from Amazon AWS Tomcat shows it wrong date (one day before).
The MySql database is common for both cases = Amazon RDS Mysql.
My Time zone is UTC +1 (Europe/Vienna)

2020-02-17

but in the browser when I get the trainig from aws is show

2020-02-16

What I've already checked:

- On AWS-RDS-MySQL Server:

SELECT now();

2020-02-17 12:55:50

and

SELECT * FROM `mydatabase`.training;

2020-02-17

- Elastic Beanstalk on SSH:

date

Mon Feb 17 11:55:50 UTC 2020

Log files

/var/log/tomcat8/catalina.out

/var/log/tomcat8/httpd/access_log

/var/log/tomcat8/httpd/error_log

2020-02-17 11:55:50.985

No matter what time I try the difference stay  one day.

Different devices and different browser same problem.

Do you have an Ideea what can be?
Thank you very much!

EDIT:

TimeZone.getDefault())

On Production Server:

sun.util.calendar.ZoneInfo[id="Universal",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]

On localhost:

sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]

Body:
RESOLVED

Solution:

I add a version to maven mysql-connector-java dependency:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.48</version>
</dependency>

I add to spring applications.properties:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

and add/change in the tail of spring.datasource.url to:

?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false

PS
Many thanks to all who try to help! Specially thanks to @Leif Åstrand and @PeMa


问:
Delete previous image after updating the new one in laravel
I updated and image is showed after that, but i need to delete the previous image (from folder) after updating with the new one.

//update
    public function edit ($id)
    {
      $user = User::find($id);
      // $user = User::where('id', $id)->first();
      // $user = DB::table('users')->where('id', $id)->first();

      return view('edit', compact('user'));
    }

    public function postEdit (Request $request) {
      request()->validate([
          'email' => 'required',
          'fullname' => 'required',
          'birthday' => 'required',
          'address' => 'required|min:10',
      ]);

      $image = $request->image;
      // dd($image);
      $id = $request->id;
      $email = $request->email;
      $fullname = $request->fullname;
      $address = $request->address;
      $birthday = $request->birthday;
      $country = $request->country;

      $image = $request -> file('image');
      $destination = base_path().'/public/img';
      $file_name = rand(100,1).date('h-i-s');
      $image->move($destination, $file_name.".".$image->getClientOriginalExtension());
      $img = $file_name.".".$image->getClientOriginalExtension();

      User::where('id',$id)->update([
        'image'    => $img,
        'email'    => $email,
        'fullname' => $fullname,
        'birthday' => $birthday,
        'address'  => $address,
        'country'  => $country,
      ]);

      return Redirect::to("dashboard")->withSuccess('Great! You have Successfully edited');
    }
```

答:
You should first find the user and determine if he already has an image, sou you can delete it from the storage. Do it like this: </p>

```<code> public function postEdit (Request $request) {
    request()->validate([
        'email' => 'required',
        'fullname' => 'required',
        'birthday' => 'required',
        'address' => 'required|min:10',
    ]);

   $user = User::where('id', $request->id)->first();

   if($user->image){ //Check if user has image and delete it from storage
       if (Storage::exists($user->image)) {
            Storage::delete( $user->image ); //Dont forget to use your real paths. $user->image should be a path to an image.
       }
   }

   $image = $request->image;
   $id = $request->id;
   $email = $request->email;
   $fullname = $request->fullname;
   $address = $request->address;
   $birthday = $request->birthday;
   $country = $request->country;

   //Insert new image
   $image = $request -> file('image');
   $destination = base_path().'/public/img';
   $file_name = rand(100,1).date('h-i-s');
   $image->move($destination, $file_name.".".$image->getClientOriginalExtension());
   $img = $file_name.".".$image->getClientOriginalExtension();

   //Now update user
   $user->update([
       'image'    => $img,
       'email'    => $email,
       'fullname' => $fullname,
       'birthday' => $birthday,
       'address'  => $address,
       'country'  => $country,
   ]);

   return Redirect::to("dashboard")->withSuccess('Great! You have Successfully edited');
}
</code>```

Body:
You should first find the user and determine if he already has an image, sou you can delete it from the storage. Do it like this:

 public function postEdit (Request $request) {
    request()->validate([
        'email' => 'required',
        'fullname' => 'required',
        'birthday' => 'required',
        'address' => 'required|min:10',
    ]);

   $user = User::where('id', $request->id)->first();

   if($user->image){ //Check if user has image and delete it from storage
       if (Storage::exists($user->image)) {
            Storage::delete( $user->image ); //Dont forget to use your real paths. $user->image should be a path to an image.
       }
   }

   $image = $request->image;
   $id = $request->id;
   $email = $request->email;
   $fullname = $request->fullname;
   $address = $request->address;
   $birthday = $request->birthday;
   $country = $request->country;

   //Insert new image
   $image = $request -> file('image');
   $destination = base_path().'/public/img';
   $file_name = rand(100,1).date('h-i-s');
   $image->move($destination, $file_name.".".$image->getClientOriginalExtension());
   $img = $file_name.".".$image->getClientOriginalExtension();

   //Now update user
   $user->update([
       'image'    => $img,
       'email'    => $email,
       'fullname' => $fullname,
       'birthday' => $birthday,
       'address'  => $address,
       'country'  => $country,
   ]);

   return Redirect::to("dashboard")->withSuccess('Great! You have Successfully edited');
}