[C++] XYZ series - Vector3 class template (imitation Unity implementation)

Preamble

With the global popularity of Unity technology, the ease of use of its API has been favored by more and more developers.

Based on D Ziyu 's work, this article imitates Unity's class structure and expands it into a C++ class template.

In order to be more convenient to use in other C++ projects.

Source code address: https://github.com/duzixi/XYZ

First blog post: https://www.csdn.net/duzixi


source code

Vector3.h

//
//  Vector3.h
//  XYZ
// C++ implementation of common class templates for 3D space. It encapsulates the common members and methods of three-dimensional space vectors.
//
//  Created by 杜子兮(duzixi[at]gmail[dot]com) on 18-4-7.
//  Copyright (c) 2018年 www.duzixi.com All rights reserved.
//

#pragma once

using namespace std;

namespace XYZ {

	template <class T>
	class Vector3
	{
	public:
		T x;
		T y;
		T z;
		// Constructor ===============================
		Vector3();
		Vector3(T _x, T _y);
		Vector3(T _x, T _y, T _z);
		// destructor
		~Vector3();

		// Properties =======================================
		// common vector
		/* This class uses the following coordinate system:
		and
		^
		|
		| Top view z-axis vertical screen facing up
		|
		o-----------> x
		*/
		// (0, -1, 0)
		static Vector3<T> back;
		// (0, 0, -1)
		static Vector3<T> down;
		// (0, 1, 0)
		static Vector3<T> forward;
		// (0, 1, 0)
		static Vector3<T> fwd;
		// (-1, 0, 0)
		static Vector3<T> left;
		// (1, 1, 1)
		static Vector3<T> one;
		// (1, 0, 0)
		static Vector3<T> right;
		// (0, 0, 1)
		static Vector3<T> up;
		// (0, 0, 0)
		static Vector3<T> zero;

		// modulo square
		T sqrMagnitude;

		// modulo
		T magnitude;

		// class method =================================

		// dot multiply
		static T Dot(Vector3<T> lhs, Vector3<T> rhs);
		// cross product
		static Vector3<T> Cross(Vector3<T> lhs, Vector3<T> rhs);
		// distance
		static T Distance(Vector3<T> a, Vector3<T> b);
		// Unitization
		static Vector3<T> Normalize(Vector3<T> value);

		// The size of the included angle (angle)
		static T Angle(Vector3<T> from, Vector3<T> to);
		// Angle size (radians)
		static T AngleBetween(Vector3<T> from, Vector3<T> to);

		// Maximum value (X, Y, Z are the maximum)
		static Vector3<T> Max(Vector3<T> lhs, Vector3<T> rhs);

		// Minimum value (X, Y, Z are the minimum)
		static Vector3<T> Min(Vector3<T> lhs, Vector3<T> rhs);

		// vector projection
		static Vector3<T> Project(Vector3<T> vector, Vector3<T> onNormal);

		// zoom
		static Vector3<T> Scale(Vector3<T> a, Vector3<T> b);

		// member method ===============================

		// normalize (do not change the vector itself)
		Vector3<T> normalized();

		// zoom
		void Scale(Vector3<T> scale);

		// set up
		void Set(T _x, T _y, T _z);

		// return string
		string ToString();


		// operator overloading ===========================

		// compare for equality
		bool operator==(const Vector3<T> &rhs) const;
		// Compare if they are not equal
		bool operator!=(const Vector3<T> &rhs) const;

	};

	// operator overloading

	template <class T>
	Vector3<T> operator+(const Vector3<T> &a, const Vector3<T> &b);

	template <class T>
	Vector3<T> operator-(const Vector3<T> &a, const Vector3<T> &b);

	template <class T>
	Vector3<T> operator*(const T d, const Vector3<T> &a);

	template <class T>
	Vector3<T> operator* (const Vector3<T> &a, const T d);

	template <class T>
	Vector3<T> operator/ (const Vector3<T> &a, const T d);

}


Vector3.cpp

//
//  Vector3.h
//  XYZ
// C++ implementation of common class templates for 3D space. It encapsulates the common members and methods of three-dimensional space vectors.
//
//  Created by 杜子兮(duzixi[at]gmail[dot]com) on 18-4-7.
//  Copyright (c) 2018年 www.duzixi.com All rights reserved.
//

#include "stdafx.h"
#include "Vector3.h"

#ifndef _VECTOR3_CPP__
#define _VECTOR3_CPP__

namespace XYZ {

	template <class T>
	Vector3<T>::Vector3()
	{
	}

	template <class T>
	Vector3<T>::~Vector3()
	{
	}

	template <class T>
	Vector3<T>::Vector3(T _x, T _y)
	{
		x = _x;
		y = _y;
		z = 0;
		sqrMagnitude = x * x + y * y + z * z;
		magnitude = sqrt(sqrMagnitude);
	}

	template <class T>
	Vector3<T>::Vector3(T _x, T _y, T _z)
	{
		x = _x;
		y = _y;
		z = _z;
		sqrMagnitude = x * x + y * y + z * z;
		magnitude = sqrt(sqrMagnitude);
	}

	// (0, -1, 0)
	template <class T>
	Vector3<T> Vector3<T>::back = Vector3<T>(0, -1, 0);

	// (0, 0, -1)
	template <class T>
	Vector3<T> Vector3<T>::down = Vector3<T>(0, 0, -1);

	// (0, 1, 0)
	template <class T>
	Vector3<T> Vector3<T>::forward = Vector3<T>(0, 1, 0);

	// (0, 1, 0)
	template <class T>
	Vector3<T> Vector3<T>::fwd = Vector3<T>(0, 1, 0);

