Repository: Zuzu-Typ/PyGLM (language: python)

Issue:
vec4 to quat conversion
Hi,

I was wondering how to convert vec4 to quat using PyGLM.
The quat constructor does not accept vec4 instances so I tried:

```py
 glm.quat(*glm.vec4(1, 2, 3, 4))
 ```
 
the example above obviously producing a bad result due to the quat constructor.
is there a solution to convert quat to vec4 and vec4 to quat using PyGLM?
if not I can make a PR extending the constructor logic. would that be welcome?

thank you


Discussion / hints:
Hey there (: 

I'm not exactly sure what behavior you would expect.
From my understanding, quaternions have a scalar (`w`) and a vector (`xyz`) part. 

I'm guessing what you would expect is the following:
```Python
# given x, y, z and w are some numbers
vec = glm.vec4(x, y, z, w)
qua = glm.quat(*vec)
assert qua.x == x
assert qua.y == y
assert qua.z == z
assert qua.w == w
```
That is not the case however, because `vec4`s are ordered `xyzw` and quaternions are ordered `w xyz`.

Taking that into account, you can happily convert between `quat` and `vec4`:
```Python
>>> q = glm.quat(1, 2,3,4)
>>> q
quat( 1, 2, 3, 4 )

>>> v = glm.vec4(*q)
>>> v
vec4( 1, 2, 3, 4 )

>>> glm.quat(*v)
quat( 1, 2, 3, 4 )

```

Though it appears that this is not the behavior you need.
Could you please explain the use case or expected behavior, so I can understand a little better?

Thank you very much!

Cheers
--Zuzu_Typ--
My use case involves compressing and decompressing quaternions.

my quaternion value is the result of vec3 and vec4 operations and right now i have to cast the vec4 to quat with `glm.quat(*vec.wxyz)`

I think it would make sens to support `glm.quat(vec)`.

I am not expecting the following to work.

```py
# given x, y, z and w are some numbers
vec = glm.vec4(x, y, z, w)
qua = glm.quat(*vec)
assert qua.x == x
assert qua.y == y
assert qua.z == z
assert qua.w == w
```

i know the "bad" quaternion parameter order is there in glm too and it should not be changed.
instead i would like to be able to cast vec to quat the way i explained above.
> right now i have to cast the vec4 to quat with `glm.quat(*vec.wxyz)`

Yeah, that's sort of what I expected.
And if I recall correctly, there is no (easy) way to do this the other way around (i.e. from quat to vec4).

About the code snippet, I think I messed up explaining what I wanted to know.
What I meant to ask was if your expected behavior would be that when converting between vec4 and quat, `x` would correspond to `x`, `y` would correspond to `y`, `z` would correspond to `z` and `w` would correspond to `w`.
That is what you need right?

Okay, so I'm not sure about using the constructor `glm.quat(vec4)` for this purpose, because I would expect some sort of actual conversion behind it. But perhaps that's just me.
I'm thinking about using a dedicated function for converting from quat to vec4 and back.
Do you think maybe such a function (or rather two functions) would be too inconvenient..?

Thanks for your input!
an explicit function call instead of the ambiguous constructor call would be a great idea.

i expect the `quat_to_vec4` and `vec4_to_quat` to do the mapping right (x=x, y=y, z=z, w=w)

Fix patch:
diff --git a/PyGLM.cpp b/PyGLM.cpp
index 438da69..7f78982 100644
--- a/PyGLM.cpp
+++ b/PyGLM.cpp
@@ -141,6 +141,8 @@ static PyMethodDef glmmethods[] = {
 	TERNARY_METHODS,
 
 	// PyGLM functions
+	CUSTOM_METHODS,
+	
 	{ "silence", (PyCFunction)silence, METH_O, silence_docstr },
 	//{ "_get_type_info", (PyCFunction)_get_type_info, METH_VARARGS, "_get_type_info(accepted_types, object) -> None\nAn internal testing funtion to check wether or not the type checking works correctly." },
 #ifdef HAS_TEST
diff --git a/PyGLM/functions/other/all.h b/PyGLM/functions/other/all.h
index 8a342a8..5d9af29 100644
--- a/PyGLM/functions/other/all.h
+++ b/PyGLM/functions/other/all.h
@@ -5,3 +5,5 @@
 #include "binary.h"
 
 #include "ternary.h"
+
+#include "custom.h"
diff --git a/PyGLM/functions/other/custom.h b/PyGLM/functions/other/custom.h
new file mode 100644
index 0000000..2d7f15f
--- /dev/null
+++ b/PyGLM/functions/other/custom.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "../../compiler_setup.h"
+#include "../../internal_functions/all.h"
+
+PyDoc_STRVAR(quat_to_vec4_docstr,
+	"quat_to_vec4(quat) -> vec4\n"
+	"	Component wise conversion of quat to vec4."
+);
+static PyObject*
+quat_to_vec4_(PyObject*, PyObject* arg) {
+	if (Py_TYPE(arg) == PyGLM_QUA_TYPE<float>()) {
+		glm::qua<float> q = unpack_qua<float>(arg);
+		return pack(glm::vec<4, float>(q.x, q.y, q.z, q.w));
+	}
+	
+	if (Py_TYPE(arg) == PyGLM_QUA_TYPE<double>()) {
+		glm::qua<double> q = unpack_qua<double>(arg);
+		return pack(glm::vec<4, double>(q.x, q.y, q.z, q.w));
+	}
+	
+	PyGLM_TYPEERROR_O("Invalid argument type for 'quat_to_vec4'. Expected 'quat', got ", arg);
+	return NULL;
+}
+
+PyDoc_STRVAR(vec4_to_quat_docstr,
+	"vec4_to_quat(vec4) -> quat\n"
+	"	Component wise conversion of vec4 to quat."
+);
+static PyObject*
+vec4_to_quat_(PyObject*, PyObject* arg) {
+	if (Py_TYPE(arg) == PyGLM_VEC_TYPE<4, float>()) {
+		glm::vec<4, float> v = unpack_vec<4, float>(arg);
+		return pack(glm::qua<float>(v.w, v.x, v.y, v.z));
+	}
+	
+	if (Py_TYPE(arg) == PyGLM_VEC_TYPE<4, double>()) {
+		glm::vec<4, double> v = unpack_vec<4, double>(arg);
+		return pack(glm::qua<double>(v.w, v.x, v.y, v.z));
+	}
+	
+	PyGLM_TYPEERROR_O("Invalid argument type for 'vec4_to_quat'. Expected 'vec4', got ", arg);
+	return NULL;
+}
+
+#define CUSTOM_METHODS \
+{ "quat_to_vec4", (PyCFunction)quat_to_vec4_, METH_O, quat_to_vec4_docstr }, \
+{ "vec4_to_quat", (PyCFunction)vec4_to_quat_, METH_O, vec4_to_quat_docstr }


Test patch:
diff --git a/test/PyGLM_test.py b/test/PyGLM_test.py
index 9c645a6..d7ffa38 100644
--- a/test/PyGLM_test.py
+++ b/test/PyGLM_test.py
@@ -478,6 +478,27 @@ def test_specific():
     assert isinstance(glm.license, str)
 #/Specific #
 
+# Custom #
+def test_custom():
+    for vec_type in (glm.vec4, glm.dvec4):
+        v = vec_type(1, 2, 3, 4)
+        
+        q = glm.vec4_to_quat(v)
+
+        assert v.x == q.x
+        assert v.y == q.y
+        assert v.z == q.z
+        assert v.w == q.w
+
+        v = glm.quat_to_vec4(q)
+
+        assert v.x == q.x
+        assert v.y == q.y
+        assert v.z == q.z
+        assert v.w == q.w
+        
+#/Custom #
+
 # Initialization #
 ## vec1
 def test_vec1_types():