	// (-1, 0, 0)
	template <class T>
	Vector3<T> Vector3<T>::left = Vector3<T>(-1, 0, 0);

	// (1, 1, 1)
	template <class T>
	Vector3<T> Vector3<T>::one = Vector3<T>(1, 1, 1);

	// (1, 0, 0)
	template <class T>
	Vector3<T> Vector3<T>::right = Vector3<T>(1, 0, 0);

	// (0, 0, 1)
	template <class T>
	Vector3<T> Vector3<T>::up = Vector3<T>(0, 0, 1);

	// (0, 0, 0)
	template <class T>
	Vector3<T> Vector3<T>::zero = Vector3<T>(0, 0, 0);


	template <class T>
	T Vector3<T>::Dot(Vector3<T> lhs, Vector3<T> rhs) {
		return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
	}

	template <class T>
	Vector3<T> Vector3<T>::Cross(Vector3<T> lhs, Vector3<T> rhs) {
		double _x = lhs.y * rhs.z - rhs.y * lhs.z;
		double _y = lhs.z * rhs.x - rhs.z * lhs.x;
		double _z = lhs.x * rhs.y - rhs.x * lhs.y;
		return Vector3<T>(_x, _y, _z);
	}

	template <class T>
	T Vector3<T>::Distance(Vector3<T> a, Vector3<T> b) {
		return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z));
	}

	template <class T>
	Vector3<T> Vector3<T>::Normalize(Vector3<T> value) {
		if (value == zero)
		{
			return zero;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
		}
		else
		{
			Vector3<T> tempVec = Vector3<T>();
			tempVec.x = value.x / value.magnitude;
			tempVec.y = value.y / value.magnitude;
			tempVec.z = value.z / value.magnitude;
			return tempVec;
		}
	}

	template <class T>
	T Vector3<T>::Angle(Vector3<T> from, Vector3<T> to) {
		T cos = Dot(from.normalized(), to.normalized());
		if (cos < -1) {
			cos = -1;
		}
		if (cos > 1) {
			cos = 1;
		}
		return acos(cos) * (180 / M_PI);
	}

	template <class T>
	T Vector3<T>::AngleBetween(Vector3<T> from, Vector3<T> to) {
		T cos = Dot(from.normalized(), to.normalized());
		if (cos < -1) {
			cos = -1;
		}
		if (cos > 1) {
			cos = 1;
		}
		return acos(cos);
	}

	template <class T>
	Vector3<T> Vector3<T>::Max(Vector3<T> lhs, Vector3<T> rhs){
		Vector3<T> temp = Vector3<T>();
		temp.x = max(lhs.x, rhs.x);
		temp.y = max(lhs.y, rhs.y);
		temp.z = max(lhs.z, rhs.z);
		return temp;
	}

	template <class T>
	Vector3<T> Vector3<T>::Min(Vector3<T> lhs, Vector3<T> rhs) {
		Vector3<T> temp = Vector3<T>();
		temp.x = min(lhs.x, rhs.x);
		temp.y = min(lhs.y, rhs.y);
		temp.z = min(lhs.z, rhs.z);
		return temp;
	}

	template <class T>
	Vector3<T> Vector3<T>::Project(Vector3<T> vector, Vector3<T> onNormal) {
		if (vector == zero || onNormal == zero)
		{
			return zero;
		}
		return Dot(vector, onNormal) / (onNormal.magnitude() * onNormal.magnitude()) * onNormal;
	}

	template <class T>
	Vector3<T> Vector3<T>::Scale(Vector3<T> a, Vector3<T> b) {
		Vector3<T> temp = Vector3<T>();
		temp.x = a.x * b.x;
		temp.y = ay * by;
		temp.z = a.z * b.z;
		return temp;
	}

	template <class T>
	Vector3<T> Vector3<T>::normalized() {
		return Normalize(Vector3<T>(x, y, z));
	}

	template <class T>
	void Vector3<T>::Scale(Vector3<T> scale) {
		x *= scale.x;
		y *= scale.y;
		z * = scale.z;
	}

	template <class T>
	void Vector3<T>::Set(T _x, T _y, T _z) {
		x = _x;
		y = _y;
		z = _z;
	}

	template <class T>
	string Vector3<T>::ToString() {
		stringstream ss;
		ss << "(" << x << "," << y << "," << z << ")";
		return ss.str();
	}

	template <class T>
	bool Vector3<T>::operator==(const Vector3<T> &rhs) const {
		if (this->x == rhs.x && this->y == rhs.y && this->z == rhs.z)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	template <class T>
	bool Vector3<T>::operator!=(const Vector3<T> &rhs) const {
		return !(this == rhs)
	}

	// operator overloading is not a class member ---------------------------------------

	template <class T>
	Vector3<T> operator+(const Vector3<T> &a, const Vector3<T> &b) {
		return Vector3<T>(a.x + b.x, a.y + b.y, a.z + b.z);
	}

	template <class T>
	Vector3<T> operator-(const Vector3<T> &a, const Vector3<T> &b) {
		return Vector3<T>(a.x - b.x, a.y - b.y, a.z - b.z);
	}

	template <class T>
	Vector3<T> operator*(const T d, const Vector3<T> &a) {
		return Vector3<T>(a.x * d, a.y * d, a.z * d);
	}

	template <class T>
	Vector3<T> operator*(const Vector3<T> &a, const T d ) {
		return Vector3<T>(a.x * d, a.y * d, a.z * d);
	}

	template <class T>
	Vector3<T> operator/(const Vector3<T> &a, const T d) {
		return Vector3<T>(a.x / d, a.y / d, a.z / d);
	}
}

#endif


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324958622&siteId=291194637