Compare commits
	
		
			No commits in common. "main" and "subtree" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,4 @@
 | 
			
		||||
doxygen/html
 | 
			
		||||
doxygen/DoxyWarnLogfile.txt
 | 
			
		||||
build
 | 
			
		||||
.vscode
 | 
			
		||||
DoxyGen/DoxyWarnLogfile.txt
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										61
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
# This file is a template, and might need editing before it works on your project.
 | 
			
		||||
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
 | 
			
		||||
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
 | 
			
		||||
# it uses echo commands to simulate the pipeline execution.
 | 
			
		||||
#
 | 
			
		||||
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
 | 
			
		||||
# Stages run in sequential order, but jobs within stages run in parallel.
 | 
			
		||||
#
 | 
			
		||||
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
 | 
			
		||||
#
 | 
			
		||||
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
 | 
			
		||||
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
 | 
			
		||||
#
 | 
			
		||||
# To contribute improvements to CI/CD templates, please follow the Development guide at:
 | 
			
		||||
# https://docs.gitlab.com/ee/development/cicd/templates.html
 | 
			
		||||
# This specific template is located at:
 | 
			
		||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
 | 
			
		||||
 | 
			
		||||
# This file is a template, and might need editing before it works on your project.
 | 
			
		||||
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
 | 
			
		||||
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
 | 
			
		||||
# it uses echo commands to simulate the pipeline execution.
 | 
			
		||||
#
 | 
			
		||||
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
 | 
			
		||||
# Stages run in sequential order, but jobs within stages run in parallel.
 | 
			
		||||
#
 | 
			
		||||
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
 | 
			
		||||
#
 | 
			
		||||
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
 | 
			
		||||
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
 | 
			
		||||
#
 | 
			
		||||
# To contribute improvements to CI/CD templates, please follow the Development guide at:
 | 
			
		||||
# https://docs.gitlab.com/ee/development/cicd/templates.html
 | 
			
		||||
# This specific template is located at:
 | 
			
		||||
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
 | 
			
		||||
 | 
			
		||||
variables:
 | 
			
		||||
  GIT_SUBMODULE_STRATEGY: recursive
 | 
			
		||||
default:
 | 
			
		||||
  image: rikorose/gcc-cmake
 | 
			
		||||
stages:
 | 
			
		||||
- test
 | 
			
		||||
unit-test-job:
 | 
			
		||||
  stage: test
 | 
			
		||||
  script:
 | 
			
		||||
  - mkdir build
 | 
			
		||||
  - cd build
 | 
			
		||||
  - cmake ..
 | 
			
		||||
  - cmake --build .
 | 
			
		||||
  - export GTEST_OUTPUT="xml:report.xml"
 | 
			
		||||
  - ls -la
 | 
			
		||||
  - ls -ls test
 | 
			
		||||
  - "./test/RoboidControlTest"
 | 
			
		||||
  artifacts:
 | 
			
		||||
    when: always
 | 
			
		||||
    reports:
 | 
			
		||||
      junit: build/report.xml
 | 
			
		||||
sast:
 | 
			
		||||
  stage: test
 | 
			
		||||
include:
 | 
			
		||||
- template: Security/SAST.gitlab-ci.yml
 | 
			
		||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
[submodule "float16"]
 | 
			
		||||
	path = float16
 | 
			
		||||
	url = ../float16.git
 | 
			
		||||
							
								
								
									
										2
									
								
								AbsoluteEncoder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								AbsoluteEncoder.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
#include "AbsoluteEncoder.h"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								AbsoluteEncoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								AbsoluteEncoder.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "ServoMotor.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidContol {
 | 
			
		||||
 | 
			
		||||
class AbsoluteEncoder {
 | 
			
		||||
 public:
 | 
			
		||||
  AbsoluteEncoder() {}
 | 
			
		||||
 | 
			
		||||
  virtual Angle16 GetActualAngle() = 0;
 | 
			
		||||
  virtual float GetActualVelocity() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidContol
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
							
								
								
									
										5
									
								
								Accelerometer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Accelerometer.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
#include "Accelerometer.h"
 | 
			
		||||
 | 
			
		||||
Accelerometer::Accelerometer() {}
 | 
			
		||||
 | 
			
		||||
Spherical Accelerometer::GetVector() { return Spherical(); }
 | 
			
		||||
							
								
								
									
										18
									
								
								Accelerometer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Accelerometer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "LinearAlgebra/Spherical.h"
 | 
			
		||||
#include "Sensor.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
class Accelerometer : public Sensor {
 | 
			
		||||
public:
 | 
			
		||||
  Accelerometer();
 | 
			
		||||
 | 
			
		||||
  virtual Spherical GetVector();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace RoboidControl
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::RoboidControl;
 | 
			
		||||
							
								
								
									
										46
									
								
								Activation.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Activation.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
#include "Activation.h"
 | 
			
		||||
 | 
			
		||||
float Activation::HeavisideStep(float inputValue, float bias) {
 | 
			
		||||
  return (inputValue + bias > 0) ? 1.0F : 0.0F;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Activation::Tanh(float inputValue) {
 | 
			
		||||
    return (exp(inputValue) - exp(-inputValue)) / (exp(inputValue) + exp(-inputValue));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Activation::Sigmoid(float inputValue) {
 | 
			
		||||
    return 1 / (1 + expf(-inputValue));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Activation::Linear(float inputValue, float minValue, float range) {
 | 
			
		||||
  if (inputValue > minValue + range)
 | 
			
		||||
    return 0;
 | 
			
		||||
  if (inputValue < minValue)
 | 
			
		||||
    return 1;
 | 
			
		||||
 | 
			
		||||
  float f = (inputValue - minValue) * (1 / range);  // normalize to 1..0
 | 
			
		||||
  float influence = 1 - f;             // invert
 | 
			
		||||
  return influence;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
float Activation::Quadratic(float inputValue, float minValue, float range) {
 | 
			
		||||
  if (inputValue > minValue + range)
 | 
			
		||||
    return 0;
 | 
			
		||||
  if (inputValue < minValue)
 | 
			
		||||
    return 1;
 | 
			
		||||
 | 
			
		||||
  float f = (inputValue - minValue) * (1 / range);  // normalize to 1..0
 | 
			
		||||
  float influence = 1 - (f * f);       // quadratic & invert
 | 
			
		||||
  return influence;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Activation::ParticleLife(float minValue, float maxValue, float attraction, float inputValue) {
 | 
			
		||||
  if (inputValue < minValue)
 | 
			
		||||
    return inputValue / minValue - 1;
 | 
			
		||||
 | 
			
		||||
  if (inputValue < maxValue)
 | 
			
		||||
    return attraction * (1 - fabs(2 * inputValue - minValue - maxValue) / (maxValue - minValue));
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								Activation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Activation.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
#ifndef RC_ACTIVATION_H
 | 
			
		||||
#define RC_ACTIVATION_H
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief Activation function for control
 | 
			
		||||
/// @note This is mainly for future use :-)
 | 
			
		||||
class Activation {
 | 
			
		||||
public:
 | 
			
		||||
  static float HeavisideStep(float inputValue, float bias = 0); // Range: {0,1}
 | 
			
		||||
 | 
			
		||||
  static float Tanh(float inputValue); // Range: (-1, 1)
 | 
			
		||||
 | 
			
		||||
  static float Sigmoid(float inputValue); // Range: (0, 1)
 | 
			
		||||
 | 
			
		||||
  static float Linear(float inputValue, float bias = 0, float range = 0);
 | 
			
		||||
 | 
			
		||||
  static float Quadratic(float inputValue, float bias = 0,
 | 
			
		||||
                         float range = 0); // minValue = bias
 | 
			
		||||
 | 
			
		||||
  static float ParticleLife(float minValue, float maxValue, float attraction,
 | 
			
		||||
                            float inputValue); // minValue = bias
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace RoboidControl
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::RoboidControl;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,135 +0,0 @@
 | 
			
		||||
#include "ArduinoParticipant.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(NO_STD)
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO)
 | 
			
		||||
#if defined(ARDUINO_ARCH_ESP8266)
 | 
			
		||||
#include <ESP8266WiFi.h>
 | 
			
		||||
 | 
			
		||||
#elif defined(ESP32)
 | 
			
		||||
#include <WiFi.h>
 | 
			
		||||
 | 
			
		||||
#elif defined(UNO_R4)
 | 
			
		||||
#include <WiFi.h>
 | 
			
		||||
 | 
			
		||||
#elif defined(ARDUINO_ARCH_RP2040)  // not functional, for future use
 | 
			
		||||
#include <WifiNINA.h>
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO) && defined(HAS_WIFI)
 | 
			
		||||
WiFiUDP* udp;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void ParticipantUDP::Setup() {
 | 
			
		||||
#if defined(ARDUINO) && defined(HAS_WIFI)
 | 
			
		||||
  GetBroadcastAddress();
 | 
			
		||||
 | 
			
		||||
#if defined(UNO_R4)
 | 
			
		||||
  if (WiFi.status() == WL_NO_MODULE) {
 | 
			
		||||
#if !defined(NO_STD)
 | 
			
		||||
    std::cout << "No network available!\n";
 | 
			
		||||
#endif
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
#else
 | 
			
		||||
  if (WiFi.isConnected() == false) {
 | 
			
		||||
    std::cout << "No network available!\n";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  udp = new WiFiUDP();
 | 
			
		||||
  udp->begin(this->port);
 | 
			
		||||
 | 
			
		||||
#if !defined(NO_STD)
 | 
			
		||||
  std::cout << "Wifi sync started local " << this->port;
 | 
			
		||||
  if (this->remoteSite != nullptr)
 | 
			
		||||
    std::cout << ", remote " << this->remoteSite->ipAddress << ":"
 | 
			
		||||
              << this->remoteSite->port << "\n";
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ParticipantUDP::GetBroadcastAddress() {
 | 
			
		||||
#if defined(ARDUINO) && defined(HAS_WIFI)
 | 
			
		||||
  IPAddress broadcastAddress = WiFi.localIP();
 | 
			
		||||
  broadcastAddress[3] = 255;
 | 
			
		||||
  String broadcastIpString = broadcastAddress.toString();
 | 
			
		||||
  this->broadcastIpAddress = new char[broadcastIpString.length() + 1];
 | 
			
		||||
  broadcastIpString.toCharArray(this->broadcastIpAddress,
 | 
			
		||||
                                broadcastIpString.length() + 1);
 | 
			
		||||
#if !defined(NO_STD)
 | 
			
		||||
  std::cout << "Broadcast address: " << broadcastIpAddress << "\n";
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ParticipantUDP::Receive() {
 | 
			
		||||
#if defined(ARDUINO) && defined(HAS_WIFI)
 | 
			
		||||
  int packetSize = udp->parsePacket();
 | 
			
		||||
  while (packetSize > 0) {
 | 
			
		||||
    udp->read(buffer, packetSize);
 | 
			
		||||
 | 
			
		||||
    String senderAddress = udp->remoteIP().toString();
 | 
			
		||||
    char sender_ipAddress[16];
 | 
			
		||||
    senderAddress.toCharArray(sender_ipAddress, 16);
 | 
			
		||||
    unsigned int sender_port = udp->remotePort();
 | 
			
		||||
 | 
			
		||||
    ReceiveData(packetSize, sender_ipAddress, sender_port);
 | 
			
		||||
    packetSize = udp->parsePacket();
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ParticipantUDP::Send(Participant* remoteParticipant, int bufferSize) {
 | 
			
		||||
#if defined(ARDUINO) && defined(HAS_WIFI)
 | 
			
		||||
  // std::cout << "Sending to:\n " << remoteParticipant->ipAddress << ":"
 | 
			
		||||
  // << remoteParticipant->port << "\n";
 | 
			
		||||
 | 
			
		||||
  int n = 0;
 | 
			
		||||
  int r = 0;
 | 
			
		||||
  do {
 | 
			
		||||
    if (n > 0) {
 | 
			
		||||
#if !defined(NO_STD)
 | 
			
		||||
      std::cout << "Retry sending\n";
 | 
			
		||||
#endif
 | 
			
		||||
      delay(10);
 | 
			
		||||
    }
 | 
			
		||||
    n++;
 | 
			
		||||
 | 
			
		||||
    udp->beginPacket(remoteParticipant->ipAddress, remoteParticipant->port);
 | 
			
		||||
    udp->write((unsigned char*)buffer, bufferSize);
 | 
			
		||||
    r = udp->endPacket();
 | 
			
		||||
    // On an Uno R4 WiFi, endPacket blocks for 10 seconds the first time
 | 
			
		||||
    // It is not cleary yet why
 | 
			
		||||
  } while (r == 0 && n < 10);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ParticipantUDP::Publish(IMessage* msg) {
 | 
			
		||||
#if defined(ARDUINO) && defined(HAS_WIFI)
 | 
			
		||||
  int bufferSize = msg->Serialize((char*)this->buffer);
 | 
			
		||||
  if (bufferSize <= 0)
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
  udp->beginPacket(this->broadcastIpAddress, this->port);
 | 
			
		||||
  udp->write((unsigned char*)buffer, bufferSize);
 | 
			
		||||
  udp->endPacket();
 | 
			
		||||
 | 
			
		||||
  //   std::cout << "Publish to " << this->broadcastIpAddress << ":"
 | 
			
		||||
  //             << this->remotePort << "\n";
 | 
			
		||||
#endif
 | 
			
		||||
  return true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,22 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "Participants/ParticipantUDP.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
class ParticipantUDP : public RoboidControl::ParticipantUDP {
 | 
			
		||||
 public:
 | 
			
		||||
  void Setup();
 | 
			
		||||
  void Receive();
 | 
			
		||||
  bool Send(Participant* remoteParticipant, int bufferSize);
 | 
			
		||||
  bool Publish(IMessage* msg);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  char* broadcastIpAddress = nullptr;
 | 
			
		||||
 | 
			
		||||
  void GetBroadcastAddress();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,218 +0,0 @@
 | 
			
		||||
#include "ArduinoUtils.h"
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO)
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO_ARCH_ESP8266)
 | 
			
		||||
#include <ESP8266WiFi.h>
 | 
			
		||||
#include <ESP8266httpUpdate.h>
 | 
			
		||||
#include <HTTPClient.h>
 | 
			
		||||
 | 
			
		||||
#elif defined(ESP32)
 | 
			
		||||
#include <HTTPClient.h>
 | 
			
		||||
#include <HTTPUpdate.h>
 | 
			
		||||
#include <WiFi.h>
 | 
			
		||||
 | 
			
		||||
#elif defined(UNO_R4)
 | 
			
		||||
#include <WiFi.h>
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const char* hotspotSSID = "Roboid";
 | 
			
		||||
const char* hotspotPassword = "alchemy7000";
 | 
			
		||||
 | 
			
		||||
#if ESP32
 | 
			
		||||
// Flash storage
 | 
			
		||||
#include "Preferences.h"
 | 
			
		||||
 | 
			
		||||
#define PREFERENCES_NAMESPACE "roboidControl"
 | 
			
		||||
Preferences wifiPreferences;
 | 
			
		||||
 | 
			
		||||
#define STORAGE_KEY_WIFI "rc/wifi"
 | 
			
		||||
struct WifiCredentials {
 | 
			
		||||
  char ssid[32] = "\0";
 | 
			
		||||
  char password[32] = "\0";
 | 
			
		||||
} credentials;
 | 
			
		||||
 | 
			
		||||
#define STORAGE_KEY_NSS "rc/nss"
 | 
			
		||||
struct NssServer {
 | 
			
		||||
  char ipAddress[16] = "127.0.0.1\0";
 | 
			
		||||
  unsigned short port = 7681;
 | 
			
		||||
} nssServer;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
bool StartWifi(const char* wifiSsid,
 | 
			
		||||
               const char* wifiPassword,
 | 
			
		||||
               bool hotspotFallback) {
 | 
			
		||||
#if !defined(HAS_WIFI)
 | 
			
		||||
  return false;
 | 
			
		||||
#else
 | 
			
		||||
#if defined(UNO_R4) || defined(ARDUINO_ARCH_RP2040)
 | 
			
		||||
  if (WiFi.status() == WL_NO_MODULE) {
 | 
			
		||||
    Serial.println("WiFi not present, WiFiSync is disabled");
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if ESP32
 | 
			
		||||
  printf("Connecting to WiFi %s\n", wifiSsid);
 | 
			
		||||
#else
 | 
			
		||||
  Serial.print("Connecting to WiFi ");
 | 
			
		||||
  Serial.println(wifiSsid);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // Connect to Wifi
 | 
			
		||||
  WiFi.begin(wifiSsid, wifiPassword);
 | 
			
		||||
  uint32_t notConnectedCounter = 0;
 | 
			
		||||
  bool connected = false;
 | 
			
		||||
  bool hotSpotEnabled = false;
 | 
			
		||||
 | 
			
		||||
  while (WiFi.status() != WL_CONNECTED && !hotSpotEnabled) {
 | 
			
		||||
#if ESP32
 | 
			
		||||
    printf(".");
 | 
			
		||||
#else
 | 
			
		||||
    Serial.print(".");
 | 
			
		||||
#endif
 | 
			
		||||
    delay(500);
 | 
			
		||||
 | 
			
		||||
    notConnectedCounter++;
 | 
			
		||||
    if (notConnectedCounter > 20 && hotspotFallback) {
 | 
			
		||||
#if ESP32
 | 
			
		||||
      printf("\nCould not connect to home network.\n");
 | 
			
		||||
#else
 | 
			
		||||
      Serial.println();
 | 
			
		||||
      Serial.println("Could not connect to home network");
 | 
			
		||||
#endif
 | 
			
		||||
      WiFi.disconnect();
 | 
			
		||||
      if (hotspotFallback) {
 | 
			
		||||
#if ESP32
 | 
			
		||||
        WiFi.mode(WIFI_OFF);
 | 
			
		||||
        WiFi.mode(WIFI_AP);
 | 
			
		||||
        IPAddress wifiMyIp(192, 168, 4, 1);
 | 
			
		||||
        WiFi.softAPConfig(wifiMyIp, wifiMyIp, IPAddress(255, 255, 255, 0));
 | 
			
		||||
 | 
			
		||||
        WiFi.softAP(hotspotSSID, hotspotPassword);
 | 
			
		||||
#elif UNO_R4 || ARDUINO_ARCH_RP2040
 | 
			
		||||
        WiFi.beginAP(hotspotSSID);
 | 
			
		||||
#endif
 | 
			
		||||
        printf("Setup WiFi hotspot...\n");
 | 
			
		||||
        // printf("ssid = %s, password = %s\n", hotspotSSID, hotspotPassword);
 | 
			
		||||
#if ARDUINO_ARCH_RP2040
 | 
			
		||||
        String ipAddress = WiFi.localIP().toString();
 | 
			
		||||
#else
 | 
			
		||||
        String ipAddress = WiFi.softAPIP().toString();
 | 
			
		||||
#endif
 | 
			
		||||
        char buf[20];
 | 
			
		||||
        ipAddress.toCharArray(buf, 20);
 | 
			
		||||
        printf("IP address: %s\n", buf);
 | 
			
		||||
        hotSpotEnabled = true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  connected = notConnectedCounter <= 20;
 | 
			
		||||
 | 
			
		||||
  if (connected) {
 | 
			
		||||
    char buf[20];
 | 
			
		||||
    String ipAddress = WiFi.localIP().toString();
 | 
			
		||||
    ipAddress.toCharArray(buf, 20);
 | 
			
		||||
#if ESP32 || ESP8266
 | 
			
		||||
    printf("\nWifi connected, IP address: %s\n", buf);
 | 
			
		||||
#else
 | 
			
		||||
    Serial.println();
 | 
			
		||||
    Serial.println("Wifi connected");
 | 
			
		||||
#endif
 | 
			
		||||
#if ESP32
 | 
			
		||||
    printf("Checking credentials in flash\n");
 | 
			
		||||
    wifiPreferences.begin(PREFERENCES_NAMESPACE);
 | 
			
		||||
    wifiPreferences.getBytes(STORAGE_KEY_WIFI, &credentials,
 | 
			
		||||
                             sizeof(credentials));
 | 
			
		||||
    if (strcmp(wifiSsid, credentials.ssid) != 0 ||
 | 
			
		||||
        strcmp(wifiPassword, credentials.password) != 0) {
 | 
			
		||||
      printf("Updating credentials in flash...");
 | 
			
		||||
      const int ssidLen = strlen(wifiSsid);
 | 
			
		||||
      if (ssidLen < 32) {
 | 
			
		||||
        memcpy(credentials.ssid, wifiSsid, ssidLen);
 | 
			
		||||
        credentials.ssid[ssidLen] = '\0';
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const int pwdLen = strlen(wifiPassword);
 | 
			
		||||
      if (pwdLen < 32) {
 | 
			
		||||
        memcpy(credentials.password, wifiPassword, pwdLen);
 | 
			
		||||
        credentials.password[pwdLen] = '\0';
 | 
			
		||||
      }
 | 
			
		||||
      wifiPreferences.putBytes(STORAGE_KEY_WIFI, &credentials,
 | 
			
		||||
                               sizeof(credentials));
 | 
			
		||||
      printf(" completed.\n");
 | 
			
		||||
    }
 | 
			
		||||
    wifiPreferences.end();
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (!hotSpotEnabled);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CheckFirmware(String url, String FIRMWARE_NAME, int FIRMWARE_VERSION) {
 | 
			
		||||
#if !defined(HAS_WIFI)
 | 
			
		||||
  return;
 | 
			
		||||
#else
 | 
			
		||||
#if defined(UNO_R4)  // Uno R4 Wifi does not support this kind of firmware
 | 
			
		||||
                     // update (as far as I know)
 | 
			
		||||
  return;
 | 
			
		||||
#else
 | 
			
		||||
  Serial.println("Checking for firmware updates.");
 | 
			
		||||
 | 
			
		||||
  WiFiClient client;
 | 
			
		||||
  HTTPClient httpClient;
 | 
			
		||||
  String versionURL = url + FIRMWARE_NAME + ".version";
 | 
			
		||||
  httpClient.begin(client, versionURL);
 | 
			
		||||
  int httpCode = httpClient.GET();
 | 
			
		||||
  if (httpCode == 200) {
 | 
			
		||||
    String newFWVersion = httpClient.getString();
 | 
			
		||||
 | 
			
		||||
    Serial.print("Current firmware version: ");
 | 
			
		||||
    Serial.println(FIRMWARE_VERSION);
 | 
			
		||||
    Serial.print("Available firmware version: ");
 | 
			
		||||
    Serial.println(newFWVersion);
 | 
			
		||||
 | 
			
		||||
    int newVersion = newFWVersion.toInt();
 | 
			
		||||
 | 
			
		||||
    if (newVersion > FIRMWARE_VERSION) {
 | 
			
		||||
      Serial.println("Preparing to update firmware.");
 | 
			
		||||
 | 
			
		||||
      String firmwareURL = url + FIRMWARE_NAME + ".bin";
 | 
			
		||||
#if defined(ESP32)
 | 
			
		||||
      t_httpUpdate_return ret = httpUpdate.update(client, firmwareURL);
 | 
			
		||||
#else
 | 
			
		||||
      t_httpUpdate_return ret = ESPhttpUpdate.update(client, firmwareURL);
 | 
			
		||||
#endif
 | 
			
		||||
      switch (ret) {
 | 
			
		||||
        case HTTP_UPDATE_FAILED:
 | 
			
		||||
#if defined(ESP32)
 | 
			
		||||
          Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s",
 | 
			
		||||
                        httpUpdate.getLastError(),
 | 
			
		||||
                        httpUpdate.getLastErrorString().c_str());
 | 
			
		||||
#else
 | 
			
		||||
          Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s",
 | 
			
		||||
                        ESPhttpUpdate.getLastError(),
 | 
			
		||||
                        ESPhttpUpdate.getLastErrorString().c_str());
 | 
			
		||||
#endif
 | 
			
		||||
          break;
 | 
			
		||||
        case HTTP_UPDATE_NO_UPDATES:
 | 
			
		||||
          Serial.println("HTTP_UPDATE_NO_UPDATES");
 | 
			
		||||
          break;
 | 
			
		||||
        case HTTP_UPDATE_OK:
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      Serial.println("No Firmware update necessary.");
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    Serial.print("Http Error: ");
 | 
			
		||||
    Serial.println(httpCode);
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,10 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#if defined(ARDUINO)
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
bool StartWifi(const char *wifiSsid, const char *wifiPassword,
 | 
			
		||||
               bool hotspotFallback = false);
 | 
			
		||||
 | 
			
		||||
void CheckFirmware(String url, String FIRMWARE_NAME, int FIRMWARE_VERSION);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,135 +0,0 @@
 | 
			
		||||
#include "DRV8833.h"
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
#pragma region DRV8833
 | 
			
		||||
 | 
			
		||||
DRV8833::DRV8833(Configuration config, Thing* parent) : Thing(Type::Undetermined, parent) {
 | 
			
		||||
  this->pinStandby = config.standby;
 | 
			
		||||
  if (pinStandby != 255)
 | 
			
		||||
    pinMode(pinStandby, OUTPUT);
 | 
			
		||||
 | 
			
		||||
  this->motorA = new DRV8833Motor(this, config.AIn1, config.AIn2);
 | 
			
		||||
  this->motorA->SetName("Motor A");
 | 
			
		||||
  this->motorB = new DRV8833Motor(this, config.BIn1, config.BIn2);
 | 
			
		||||
  this->motorB->SetName("Motor B");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion DRV8833
 | 
			
		||||
 | 
			
		||||
#pragma region Differential drive
 | 
			
		||||
 | 
			
		||||
DRV8833::DifferentialDrive::DifferentialDrive(DRV8833::Configuration config,
 | 
			
		||||
                                              Thing* parent)
 | 
			
		||||
    : RoboidControl::DifferentialDrive(this->drv8833.motorA,
 | 
			
		||||
                                       this->drv8833.motorB,
 | 
			
		||||
                                       parent),
 | 
			
		||||
      drv8833(config, this) {}
 | 
			
		||||
 | 
			
		||||
void DRV8833::DifferentialDrive::Update(bool recurse) {
 | 
			
		||||
  RoboidControl::DifferentialDrive::Update(recurse);
 | 
			
		||||
  this->drv8833.Update(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion Differential drive
 | 
			
		||||
 | 
			
		||||
#pragma region Motor
 | 
			
		||||
 | 
			
		||||
#if (ESP32)
 | 
			
		||||
uint8_t DRV8833Motor::nextAvailablePwmChannel = 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
DRV8833Motor::DRV8833Motor(DRV8833* driver,
 | 
			
		||||
                           unsigned char pinIn1,
 | 
			
		||||
                           unsigned char pinIn2,
 | 
			
		||||
                           bool reverse)
 | 
			
		||||
    : Motor() {
 | 
			
		||||
  this->SetParent(driver);
 | 
			
		||||
 | 
			
		||||
  this->pinIn1 = pinIn1;
 | 
			
		||||
  this->pinIn2 = pinIn2;
 | 
			
		||||
 | 
			
		||||
#if (ESP32)
 | 
			
		||||
  in1Ch = DRV8833Motor::nextAvailablePwmChannel++;
 | 
			
		||||
  ledcSetup(in1Ch, 500, 8);
 | 
			
		||||
  ledcAttachPin(pinIn1, in1Ch);
 | 
			
		||||
 | 
			
		||||
  in2Ch = DRV8833Motor::nextAvailablePwmChannel++;
 | 
			
		||||
  ledcSetup(in2Ch, 500, 8);
 | 
			
		||||
  ledcAttachPin(pinIn2, in2Ch);
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
  pinMode(pinIn1, OUTPUT);  // configure the in1 pin to output mode
 | 
			
		||||
  pinMode(pinIn2, OUTPUT);  // configure the in1 pin to output mode
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  // this->reverse = reverse;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// void DRV8833Motor::SetMaxRPM(unsigned int rpm) {
 | 
			
		||||
//   this->maxRpm = rpm;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
void DRV8833Motor::SetTargetVelocity(float motorSpeed) {
 | 
			
		||||
  Motor::SetTargetVelocity(motorSpeed);
 | 
			
		||||
 | 
			
		||||
  uint8_t motorSignal =
 | 
			
		||||
      (uint8_t)(motorSpeed > 0 ? motorSpeed * 255 : -motorSpeed * 255);
 | 
			
		||||
 | 
			
		||||
  // std::cout << "moto speed " << this->name << " = " << motorSpeed
 | 
			
		||||
  //           << ", motor signal = " << (int)motorSignal << "\n";
 | 
			
		||||
 | 
			
		||||
#if (ESP32)
 | 
			
		||||
  if (motorSpeed == 0) {  // stop
 | 
			
		||||
    ledcWrite(in1Ch, 0);
 | 
			
		||||
    ledcWrite(in2Ch, 0);
 | 
			
		||||
 | 
			
		||||
  } else if (motorSpeed > 0) {  // forward
 | 
			
		||||
#if FAST_DECAY
 | 
			
		||||
    ledcWrite(in1Ch, motorSignal);
 | 
			
		||||
    ledcWrite(in2Ch, 0);
 | 
			
		||||
#else
 | 
			
		||||
    ledcWrite(in1Ch, 255);
 | 
			
		||||
    ledcWrite(in2Ch, 255 - motorSignal);
 | 
			
		||||
#endif
 | 
			
		||||
  } else {  // (motorSpeed < 0) reverse
 | 
			
		||||
#if FAST_DECAY
 | 
			
		||||
    ledcWrite(in1Ch, 0);
 | 
			
		||||
    ledcWrite(in2Ch, motorSignal);
 | 
			
		||||
#else
 | 
			
		||||
    ledcWrite(in1Ch, 255 - motorSignal);
 | 
			
		||||
    ledcWrite(in2Ch, 255);
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
#else  // not ESP32
 | 
			
		||||
  if (motorSpeed == 0) {  // stop
 | 
			
		||||
    analogWrite(pinIn1, 0);
 | 
			
		||||
    analogWrite(pinIn2, 0);
 | 
			
		||||
 | 
			
		||||
  } else if (motorSpeed > 0) {  // forward
 | 
			
		||||
#if FAST_DECAY
 | 
			
		||||
    analogWrite(pinIn1, motorSignal);
 | 
			
		||||
    analogWrite(pinIn2, 0);
 | 
			
		||||
#else
 | 
			
		||||
    analogWrite(pinIn1, 255);
 | 
			
		||||
    analogWrite(pinIn2, 255 - motorSignal);
 | 
			
		||||
#endif
 | 
			
		||||
  } else {  // (motorSpeed < 0) reverse
 | 
			
		||||
#if FAST_DECAY
 | 
			
		||||
    analogWrite(pinIn1, 0);
 | 
			
		||||
    analogWrite(pinIn2, motorSignal);
 | 
			
		||||
#else
 | 
			
		||||
    analogWrite(pinIn1, 255 - motorSignal);
 | 
			
		||||
    analogWrite(pinIn2, 255);
 | 
			
		||||
#endif
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion Motor
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,85 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#include "Participants/IsolatedParticipant.h"
 | 
			
		||||
#include "Thing.h"
 | 
			
		||||
#include "Things/DifferentialDrive.h"
 | 
			
		||||
#include "Things/Motor.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
class DRV8833Motor;
 | 
			
		||||
 | 
			
		||||
class DRV8833 : public Thing {
 | 
			
		||||
 public:
 | 
			
		||||
  struct Configuration {
 | 
			
		||||
    int AIn1;
 | 
			
		||||
    int AIn2;
 | 
			
		||||
    int BIn1;
 | 
			
		||||
    int BIn2;
 | 
			
		||||
    int standby = 255;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /// @brief Setup a DRV8833 motor controller
 | 
			
		||||
  DRV8833(Configuration config, Thing* parent = Thing::LocalRoot());
 | 
			
		||||
 | 
			
		||||
  DRV8833Motor* motorA = nullptr;
 | 
			
		||||
  DRV8833Motor* motorB = nullptr;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  unsigned char pinStandby = 255;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  class DifferentialDrive;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma region Differential drive
 | 
			
		||||
 | 
			
		||||
class DRV8833::DifferentialDrive : public RoboidControl::DifferentialDrive {
 | 
			
		||||
 public:
 | 
			
		||||
  DifferentialDrive(DRV8833::Configuration config, Thing* parent = Thing::LocalRoot());
 | 
			
		||||
 | 
			
		||||
  virtual void Update(bool recurse = false) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  DRV8833 drv8833;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma endregion Differential drive
 | 
			
		||||
 | 
			
		||||
#pragma region Motor
 | 
			
		||||
 | 
			
		||||
/// @brief Support for a DRV8833 motor controller
 | 
			
		||||
class DRV8833Motor : public Motor {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief Setup the DC motor
 | 
			
		||||
  /// @param pinIn1 the pin number for the in1 signal
 | 
			
		||||
  /// @param pinIn2 the pin number for the in2 signal
 | 
			
		||||
  /// @param direction the forward turning direction of the motor
 | 
			
		||||
  DRV8833Motor(DRV8833* driver,
 | 
			
		||||
               unsigned char pinIn1,
 | 
			
		||||
               unsigned char pinIn2,
 | 
			
		||||
               bool reverse = false);
 | 
			
		||||
  // void SetMaxRPM(unsigned int rpm);
 | 
			
		||||
 | 
			
		||||
  // virtual void SetAngularVelocity(Spherical velocity) override;
 | 
			
		||||
  virtual void SetTargetVelocity(float targetSpeed) override;
 | 
			
		||||
  // bool reverse = false;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  unsigned char pinIn1 = 255;
 | 
			
		||||
  unsigned char pinIn2 = 255;
 | 
			
		||||
  // unsigned int maxRpm = 200;
 | 
			
		||||
 | 
			
		||||
#if (ESP32)
 | 
			
		||||
  uint8_t in1Ch;
 | 
			
		||||
  uint8_t in2Ch;
 | 
			
		||||
  static uint8_t nextAvailablePwmChannel;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma endregion Motor
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,129 +0,0 @@
 | 
			
		||||
#include "DigitalInput.h"
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
#pragma region Digital input
 | 
			
		||||
 | 
			
		||||
DigitalInput::DigitalInput(unsigned char pin, Thing* parent)
 | 
			
		||||
    : Thing(Type::Undetermined, parent) {
 | 
			
		||||
  this->pin = pin;
 | 
			
		||||
  pinMode(this->pin, INPUT);
 | 
			
		||||
  std::cout << "digital input start\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DigitalInput::Update(bool recursive) {
 | 
			
		||||
  this->isHigh = digitalRead(this->pin);
 | 
			
		||||
  this->isLow = !this->isHigh;
 | 
			
		||||
  Thing::Update(recursive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion Digital input
 | 
			
		||||
 | 
			
		||||
#pragma region Touch sensor
 | 
			
		||||
 | 
			
		||||
DigitalInput::TouchSensor::TouchSensor(unsigned char pin, Thing* parent)
 | 
			
		||||
    : RoboidControl::TouchSensor(parent), digitalInput(pin, parent) {}
 | 
			
		||||
 | 
			
		||||
void DigitalInput::TouchSensor::Update(bool recursive) {
 | 
			
		||||
  this->touchedSomething = digitalInput.isLow;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma endregion Touch sensor
 | 
			
		||||
 | 
			
		||||
#pragma region Relative encoder
 | 
			
		||||
 | 
			
		||||
int DigitalInput::RelativeEncoder::interruptCount = 0;
 | 
			
		||||
volatile int DigitalInput::RelativeEncoder::pulseCount0 = 0;
 | 
			
		||||
volatile int DigitalInput::RelativeEncoder::pulseCount1 = 0;
 | 
			
		||||
 | 
			
		||||
DigitalInput::RelativeEncoder::RelativeEncoder(Configuration config,
 | 
			
		||||
                                               Thing* parent)
 | 
			
		||||
    : RoboidControl::RelativeEncoder(parent),
 | 
			
		||||
      digitalInput(config.pin, parent),
 | 
			
		||||
      pulsesPerRevolution(config.pulsesPerRevolution) {}
 | 
			
		||||
 | 
			
		||||
void DigitalInput::RelativeEncoder::Start() {
 | 
			
		||||
  // We support up to 2 pulse counters
 | 
			
		||||
  if (interruptCount == 0) {
 | 
			
		||||
    std::cout << "pin interrupt 1 activated" << std::endl;
 | 
			
		||||
    attachInterrupt(digitalPinToInterrupt(digitalInput.pin), PulseInterrupt0,
 | 
			
		||||
                    RISING);
 | 
			
		||||
  } else if (interruptCount == 1) {
 | 
			
		||||
    std::cout << "pin interrupt 2 activated" << std::endl;
 | 
			
		||||
    attachInterrupt(digitalPinToInterrupt(digitalInput.pin), PulseInterrupt1,
 | 
			
		||||
                    RISING);
 | 
			
		||||
  } else {
 | 
			
		||||
    // maximum interrupt count reached
 | 
			
		||||
    std::cout << "DigitalInput::RelativeEncoder: max. # counters of 2 reached"
 | 
			
		||||
              << std::endl;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  interruptIx = interruptCount;
 | 
			
		||||
  interruptCount++;
 | 
			
		||||
  std::cout << "pin ints. " << interruptCount << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DigitalInput::RelativeEncoder::GetPulseCount() {
 | 
			
		||||
  if (interruptIx == 0) {
 | 
			
		||||
    int pulseCount = pulseCount0;
 | 
			
		||||
    pulseCount0 = 0;
 | 
			
		||||
    return pulseCount;
 | 
			
		||||
  } else if (interruptIx == 1) {
 | 
			
		||||
    int pulseCount = pulseCount1;
 | 
			
		||||
    pulseCount1 = 0;
 | 
			
		||||
    return pulseCount;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DigitalInput::RelativeEncoder::Update(bool recursive) {
 | 
			
		||||
  unsigned long currentTimeMs = GetTimeMs();
 | 
			
		||||
  if (this->lastUpdateTime == 0) {
 | 
			
		||||
    this->Start();
 | 
			
		||||
    this->lastUpdateTime = currentTimeMs;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  float timeStep = (float)(currentTimeMs - this->lastUpdateTime) / 1000.0f;
 | 
			
		||||
  if (timeStep <= 0)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  int pulseCount = GetPulseCount();
 | 
			
		||||
  netPulseCount += pulseCount;
 | 
			
		||||
 | 
			
		||||
  this->pulseFrequency = pulseCount / timeStep;
 | 
			
		||||
  this->rotationSpeed = pulseFrequency / pulsesPerRevolution;
 | 
			
		||||
 | 
			
		||||
  std::cout << "pulses: " << pulseCount << " per second " << pulseFrequency
 | 
			
		||||
            << " timestep " << timeStep << std::endl;
 | 
			
		||||
 | 
			
		||||
  this->lastUpdateTime = currentTimeMs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(ESP8266) || defined(ESP32)
 | 
			
		||||
void ICACHE_RAM_ATTR DigitalInput::RelativeEncoder::PulseInterrupt0() {
 | 
			
		||||
  pulseCount0++;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
void DigitalInput::RelativeEncoder::PulseInterrupt0() {
 | 
			
		||||
  pulseCount0++;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(ESP8266) || defined(ESP32)
 | 
			
		||||
void IRAM_ATTR DigitalInput::RelativeEncoder::PulseInterrupt1() {
 | 
			
		||||
  pulseCount1++;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
void DigitalInput::RelativeEncoder::PulseInterrupt1() {
 | 
			
		||||
  pulseCount1++;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#pragma endregion Relative encoder
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,92 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "Things/RelativeEncoder.h"
 | 
			
		||||
#include "Things/TouchSensor.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
/// @brief A digital input represents the stat of a digital GPIO pin
 | 
			
		||||
class DigitalInput : public Thing {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief Create a new digital input
 | 
			
		||||
  /// @param participant The participant to use
 | 
			
		||||
  /// @param pin The digital pin
 | 
			
		||||
  //DigitalInput(Participant* participant, unsigned char pin);
 | 
			
		||||
  // DigitalInput(Thing* parent, unsigned char pin);
 | 
			
		||||
  DigitalInput(unsigned char pin, Thing* parent);
 | 
			
		||||
 | 
			
		||||
  bool isHigh = false;
 | 
			
		||||
  bool isLow = false;
 | 
			
		||||
 | 
			
		||||
  /// @copydoc RoboidControl::Thing::Update(unsigned long currentTimeMs)
 | 
			
		||||
  virtual void Update(bool recursive = false) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /// @brief The pin used for digital input
 | 
			
		||||
  unsigned char pin = 0;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  class TouchSensor;
 | 
			
		||||
  class RelativeEncoder;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma region Touch sensor
 | 
			
		||||
 | 
			
		||||
class DigitalInput::TouchSensor : public RoboidControl::TouchSensor {
 | 
			
		||||
 public:
 | 
			
		||||
  TouchSensor(unsigned char pin, Thing* parent);
 | 
			
		||||
 | 
			
		||||
  /// @copydoc RoboidControl::Thing::Update(unsigned long currentTimeMs)
 | 
			
		||||
  virtual void Update(bool recurse = false) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  DigitalInput digitalInput;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma endregion Touch sensor
 | 
			
		||||
 | 
			
		||||
#pragma region Incremental encoder
 | 
			
		||||
 | 
			
		||||
class DigitalInput::RelativeEncoder : public RoboidControl::RelativeEncoder {
 | 
			
		||||
 public:
 | 
			
		||||
  struct Configuration {
 | 
			
		||||
    unsigned char pin;
 | 
			
		||||
    unsigned char pulsesPerRevolution;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  RelativeEncoder(Configuration config, Thing* parent = Thing::LocalRoot());
 | 
			
		||||
 | 
			
		||||
  unsigned char pulsesPerRevolution;
 | 
			
		||||
 | 
			
		||||
  /// @brief The current pulse frequency in Hz
 | 
			
		||||
  float pulseFrequency = 0;
 | 
			
		||||
 | 
			
		||||
  /// @copydoc RoboidControl::Thing::Update()
 | 
			
		||||
  virtual void Update(bool recurse = false) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  DigitalInput digitalInput;
 | 
			
		||||
 | 
			
		||||
  int interruptIx = 0;
 | 
			
		||||
 | 
			
		||||
  static int interruptCount;
 | 
			
		||||
 | 
			
		||||
  volatile static int pulseCount0;
 | 
			
		||||
  static void PulseInterrupt0();
 | 
			
		||||
 | 
			
		||||
  volatile static int pulseCount1;
 | 
			
		||||
  static void PulseInterrupt1();
 | 
			
		||||
 | 
			
		||||
  int GetPulseCount();
 | 
			
		||||
  long netPulseCount = 0;
 | 
			
		||||
  unsigned long lastUpdateTime = 0;
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  void Start();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma endregion Incremental encoder
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,74 +0,0 @@
 | 
			
		||||
#include "UltrasonicSensor.h"
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
UltrasonicSensor::UltrasonicSensor(Configuration config, Thing* parent)
 | 
			
		||||
    : Thing(Type::Undetermined, parent) {
 | 
			
		||||
  this->name = "Ultrasonic sensor";
 | 
			
		||||
  this->pinTrigger = config.trigger;
 | 
			
		||||
  this->pinEcho = config.echo;
 | 
			
		||||
 | 
			
		||||
  pinMode(pinTrigger, OUTPUT);  // configure the trigger pin to output mode
 | 
			
		||||
  pinMode(pinEcho, INPUT);      // configure the echo pin to input mode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float UltrasonicSensor::GetDistance() {
 | 
			
		||||
  // Start the ultrasonic 'ping'
 | 
			
		||||
  digitalWrite(pinTrigger, LOW);
 | 
			
		||||
  delayMicroseconds(2);
 | 
			
		||||
  digitalWrite(pinTrigger, HIGH);
 | 
			
		||||
  delayMicroseconds(10);
 | 
			
		||||
  digitalWrite(pinTrigger, LOW);
 | 
			
		||||
 | 
			
		||||
  // Measure the duration of the pulse on the echo pin
 | 
			
		||||
  unsigned long duration_us =
 | 
			
		||||
      pulseIn(pinEcho, HIGH, 10000);  // the result is in microseconds
 | 
			
		||||
 | 
			
		||||
  // Calculate the distance:
 | 
			
		||||
  // * Duration should be divided by 2, because the ping goes to the object
 | 
			
		||||
  // and back again. The distance to the object is therefore half the duration
 | 
			
		||||
  // of the pulse: duration_us /= 2;
 | 
			
		||||
  // * Then we need to convert from microseconds to seconds: duration_sec =
 | 
			
		||||
  // duration_us / 1000000;
 | 
			
		||||
  // * Now we calculate the distance based on the speed of sound (340 m/s):
 | 
			
		||||
  // distance = duration_sec * 340;
 | 
			
		||||
  // * The result calculation is therefore:
 | 
			
		||||
  this->distance = (float)duration_us / 2 / 1000000 * 340;
 | 
			
		||||
 | 
			
		||||
  // Serial.println(this->distance);
 | 
			
		||||
 | 
			
		||||
  // std::cout << "US distance " << this->distance << std::endl;
 | 
			
		||||
 | 
			
		||||
  // Filter faulty measurements. The sensor can often give values > 30 m which
 | 
			
		||||
  // are not correct
 | 
			
		||||
  // if (distance > 30)
 | 
			
		||||
  //   distance = 0;
 | 
			
		||||
 | 
			
		||||
  return this->distance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UltrasonicSensor::Update(bool recursive) {
 | 
			
		||||
  GetDistance();
 | 
			
		||||
  Thing::Update(recursive);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma region Touch sensor
 | 
			
		||||
 | 
			
		||||
UltrasonicSensor::TouchSensor::TouchSensor(Configuration config, Thing* parent)
 | 
			
		||||
    : RoboidControl::TouchSensor(parent), ultrasonic(config, this) {}
 | 
			
		||||
 | 
			
		||||
void UltrasonicSensor::TouchSensor::Update(bool recursive) {
 | 
			
		||||
  RoboidControl::TouchSensor::Update(recursive);
 | 
			
		||||
  this->ultrasonic.Update(false);
 | 
			
		||||
  this->touchedSomething |= (this->ultrasonic.distance > 0 &&
 | 
			
		||||
                            this->ultrasonic.distance <= this->touchDistance);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#pragma region Touch sensor
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,64 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "Things/TouchSensor.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace Arduino {
 | 
			
		||||
 | 
			
		||||
/// @brief An HC-SR04 ultrasonic distance sensor
 | 
			
		||||
class UltrasonicSensor : Thing {
 | 
			
		||||
 public:
 | 
			
		||||
  struct Configuration {
 | 
			
		||||
    int trigger;
 | 
			
		||||
    int echo;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  UltrasonicSensor(Configuration config, Thing* parent = Thing::LocalRoot());
 | 
			
		||||
 | 
			
		||||
  // parameters
 | 
			
		||||
 | 
			
		||||
  /// @brief The distance at which the object is considered to be touched
 | 
			
		||||
  // float touchDistance = 0.2f;
 | 
			
		||||
 | 
			
		||||
  // state
 | 
			
		||||
 | 
			
		||||
  /// @brief The last read distance
 | 
			
		||||
  float distance = 0;
 | 
			
		||||
  /// @brief erform an ultrasonic 'ping' to determine the distance to the
 | 
			
		||||
  /// nearest object
 | 
			
		||||
  /// @return the measured distance in meters to the nearest object
 | 
			
		||||
  float GetDistance();
 | 
			
		||||
 | 
			
		||||
  /// @copydoc RoboidControl::Thing::Update(unsigned long currentTimeMs)
 | 
			
		||||
  virtual void Update(bool recursive = false) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /// @brief The pin number of the trigger signal
 | 
			
		||||
  unsigned char pinTrigger = 0;
 | 
			
		||||
  /// @brief The pin number of the echo signal
 | 
			
		||||
  unsigned char pinEcho = 0;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
  class TouchSensor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma region Touch sensor
 | 
			
		||||
 | 
			
		||||
class UltrasonicSensor::TouchSensor : public RoboidControl::TouchSensor {
 | 
			
		||||
 public:
 | 
			
		||||
  TouchSensor(UltrasonicSensor::Configuration config,
 | 
			
		||||
              Thing* parent = Thing::LocalRoot());
 | 
			
		||||
 | 
			
		||||
  float touchDistance = 0.2f;
 | 
			
		||||
 | 
			
		||||
  /// @copydoc RoboidControl::Thing::Update(unsigned long currentTimeMs)
 | 
			
		||||
  virtual void Update(bool recursive = false) override;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  UltrasonicSensor ultrasonic;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma region Touch sensor
 | 
			
		||||
 | 
			
		||||
}  // namespace Arduino
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
							
								
								
									
										101
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								CMakeLists.txt
									
									
									
									
									
								
							@ -1,64 +1,59 @@
 | 
			
		||||
cmake_minimum_required(VERSION 3.13)  # CMake version check
 | 
			
		||||
 | 
			
		||||
file(GLOB srcs 
 | 
			
		||||
    *.cpp
 | 
			
		||||
    Things/*.cpp
 | 
			
		||||
    Messages/*.cpp
 | 
			
		||||
    Arduino/*.cpp
 | 
			
		||||
    Posix/*.cpp
 | 
			
		||||
    Windows/*.cpp
 | 
			
		||||
    EspIdf/*.cpp
 | 
			
		||||
    LinearAlgebra/*.cpp
 | 
			
		||||
    Participants/*.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
if(ESP_PLATFORM)
 | 
			
		||||
    idf_component_register(
 | 
			
		||||
        SRCS ${srcs}
 | 
			
		||||
        INCLUDE_DIRS "." "LinearAlgebra"
 | 
			
		||||
        REQUIRES esp_netif esp_wifi
 | 
			
		||||
    )
 | 
			
		||||
else() 
 | 
			
		||||
    set(CMAKE_CXX_STANDARD 17)      # Enable c++11 standard
 | 
			
		||||
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 | 
			
		||||
 | 
			
		||||
    project(RoboidControl)
 | 
			
		||||
    add_subdirectory(LinearAlgebra)
 | 
			
		||||
    add_subdirectory(Examples)
 | 
			
		||||
 | 
			
		||||
    add_compile_definitions(GTEST)
 | 
			
		||||
    include(FetchContent)
 | 
			
		||||
    FetchContent_Declare(
 | 
			
		||||
        googletest
 | 
			
		||||
        DOWNLOAD_EXTRACT_TIMESTAMP ON
 | 
			
		||||
        URL https://github.com/google/googletest/archive/refs/heads/main.zip
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # For Windows: Prevent overriding the parent project's compiler/linker settings
 | 
			
		||||
    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
 | 
			
		||||
    FetchContent_MakeAvailable(googletest)
 | 
			
		||||
 | 
			
		||||
    include_directories(
 | 
			
		||||
    set(sourcedirs
 | 
			
		||||
        .
 | 
			
		||||
        LinearAlgebra
 | 
			
		||||
    )
 | 
			
		||||
    add_library(RoboidControl STATIC ${srcs})
 | 
			
		||||
    
 | 
			
		||||
    enable_testing()
 | 
			
		||||
 | 
			
		||||
    file(GLOB_RECURSE test_srcs test/*_test.cc)
 | 
			
		||||
    add_executable(
 | 
			
		||||
        RoboidControlTest
 | 
			
		||||
        ${test_srcs}
 | 
			
		||||
    )
 | 
			
		||||
    target_link_libraries(
 | 
			
		||||
        RoboidControlTest
 | 
			
		||||
        gtest_main
 | 
			
		||||
        RoboidControl
 | 
			
		||||
    set(includedirs
 | 
			
		||||
        .
 | 
			
		||||
        LinearAlgebra
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    include(GoogleTest)
 | 
			
		||||
    gtest_discover_tests(RoboidControlTest)
 | 
			
		||||
    idf_component_register(
 | 
			
		||||
        SRC_DIRS ${sourcedirs}
 | 
			
		||||
        INCLUDE_DIRS ${includedirs}
 | 
			
		||||
        REQUIRES arduino
 | 
			
		||||
    )
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
project(RoboidControl)
 | 
			
		||||
add_subdirectory(LinearAlgebra)
 | 
			
		||||
add_subdirectory(test)
 | 
			
		||||
 | 
			
		||||
set(CMAKE_CXX_STANDARD 11)
 | 
			
		||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 | 
			
		||||
 | 
			
		||||
add_compile_definitions(GTEST)
 | 
			
		||||
include(FetchContent)
 | 
			
		||||
FetchContent_Declare(
 | 
			
		||||
    googletest
 | 
			
		||||
    URL https://github.com/google/googletest/archive/refs/heads/main.zip
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# For Windows: Prevent overriding the parent project's compiler/linker settings
 | 
			
		||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
 | 
			
		||||
FetchContent_MakeAvailable(googletest)
 | 
			
		||||
 | 
			
		||||
include_directories(
 | 
			
		||||
    .
 | 
			
		||||
    LinearAlgebra
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
add_library(RoboidControl STATIC 
 | 
			
		||||
    "Roboid.cpp"
 | 
			
		||||
    "Perception.cpp"
 | 
			
		||||
    "TrackedObject.cpp"
 | 
			
		||||
    "Propulsion.cpp"
 | 
			
		||||
    "Motor.cpp"
 | 
			
		||||
    "DifferentialDrive.cpp"
 | 
			
		||||
    "DistanceSensor.cpp"
 | 
			
		||||
    "Sensor.cpp"
 | 
			
		||||
    "Switch.cpp"
 | 
			
		||||
    "Thing.cpp"
 | 
			
		||||
    "Quadcopter.cpp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
enable_testing()
 | 
			
		||||
 | 
			
		||||
include(GoogleTest)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										63
									
								
								ControlledMotor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								ControlledMotor.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
#include "ControlledMotor.h"
 | 
			
		||||
 | 
			
		||||
ControlledMotor::ControlledMotor() { this->type = Thing::ControlledMotorType; }
 | 
			
		||||
 | 
			
		||||
ControlledMotor::ControlledMotor(Motor *motor, Encoder *encoder)
 | 
			
		||||
    : ControlledMotor() {
 | 
			
		||||
  this->motor = motor;
 | 
			
		||||
  this->encoder = encoder;
 | 
			
		||||
  // this->rotationDirection = Direction::Forward;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
 | 
			
		||||
void ControlledMotor::SetTargetSpeed(float speed) {
 | 
			
		||||
  this->currentTargetSpeed = speed;
 | 
			
		||||
  // this->rotationDirection =
 | 
			
		||||
  //     (targetSpeed < 0) ? Direction::Reverse : Direction::Forward;
 | 
			
		||||
  // this->direction = (targetSpeed < 0) ? Motor::Direction::CounterClockwise
 | 
			
		||||
  //                                     : Motor::Direction::Clockwise;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ControlledMotor::Update(unsigned long currentTimeMs) {
 | 
			
		||||
  this->actualSpeed = encoder->GetRevolutionsPerSecond(currentTimeMs);
 | 
			
		||||
  if (this->currentTargetSpeed < 0)
 | 
			
		||||
    this->actualSpeed = -this->actualSpeed;
 | 
			
		||||
 | 
			
		||||
  float deltaTime = currentTimeMs - this->lastUpdateTime;
 | 
			
		||||
 | 
			
		||||
  float error = this->currentTargetSpeed - this->actualSpeed;
 | 
			
		||||
  float errorChange = (error - lastError) * deltaTime;
 | 
			
		||||
 | 
			
		||||
  float delta = error * pidP + errorChange * pidD;
 | 
			
		||||
 | 
			
		||||
  Serial.print("  actual Speed ");
 | 
			
		||||
  Serial.print(actualSpeed);
 | 
			
		||||
  Serial.print("  target Speed ");
 | 
			
		||||
  Serial.print(this->currentTargetSpeed);
 | 
			
		||||
  Serial.print("    motor target speed ");
 | 
			
		||||
  Serial.print(motor->currentTargetSpeed);
 | 
			
		||||
  Serial.print(" + ");
 | 
			
		||||
  Serial.print(error * pidP);
 | 
			
		||||
  Serial.print(" + ");
 | 
			
		||||
  Serial.print(errorChange * pidD);
 | 
			
		||||
  Serial.print(" = ");
 | 
			
		||||
  Serial.println(motor->currentTargetSpeed + delta);
 | 
			
		||||
 | 
			
		||||
  motor->SetTargetSpeed(motor->currentTargetSpeed +
 | 
			
		||||
                        delta); // or something like that
 | 
			
		||||
  this->lastUpdateTime = currentTimeMs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float ControlledMotor::GetActualSpeed() { return actualSpeed; }
 | 
			
		||||
 | 
			
		||||
bool ControlledMotor::Drive(float distance) {
 | 
			
		||||
  if (!driving) {
 | 
			
		||||
    targetDistance = distance;
 | 
			
		||||
    startDistance = encoder->GetDistance();
 | 
			
		||||
    driving = true;
 | 
			
		||||
  }
 | 
			
		||||
  float totalDistance = encoder->GetDistance() - startDistance;
 | 
			
		||||
  bool completed = totalDistance > targetDistance;
 | 
			
		||||
  return completed;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								ControlledMotor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								ControlledMotor.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "Encoder.h"
 | 
			
		||||
#include "Motor.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief A motor with speed control
 | 
			
		||||
/// It uses a feedback loop from an encoder to regulate the speed
 | 
			
		||||
/// The speed is measured in revolutions per second.
 | 
			
		||||
class ControlledMotor : public Motor {
 | 
			
		||||
public:
 | 
			
		||||
  ControlledMotor();
 | 
			
		||||
  ControlledMotor(Motor *motor, Encoder *encoder);
 | 
			
		||||
 | 
			
		||||
  inline static bool CheckType(Thing *thing) {
 | 
			
		||||
    return (thing->type & (int)Thing::Type::ControlledMotor) != 0;
 | 
			
		||||
  }
 | 
			
		||||
  float velocity;
 | 
			
		||||
 | 
			
		||||
  float pidP = 0.1F;
 | 
			
		||||
  float pidD = 0.0F;
 | 
			
		||||
  float pidI = 0.0F;
 | 
			
		||||
 | 
			
		||||
  void Update(unsigned long currentTimeMs) override;
 | 
			
		||||
 | 
			
		||||
  /// @brief Set the target speed for the motor controller
 | 
			
		||||
  /// @param speed the target in revolutions per second.
 | 
			
		||||
  virtual void SetTargetSpeed(float speed) override;
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the actual speed from the encoder
 | 
			
		||||
  /// @return The speed in revolutions per second
 | 
			
		||||
  virtual float GetActualSpeed() override;
 | 
			
		||||
 | 
			
		||||
  bool Drive(float distance);
 | 
			
		||||
 | 
			
		||||
  Motor *motor;
 | 
			
		||||
  Encoder *encoder;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  float lastUpdateTime = 0;
 | 
			
		||||
  float lastError = 0;
 | 
			
		||||
  // float targetSpeed;
 | 
			
		||||
  float actualSpeed;
 | 
			
		||||
  float netDistance = 0;
 | 
			
		||||
  float startDistance = 0;
 | 
			
		||||
 | 
			
		||||
  // enum Direction { Forward = 1, Reverse = -1 };
 | 
			
		||||
 | 
			
		||||
  // Direction rotationDirection;
 | 
			
		||||
 | 
			
		||||
  bool driving = false;
 | 
			
		||||
  float targetDistance = 0;
 | 
			
		||||
  float lastEncoderPosition = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace RoboidControl
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::RoboidControl;
 | 
			
		||||
							
								
								
									
										109
									
								
								DifferentialDrive.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								DifferentialDrive.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
#include "DifferentialDrive.h"
 | 
			
		||||
#include "LinearAlgebra/Angle.h"
 | 
			
		||||
#include "LinearAlgebra/FloatSingle.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
DifferentialDrive::DifferentialDrive() {};
 | 
			
		||||
 | 
			
		||||
DifferentialDrive::DifferentialDrive(Motor* leftMotor, Motor* rightMotor) {
 | 
			
		||||
  this->motorCount = 2;
 | 
			
		||||
  this->motors = new Motor*[2];
 | 
			
		||||
  this->motors[0] = leftMotor;
 | 
			
		||||
  this->motors[1] = rightMotor;
 | 
			
		||||
 | 
			
		||||
  float distance = this->wheelSeparation / 2;
 | 
			
		||||
  leftMotor->direction = Motor::Direction::CounterClockwise;
 | 
			
		||||
  leftMotor->position.horizontal = -90;
 | 
			
		||||
  leftMotor->position.distance = distance;
 | 
			
		||||
  rightMotor->direction = Motor::Direction::Clockwise;
 | 
			
		||||
  rightMotor->position.horizontal = 90;
 | 
			
		||||
  rightMotor->position.distance = distance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DifferentialDrive::SetDimensions(float wheelDiameter,
 | 
			
		||||
                                      float wheelSeparation) {
 | 
			
		||||
  this->wheelDiameter = wheelDiameter;
 | 
			
		||||
  this->wheelSeparation = wheelSeparation;
 | 
			
		||||
  this->rpsToMs = wheelDiameter * Passer::LinearAlgebra::pi;
 | 
			
		||||
 | 
			
		||||
  float distance = this->wheelSeparation / 2;
 | 
			
		||||
  this->motors[0]->position.distance = distance;
 | 
			
		||||
  this->motors[1]->position.distance = distance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DifferentialDrive::SetMotorTargetSpeeds(float leftSpeed,
 | 
			
		||||
                                             float rightSpeed) {
 | 
			
		||||
  for (unsigned int motorIx = 0; motorIx < this->motorCount; motorIx++) {
 | 
			
		||||
    Motor* motor = motors[motorIx];
 | 
			
		||||
    if (motor == nullptr)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    float xPosition = motors[motorIx]->position.horizontal.ToFloat();
 | 
			
		||||
    if (xPosition < 0)
 | 
			
		||||
      motor->SetTargetSpeed(leftSpeed);
 | 
			
		||||
    else if (xPosition > 0)
 | 
			
		||||
      motor->SetTargetSpeed(rightSpeed);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DifferentialDrive::SetTwistSpeed(float forward, float yaw) {
 | 
			
		||||
  float leftSpeed =
 | 
			
		||||
      Float::Clamp(forward + yaw, -1, 1);  // revolutions per second
 | 
			
		||||
  float rightSpeed =
 | 
			
		||||
      Float::Clamp(forward - yaw, -1, 1);  // revolutions per second
 | 
			
		||||
 | 
			
		||||
  float leftMotorSpeed = leftSpeed / rpsToMs;    // meters per second
 | 
			
		||||
  float rightMotorSpeed = rightSpeed / rpsToMs;  // meters per second
 | 
			
		||||
 | 
			
		||||
  SetMotorTargetSpeeds(leftMotorSpeed, rightMotorSpeed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DifferentialDrive::SetTwistSpeed(Vector2 linear, float yaw) {
 | 
			
		||||
  SetTwistSpeed(linear.y, yaw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DifferentialDrive::SetTwistSpeed(Vector3 linear,
 | 
			
		||||
                                      float yaw,
 | 
			
		||||
                                      float pitch,
 | 
			
		||||
                                      float roll) {
 | 
			
		||||
  SetTwistSpeed(linear.Forward(), yaw);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DifferentialDrive::SetVelocity(Polar velocity) {
 | 
			
		||||
  SetTwistSpeed(velocity.distance, velocity.angle.ToFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Polar DifferentialDrive::GetVelocity() {
 | 
			
		||||
  Motor* leftMotor = motors[0];
 | 
			
		||||
  Motor* rightMotor = motors[1];
 | 
			
		||||
  float leftSpeed = leftMotor->GetActualSpeed();    // in revolutions per second
 | 
			
		||||
  float rightSpeed = rightMotor->GetActualSpeed();  // in revolutions per second
 | 
			
		||||
 | 
			
		||||
  leftSpeed = leftSpeed * rpsToMs;    // in meters per second
 | 
			
		||||
  rightSpeed = rightSpeed * rpsToMs;  // in meters per second
 | 
			
		||||
  float speed = (leftSpeed + rightSpeed) / 2;
 | 
			
		||||
 | 
			
		||||
  float direction = speed >= 0 ? 0.0F : 180.0F;
 | 
			
		||||
  float magnitude = fabsf(speed);
 | 
			
		||||
  Polar velocity = Polar(magnitude, direction);  // Polar(direction, magnitude);
 | 
			
		||||
  return velocity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float DifferentialDrive::GetAngularVelocity() {
 | 
			
		||||
  Motor* leftMotor = motors[0];
 | 
			
		||||
  Motor* rightMotor = motors[1];
 | 
			
		||||
  float leftSpeed = leftMotor->GetActualSpeed();    // in revolutions per second
 | 
			
		||||
  float rightSpeed = rightMotor->GetActualSpeed();  // in revolutions per second
 | 
			
		||||
 | 
			
		||||
  leftSpeed = leftSpeed * rpsToMs;    // in meters per second
 | 
			
		||||
  rightSpeed = rightSpeed * rpsToMs;  // in meters per second
 | 
			
		||||
 | 
			
		||||
  float angularSpeed = (leftSpeed - rightSpeed) / 2;
 | 
			
		||||
  float angularDistance = wheelSeparation / 2 * Passer::LinearAlgebra::pi;
 | 
			
		||||
  float rotationsPerSecond = angularSpeed / angularDistance;
 | 
			
		||||
  float degreesPerSecond = Angle::Normalize(360 * rotationsPerSecond).ToFloat();
 | 
			
		||||
  float angularVelocity = degreesPerSecond;
 | 
			
		||||
 | 
			
		||||
  return angularVelocity;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								DifferentialDrive.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								DifferentialDrive.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "Propulsion.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief A two-wheeled Propulsion method
 | 
			
		||||
///
 | 
			
		||||
/// The wheels are put at either side of the roboid with the following behaviour
 | 
			
		||||
/// * When both wheels spin forward, the Roboid moves forward
 | 
			
		||||
/// * When both wheels spin backward, the Roboid moves backward
 | 
			
		||||
/// * When both wheels are spinning in opposite directions, the Roboid rotates
 | 
			
		||||
/// wihout moving forward or backward
 | 
			
		||||
/// * When just one wheel is spinning, the Roboid turnes while moving forward or
 | 
			
		||||
/// backward.
 | 
			
		||||
class DifferentialDrive : public Propulsion {
 | 
			
		||||
public:
 | 
			
		||||
  /// @brief Default constructor
 | 
			
		||||
  DifferentialDrive();
 | 
			
		||||
  /// @brief Setup of the DifferentialDrive with the Placement of the motors
 | 
			
		||||
  /// @param leftMotorPlacement Placement of the left Motor
 | 
			
		||||
  /// @param rightMotorPlacement Placement of the right Motor
 | 
			
		||||
  /// In this setup, the left motor Direction will be CounterClockWise when
 | 
			
		||||
  /// driving forward, while the right motor will turn Clockwise.
 | 
			
		||||
  /// @note When not using controlled motors, the placement of the motors is
 | 
			
		||||
  /// irrelevant.
 | 
			
		||||
  // DifferentialDrive(Placement leftMotorPlacement,
 | 
			
		||||
  //                   Placement rightMotorPlacement);
 | 
			
		||||
 | 
			
		||||
  DifferentialDrive(Motor *leftMotor, Motor *rightMotor);
 | 
			
		||||
 | 
			
		||||
  void SetDimensions(float wheelDiameter, float wheelSeparation);
 | 
			
		||||
 | 
			
		||||
  /// @brief Set the target speeds of the motors directly
 | 
			
		||||
  /// @param leftSpeed The target speed of the left Motor
 | 
			
		||||
  /// @param rightSpeed The target speed of the right Motor
 | 
			
		||||
  void SetMotorTargetSpeeds(float leftSpeed, float rightSpeed);
 | 
			
		||||
 | 
			
		||||
  /// @brief Controls the motors through forward and rotation speeds
 | 
			
		||||
  /// @param forward The target forward speed of the Roboid
 | 
			
		||||
  /// @param yaw The target rotation speed of the Roboid
 | 
			
		||||
  virtual void SetTwistSpeed(float forward, float yaw) override;
 | 
			
		||||
  /// @brief Controls the motors through forward and rotation speeds
 | 
			
		||||
  /// @param linear The target linear speed of the Roboid
 | 
			
		||||
  /// @param yaw The target rotation speed of the Roboid
 | 
			
		||||
  /// @note As a DifferentialDrive cannot move sideward, this function has the
 | 
			
		||||
  /// same effect as using the void SetTwistSpeed(float forward, float yaw)
 | 
			
		||||
  /// function.
 | 
			
		||||
  virtual void SetTwistSpeed(Vector2 linear, float yaw = 0.0F);
 | 
			
		||||
  /// @brief Controls the motors through forward and rotation speeds
 | 
			
		||||
  /// @param linear The target linear speed
 | 
			
		||||
  /// @param yaw The target rotation speed around the vertical axis
 | 
			
		||||
  /// @param pitch Pitch is not supported and is ignored
 | 
			
		||||
  /// @param roll Roll is not supported and is ignores
 | 
			
		||||
  /// @note As a DifferentialDrive cannot move sideward or vertical, this
 | 
			
		||||
  /// function has the same effect as using the void SetTwistSpeed(float
 | 
			
		||||
  /// forward, float yaw) function.
 | 
			
		||||
  virtual void SetTwistSpeed(Vector3 linear, float yaw = 0.0F,
 | 
			
		||||
                             float pitch = 0.0F, float roll = 0.0F);
 | 
			
		||||
 | 
			
		||||
  virtual void SetVelocity(Polar velocity);
 | 
			
		||||
 | 
			
		||||
  /// @brief Calculate the linear velocity of the roboid based on the wheel
 | 
			
		||||
  /// velocities
 | 
			
		||||
  /// @return The velocity of the roboid in local space
 | 
			
		||||
  /// @details The actual values may not be accurate, depending on the available
 | 
			
		||||
  /// information
 | 
			
		||||
  /// @remark This will be more expanded/detailed in a future version of Roboid
 | 
			
		||||
  /// Control
 | 
			
		||||
  virtual Polar GetVelocity() override;
 | 
			
		||||
  /// @brief Calculate the angular velocity of the roboid based on the wheel
 | 
			
		||||
  /// velocities
 | 
			
		||||
  /// @return The angular speed of the roboid in local space
 | 
			
		||||
  /// @details The actual value may not be accurate, depending on the available
 | 
			
		||||
  /// information
 | 
			
		||||
  /// @remark This will be more expanded/detailed in a future version of Roboid
 | 
			
		||||
  /// Control
 | 
			
		||||
  virtual float GetAngularVelocity() override;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  float wheelDiameter = 1.0F;   // in meters
 | 
			
		||||
  float wheelSeparation = 1.0F; // in meters;
 | 
			
		||||
 | 
			
		||||
  float rpsToMs = 1.0F; // convert revolutions per second to meters per second
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace RoboidControl
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::RoboidControl;
 | 
			
		||||
							
								
								
									
										28
									
								
								DistanceSensor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								DistanceSensor.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
#include "DistanceSensor.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
DistanceSensor::DistanceSensor() {
 | 
			
		||||
  this->type = Thing::DistanceSensorType;
 | 
			
		||||
  this->distance = INFINITY;
 | 
			
		||||
  this->triggerDistance = 1.0F;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DistanceSensor::DistanceSensor(float triggerDistance) : DistanceSensor() {
 | 
			
		||||
  this->triggerDistance = triggerDistance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float DistanceSensor::GetDistance() {
 | 
			
		||||
  if (distance < minRange || distance > maxRange)
 | 
			
		||||
    return -1; // invalid distance
 | 
			
		||||
 | 
			
		||||
  return distance;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool DistanceSensor::ObjectNearby() {
 | 
			
		||||
  if (distance < minRange || distance > maxRange)
 | 
			
		||||
    return false;
 | 
			
		||||
 | 
			
		||||
  bool isOn = distance <= triggerDistance;
 | 
			
		||||
  return isOn;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								DistanceSensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								DistanceSensor.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "Sensor.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief A Sensor which can measure the distance to the nearest object
 | 
			
		||||
class DistanceSensor : public Sensor {
 | 
			
		||||
public:
 | 
			
		||||
  /// @brief Default constructor
 | 
			
		||||
  DistanceSensor();
 | 
			
		||||
  /// @brief Creates a DistanceSensor with the given trigger distance
 | 
			
		||||
  /// @param triggerDistance The distance at which the sensors indicates that a
 | 
			
		||||
  /// object is close by
 | 
			
		||||
  DistanceSensor(float triggerDistance);
 | 
			
		||||
 | 
			
		||||
  /// @brief Determine the distance to the nearest object
 | 
			
		||||
  /// @return the measured distance in meters to the nearest object
 | 
			
		||||
  virtual float GetDistance();
 | 
			
		||||
 | 
			
		||||
  /// @brief The minimum range at which the sensor gives reliable measurements
 | 
			
		||||
  float minRange = 0.01F;
 | 
			
		||||
  /// @brief The maximum range at which the sensor gives reliable measurements
 | 
			
		||||
  float maxRange = 10.0F;
 | 
			
		||||
 | 
			
		||||
  /// @brief The distance at which ObjectNearby triggers
 | 
			
		||||
  float triggerDistance = 1;
 | 
			
		||||
 | 
			
		||||
  /// @brief Indicate that an object is nearby
 | 
			
		||||
  /// @return True when an object is nearby
 | 
			
		||||
  bool ObjectNearby();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  /// @brief Distance to the closest object
 | 
			
		||||
  float distance = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace RoboidControl
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::RoboidControl;
 | 
			
		||||
@ -1,226 +0,0 @@
 | 
			
		||||
<doxygenlayout version="1.0">
 | 
			
		||||
  <!-- Generated by doxygen 1.8.18 -->
 | 
			
		||||
  <!-- Navigation index tabs for HTML output -->
 | 
			
		||||
  <navindex>
 | 
			
		||||
    <tab type="mainpage" visible="yes" title=""/>
 | 
			
		||||
    <tab type="pages" visible="yes" title="" intro=""/>
 | 
			
		||||
    <tab type="modules" visible="yes" title="" intro=""/>
 | 
			
		||||
    <tab type="namespaces" visible="yes" title="">
 | 
			
		||||
      <tab type="namespacelist" visible="yes" title="" intro=""/>
 | 
			
		||||
      <tab type="namespacemembers" visible="yes" title="" intro=""/>
 | 
			
		||||
    </tab>
 | 
			
		||||
    <tab type="interfaces" visible="yes" title="">
 | 
			
		||||
      <tab type="interfacelist" visible="yes" title="" intro=""/>
 | 
			
		||||
      <tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/> 
 | 
			
		||||
      <tab type="interfacehierarchy" visible="yes" title="" intro=""/>
 | 
			
		||||
    </tab>
 | 
			
		||||
    <tab type="classes" visible="yes" title="">
 | 
			
		||||
      <tab type="classlist" visible="yes" title="" intro=""/>
 | 
			
		||||
      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
 | 
			
		||||
      <tab type="hierarchy" visible="yes" title="" intro=""/>
 | 
			
		||||
      <tab type="classmembers" visible="yes" title="" intro=""/>
 | 
			
		||||
    </tab>
 | 
			
		||||
    <tab type="structs" visible="yes" title="">
 | 
			
		||||
      <tab type="structlist" visible="yes" title="" intro=""/>
 | 
			
		||||
      <tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/> 
 | 
			
		||||
    </tab>
 | 
			
		||||
    <tab type="exceptions" visible="yes" title="">
 | 
			
		||||
      <tab type="exceptionlist" visible="yes" title="" intro=""/>
 | 
			
		||||
      <tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/> 
 | 
			
		||||
      <tab type="exceptionhierarchy" visible="yes" title="" intro=""/>
 | 
			
		||||
    </tab>
 | 
			
		||||
    <tab type="files" visible="yes" title="">
 | 
			
		||||
      <tab type="filelist" visible="yes" title="" intro=""/>
 | 
			
		||||
      <tab type="globals" visible="yes" title="" intro=""/>
 | 
			
		||||
    </tab>
 | 
			
		||||
    <tab type="examples" visible="yes" title="" intro=""/>  
 | 
			
		||||
  </navindex>
 | 
			
		||||
 | 
			
		||||
  <!-- Layout definition for a class page -->
 | 
			
		||||
  <class>
 | 
			
		||||
    <briefdescription visible="no"/>
 | 
			
		||||
    <detaileddescription title=""/>
 | 
			
		||||
    <includes visible="$SHOW_INCLUDE_FILES"/>
 | 
			
		||||
    <inheritancegraph visible="$CLASS_GRAPH"/>
 | 
			
		||||
    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
 | 
			
		||||
    <memberdecl>
 | 
			
		||||
      <nestedclasses visible="yes" title=""/>
 | 
			
		||||
      <publictypes title=""/>
 | 
			
		||||
      <services title=""/>
 | 
			
		||||
      <interfaces title=""/>
 | 
			
		||||
      <publicslots title=""/>
 | 
			
		||||
      <signals title=""/>
 | 
			
		||||
      <publicmethods title=""/>
 | 
			
		||||
      <publicstaticmethods title=""/>
 | 
			
		||||
      <publicattributes title=""/>
 | 
			
		||||
      <publicstaticattributes title=""/>
 | 
			
		||||
      <protectedtypes title=""/>
 | 
			
		||||
      <protectedslots title=""/>
 | 
			
		||||
      <protectedmethods title=""/>
 | 
			
		||||
      <protectedstaticmethods title=""/>
 | 
			
		||||
      <protectedattributes title=""/>
 | 
			
		||||
      <protectedstaticattributes title=""/>
 | 
			
		||||
      <packagetypes title=""/>
 | 
			
		||||
      <packagemethods title=""/>
 | 
			
		||||
      <packagestaticmethods title=""/>
 | 
			
		||||
      <packageattributes title=""/>
 | 
			
		||||
      <packagestaticattributes title=""/>
 | 
			
		||||
      <properties title=""/>
 | 
			
		||||
      <events title=""/>
 | 
			
		||||
      <privatetypes title=""/>
 | 
			
		||||
      <privateslots title=""/>
 | 
			
		||||
      <privatemethods title=""/>
 | 
			
		||||
      <privatestaticmethods title=""/>
 | 
			
		||||
      <privateattributes title=""/>
 | 
			
		||||
      <privatestaticattributes title=""/>
 | 
			
		||||
      <friends title=""/>
 | 
			
		||||
      <related title="" subtitle=""/>
 | 
			
		||||
      <membergroups visible="yes"/>
 | 
			
		||||
    </memberdecl>
 | 
			
		||||
    <memberdef>
 | 
			
		||||
      <inlineclasses title=""/>
 | 
			
		||||
      <typedefs title=""/>
 | 
			
		||||
      <enums title=""/>
 | 
			
		||||
      <services title=""/>
 | 
			
		||||
      <interfaces title=""/>
 | 
			
		||||
      <constructors title=""/>
 | 
			
		||||
      <functions title=""/>
 | 
			
		||||
      <related title=""/>
 | 
			
		||||
      <variables title=""/>
 | 
			
		||||
      <properties title=""/>
 | 
			
		||||
      <events title=""/>
 | 
			
		||||
    </memberdef>
 | 
			
		||||
    <allmemberslink visible="yes"/>
 | 
			
		||||
    <usedfiles visible="$SHOW_USED_FILES"/>
 | 
			
		||||
    <authorsection visible="yes"/>
 | 
			
		||||
  </class>
 | 
			
		||||
 | 
			
		||||
  <!-- Layout definition for a namespace page -->
 | 
			
		||||
  <namespace>
 | 
			
		||||
    <briefdescription visible="yes"/>
 | 
			
		||||
    <memberdecl>
 | 
			
		||||
      <nestednamespaces visible="yes" title=""/>
 | 
			
		||||
      <constantgroups visible="yes" title=""/>
 | 
			
		||||
      <interfaces visible="yes" title=""/>
 | 
			
		||||
      <classes visible="yes" title=""/>
 | 
			
		||||
      <structs visible="yes" title=""/>
 | 
			
		||||
      <exceptions visible="yes" title=""/>
 | 
			
		||||
      <typedefs title=""/>
 | 
			
		||||
      <sequences title=""/>
 | 
			
		||||
      <dictionaries title=""/>
 | 
			
		||||
      <enums title=""/>
 | 
			
		||||
      <functions title=""/>
 | 
			
		||||
      <variables title=""/>
 | 
			
		||||
      <membergroups visible="yes"/>
 | 
			
		||||
    </memberdecl>
 | 
			
		||||
    <detaileddescription title=""/>
 | 
			
		||||
    <memberdef>
 | 
			
		||||
      <inlineclasses title=""/>
 | 
			
		||||
      <typedefs title=""/>
 | 
			
		||||
      <sequences title=""/>
 | 
			
		||||
      <dictionaries title=""/>
 | 
			
		||||
      <enums title=""/>
 | 
			
		||||
      <functions title=""/>
 | 
			
		||||
      <variables title=""/>
 | 
			
		||||
    </memberdef>
 | 
			
		||||
    <authorsection visible="yes"/>
 | 
			
		||||
  </namespace>
 | 
			
		||||
 | 
			
		||||
  <!-- Layout definition for a file page -->
 | 
			
		||||
  <file>
 | 
			
		||||
    <briefdescription visible="yes"/>
 | 
			
		||||
    <includes visible="$SHOW_INCLUDE_FILES"/>
 | 
			
		||||
    <includegraph visible="$INCLUDE_GRAPH"/>
 | 
			
		||||
    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
 | 
			
		||||
    <sourcelink visible="yes"/>
 | 
			
		||||
    <memberdecl>
 | 
			
		||||
      <interfaces visible="yes" title=""/>
 | 
			
		||||
      <classes visible="yes" title=""/>
 | 
			
		||||
      <structs visible="yes" title=""/>
 | 
			
		||||
      <exceptions visible="yes" title=""/>
 | 
			
		||||
      <namespaces visible="yes" title=""/>
 | 
			
		||||
      <constantgroups visible="yes" title=""/>
 | 
			
		||||
      <defines title=""/>
 | 
			
		||||
      <typedefs title=""/>
 | 
			
		||||
      <sequences title=""/>
 | 
			
		||||
      <dictionaries title=""/>
 | 
			
		||||
      <enums title=""/>
 | 
			
		||||
      <functions title=""/>
 | 
			
		||||
      <variables title=""/>
 | 
			
		||||
      <membergroups visible="yes"/>
 | 
			
		||||
    </memberdecl>
 | 
			
		||||
    <detaileddescription title=""/>
 | 
			
		||||
    <memberdef>
 | 
			
		||||
      <inlineclasses title=""/>
 | 
			
		||||
      <defines title=""/>
 | 
			
		||||
      <typedefs title=""/>
 | 
			
		||||
      <sequences title=""/>
 | 
			
		||||
      <dictionaries title=""/>
 | 
			
		||||
      <enums title=""/>
 | 
			
		||||
      <functions title=""/>
 | 
			
		||||
      <variables title=""/>
 | 
			
		||||
    </memberdef>
 | 
			
		||||
    <authorsection/>
 | 
			
		||||
  </file>
 | 
			
		||||
 | 
			
		||||
  <!-- Layout definition for a group page -->
 | 
			
		||||
  <group>
 | 
			
		||||
    <briefdescription visible="yes"/>
 | 
			
		||||
    <groupgraph visible="$GROUP_GRAPHS"/>
 | 
			
		||||
    <memberdecl>
 | 
			
		||||
      <nestedgroups visible="yes" title=""/>
 | 
			
		||||
      <dirs visible="yes" title=""/>
 | 
			
		||||
      <files visible="yes" title=""/>
 | 
			
		||||
      <namespaces visible="yes" title=""/>
 | 
			
		||||
      <classes visible="yes" title=""/>
 | 
			
		||||
      <defines title=""/>
 | 
			
		||||
      <typedefs title=""/>
 | 
			
		||||
      <sequences title=""/>
 | 
			
		||||
      <dictionaries title=""/>
 | 
			
		||||
      <enums title=""/>
 | 
			
		||||
      <enumvalues title=""/>
 | 
			
		||||
      <functions title=""/>
 | 
			
		||||
      <variables title=""/>
 | 
			
		||||
      <signals title=""/>
 | 
			
		||||
      <publicslots title=""/>
 | 
			
		||||
      <protectedslots title=""/>
 | 
			
		||||
      <privateslots title=""/>
 | 
			
		||||
      <events title=""/>
 | 
			
		||||
      <properties title=""/>
 | 
			
		||||
      <friends title=""/>
 | 
			
		||||
      <membergroups visible="yes"/>
 | 
			
		||||
    </memberdecl>
 | 
			
		||||
    <detaileddescription title=""/>
 | 
			
		||||
    <memberdef>
 | 
			
		||||
      <pagedocs/>
 | 
			
		||||
      <inlineclasses title=""/>
 | 
			
		||||
      <defines title=""/>
 | 
			
		||||
      <typedefs title=""/>
 | 
			
		||||
      <sequences title=""/>
 | 
			
		||||
      <dictionaries title=""/>
 | 
			
		||||
      <enums title=""/>
 | 
			
		||||
      <enumvalues title=""/>
 | 
			
		||||
      <functions title=""/>
 | 
			
		||||
      <variables title=""/>
 | 
			
		||||
      <signals title=""/>
 | 
			
		||||
      <publicslots title=""/>
 | 
			
		||||
      <protectedslots title=""/>
 | 
			
		||||
      <privateslots title=""/>
 | 
			
		||||
      <events title=""/>
 | 
			
		||||
      <properties title=""/>
 | 
			
		||||
      <friends title=""/>
 | 
			
		||||
    </memberdef>
 | 
			
		||||
    <authorsection visible="yes"/>
 | 
			
		||||
  </group>
 | 
			
		||||
 | 
			
		||||
  <!-- Layout definition for a directory page -->
 | 
			
		||||
  <directory>
 | 
			
		||||
    <briefdescription visible="yes"/>
 | 
			
		||||
    <directorygraph visible="yes"/>
 | 
			
		||||
    <memberdecl>
 | 
			
		||||
      <dirs visible="yes"/>
 | 
			
		||||
      <files visible="yes"/>
 | 
			
		||||
    </memberdecl>
 | 
			
		||||
    <detaileddescription title=""/>
 | 
			
		||||
  </directory>
 | 
			
		||||
</doxygenlayout>
 | 
			
		||||
							
								
								
									
										21
									
								
								Encoder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Encoder.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
/*
 | 
			
		||||
#include "Encoder.h"
 | 
			
		||||
 | 
			
		||||
IncrementalEncoder::IncrementalEncoder(unsigned char pulsesPerRevolution,
 | 
			
		||||
                                       unsigned char distancePerRotation) {
 | 
			
		||||
  this->pulsesPerRevolution = pulsesPerRevolution;
 | 
			
		||||
  this->distancePerRevolution = distancePerRotation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int IncrementalEncoder::GetPulseCount() { return 0; }
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetDistance() { return 0; }
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetPulsesPerSecond(float currentTimeMs) { return 0; }
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetRevolutionsPerSecond(float currentTimeMs) {
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetSpeed(float currentTimeMs) { return 0; }
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										57
									
								
								Encoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Encoder.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IncrementalEncoder.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
// Deprecated, use explicit IncrementalEncoder in the future
 | 
			
		||||
using Encoder = IncrementalEncoder;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
/// @brief An Encoder measures the rotations of an axle using a rotary
 | 
			
		||||
/// sensor Some encoders are able to detect direction, while others can not.
 | 
			
		||||
class IncrementalEncoder {
 | 
			
		||||
public:
 | 
			
		||||
  /// @brief Creates a sensor which measures distance from pulses
 | 
			
		||||
  /// @param pulsesPerRevolution The number of pulse edges which make a
 | 
			
		||||
  /// full rotation
 | 
			
		||||
  /// @param distancePerRevolution The distance a wheel travels per full
 | 
			
		||||
  /// rotation
 | 
			
		||||
  IncrementalEncoder(unsigned char pulsesPerRevolution = 1,
 | 
			
		||||
                     unsigned char distancePerRevolution = 1);
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the total number of pulses since the previous call
 | 
			
		||||
  /// @return The number of pulses, is zero or greater
 | 
			
		||||
  virtual int GetPulseCount();
 | 
			
		||||
  /// @brief Get the pulse speed since the previous call
 | 
			
		||||
  /// @param currentTimeMs The clock time in milliseconds
 | 
			
		||||
  /// @return The average pulses per second in the last period.
 | 
			
		||||
  virtual float GetPulsesPerSecond(float currentTimeMs);
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the distance traveled since the previous call
 | 
			
		||||
  /// @return The distance in meters.
 | 
			
		||||
  virtual float GetDistance();
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the rotation speed since the previous call
 | 
			
		||||
  /// @param currentTimeMs The clock time in milliseconds
 | 
			
		||||
  /// @return The speed in rotations per second
 | 
			
		||||
  virtual float GetRevolutionsPerSecond(float currentTimeMs);
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the speed since the previous call
 | 
			
		||||
  /// @param currentTimeMs The clock time in milliseconds
 | 
			
		||||
  /// @return The speed in meters per second.
 | 
			
		||||
  /// @note this value is dependent on the accurate setting of the
 | 
			
		||||
  /// pulsesPerRevolution and distancePerRevolution parameters;
 | 
			
		||||
  virtual float GetSpeed(float currentTimeMs);
 | 
			
		||||
 | 
			
		||||
  /// @brief The numer of pulses corresponding to a full rotation of the axle
 | 
			
		||||
  unsigned char pulsesPerRevolution = 1;
 | 
			
		||||
  /// @brief The number of revolutions which makes the wheel move forward 1
 | 
			
		||||
  /// meter
 | 
			
		||||
  unsigned char distancePerRevolution = 1;
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
} // namespace RoboidControl
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::RoboidControl;
 | 
			
		||||
@ -1,166 +0,0 @@
 | 
			
		||||
#include "EspIdfParticipant.h"
 | 
			
		||||
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
#include "esp_wifi.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace EspIdf {
 | 
			
		||||
 | 
			
		||||
void ParticipantUDP::Setup(int localPort,
 | 
			
		||||
                           const char* remoteIpAddress,
 | 
			
		||||
                           int remotePort) {
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
  std::cout << "Set up UDP\n";
 | 
			
		||||
  GetBroadcastAddress();
 | 
			
		||||
 | 
			
		||||
  wifi_ap_record_t ap_info;
 | 
			
		||||
  esp_err_t result = esp_wifi_sta_get_ap_info(&ap_info);
 | 
			
		||||
  if (result != ESP_OK) {
 | 
			
		||||
    std::cout << "No network available!\n";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Create a UDP socket
 | 
			
		||||
  this->sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 | 
			
		||||
  if (this->sockfd < 0) {
 | 
			
		||||
    std::cout << "Unable to create UDP socket: errno " << errno << "\n";
 | 
			
		||||
    vTaskDelete(NULL);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Set up the server address structure
 | 
			
		||||
  struct sockaddr_in local_addr;
 | 
			
		||||
  memset(&local_addr, 0, sizeof(local_addr));
 | 
			
		||||
  local_addr.sin_family = AF_INET;
 | 
			
		||||
  local_addr.sin_port = htons(this->port);
 | 
			
		||||
  local_addr.sin_addr.s_addr =
 | 
			
		||||
      htonl(INADDR_ANY);  // Listen on all available network interfaces
 | 
			
		||||
 | 
			
		||||
  // Bind the socket to the address and port
 | 
			
		||||
  if (bind(this->sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr)) <
 | 
			
		||||
      0) {
 | 
			
		||||
    std::cout << "Unable to bind UDP socket: errno " << errno << "\n";
 | 
			
		||||
    close(sockfd);
 | 
			
		||||
    vTaskDelete(NULL);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Initialize the dest_addr structure
 | 
			
		||||
  memset(&this->dest_addr, 0,
 | 
			
		||||
         sizeof(this->dest_addr));  // Clear the entire structure
 | 
			
		||||
  this->dest_addr.sin_family = AF_INET;
 | 
			
		||||
  this->dest_addr.sin_port = htons(this->remoteSite->port);
 | 
			
		||||
  inet_pton(AF_INET, this->remoteSite->ipAddress,
 | 
			
		||||
            &this->dest_addr.sin_addr.s_addr);
 | 
			
		||||
 | 
			
		||||
  std::cout << "Wifi sync started local " << this->port << ", remote "
 | 
			
		||||
            << this->remoteSite->ipAddress << ":" << this->remoteSite->port
 | 
			
		||||
            << "\n";
 | 
			
		||||
#endif  // IDF_VER
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ParticipantUDP::GetBroadcastAddress() {
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
  // SOMEHOW, THIS FUNCTION RESULTS IN MEMORY CORRUPION...
 | 
			
		||||
 | 
			
		||||
  esp_netif_ip_info_t ip_info;
 | 
			
		||||
  esp_netif_t* esp_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
 | 
			
		||||
 | 
			
		||||
  // Get IP information (IP address, netmask, gateway)
 | 
			
		||||
  if (esp_netif_get_ip_info(esp_netif, &ip_info) != ESP_OK) {
 | 
			
		||||
    std::cout << "Failed to get IP info\n";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ip_addr_t broadcast_addr = {};
 | 
			
		||||
  broadcast_addr.u_addr.ip4.addr =
 | 
			
		||||
      (ip_info.ip.addr & ip_info.netmask.addr) | ~ip_info.netmask.addr;
 | 
			
		||||
 | 
			
		||||
  snprintf(this->broadcastIpAddress, INET_ADDRSTRLEN, IPSTR,
 | 
			
		||||
           IP2STR(&broadcast_addr.u_addr.ip4));
 | 
			
		||||
  std::cout << "Broadcast address: " << this->broadcastIpAddress << "\n";
 | 
			
		||||
#endif  // IDF_VER
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ParticipantUDP::Receive() {
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
  struct pollfd fds[1];
 | 
			
		||||
  fds[0].fd = sockfd;
 | 
			
		||||
  fds[0].events = POLLIN;  // We're looking for data available to read
 | 
			
		||||
 | 
			
		||||
  // Use poll() with a timeout of 0 to return immediately
 | 
			
		||||
  int ret = poll(fds, 1, 0);
 | 
			
		||||
  if (ret == -1) {
 | 
			
		||||
    std::cout << "poll() error\n";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // char buffer[1024];
 | 
			
		||||
  struct sockaddr_in source_addr;
 | 
			
		||||
 | 
			
		||||
  socklen_t addr_len = sizeof(source_addr);
 | 
			
		||||
  char sender_ipAddress[INET_ADDRSTRLEN];
 | 
			
		||||
 | 
			
		||||
  while (ret > 0 && fds[0].revents & POLLIN) {
 | 
			
		||||
    int packetSize = recvfrom(this->sockfd, buffer, sizeof(buffer) - 1, 0,
 | 
			
		||||
                              (struct sockaddr*)&source_addr, &addr_len);
 | 
			
		||||
    if (packetSize < 0) {
 | 
			
		||||
      std::cout << "recvfrom() error\n";
 | 
			
		||||
      return;
 | 
			
		||||
    } else if (packetSize == 0) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // std::cout << "receiving " << packetSize << " bytes, msgId " <<
 | 
			
		||||
    // (int)this->buffer[0] << "\n";
 | 
			
		||||
    inet_ntoa_r(source_addr.sin_addr, sender_ipAddress, INET_ADDRSTRLEN);
 | 
			
		||||
    unsigned int sender_port = ntohs(source_addr.sin_port);
 | 
			
		||||
 | 
			
		||||
    ReceiveData(packetSize, sender_ipAddress, sender_port);
 | 
			
		||||
 | 
			
		||||
    ret = poll(fds, 1, 0);
 | 
			
		||||
    if (ret == -1) {
 | 
			
		||||
      std::cout << "poll() error\n";
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // std::cout << "no more messages\n";
 | 
			
		||||
 | 
			
		||||
#endif  // IDF_VER
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ParticipantUDP::Send(Participant* remoteParticipant, int bufferSize) {
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
  // std::cout << "Sending to " << remoteParticipant->ipAddress << ":"
 | 
			
		||||
  //           << remoteParticipant->port << "\n";
 | 
			
		||||
 | 
			
		||||
  int err = sendto(this->sockfd, buffer, bufferSize, 0,
 | 
			
		||||
                   (struct sockaddr*)&dest_addr, sizeof(dest_addr));
 | 
			
		||||
  if (errno != 0)
 | 
			
		||||
    std::cout << "Send error " << err << " or " << errno << "\n";
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ParticipantUDP::Publish(IMessage* msg) {
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
  int bufferSize = msg->Serialize((char*)this->buffer);
 | 
			
		||||
  if (bufferSize <= 0)
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
  struct sockaddr_in dest_addr;
 | 
			
		||||
  dest_addr.sin_family = AF_INET;
 | 
			
		||||
  dest_addr.sin_port = htons(this->port);
 | 
			
		||||
  inet_pton(AF_INET, this->broadcastIpAddress, &dest_addr.sin_addr.s_addr);
 | 
			
		||||
  int err = sendto(sockfd, buffer, bufferSize, 0, (struct sockaddr*)&dest_addr,
 | 
			
		||||
                   sizeof(dest_addr));
 | 
			
		||||
  if (err != 0)
 | 
			
		||||
    std::cout << "Publish error\n";
 | 
			
		||||
#endif
 | 
			
		||||
  return true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace EspIdf
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,32 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "Participants/ParticipantUDP.h"
 | 
			
		||||
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
#include "lwip/sockets.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
namespace EspIdf {
 | 
			
		||||
 | 
			
		||||
class ParticipantUDP : public RoboidControl::ParticipantUDP {
 | 
			
		||||
 public:
 | 
			
		||||
  void Setup(int localPort, const char* remoteIpAddress, int remotePort);
 | 
			
		||||
  void Receive();
 | 
			
		||||
  bool Send(Participant* remoteParticipant, int bufferSize);
 | 
			
		||||
  bool Publish(IMessage* msg);
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
  char broadcastIpAddress[INET_ADDRSTRLEN];
 | 
			
		||||
 | 
			
		||||
  int sockfd;
 | 
			
		||||
  struct sockaddr_in dest_addr;
 | 
			
		||||
  // struct sockaddr_in src_addr;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  void GetBroadcastAddress();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace EspIdf
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,100 +0,0 @@
 | 
			
		||||
#include "EspIdfUtils.h"
 | 
			
		||||
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
#include <iostream>
 | 
			
		||||
// #include "esp_event.h"
 | 
			
		||||
// #include "esp_log.h"
 | 
			
		||||
#include "esp_netif.h"
 | 
			
		||||
#include "esp_wifi.h"
 | 
			
		||||
// #include "lwip/inet.h"
 | 
			
		||||
// #include "lwip/ip_addr.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
const char* hotspotSSID = "Roboid";
 | 
			
		||||
const char* hotspotPassword = "alchemy7000";
 | 
			
		||||
 | 
			
		||||
esp_netif_t* wifi_netif = nullptr;
 | 
			
		||||
// Semaphore to signal Wi-Fi connection status
 | 
			
		||||
// SemaphoreHandle_t wifi_semaphore;
 | 
			
		||||
static bool wifi_connected = false;
 | 
			
		||||
 | 
			
		||||
static void wifi_event_handler(void* arg,
 | 
			
		||||
                               esp_event_base_t event_base,
 | 
			
		||||
                               int32_t event_id,
 | 
			
		||||
                               void* event_data) {
 | 
			
		||||
  if (event_base == WIFI_EVENT) {
 | 
			
		||||
    if (event_id == WIFI_EVENT_STA_START)
 | 
			
		||||
      esp_wifi_connect();
 | 
			
		||||
    else if (event_id == WIFI_EVENT_STA_DISCONNECTED)
 | 
			
		||||
      esp_wifi_connect();
 | 
			
		||||
  } else if (event_base == IP_EVENT) {
 | 
			
		||||
    if (event_id == IP_EVENT_STA_GOT_IP) {
 | 
			
		||||
      // ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
 | 
			
		||||
      // const char* ipaddr = IP2STR(&event->ip_info.ip);
 | 
			
		||||
      wifi_connected = true;
 | 
			
		||||
      // xSemaphoreGive(wifi_semaphore);  // Signal that connection is
 | 
			
		||||
      // established
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool StartWifi(const char* wifiSsid, const char* wifiPassword) {
 | 
			
		||||
  std::cout << "Connecting to WiFi " << wifiSsid << "\n";
 | 
			
		||||
 | 
			
		||||
  esp_netif_init();
 | 
			
		||||
  esp_event_loop_create_default();
 | 
			
		||||
 | 
			
		||||
  wifi_netif = esp_netif_create_default_wifi_sta();
 | 
			
		||||
  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
 | 
			
		||||
  esp_wifi_init(&cfg);
 | 
			
		||||
 | 
			
		||||
  esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler,
 | 
			
		||||
                             NULL);
 | 
			
		||||
  esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler,
 | 
			
		||||
                             NULL);
 | 
			
		||||
 | 
			
		||||
  wifi_config_t wifi_config = {};
 | 
			
		||||
  strncpy((char*)wifi_config.sta.ssid, wifiSsid, strlen(wifiSsid) + 1);
 | 
			
		||||
  strncpy((char*)wifi_config.sta.password, wifiPassword,
 | 
			
		||||
          strlen(wifiPassword) + 1);
 | 
			
		||||
 | 
			
		||||
  esp_wifi_set_mode(WIFI_MODE_STA);
 | 
			
		||||
  esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
 | 
			
		||||
  esp_wifi_start();
 | 
			
		||||
 | 
			
		||||
  // Wait for connection with a timeout of 10 seconds
 | 
			
		||||
  TickType_t xLastWakeTime = xTaskGetTickCount();
 | 
			
		||||
  bool success = false;
 | 
			
		||||
  for (int i = 0; i < 20; i++) {  // 20 iterations, each 500ms
 | 
			
		||||
    if (wifi_connected) {
 | 
			
		||||
      success = true;
 | 
			
		||||
      std::cout << " Connected.\n";
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    std::cout << ".";
 | 
			
		||||
    fflush(stdout);  // Ensure output is printed immediately
 | 
			
		||||
    vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(500));  // Wait 500ms
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (wifi_connected) {
 | 
			
		||||
    esp_netif_ip_info_t ip_info = {};
 | 
			
		||||
    esp_netif_t* esp_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
 | 
			
		||||
 | 
			
		||||
    // Get IP information (IP address, netmask, gateway)
 | 
			
		||||
    if (esp_netif_get_ip_info(esp_netif, &ip_info) != ESP_OK) {
 | 
			
		||||
      std::cout << "Failed to get IP info\n";
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Convert the IP address to string format using inet_ntoa
 | 
			
		||||
    char ip_str[16];  // IPv4 address can have a max of 15 characters + null
 | 
			
		||||
                      // terminator
 | 
			
		||||
    snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&ip_info.ip));
 | 
			
		||||
    std::cout << "IP address = " << ip_str << "\n";
 | 
			
		||||
  } else
 | 
			
		||||
    std::cout << "\nCould not connect to home network.\n";
 | 
			
		||||
 | 
			
		||||
  return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,6 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#if defined(IDF_VER)
 | 
			
		||||
 | 
			
		||||
bool StartWifi(const char *wifiSsid, const char *wifiPassword);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										19
									
								
								IncrementalEncoder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								IncrementalEncoder.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#include "Encoder.h"
 | 
			
		||||
 | 
			
		||||
IncrementalEncoder::IncrementalEncoder(unsigned char pulsesPerRevolution,
 | 
			
		||||
                                       unsigned char distancePerRotation) {
 | 
			
		||||
  this->pulsesPerRevolution = pulsesPerRevolution;
 | 
			
		||||
  this->distancePerRevolution = distancePerRotation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int IncrementalEncoder::GetPulseCount() { return 0; }
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetDistance() { return 0; }
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetPulsesPerSecond(float currentTimeMs) { return 0; }
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetRevolutionsPerSecond(float currentTimeMs) {
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float IncrementalEncoder::GetSpeed(float currentTimeMs) { return 0; }
 | 
			
		||||
							
								
								
									
										51
									
								
								IncrementalEncoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								IncrementalEncoder.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief An Encoder measures the rotations of an axle using a rotary
 | 
			
		||||
/// sensor Some encoders are able to detect direction, while others can not.
 | 
			
		||||
class IncrementalEncoder {
 | 
			
		||||
public:
 | 
			
		||||
  /// @brief Creates a sensor which measures distance from pulses
 | 
			
		||||
  /// @param pulsesPerRevolution The number of pulse edges which make a
 | 
			
		||||
  /// full rotation
 | 
			
		||||
  /// @param distancePerRevolution The distance a wheel travels per full
 | 
			
		||||
  /// rotation
 | 
			
		||||
  IncrementalEncoder(unsigned char pulsesPerRevolution = 1,
 | 
			
		||||
                     unsigned char distancePerRevolution = 1);
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the total number of pulses since the previous call
 | 
			
		||||
  /// @return The number of pulses, is zero or greater
 | 
			
		||||
  virtual int GetPulseCount();
 | 
			
		||||
  /// @brief Get the pulse speed since the previous call
 | 
			
		||||
  /// @param currentTimeMs The clock time in milliseconds
 | 
			
		||||
  /// @return The average pulses per second in the last period.
 | 
			
		||||
  virtual float GetPulsesPerSecond(float currentTimeMs);
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the distance traveled since the previous call
 | 
			
		||||
  /// @return The distance in meters.
 | 
			
		||||
  virtual float GetDistance();
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the rotation speed since the previous call
 | 
			
		||||
  /// @param currentTimeMs The clock time in milliseconds
 | 
			
		||||
  /// @return The speed in rotations per second
 | 
			
		||||
  virtual float GetRevolutionsPerSecond(float currentTimeMs);
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the speed since the previous call
 | 
			
		||||
  /// @param currentTimeMs The clock time in milliseconds
 | 
			
		||||
  /// @return The speed in meters per second.
 | 
			
		||||
  /// @note this value is dependent on the accurate setting of the
 | 
			
		||||
  /// pulsesPerRevolution and distancePerRevolution parameters;
 | 
			
		||||
  virtual float GetSpeed(float currentTimeMs);
 | 
			
		||||
 | 
			
		||||
  /// @brief The numer of pulses corresponding to a full rotation of the axle
 | 
			
		||||
  unsigned char pulsesPerRevolution = 1;
 | 
			
		||||
  /// @brief The number of revolutions which makes the wheel move forward 1
 | 
			
		||||
  /// meter
 | 
			
		||||
  unsigned char distancePerRevolution = 1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace RoboidControl
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::RoboidControl;
 | 
			
		||||
							
								
								
									
										373
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,373 @@
 | 
			
		||||
Mozilla Public License Version 2.0
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
1. Definitions
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
1.1. "Contributor"
 | 
			
		||||
    means each individual or legal entity that creates, contributes to
 | 
			
		||||
    the creation of, or owns Covered Software.
 | 
			
		||||
 | 
			
		||||
1.2. "Contributor Version"
 | 
			
		||||
    means the combination of the Contributions of others (if any) used
 | 
			
		||||
    by a Contributor and that particular Contributor's Contribution.
 | 
			
		||||
 | 
			
		||||
1.3. "Contribution"
 | 
			
		||||
    means Covered Software of a particular Contributor.
 | 
			
		||||
 | 
			
		||||
1.4. "Covered Software"
 | 
			
		||||
    means Source Code Form to which the initial Contributor has attached
 | 
			
		||||
    the notice in Exhibit A, the Executable Form of such Source Code
 | 
			
		||||
    Form, and Modifications of such Source Code Form, in each case
 | 
			
		||||
    including portions thereof.
 | 
			
		||||
 | 
			
		||||
1.5. "Incompatible With Secondary Licenses"
 | 
			
		||||
    means
 | 
			
		||||
 | 
			
		||||
    (a) that the initial Contributor has attached the notice described
 | 
			
		||||
        in Exhibit B to the Covered Software; or
 | 
			
		||||
 | 
			
		||||
    (b) that the Covered Software was made available under the terms of
 | 
			
		||||
        version 1.1 or earlier of the License, but not also under the
 | 
			
		||||
        terms of a Secondary License.
 | 
			
		||||
 | 
			
		||||
1.6. "Executable Form"
 | 
			
		||||
    means any form of the work other than Source Code Form.
 | 
			
		||||
 | 
			
		||||
1.7. "Larger Work"
 | 
			
		||||
    means a work that combines Covered Software with other material, in
 | 
			
		||||
    a separate file or files, that is not Covered Software.
 | 
			
		||||
 | 
			
		||||
1.8. "License"
 | 
			
		||||
    means this document.
 | 
			
		||||
 | 
			
		||||
1.9. "Licensable"
 | 
			
		||||
    means having the right to grant, to the maximum extent possible,
 | 
			
		||||
    whether at the time of the initial grant or subsequently, any and
 | 
			
		||||
    all of the rights conveyed by this License.
 | 
			
		||||
 | 
			
		||||
1.10. "Modifications"
 | 
			
		||||
    means any of the following:
 | 
			
		||||
 | 
			
		||||
    (a) any file in Source Code Form that results from an addition to,
 | 
			
		||||
        deletion from, or modification of the contents of Covered
 | 
			
		||||
        Software; or
 | 
			
		||||
 | 
			
		||||
    (b) any new file in Source Code Form that contains any Covered
 | 
			
		||||
        Software.
 | 
			
		||||
 | 
			
		||||
1.11. "Patent Claims" of a Contributor
 | 
			
		||||
    means any patent claim(s), including without limitation, method,
 | 
			
		||||
    process, and apparatus claims, in any patent Licensable by such
 | 
			
		||||
    Contributor that would be infringed, but for the grant of the
 | 
			
		||||
    License, by the making, using, selling, offering for sale, having
 | 
			
		||||
    made, import, or transfer of either its Contributions or its
 | 
			
		||||
    Contributor Version.
 | 
			
		||||
 | 
			
		||||
1.12. "Secondary License"
 | 
			
		||||
    means either the GNU General Public License, Version 2.0, the GNU
 | 
			
		||||
    Lesser General Public License, Version 2.1, the GNU Affero General
 | 
			
		||||
    Public License, Version 3.0, or any later versions of those
 | 
			
		||||
    licenses.
 | 
			
		||||
 | 
			
		||||
1.13. "Source Code Form"
 | 
			
		||||
    means the form of the work preferred for making modifications.
 | 
			
		||||
 | 
			
		||||
1.14. "You" (or "Your")
 | 
			
		||||
    means an individual or a legal entity exercising rights under this
 | 
			
		||||
    License. For legal entities, "You" includes any entity that
 | 
			
		||||
    controls, is controlled by, or is under common control with You. For
 | 
			
		||||
    purposes of this definition, "control" means (a) the power, direct
 | 
			
		||||
    or indirect, to cause the direction or management of such entity,
 | 
			
		||||
    whether by contract or otherwise, or (b) ownership of more than
 | 
			
		||||
    fifty percent (50%) of the outstanding shares or beneficial
 | 
			
		||||
    ownership of such entity.
 | 
			
		||||
 | 
			
		||||
2. License Grants and Conditions
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
2.1. Grants
 | 
			
		||||
 | 
			
		||||
Each Contributor hereby grants You a world-wide, royalty-free,
 | 
			
		||||
non-exclusive license:
 | 
			
		||||
 | 
			
		||||
(a) under intellectual property rights (other than patent or trademark)
 | 
			
		||||
    Licensable by such Contributor to use, reproduce, make available,
 | 
			
		||||
    modify, display, perform, distribute, and otherwise exploit its
 | 
			
		||||
    Contributions, either on an unmodified basis, with Modifications, or
 | 
			
		||||
    as part of a Larger Work; and
 | 
			
		||||
 | 
			
		||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
 | 
			
		||||
    for sale, have made, import, and otherwise transfer either its
 | 
			
		||||
    Contributions or its Contributor Version.
 | 
			
		||||
 | 
			
		||||
2.2. Effective Date
 | 
			
		||||
 | 
			
		||||
The licenses granted in Section 2.1 with respect to any Contribution
 | 
			
		||||
become effective for each Contribution on the date the Contributor first
 | 
			
		||||
distributes such Contribution.
 | 
			
		||||
 | 
			
		||||
2.3. Limitations on Grant Scope
 | 
			
		||||
 | 
			
		||||
The licenses granted in this Section 2 are the only rights granted under
 | 
			
		||||
this License. No additional rights or licenses will be implied from the
 | 
			
		||||
distribution or licensing of Covered Software under this License.
 | 
			
		||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
 | 
			
		||||
Contributor:
 | 
			
		||||
 | 
			
		||||
(a) for any code that a Contributor has removed from Covered Software;
 | 
			
		||||
    or
 | 
			
		||||
 | 
			
		||||
(b) for infringements caused by: (i) Your and any other third party's
 | 
			
		||||
    modifications of Covered Software, or (ii) the combination of its
 | 
			
		||||
    Contributions with other software (except as part of its Contributor
 | 
			
		||||
    Version); or
 | 
			
		||||
 | 
			
		||||
(c) under Patent Claims infringed by Covered Software in the absence of
 | 
			
		||||
    its Contributions.
 | 
			
		||||
 | 
			
		||||
This License does not grant any rights in the trademarks, service marks,
 | 
			
		||||
or logos of any Contributor (except as may be necessary to comply with
 | 
			
		||||
the notice requirements in Section 3.4).
 | 
			
		||||
 | 
			
		||||
2.4. Subsequent Licenses
 | 
			
		||||
 | 
			
		||||
No Contributor makes additional grants as a result of Your choice to
 | 
			
		||||
distribute the Covered Software under a subsequent version of this
 | 
			
		||||
License (see Section 10.2) or under the terms of a Secondary License (if
 | 
			
		||||
permitted under the terms of Section 3.3).
 | 
			
		||||
 | 
			
		||||
2.5. Representation
 | 
			
		||||
 | 
			
		||||
Each Contributor represents that the Contributor believes its
 | 
			
		||||
Contributions are its original creation(s) or it has sufficient rights
 | 
			
		||||
to grant the rights to its Contributions conveyed by this License.
 | 
			
		||||
 | 
			
		||||
2.6. Fair Use
 | 
			
		||||
 | 
			
		||||
This License is not intended to limit any rights You have under
 | 
			
		||||
applicable copyright doctrines of fair use, fair dealing, or other
 | 
			
		||||
equivalents.
 | 
			
		||||
 | 
			
		||||
2.7. Conditions
 | 
			
		||||
 | 
			
		||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
 | 
			
		||||
in Section 2.1.
 | 
			
		||||
 | 
			
		||||
3. Responsibilities
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
3.1. Distribution of Source Form
 | 
			
		||||
 | 
			
		||||
All distribution of Covered Software in Source Code Form, including any
 | 
			
		||||
Modifications that You create or to which You contribute, must be under
 | 
			
		||||
the terms of this License. You must inform recipients that the Source
 | 
			
		||||
Code Form of the Covered Software is governed by the terms of this
 | 
			
		||||
License, and how they can obtain a copy of this License. You may not
 | 
			
		||||
attempt to alter or restrict the recipients' rights in the Source Code
 | 
			
		||||
Form.
 | 
			
		||||
 | 
			
		||||
3.2. Distribution of Executable Form
 | 
			
		||||
 | 
			
		||||
If You distribute Covered Software in Executable Form then:
 | 
			
		||||
 | 
			
		||||
(a) such Covered Software must also be made available in Source Code
 | 
			
		||||
    Form, as described in Section 3.1, and You must inform recipients of
 | 
			
		||||
    the Executable Form how they can obtain a copy of such Source Code
 | 
			
		||||
    Form by reasonable means in a timely manner, at a charge no more
 | 
			
		||||
    than the cost of distribution to the recipient; and
 | 
			
		||||
 | 
			
		||||
(b) You may distribute such Executable Form under the terms of this
 | 
			
		||||
    License, or sublicense it under different terms, provided that the
 | 
			
		||||
    license for the Executable Form does not attempt to limit or alter
 | 
			
		||||
    the recipients' rights in the Source Code Form under this License.
 | 
			
		||||
 | 
			
		||||
3.3. Distribution of a Larger Work
 | 
			
		||||
 | 
			
		||||
You may create and distribute a Larger Work under terms of Your choice,
 | 
			
		||||
provided that You also comply with the requirements of this License for
 | 
			
		||||
the Covered Software. If the Larger Work is a combination of Covered
 | 
			
		||||
Software with a work governed by one or more Secondary Licenses, and the
 | 
			
		||||
Covered Software is not Incompatible With Secondary Licenses, this
 | 
			
		||||
License permits You to additionally distribute such Covered Software
 | 
			
		||||
under the terms of such Secondary License(s), so that the recipient of
 | 
			
		||||
the Larger Work may, at their option, further distribute the Covered
 | 
			
		||||
Software under the terms of either this License or such Secondary
 | 
			
		||||
License(s).
 | 
			
		||||
 | 
			
		||||
3.4. Notices
 | 
			
		||||
 | 
			
		||||
You may not remove or alter the substance of any license notices
 | 
			
		||||
(including copyright notices, patent notices, disclaimers of warranty,
 | 
			
		||||
or limitations of liability) contained within the Source Code Form of
 | 
			
		||||
the Covered Software, except that You may alter any license notices to
 | 
			
		||||
the extent required to remedy known factual inaccuracies.
 | 
			
		||||
 | 
			
		||||
3.5. Application of Additional Terms
 | 
			
		||||
 | 
			
		||||
You may choose to offer, and to charge a fee for, warranty, support,
 | 
			
		||||
indemnity or liability obligations to one or more recipients of Covered
 | 
			
		||||
Software. However, You may do so only on Your own behalf, and not on
 | 
			
		||||
behalf of any Contributor. You must make it absolutely clear that any
 | 
			
		||||
such warranty, support, indemnity, or liability obligation is offered by
 | 
			
		||||
You alone, and You hereby agree to indemnify every Contributor for any
 | 
			
		||||
liability incurred by such Contributor as a result of warranty, support,
 | 
			
		||||
indemnity or liability terms You offer. You may include additional
 | 
			
		||||
disclaimers of warranty and limitations of liability specific to any
 | 
			
		||||
jurisdiction.
 | 
			
		||||
 | 
			
		||||
4. Inability to Comply Due to Statute or Regulation
 | 
			
		||||
---------------------------------------------------
 | 
			
		||||
 | 
			
		||||
If it is impossible for You to comply with any of the terms of this
 | 
			
		||||
License with respect to some or all of the Covered Software due to
 | 
			
		||||
statute, judicial order, or regulation then You must: (a) comply with
 | 
			
		||||
the terms of this License to the maximum extent possible; and (b)
 | 
			
		||||
describe the limitations and the code they affect. Such description must
 | 
			
		||||
be placed in a text file included with all distributions of the Covered
 | 
			
		||||
Software under this License. Except to the extent prohibited by statute
 | 
			
		||||
or regulation, such description must be sufficiently detailed for a
 | 
			
		||||
recipient of ordinary skill to be able to understand it.
 | 
			
		||||
 | 
			
		||||
5. Termination
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
5.1. The rights granted under this License will terminate automatically
 | 
			
		||||
if You fail to comply with any of its terms. However, if You become
 | 
			
		||||
compliant, then the rights granted under this License from a particular
 | 
			
		||||
Contributor are reinstated (a) provisionally, unless and until such
 | 
			
		||||
Contributor explicitly and finally terminates Your grants, and (b) on an
 | 
			
		||||
ongoing basis, if such Contributor fails to notify You of the
 | 
			
		||||
non-compliance by some reasonable means prior to 60 days after You have
 | 
			
		||||
come back into compliance. Moreover, Your grants from a particular
 | 
			
		||||
Contributor are reinstated on an ongoing basis if such Contributor
 | 
			
		||||
notifies You of the non-compliance by some reasonable means, this is the
 | 
			
		||||
first time You have received notice of non-compliance with this License
 | 
			
		||||
from such Contributor, and You become compliant prior to 30 days after
 | 
			
		||||
Your receipt of the notice.
 | 
			
		||||
 | 
			
		||||
5.2. If You initiate litigation against any entity by asserting a patent
 | 
			
		||||
infringement claim (excluding declaratory judgment actions,
 | 
			
		||||
counter-claims, and cross-claims) alleging that a Contributor Version
 | 
			
		||||
directly or indirectly infringes any patent, then the rights granted to
 | 
			
		||||
You by any and all Contributors for the Covered Software under Section
 | 
			
		||||
2.1 of this License shall terminate.
 | 
			
		||||
 | 
			
		||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
 | 
			
		||||
end user license agreements (excluding distributors and resellers) which
 | 
			
		||||
have been validly granted by You or Your distributors under this License
 | 
			
		||||
prior to termination shall survive termination.
 | 
			
		||||
 | 
			
		||||
************************************************************************
 | 
			
		||||
*                                                                      *
 | 
			
		||||
*  6. Disclaimer of Warranty                                           *
 | 
			
		||||
*  -------------------------                                           *
 | 
			
		||||
*                                                                      *
 | 
			
		||||
*  Covered Software is provided under this License on an "as is"       *
 | 
			
		||||
*  basis, without warranty of any kind, either expressed, implied, or  *
 | 
			
		||||
*  statutory, including, without limitation, warranties that the       *
 | 
			
		||||
*  Covered Software is free of defects, merchantable, fit for a        *
 | 
			
		||||
*  particular purpose or non-infringing. The entire risk as to the     *
 | 
			
		||||
*  quality and performance of the Covered Software is with You.        *
 | 
			
		||||
*  Should any Covered Software prove defective in any respect, You     *
 | 
			
		||||
*  (not any Contributor) assume the cost of any necessary servicing,   *
 | 
			
		||||
*  repair, or correction. This disclaimer of warranty constitutes an   *
 | 
			
		||||
*  essential part of this License. No use of any Covered Software is   *
 | 
			
		||||
*  authorized under this License except under this disclaimer.         *
 | 
			
		||||
*                                                                      *
 | 
			
		||||
************************************************************************
 | 
			
		||||
 | 
			
		||||
************************************************************************
 | 
			
		||||
*                                                                      *
 | 
			
		||||
*  7. Limitation of Liability                                          *
 | 
			
		||||
*  --------------------------                                          *
 | 
			
		||||
*                                                                      *
 | 
			
		||||
*  Under no circumstances and under no legal theory, whether tort      *
 | 
			
		||||
*  (including negligence), contract, or otherwise, shall any           *
 | 
			
		||||
*  Contributor, or anyone who distributes Covered Software as          *
 | 
			
		||||
*  permitted above, be liable to You for any direct, indirect,         *
 | 
			
		||||
*  special, incidental, or consequential damages of any character      *
 | 
			
		||||
*  including, without limitation, damages for lost profits, loss of    *
 | 
			
		||||
*  goodwill, work stoppage, computer failure or malfunction, or any    *
 | 
			
		||||
*  and all other commercial damages or losses, even if such party      *
 | 
			
		||||
*  shall have been informed of the possibility of such damages. This   *
 | 
			
		||||
*  limitation of liability shall not apply to liability for death or   *
 | 
			
		||||
*  personal injury resulting from such party's negligence to the       *
 | 
			
		||||
*  extent applicable law prohibits such limitation. Some               *
 | 
			
		||||
*  jurisdictions do not allow the exclusion or limitation of           *
 | 
			
		||||
*  incidental or consequential damages, so this exclusion and          *
 | 
			
		||||
*  limitation may not apply to You.                                    *
 | 
			
		||||
*                                                                      *
 | 
			
		||||
************************************************************************
 | 
			
		||||
 | 
			
		||||
8. Litigation
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Any litigation relating to this License may be brought only in the
 | 
			
		||||
courts of a jurisdiction where the defendant maintains its principal
 | 
			
		||||
place of business and such litigation shall be governed by laws of that
 | 
			
		||||
jurisdiction, without reference to its conflict-of-law provisions.
 | 
			
		||||
Nothing in this Section shall prevent a party's ability to bring
 | 
			
		||||
cross-claims or counter-claims.
 | 
			
		||||
 | 
			
		||||
9. Miscellaneous
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
This License represents the complete agreement concerning the subject
 | 
			
		||||
matter hereof. If any provision of this License is held to be
 | 
			
		||||
unenforceable, such provision shall be reformed only to the extent
 | 
			
		||||
necessary to make it enforceable. Any law or regulation which provides
 | 
			
		||||
that the language of a contract shall be construed against the drafter
 | 
			
		||||
shall not be used to construe this License against a Contributor.
 | 
			
		||||
 | 
			
		||||
10. Versions of the License
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
10.1. New Versions
 | 
			
		||||
 | 
			
		||||
Mozilla Foundation is the license steward. Except as provided in Section
 | 
			
		||||
10.3, no one other than the license steward has the right to modify or
 | 
			
		||||
publish new versions of this License. Each version will be given a
 | 
			
		||||
distinguishing version number.
 | 
			
		||||
 | 
			
		||||
10.2. Effect of New Versions
 | 
			
		||||
 | 
			
		||||
You may distribute the Covered Software under the terms of the version
 | 
			
		||||
of the License under which You originally received the Covered Software,
 | 
			
		||||
or under the terms of any subsequent version published by the license
 | 
			
		||||
steward.
 | 
			
		||||
 | 
			
		||||
10.3. Modified Versions
 | 
			
		||||
 | 
			
		||||
If you create software not governed by this License, and you want to
 | 
			
		||||
create a new license for such software, you may create and use a
 | 
			
		||||
modified version of this License if you rename the license and remove
 | 
			
		||||
any references to the name of the license steward (except to note that
 | 
			
		||||
such modified license differs from this License).
 | 
			
		||||
 | 
			
		||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
 | 
			
		||||
Licenses
 | 
			
		||||
 | 
			
		||||
If You choose to distribute Source Code Form that is Incompatible With
 | 
			
		||||
Secondary Licenses under the terms of this version of the License, the
 | 
			
		||||
notice described in Exhibit B of this License must be attached.
 | 
			
		||||
 | 
			
		||||
Exhibit A - Source Code Form License Notice
 | 
			
		||||
-------------------------------------------
 | 
			
		||||
 | 
			
		||||
  This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
  License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
			
		||||
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
If it is not possible or desirable to put the notice in a particular
 | 
			
		||||
file, then You may include the notice in a location (such as a LICENSE
 | 
			
		||||
file in a relevant directory) where a recipient would be likely to look
 | 
			
		||||
for such a notice.
 | 
			
		||||
 | 
			
		||||
You may add additional accurate notices of copyright ownership.
 | 
			
		||||
 | 
			
		||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
 | 
			
		||||
---------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
  This Source Code Form is "Incompatible With Secondary Licenses", as
 | 
			
		||||
  defined by the Mozilla Public License, v. 2.0.
 | 
			
		||||
@ -6,331 +6,42 @@
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include "FloatSingle.h"
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
const float Rad2Deg = 57.29578F;
 | 
			
		||||
const float Deg2Rad = 0.0174532924F;
 | 
			
		||||
/*
 | 
			
		||||
float Angle::Normalize(float angle) {
 | 
			
		||||
  if (!isfinite(angle))
 | 
			
		||||
    return angle;
 | 
			
		||||
 | 
			
		||||
//===== AngleSingle, AngleOf<float>
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::Degrees(float degrees) {
 | 
			
		||||
  if (isfinite(degrees)) {
 | 
			
		||||
    while (degrees < -180)
 | 
			
		||||
      degrees += 360;
 | 
			
		||||
    while (degrees >= 180)
 | 
			
		||||
      degrees -= 360;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return AngleOf<float>(degrees);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::Radians(float radians) {
 | 
			
		||||
  if (isfinite(radians)) {
 | 
			
		||||
    while (radians <= -pi)
 | 
			
		||||
      radians += 2 * pi;
 | 
			
		||||
    while (radians > pi)
 | 
			
		||||
      radians -= 2 * pi;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return Binary(radians * Rad2Deg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<float>::InDegrees() const {
 | 
			
		||||
  return this->value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<float>::InRadians() const {
 | 
			
		||||
  return this->value * Deg2Rad;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//===== Angle16, AngleOf<signed short>
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short> AngleOf<signed short>::Degrees(float degrees) {
 | 
			
		||||
  // map float [-180..180) to integer [-32768..32767]
 | 
			
		||||
  signed short value = (signed short)roundf(degrees / 360.0F * 65536.0F);
 | 
			
		||||
  return Binary(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short> AngleOf<signed short>::Radians(float radians) {
 | 
			
		||||
  if (!isfinite(radians))
 | 
			
		||||
    return AngleOf<signed short>::zero;
 | 
			
		||||
 | 
			
		||||
  // map float [-PI..PI) to integer [-32768..32767]
 | 
			
		||||
  signed short value = (signed short)roundf(radians / pi * 32768.0F);
 | 
			
		||||
  return Binary(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<signed short>::InDegrees() const {
 | 
			
		||||
  float degrees = this->value / 65536.0f * 360.0f;
 | 
			
		||||
  return degrees;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<signed short>::InRadians() const {
 | 
			
		||||
  float radians = this->value / 65536.0f * (2 * pi);
 | 
			
		||||
  return radians;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//===== Angle8, AngleOf<signed char>
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed char> AngleOf<signed char>::Degrees(float degrees) {
 | 
			
		||||
  // map float [-180..180) to integer [-128..127)
 | 
			
		||||
  signed char value = (signed char)roundf(degrees / 360.0F * 256.0F);
 | 
			
		||||
  return Binary(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed char> AngleOf<signed char>::Radians(float radians) {
 | 
			
		||||
  if (!isfinite(radians))
 | 
			
		||||
    return AngleOf<signed char>::zero;
 | 
			
		||||
 | 
			
		||||
  // map float [-pi..pi) to integer [-128..127)
 | 
			
		||||
  signed char value = (signed char)roundf(radians / pi * 128.0f);
 | 
			
		||||
  return Binary(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<signed char>::InDegrees() const {
 | 
			
		||||
  float degrees = this->value / 256.0f * 360.0f;
 | 
			
		||||
  return degrees;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<signed char>::InRadians() const {
 | 
			
		||||
  float radians = this->value / 128.0f * pi;
 | 
			
		||||
  return radians;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//===== Generic
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T>::AngleOf() : value(0) {}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T>::AngleOf(T rawValue) : value(rawValue) {}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
const AngleOf<T> AngleOf<T>::zero = AngleOf<T>();
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Binary(T rawValue) {
 | 
			
		||||
  AngleOf<T> angle = AngleOf<T>();
 | 
			
		||||
  angle.SetBinary(rawValue);
 | 
			
		||||
  while (angle <= -180)
 | 
			
		||||
    angle += 360;
 | 
			
		||||
  while (angle > 180)
 | 
			
		||||
    angle -= 360;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
T AngleOf<T>::GetBinary() const {
 | 
			
		||||
  return this->value;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
void AngleOf<T>::SetBinary(T rawValue) {
 | 
			
		||||
  this->value = rawValue;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool AngleOf<T>::operator==(const AngleOf<T> angle) const {
 | 
			
		||||
  return this->value == angle.value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool AngleOf<T>::operator>(AngleOf<T> angle) const {
 | 
			
		||||
  return this->value > angle.value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool AngleOf<T>::operator>=(AngleOf<T> angle) const {
 | 
			
		||||
  return this->value >= angle.value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool AngleOf<T>::operator<(AngleOf<T> angle) const {
 | 
			
		||||
  return this->value < angle.value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool AngleOf<T>::operator<=(AngleOf<T> angle) const {
 | 
			
		||||
  return this->value <= angle.value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
signed int AngleOf<T>::Sign(AngleOf<T> angle) {
 | 
			
		||||
  if (angle.value < 0)
 | 
			
		||||
    return -1;
 | 
			
		||||
  if (angle.value > 0)
 | 
			
		||||
    return 1;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Abs(AngleOf<T> angle) {
 | 
			
		||||
  if (Sign(angle) < 0)
 | 
			
		||||
    return -angle;
 | 
			
		||||
  else
 | 
			
		||||
    return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::operator-() const {
 | 
			
		||||
  AngleOf<T> angle = Binary(-this->value);
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::operator-(const AngleOf<float>& angle) const {
 | 
			
		||||
  AngleOf<float> r = Binary(this->value - angle.value);
 | 
			
		||||
  r = Normalize(r);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::operator-(const AngleOf<T>& angle) const {
 | 
			
		||||
  AngleOf<T> r = Binary(this->value - angle.value);
 | 
			
		||||
float Angle::Clamp(float angle, float min, float max) {
 | 
			
		||||
  float normalizedAngle = Normalize(angle);
 | 
			
		||||
  float r = Float::Clamp(normalizedAngle, min, max);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::operator+(const AngleOf<float>& angle) const {
 | 
			
		||||
  AngleOf<float> r = Binary(this->value + angle.value);
 | 
			
		||||
  r = Normalize(r);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::operator+(const AngleOf<T>& angle) const {
 | 
			
		||||
  AngleOf<T> r = Binary(this->value + angle.value);
 | 
			
		||||
float Angle::Difference(float a, float b) {
 | 
			
		||||
  float r = Normalize(b - a);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::operator+=(const AngleOf<float>& angle) {
 | 
			
		||||
  this->value += angle.value;
 | 
			
		||||
  this->Normalize();
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::operator+=(const AngleOf<T>& angle) {
 | 
			
		||||
  this->value += angle.value;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This defintion is not matching the declaration in the header file somehow
 | 
			
		||||
// template <typename T>
 | 
			
		||||
// AngleOf<T> operator*(const AngleOf<T> &angle, float factor) {
 | 
			
		||||
//   return AngleOf::Degrees((float)angle.InDegrees() * factor);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// This defintion is not matching the declaration in the header file somehow
 | 
			
		||||
// template <typename T>
 | 
			
		||||
// AngleOf<T> operator*(float factor, const AngleOf<T> &angle) {
 | 
			
		||||
//   return AngleOf::Degrees((float)factor * angle.InDegrees());
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void AngleOf<T>::Normalize() {
 | 
			
		||||
  float angleValue = this->InDegrees();
 | 
			
		||||
  if (!isfinite(angleValue))
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  while (angleValue <= -180)
 | 
			
		||||
    angleValue += 360;
 | 
			
		||||
  while (angleValue > 180)
 | 
			
		||||
    angleValue -= 360;
 | 
			
		||||
  *this = AngleOf::Degrees(angleValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Normalize(AngleOf<T> angle) {
 | 
			
		||||
  float angleValue = angle.InDegrees();
 | 
			
		||||
  if (!isfinite(angleValue))
 | 
			
		||||
    return angle;
 | 
			
		||||
 | 
			
		||||
  while (angleValue <= -180)
 | 
			
		||||
    angleValue += 360;
 | 
			
		||||
  while (angleValue > 180)
 | 
			
		||||
    angleValue -= 360;
 | 
			
		||||
  return AngleOf::Degrees(angleValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Clamp(AngleOf<T> angle, AngleOf<T> min, AngleOf<T> max) {
 | 
			
		||||
  float r = Float::Clamp(angle.InDegrees(), min.InDegrees(), max.InDegrees());
 | 
			
		||||
  return AngleOf<T>::Degrees(r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::MoveTowards(AngleOf<T> fromAngle,
 | 
			
		||||
                                   AngleOf<T> toAngle,
 | 
			
		||||
                                   float maxDegrees) {
 | 
			
		||||
  maxDegrees = fmaxf(0, maxDegrees);  // filter out negative distances
 | 
			
		||||
  AngleOf<T> d = toAngle - fromAngle;
 | 
			
		||||
  float dDegrees = Abs(d).InDegrees();
 | 
			
		||||
  d = AngleOf<T>::Degrees(Float::Clamp(dDegrees, 0, maxDegrees));
 | 
			
		||||
  if (Sign(d) < 0)
 | 
			
		||||
    d = -d;
 | 
			
		||||
 | 
			
		||||
float Angle::MoveTowards(float fromAngle, float toAngle, float maxAngle) {
 | 
			
		||||
  float d = toAngle - fromAngle;
 | 
			
		||||
  float sign = signbit(d) ? -1 : 1;
 | 
			
		||||
  d = sign * Float::Clamp(fabs(d), 0, maxAngle);
 | 
			
		||||
  return fromAngle + d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
float AngleOf<T>::Cos(AngleOf<T> angle) {
 | 
			
		||||
  return cosf(angle.InRadians());
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
float AngleOf<T>::Sin(AngleOf<T> angle) {
 | 
			
		||||
  return sinf(angle.InRadians());
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
float AngleOf<T>::Tan(AngleOf<T> angle) {
 | 
			
		||||
  return tanf(angle.InRadians());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Acos(float f) {
 | 
			
		||||
  return AngleOf<T>::Radians(acosf(f));
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Asin(float f) {
 | 
			
		||||
  return AngleOf<T>::Radians(asinf(f));
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Atan(float f) {
 | 
			
		||||
  return AngleOf<T>::Radians(atanf(f));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Atan2(float y, float x) {
 | 
			
		||||
  return AngleOf<T>::Radians(atan2f(y, x));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// float AngleOf<float>::CosineRuleSide(float a, float b, AngleOf<float> gamma)
 | 
			
		||||
// {
 | 
			
		||||
//   float a2 = a * a;
 | 
			
		||||
//   float b2 = b * b;
 | 
			
		||||
//   float d =
 | 
			
		||||
//       a2 + b2 -
 | 
			
		||||
//       2 * a * b * Cos(gamma);  // cosf(gamma *
 | 
			
		||||
//       Passer::LinearAlgebra::Deg2Rad);
 | 
			
		||||
//   // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
//   if (d < 0)
 | 
			
		||||
//     return 0.0f;
 | 
			
		||||
 | 
			
		||||
//   float c = sqrtf(d);
 | 
			
		||||
//   return c;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
float AngleOf<T>::CosineRuleSide(float a, float b, AngleOf<T> gamma) {
 | 
			
		||||
float Angle::CosineRuleSide(float a, float b, float gamma) {
 | 
			
		||||
  float a2 = a * a;
 | 
			
		||||
  float b2 = b * b;
 | 
			
		||||
  float d =
 | 
			
		||||
      a2 + b2 -
 | 
			
		||||
      2 * a * b * Cos(gamma);  // cosf(gamma * Passer::LinearAlgebra::Deg2Rad);
 | 
			
		||||
  float d = a2 + b2 - 2 * a * b * cos(gamma * Angle::Deg2Rad);
 | 
			
		||||
  // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
  if (d < 0)
 | 
			
		||||
    return 0;
 | 
			
		||||
@ -339,56 +50,161 @@ float AngleOf<T>::CosineRuleSide(float a, float b, AngleOf<T> gamma) {
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// AngleOf<float> AngleOf<float>::CosineRuleAngle(float a, float b, float c) {
 | 
			
		||||
//   float a2 = a * a;
 | 
			
		||||
//   float b2 = b * b;
 | 
			
		||||
//   float c2 = c * c;
 | 
			
		||||
//   float d = (a2 + b2 - c2) / (2 * a * b);
 | 
			
		||||
//   // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
//   if (d >= 1)
 | 
			
		||||
//     return 0.0f;
 | 
			
		||||
//   if (d <= -1)
 | 
			
		||||
//     return 180.0f;
 | 
			
		||||
 | 
			
		||||
//   float gamma = acosf(d) * Rad2Deg;
 | 
			
		||||
//   return gamma;
 | 
			
		||||
// }
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::CosineRuleAngle(float a, float b, float c) {
 | 
			
		||||
float Angle::CosineRuleAngle(float a, float b, float c) {
 | 
			
		||||
  float a2 = a * a;
 | 
			
		||||
  float b2 = b * b;
 | 
			
		||||
  float c2 = c * c;
 | 
			
		||||
  float d = (a2 + b2 - c2) / (2 * a * b);
 | 
			
		||||
  // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
  if (d >= 1)
 | 
			
		||||
    return AngleOf<T>();
 | 
			
		||||
    return 0;
 | 
			
		||||
  if (d <= -1)
 | 
			
		||||
    return AngleOf<T>::Degrees(180);
 | 
			
		||||
    return 180;
 | 
			
		||||
 | 
			
		||||
  // float gamma = acosf(d) * Rad2Deg;
 | 
			
		||||
  AngleOf<T> gamma = Acos(d);
 | 
			
		||||
  float gamma = acos(d) * Angle::Rad2Deg;
 | 
			
		||||
  return gamma;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Angle::SineRuleAngle(float a, float beta, float b) {
 | 
			
		||||
  float alpha = asin(a * sin(beta * Angle::Deg2Rad) / b);
 | 
			
		||||
  return alpha;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
//----------------------
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float>::AngleOf(int angle) : value((float)angle) {}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float>::AngleOf(float angle) : value(angle) {}
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// AngleOf<float> AngleOf<float>::SineRuleAngle(float a,
 | 
			
		||||
//                                              AngleOf<float> beta,
 | 
			
		||||
//                                              float b) {
 | 
			
		||||
//   float deg2rad = Deg2Rad;
 | 
			
		||||
//   float alpha = asinf(a * sinf(beta.InDegrees() * deg2rad) / b);
 | 
			
		||||
//   return alpha;
 | 
			
		||||
// AngleOf<float>::operator float() const {
 | 
			
		||||
//   return value;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<float>::ToFloat() const {
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// AngleOf<float> AngleOf<float>::pi = 3.1415927410125732421875F;
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// AngleOf<float> AngleOf<float>::Rad2Deg = 360.0f / (pi * 2);
 | 
			
		||||
// template <>
 | 
			
		||||
// AngleOf<float> AngleOf<float>::Deg2Rad = (pi * 2) / 360.0f;
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
bool AngleOf<float>::operator==(AngleOf<float> a) {
 | 
			
		||||
  return this->ToFloat() == a.ToFloat();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::operator-() const {
 | 
			
		||||
  AngleOf<float> angle = AngleOf(-this->value);
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::operator-(const AngleOf<float>& a) const {
 | 
			
		||||
  AngleOf<float> angle = AngleOf();
 | 
			
		||||
  angle.value = this->value - a.value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::operator+(const AngleOf<float>& a) const {
 | 
			
		||||
  AngleOf<float> angle = AngleOf();
 | 
			
		||||
  angle.value = this->value + a.value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::SineRuleAngle(float a, AngleOf<T> beta, float b) {
 | 
			
		||||
  // float deg2rad = Deg2Rad;
 | 
			
		||||
  // float alpha = asinf(a * sinf(beta.InDegrees() * deg2rad) / b);
 | 
			
		||||
  AngleOf<T> alpha = Asin(a * Sin(beta) / b);
 | 
			
		||||
AngleOf<T> AngleOf<T>::operator+=(const AngleOf<T>& a) {
 | 
			
		||||
  this->value += a.value;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> AngleOf<T>::Normalize(AngleOf<T> angle) {
 | 
			
		||||
  float angleValue = angle.ToFloat();
 | 
			
		||||
  if (!isfinite(angleValue))
 | 
			
		||||
    return angle;
 | 
			
		||||
 | 
			
		||||
  while (angleValue <= -180)
 | 
			
		||||
    angleValue += 360;
 | 
			
		||||
  while (angleValue > 180)
 | 
			
		||||
    angleValue -= 360;
 | 
			
		||||
  return AngleOf(angleValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::Clamp(AngleOf<float> angle,
 | 
			
		||||
                                     AngleOf<float> min,
 | 
			
		||||
                                     AngleOf<float> max) {
 | 
			
		||||
  float normalizedAngle = Normalize(angle).ToFloat();
 | 
			
		||||
  float r = Float::Clamp(normalizedAngle, min.ToFloat(), max.ToFloat());
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// template <typename T>
 | 
			
		||||
// Angle2<T> Angle2<T>::Difference(Angle2<T> a, Angle2<T> b) {
 | 
			
		||||
//   Angle2<T> r = Normalize(b - a);
 | 
			
		||||
//   return r;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::MoveTowards(AngleOf<float> fromAngle,
 | 
			
		||||
                                           AngleOf<float> toAngle,
 | 
			
		||||
                                           AngleOf<float> maxAngle) {
 | 
			
		||||
  float d = toAngle.ToFloat() - fromAngle.ToFloat();
 | 
			
		||||
  int sign = signbit(d) ? -1 : 1;
 | 
			
		||||
  d = sign * Float::Clamp(fabsf(d), 0, maxAngle.ToFloat());
 | 
			
		||||
  return fromAngle.ToFloat() + d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::CosineRuleSide(float a,
 | 
			
		||||
                                              float b,
 | 
			
		||||
                                              AngleOf<float> gamma) {
 | 
			
		||||
  float a2 = a * a;
 | 
			
		||||
  float b2 = b * b;
 | 
			
		||||
  float d = a2 + b2 -
 | 
			
		||||
            2 * a * b * cosf(gamma.ToFloat() * Passer::LinearAlgebra::Deg2Rad);
 | 
			
		||||
  // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
  if (d < 0)
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
 | 
			
		||||
  float c = sqrtf(d);
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::CosineRuleAngle(float a, float b, float c) {
 | 
			
		||||
  float a2 = a * a;
 | 
			
		||||
  float b2 = b * b;
 | 
			
		||||
  float c2 = c * c;
 | 
			
		||||
  float d = (a2 + b2 - c2) / (2 * a * b);
 | 
			
		||||
  // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
  if (d >= 1)
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
  if (d <= -1)
 | 
			
		||||
    return 180.0f;
 | 
			
		||||
 | 
			
		||||
  float gamma = acosf(d) * Rad2Deg;
 | 
			
		||||
  return gamma;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<float> AngleOf<float>::SineRuleAngle(float a,
 | 
			
		||||
                                             AngleOf<float> beta,
 | 
			
		||||
                                             float b) {
 | 
			
		||||
  float deg2rad = Deg2Rad;
 | 
			
		||||
  float alpha = asinf(a * sinf(beta.ToFloat() * deg2rad) / b);
 | 
			
		||||
  return alpha;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template class AngleOf<float>;
 | 
			
		||||
template class AngleOf<signed char>;
 | 
			
		||||
template class AngleOf<signed short>;
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
#ifndef ANGLE_H
 | 
			
		||||
#define ANGLE_H
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
static float pi = 3.1415927410125732421875F;
 | 
			
		||||
@ -12,216 +13,58 @@ static float pi = 3.1415927410125732421875F;
 | 
			
		||||
static float Rad2Deg = 360.0f / (pi * 2);
 | 
			
		||||
static float Deg2Rad = (pi * 2) / 360.0f;
 | 
			
		||||
 | 
			
		||||
/// @brief An angle in various representations.
 | 
			
		||||
/// @tparam T The internal type used for the representation of the angle.
 | 
			
		||||
/// The angle is internally limited to (-180..180] degrees or (-PI...PI]
 | 
			
		||||
/// radians. When an angle exceeds this range, it is normalized to a value
 | 
			
		||||
/// within the range.
 | 
			
		||||
template <typename T>
 | 
			
		||||
class AngleOf {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief Create a new angle with a zero value
 | 
			
		||||
  AngleOf();
 | 
			
		||||
  AngleOf() {};
 | 
			
		||||
  AngleOf(int f);
 | 
			
		||||
  AngleOf(float f);
 | 
			
		||||
  // operator float() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief An zero value angle
 | 
			
		||||
  const static AngleOf<T> zero;
 | 
			
		||||
  // const static AngleOf<T> deg90;
 | 
			
		||||
  // const static AngleOf<T> deg180;
 | 
			
		||||
  float ToFloat() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Creates an angle in degrees
 | 
			
		||||
  /// @param degrees the angle in degrees
 | 
			
		||||
  /// @return The angle value
 | 
			
		||||
  static AngleOf<T> Degrees(float degrees);
 | 
			
		||||
  /// @brief Creates an angle in radians
 | 
			
		||||
  /// @param radians the angle in radians
 | 
			
		||||
  /// @return The angle value
 | 
			
		||||
  static AngleOf<T> Radians(float radians);
 | 
			
		||||
  inline T GetBinary() const { return this->value; }
 | 
			
		||||
 | 
			
		||||
  /// @brief Creates an angle from a raw value
 | 
			
		||||
  /// @param rawValue the raw value to use for the angle
 | 
			
		||||
  /// @return The the angle
 | 
			
		||||
  static AngleOf<T> Binary(T rawValue);
 | 
			
		||||
  static AngleOf<T> pi;
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the angle value in degrees
 | 
			
		||||
  /// @return The angle value in degrees
 | 
			
		||||
  float InDegrees() const;
 | 
			
		||||
  /// @brief Get the angle value in radians
 | 
			
		||||
  /// @return The angle value in radians
 | 
			
		||||
  float InRadians() const;
 | 
			
		||||
  bool operator==(AngleOf<T> a);
 | 
			
		||||
 | 
			
		||||
  /// @brief Get the raw value for the angle
 | 
			
		||||
  /// @return The raw value
 | 
			
		||||
  T GetBinary() const;
 | 
			
		||||
  /// @brief Set the raw value of the angle
 | 
			
		||||
  /// @param rawValue The raw value
 | 
			
		||||
  void SetBinary(T rawValue);
 | 
			
		||||
 | 
			
		||||
  /// @brief Tests whether this angle is equal to the given angle
 | 
			
		||||
  /// @param angle The angle to compare to
 | 
			
		||||
  /// @return True when the angles are equal, False otherwise
 | 
			
		||||
  /// @note The equality is determine within the limits of precision of the raw
 | 
			
		||||
  /// type T
 | 
			
		||||
  bool operator==(const AngleOf<T> angle) const;
 | 
			
		||||
  /// @brief Tests if this angle is greater than the given angle
 | 
			
		||||
  /// @param angle The given angle
 | 
			
		||||
  /// @return True when this angle is greater than the given angle, False
 | 
			
		||||
  /// otherwise
 | 
			
		||||
  bool operator>(AngleOf<T> angle) const;
 | 
			
		||||
  /// @brief Tests if this angle is greater than or equal to the given angle
 | 
			
		||||
  /// @param angle The given angle
 | 
			
		||||
  /// @return True when this angle is greater than or equal to the given angle.
 | 
			
		||||
  /// False otherwise.
 | 
			
		||||
  bool operator>=(AngleOf<T> angle) const;
 | 
			
		||||
  /// @brief Tests if this angle is less than the given angle
 | 
			
		||||
  /// @param angle The given angle
 | 
			
		||||
  /// @return True when this angle is less than the given angle. False
 | 
			
		||||
  /// otherwise.
 | 
			
		||||
  bool operator<(AngleOf<T> angle) const;
 | 
			
		||||
  /// @brief Tests if this angle is less than or equal to the given angle
 | 
			
		||||
  /// @param angle The given angle
 | 
			
		||||
  /// @return True when this angle is less than or equal to the given angle.
 | 
			
		||||
  /// False otherwise.
 | 
			
		||||
  bool operator<=(AngleOf<T> angle) const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Returns the sign of the angle
 | 
			
		||||
  /// @param angle The angle
 | 
			
		||||
  /// @return -1 when the angle is negative, 1 when it is positive and 0
 | 
			
		||||
  /// otherwise.
 | 
			
		||||
  static signed int Sign(AngleOf<T> angle);
 | 
			
		||||
  /// @brief Returns the magnitude of the angle
 | 
			
		||||
  /// @param angle The angle
 | 
			
		||||
  /// @return The positive magitude of the angle.
 | 
			
		||||
  /// Negative values are negated to get a positive result
 | 
			
		||||
  static AngleOf<T> Abs(AngleOf<T> angle);
 | 
			
		||||
 | 
			
		||||
  /// @brief Negate the angle
 | 
			
		||||
  /// @return The negated angle
 | 
			
		||||
  AngleOf<T> operator-() const;
 | 
			
		||||
  /// @brief Substract another angle from this angle
 | 
			
		||||
  /// @param angle The angle to subtract from this angle
 | 
			
		||||
  /// @return The result of the subtraction
 | 
			
		||||
  AngleOf<T> operator-(const AngleOf<T>& angle) const;
 | 
			
		||||
  /// @brief Add another angle from this angle
 | 
			
		||||
  /// @param angle The angle to add to this angle
 | 
			
		||||
  /// @return The result of the addition
 | 
			
		||||
  AngleOf<T> operator+(const AngleOf<T>& angle) const;
 | 
			
		||||
  /// @brief Add another angle to this angle
 | 
			
		||||
  /// @param angle The angle to add to this angle
 | 
			
		||||
  /// @return The result of the addition
 | 
			
		||||
  AngleOf<T> operator+=(const AngleOf<T>& angle);
 | 
			
		||||
  AngleOf<T> operator-(const AngleOf<T>& a) const;
 | 
			
		||||
  AngleOf<T> operator+(const AngleOf<T>& a) const;
 | 
			
		||||
  AngleOf<T> operator+=(const AngleOf<T>& a);
 | 
			
		||||
 | 
			
		||||
  /// @brief Mutliplies the angle
 | 
			
		||||
  /// @param angle The angle to multiply
 | 
			
		||||
  /// @param factor The factor by which the angle is multiplied
 | 
			
		||||
  /// @return The multiplied angle
 | 
			
		||||
  friend AngleOf<T> operator*(const AngleOf<T>& angle, float factor) {
 | 
			
		||||
    return AngleOf::Degrees((float)angle.InDegrees() * factor);
 | 
			
		||||
  friend AngleOf<T> operator*(const AngleOf<T>& a, float f) {
 | 
			
		||||
    return AngleOf((float)a.ToFloat() * f);
 | 
			
		||||
  }
 | 
			
		||||
  /// @brief Multiplies the angle
 | 
			
		||||
  /// @param factor The factor by which the angle is multiplies
 | 
			
		||||
  /// @param angle The angle to multiply
 | 
			
		||||
  /// @return The multiplied angle
 | 
			
		||||
  friend AngleOf<T> operator*(float factor, const AngleOf<T>& angle) {
 | 
			
		||||
    return AngleOf::Degrees((float)factor * angle.InDegrees());
 | 
			
		||||
  friend AngleOf<T> operator*(float f, const AngleOf<T>& a) {
 | 
			
		||||
    return AngleOf((float)f * a.ToFloat());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// @brief Normalizes the angle to (-180..180] or (-PI..PI]
 | 
			
		||||
  /// Should not be needed but available in case it is.
 | 
			
		||||
  void Normalize();
 | 
			
		||||
  /// @brief Normalizes the angle to (-180..180] or (-PI..PI]
 | 
			
		||||
  /// @param angle The angle to normalize
 | 
			
		||||
  /// @return The normalized angle;
 | 
			
		||||
  static AngleOf<T> Normalize(AngleOf<T> angle);
 | 
			
		||||
  /// @brief Clamps the angle value between the two given angles
 | 
			
		||||
  /// @param angle The angle to clamp
 | 
			
		||||
  /// @param min The minimum angle
 | 
			
		||||
  /// @param max The maximum angle
 | 
			
		||||
  /// @return The clamped value
 | 
			
		||||
  /// @remark When the min value is greater than the max value, angle is
 | 
			
		||||
  /// returned unclamped.
 | 
			
		||||
  static AngleOf<T> Clamp(AngleOf<T> angle, AngleOf<T> min, AngleOf<T> max);
 | 
			
		||||
  // static AngleOf<T> Difference(AngleOf<T> a, AngleOf<T> b) {
 | 
			
		||||
  //   AngleOf<T> r = Normalize(b.InDegrees() - a.InDegrees());
 | 
			
		||||
  //   return r;
 | 
			
		||||
  // };
 | 
			
		||||
 | 
			
		||||
  /// @brief Rotates an angle towards another angle with a max distance
 | 
			
		||||
  /// @param fromAngle The angle to start from
 | 
			
		||||
  /// @param toAngle The angle to rotate towards
 | 
			
		||||
  /// @param maxAngle The maximum angle to rotate
 | 
			
		||||
  /// @return The rotated angle
 | 
			
		||||
  static AngleOf<T> Normalize(AngleOf<T> a);
 | 
			
		||||
  static AngleOf<T> Clamp(AngleOf<T> a, AngleOf<T> min, AngleOf<T> max);
 | 
			
		||||
  static AngleOf<T> Difference(AngleOf<T> a, AngleOf<T> b) {
 | 
			
		||||
    AngleOf<T> r = Normalize(b.ToFloat() - a.ToFloat());
 | 
			
		||||
    return r;
 | 
			
		||||
  };
 | 
			
		||||
  static AngleOf<T> MoveTowards(AngleOf<T> fromAngle,
 | 
			
		||||
                                AngleOf<T> toAngle,
 | 
			
		||||
                                float maxAngle);
 | 
			
		||||
                                AngleOf<T> maxAngle);
 | 
			
		||||
 | 
			
		||||
  /// @brief Calculates the cosine of an angle
 | 
			
		||||
  /// @param angle The given angle
 | 
			
		||||
  /// @return The cosine of the angle
 | 
			
		||||
  static float Cos(AngleOf<T> angle);
 | 
			
		||||
  /// @brief Calculates the sine of an angle
 | 
			
		||||
  /// @param angle The given angle
 | 
			
		||||
  /// @return The sine of the angle
 | 
			
		||||
  static float Sin(AngleOf<T> angle);
 | 
			
		||||
  /// @brief Calculates the tangent of an angle
 | 
			
		||||
  /// @param angle The given angle
 | 
			
		||||
  /// @return The tangent of the angle
 | 
			
		||||
  static float Tan(AngleOf<T> angle);
 | 
			
		||||
 | 
			
		||||
  /// @brief Calculates the arc cosine angle
 | 
			
		||||
  /// @param f The value
 | 
			
		||||
  /// @return The arc cosine for the given value
 | 
			
		||||
  static AngleOf<T> Acos(float f);
 | 
			
		||||
  /// @brief Calculates the arc sine angle
 | 
			
		||||
  /// @param f The value
 | 
			
		||||
  /// @return The arc sine for the given value
 | 
			
		||||
  static AngleOf<T> Asin(float f);
 | 
			
		||||
  /// @brief Calculates the arc tangent angle
 | 
			
		||||
  /// @param f The value
 | 
			
		||||
  /// @return The arc tangent for the given value
 | 
			
		||||
  static AngleOf<T> Atan(float f);
 | 
			
		||||
  /// @brief Calculates the tangent for the given values
 | 
			
		||||
  /// @param y The vertical value
 | 
			
		||||
  /// @param x The horizontal value
 | 
			
		||||
  /// @return The tanget for the given values
 | 
			
		||||
  /// Uses the y and x signs to compute the quadrant
 | 
			
		||||
  static AngleOf<T> Atan2(float y, float x);
 | 
			
		||||
 | 
			
		||||
  /// @brief Computes the length of a side using the rule of cosines
 | 
			
		||||
  /// @param a The length of side A
 | 
			
		||||
  /// @param b The length of side B
 | 
			
		||||
  /// @param gamma The angle of the corner opposing side C
 | 
			
		||||
  /// @return The length of side C
 | 
			
		||||
  static float CosineRuleSide(float a, float b, AngleOf<T> gamma);
 | 
			
		||||
  /// @brief Computes the angle of a corner using the rule of cosines
 | 
			
		||||
  /// @param a The length of side A
 | 
			
		||||
  /// @param b The length of side B
 | 
			
		||||
  /// @param c The length of side C
 | 
			
		||||
  /// @return The angle of the corner opposing side C
 | 
			
		||||
  static AngleOf<T> CosineRuleSide(float a, float b, AngleOf<T> gamma);
 | 
			
		||||
  static AngleOf<T> CosineRuleAngle(float a, float b, float c);
 | 
			
		||||
 | 
			
		||||
  /// @brief Computes the angle of a corner using the rule of sines
 | 
			
		||||
  /// @param a The length of side A
 | 
			
		||||
  /// @param beta the angle of the corner opposing side B
 | 
			
		||||
  /// @param c The length of side C
 | 
			
		||||
  /// @return The angle of the corner opposing side A
 | 
			
		||||
  static AngleOf<T> SineRuleAngle(float a, AngleOf<T> beta, float c);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  T value;
 | 
			
		||||
 | 
			
		||||
  AngleOf(T rawValue);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using AngleSingle = AngleOf<float>;
 | 
			
		||||
using Angle = AngleOf<float>;
 | 
			
		||||
using Angle16 = AngleOf<signed short>;
 | 
			
		||||
using Angle8 = AngleOf<signed char>;
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO)
 | 
			
		||||
using Angle = Angle16;
 | 
			
		||||
#else
 | 
			
		||||
using Angle = AngleSingle;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										96
									
								
								LinearAlgebra/Angle16.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								LinearAlgebra/Angle16.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short>::AngleOf(int angle) {
 | 
			
		||||
  signed long long_angle = (signed short)angle * 65536;
 | 
			
		||||
  this->value = (signed short)(long_angle / 360);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short>::AngleOf(float angle) {
 | 
			
		||||
  if (!isfinite(angle)) {
 | 
			
		||||
    value = 0;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // map float [-180..180) to integer [-32768..32767]
 | 
			
		||||
  this->value = (signed short)(angle / 360.0F * 65536.0F);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// AngleOf<signed short>::operator float() const {
 | 
			
		||||
//   float f = ((this->value * 180) / 32768.0F);
 | 
			
		||||
//   return f;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<signed short>::ToFloat() const {
 | 
			
		||||
  float f = ((this->value * 180) / 32768.0F);
 | 
			
		||||
  return f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short> AngleOf<signed short>::operator-() const {
 | 
			
		||||
  AngleOf<signed short> angle = AngleOf();
 | 
			
		||||
  angle.value = -this->value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short> AngleOf<signed short>::operator-(
 | 
			
		||||
    const AngleOf<signed short>& a) const {
 | 
			
		||||
  AngleOf<signed short> angle = AngleOf();
 | 
			
		||||
  angle.value = this->value - a.value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short> AngleOf<signed short>::operator+(
 | 
			
		||||
    const AngleOf<signed short>& a) const {
 | 
			
		||||
  AngleOf<signed short> angle = AngleOf();
 | 
			
		||||
  angle.value = this->value + a.value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Not correct!!! just for syntactical compilation ATM
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short> AngleOf<signed short>::CosineRuleSide(
 | 
			
		||||
    float a,
 | 
			
		||||
    float b,
 | 
			
		||||
    AngleOf<signed short> gamma) {
 | 
			
		||||
  float a2 = a * a;
 | 
			
		||||
  float b2 = b * b;
 | 
			
		||||
  float d = a2 + b2 -
 | 
			
		||||
            2 * a * b * cosf(gamma.ToFloat() * Passer::LinearAlgebra::Deg2Rad);
 | 
			
		||||
  // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
  if (d < 0)
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
 | 
			
		||||
  float c = sqrtf(d);
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Not correct!!! just for syntactical compilation ATM
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed short> AngleOf<signed short>::CosineRuleAngle(float a,
 | 
			
		||||
                                                             float b,
 | 
			
		||||
                                                             float c) {
 | 
			
		||||
  float a2 = a * a;
 | 
			
		||||
  float b2 = b * b;
 | 
			
		||||
  float c2 = c * c;
 | 
			
		||||
  float d = (a2 + b2 - c2) / (2 * a * b);
 | 
			
		||||
  // Catch edge cases where float inacuracies lead tot nans
 | 
			
		||||
  if (d >= 1)
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
  if (d <= -1)
 | 
			
		||||
    return 180.0f;
 | 
			
		||||
 | 
			
		||||
  float gamma = acosf(d) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
  return gamma;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								LinearAlgebra/Angle16.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								LinearAlgebra/Angle16.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
// #include "AngleUsing.h"
 | 
			
		||||
/*
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
typedef AngleOf<signed short> Angle16;
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// inline static Angle16 Angle16::Degrees(short angle) {
 | 
			
		||||
//   long long_angle = angle * 65535;
 | 
			
		||||
//   long_angle = div(long_angle, (long)360);
 | 
			
		||||
//   return Angle16(long_angle);  //(long_angle / 360);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// inline static Angle16 Angle16::Degrees(float angle) {
 | 
			
		||||
//   return (angle / 360.0F * 65536.0F);
 | 
			
		||||
// }
 | 
			
		||||
// template <> Angle16::AngleOf(float angle) {
 | 
			
		||||
//   if (!isfinite(angle)) {
 | 
			
		||||
//     value = 0;
 | 
			
		||||
//     return;
 | 
			
		||||
//   }
 | 
			
		||||
 | 
			
		||||
//   // map float [-180..180) to integer [-32768..32767]
 | 
			
		||||
//   this->value = (signed short)((angle / 360.0F) * 65536.0F);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// template <> float Angle16::ToFloat() const {
 | 
			
		||||
//   float f = ((this->value * 180) / 32768.0F);
 | 
			
		||||
//   return f;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										30
									
								
								LinearAlgebra/Angle32.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								LinearAlgebra/Angle32.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
// #include "AngleUsing.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
typedef AngleOf<signed long> Angle32;
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// Angle32::AngleOf(float angle) {
 | 
			
		||||
//   if (!isfinite(angle)) {
 | 
			
		||||
//     value = 0;
 | 
			
		||||
//     return;
 | 
			
		||||
//   }
 | 
			
		||||
 | 
			
		||||
//   // map float [-180..180) to integer [-2147483648..2147483647]
 | 
			
		||||
//   this->value = (signed long)((angle / 360.0F) * 4294967295.0F);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// float Angle32::ToFloat() const {
 | 
			
		||||
//   float f = ((this->value * 180) / 2147483648.0F);
 | 
			
		||||
//   return f;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
							
								
								
									
										59
									
								
								LinearAlgebra/Angle8.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								LinearAlgebra/Angle8.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed char>::AngleOf(int angle) {
 | 
			
		||||
  signed short short_angle = (signed char)angle * 256;
 | 
			
		||||
  this->value = (signed char)(short_angle / 360);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed char>::AngleOf(float angle) {
 | 
			
		||||
  if (!isfinite(angle)) {
 | 
			
		||||
    value = 0;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // map float [-180..180) to integer [-128..127]
 | 
			
		||||
  float f = angle / 360.0F;
 | 
			
		||||
  this->value = (signed char)(f * 256.0F);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// AngleOf<signed char>::operator float() const {
 | 
			
		||||
//   float f = (this->value * 180) / 128.0F;
 | 
			
		||||
//   return f;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
float AngleOf<signed char>::ToFloat() const {
 | 
			
		||||
  float f = (this->value * 180) / 128.0F;
 | 
			
		||||
  return f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed char> AngleOf<signed char>::operator-() const {
 | 
			
		||||
  AngleOf<signed char> angle = AngleOf();
 | 
			
		||||
  angle.value = -this->value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed char> AngleOf<signed char>::operator-(
 | 
			
		||||
    const AngleOf<signed char>& a) const {
 | 
			
		||||
  AngleOf<signed char> angle = AngleOf();
 | 
			
		||||
  angle.value = this->value - a.value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
AngleOf<signed char> AngleOf<signed char>::operator+(
 | 
			
		||||
    const AngleOf<signed char>& a) const {
 | 
			
		||||
  AngleOf<signed char> angle = AngleOf();
 | 
			
		||||
  angle.value = this->value + a.value;
 | 
			
		||||
  return angle;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								LinearAlgebra/Angle8.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								LinearAlgebra/Angle8.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
// #include "AngleUsing.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
typedef AngleOf<signed char> Angle8;
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// inline static Angle8 Angle8::Degrees(float angle) {
 | 
			
		||||
//   return (angle / 360.0F * 256.0F);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// template <> Angle8::AngleOf(float angle) {
 | 
			
		||||
//   if (!isfinite(angle)) {
 | 
			
		||||
//     value = 0;
 | 
			
		||||
//     return;
 | 
			
		||||
//   }
 | 
			
		||||
 | 
			
		||||
//   // map float [-180..180) to integer [-128..127]
 | 
			
		||||
//   float f = angle / 360.0F;
 | 
			
		||||
//   this->value = (signed char)(f * 256.0F);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// template <> float Angle8::ToFloat() const {
 | 
			
		||||
//   float f = (this->value * 180) / 128.0F;
 | 
			
		||||
//   return f;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
							
								
								
									
										48
									
								
								LinearAlgebra/AngleAxis.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								LinearAlgebra/AngleAxis.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#include "AngleAxis.h"
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleAxis<T>::AngleAxis() {
 | 
			
		||||
  this->angle = AngleOf<T>();
 | 
			
		||||
  this->axis = Direction<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleAxis<T>::AngleAxis(AngleOf<T> angle, Direction<T> axis) {
 | 
			
		||||
  this->angle = angle;
 | 
			
		||||
  this->axis = axis;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleAxis<T>::AngleAxis(float angle, Vector3 axis) {
 | 
			
		||||
  this->angle = AngleOf<T>(angle);
 | 
			
		||||
  this->axis = Direction<T>(axis);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleAxis<T>::AngleAxis(Quaternion q) {
 | 
			
		||||
  float angle;
 | 
			
		||||
  Vector3 axis;
 | 
			
		||||
  q.ToAngleAxis(&angle, &axis);
 | 
			
		||||
  this->angle = AngleOf<T>(angle);
 | 
			
		||||
  this->axis = Direction<T>(axis);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
Quaternion AngleAxis<T>::ToQuaternion() {
 | 
			
		||||
  Vector3 axisVector = this->axis.ToVector3();
 | 
			
		||||
  float angleFloat = this->angle.ToFloat();
 | 
			
		||||
  Quaternion q = Quaternion::AngleAxis(angleFloat, axisVector);
 | 
			
		||||
  return q;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
Direction<T> AngleAxis<T>::GetSwing() {
 | 
			
		||||
  return this->axis;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template class AngleAxis<float>;
 | 
			
		||||
template class AngleAxis<signed short>;
 | 
			
		||||
							
								
								
									
										35
									
								
								LinearAlgebra/AngleAxis.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								LinearAlgebra/AngleAxis.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#ifndef ANGLEAXIS_H
 | 
			
		||||
#define ANGLEAXIS_H
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
#include "Direction.h"
 | 
			
		||||
#include "Quaternion.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class AngleAxis {
 | 
			
		||||
 public:
 | 
			
		||||
  AngleOf<T> angle;
 | 
			
		||||
  Direction<T> axis;
 | 
			
		||||
 | 
			
		||||
  AngleAxis();
 | 
			
		||||
  AngleAxis(AngleOf<T> angle, Direction<T> axis);
 | 
			
		||||
  AngleAxis(Quaternion q);
 | 
			
		||||
  AngleAxis(float angle, Vector3 axis);
 | 
			
		||||
 | 
			
		||||
  Quaternion ToQuaternion();
 | 
			
		||||
 | 
			
		||||
  Direction<T> GetSwing();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										52
									
								
								LinearAlgebra/AngleUsing.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								LinearAlgebra/AngleUsing.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
#ifndef DISCRETEANGLE_H
 | 
			
		||||
#define DISCRETEANGLE_H
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
#include "Range.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
// A fixed angle between (-180..180]
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class AngleUsing {
 | 
			
		||||
 public:
 | 
			
		||||
  AngleUsing(T sourceValue) { this->value = sourceValue; }
 | 
			
		||||
  AngleUsing(float f);
 | 
			
		||||
  float ToFloat() const;
 | 
			
		||||
  inline T GetValue() const { return this->value; }
 | 
			
		||||
 | 
			
		||||
  AngleUsing<T> operator+(const AngleUsing<T> a) {
 | 
			
		||||
    AngleUsing<T> r = AngleUsing((float)this->value + a.value);
 | 
			
		||||
    return r;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  inline AngleUsing<T> operator+=(const AngleUsing<T> a) {
 | 
			
		||||
    return this->value + a.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  inline AngleUsing<T> operator-(const AngleUsing<T> a) {
 | 
			
		||||
    return this->value - a.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  inline AngleUsing<T> operator-() {
 | 
			
		||||
    this->value = -this->value;
 | 
			
		||||
    return *this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  inline bool operator==(const AngleUsing<T> a) {
 | 
			
		||||
    return this->value == a.value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // protected:
 | 
			
		||||
  T value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										40
									
								
								LinearAlgebra/Axis.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								LinearAlgebra/Axis.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#include "Axis.h"
 | 
			
		||||
 | 
			
		||||
#include "Quaternion.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
Axis::Axis() {
 | 
			
		||||
  horizontalAngle = 0.0f;
 | 
			
		||||
  verticalAngle = 0.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Axis::Axis(Angle horizontal, Angle vertical) {
 | 
			
		||||
  this->horizontalAngle = horizontal;
 | 
			
		||||
  this->verticalAngle = vertical;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Axis::Axis(Vector3 v) {
 | 
			
		||||
  this->horizontalAngle =
 | 
			
		||||
      atan2f(v.Right(), v.Forward()) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
  this->verticalAngle = 90 - acosf(v.Up()) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Axis Axis::forward = Axis(0.0f, 0.0f);
 | 
			
		||||
const Axis Axis::back = Axis(180.0f, 0.0f);
 | 
			
		||||
const Axis Axis::up = Axis(0.0f, 90.0f);
 | 
			
		||||
const Axis Axis::down = Axis(0.0f, -90.0f);
 | 
			
		||||
const Axis Axis::left = Axis(-90.0f, 0.0f);
 | 
			
		||||
const Axis Axis::right = Axis(90.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
Vector3 Axis::ToVector3() {
 | 
			
		||||
  Vector3 v = Quaternion::Euler(-(this->verticalAngle.ToFloat()),
 | 
			
		||||
                                this->horizontalAngle.ToFloat(), 0) *
 | 
			
		||||
              Vector3::forward;
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								LinearAlgebra/Axis.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								LinearAlgebra/Axis.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#ifndef AXIS_H
 | 
			
		||||
#define AXIS_H
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
struct Vector3;
 | 
			
		||||
 | 
			
		||||
class Axis {
 | 
			
		||||
public:
 | 
			
		||||
  Angle horizontalAngle;
 | 
			
		||||
  Angle verticalAngle;
 | 
			
		||||
 | 
			
		||||
  Axis();
 | 
			
		||||
  Axis(Angle horizontal, Angle vertical);
 | 
			
		||||
  Axis(Vector3 v);
 | 
			
		||||
 | 
			
		||||
  const static Axis forward;
 | 
			
		||||
  const static Axis back;
 | 
			
		||||
  const static Axis up;
 | 
			
		||||
  const static Axis down;
 | 
			
		||||
  const static Axis left;
 | 
			
		||||
  const static Axis right;
 | 
			
		||||
 | 
			
		||||
  Vector3 ToVector3();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace LinearAlgebra
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -7,14 +7,14 @@ if(ESP_PLATFORM)
 | 
			
		||||
else() 
 | 
			
		||||
    project(LinearAlgebra)
 | 
			
		||||
 | 
			
		||||
    set(CMAKE_CXX_STANDARD 17)            # Enable c++11 standard
 | 
			
		||||
    set(CMAKE_CXX_STANDARD 11)            # Enable c++11 standard
 | 
			
		||||
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 | 
			
		||||
 | 
			
		||||
    add_compile_definitions(GTEST)
 | 
			
		||||
    include(FetchContent)
 | 
			
		||||
    FetchContent_Declare(
 | 
			
		||||
        googletest
 | 
			
		||||
        DOWNLOAD_EXTRACT_TIMESTAMP ON
 | 
			
		||||
        DOWNLOAD_EXTRACT_TIMESTAMP 
 | 
			
		||||
        URL https://github.com/google/googletest/archive/refs/heads/main.zip
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
@ -23,28 +23,37 @@ else()
 | 
			
		||||
    FetchContent_MakeAvailable(googletest)
 | 
			
		||||
 | 
			
		||||
    include_directories(.)
 | 
			
		||||
    file(GLOB srcs
 | 
			
		||||
        *.cpp
 | 
			
		||||
    )
 | 
			
		||||
    add_library(LinearAlgebra STATIC ${srcs}
 | 
			
		||||
        # "FloatSingle.cpp"
 | 
			
		||||
        # "Angle.cpp"
 | 
			
		||||
        # "Vector2.cpp" 
 | 
			
		||||
        # "Vector3.cpp" 
 | 
			
		||||
        # "Quaternion.cpp"
 | 
			
		||||
        # "Polar.cpp" 
 | 
			
		||||
        # "Spherical.cpp"
 | 
			
		||||
        # "Matrix.cpp"
 | 
			
		||||
        # "SwingTwist.cpp"
 | 
			
		||||
        # "Direction.cpp"
 | 
			
		||||
    add_library(LinearAlgebra STATIC 
 | 
			
		||||
        "FloatSingle.cpp"
 | 
			
		||||
        "Angle.cpp"
 | 
			
		||||
        "Angle8.cpp"
 | 
			
		||||
        "Angle16.cpp"
 | 
			
		||||
        "Vector2.cpp" 
 | 
			
		||||
        "Vector3.cpp" 
 | 
			
		||||
        "Quaternion.cpp"
 | 
			
		||||
        "Polar.cpp" 
 | 
			
		||||
        "Spherical.cpp"
 | 
			
		||||
        "Spherical16.cpp"
 | 
			
		||||
        "Matrix.cpp"
 | 
			
		||||
        "Axis.cpp"
 | 
			
		||||
        "AngleAxis.cpp"
 | 
			
		||||
        "Direction.cpp"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    enable_testing()
 | 
			
		||||
 | 
			
		||||
    file(GLOB_RECURSE test_srcs test/*_test.cc)
 | 
			
		||||
    add_executable(
 | 
			
		||||
        LinearAlgebraTest
 | 
			
		||||
        ${test_srcs}
 | 
			
		||||
        "test/Angle_test.cc"
 | 
			
		||||
        "test/FloatSingle_test.cc"
 | 
			
		||||
        "test/Vector2_test.cc"
 | 
			
		||||
        "test/Vector3_test.cc"
 | 
			
		||||
        "test/Quaternion_test.cc"
 | 
			
		||||
        "test/Matrix_test.cc"
 | 
			
		||||
        "test/Polar_test.cc"
 | 
			
		||||
        "test/Spherical_test.cc"
 | 
			
		||||
        "test/Spherical16_test.cc"
 | 
			
		||||
        "test/DiscreteAngle_test.cc"
 | 
			
		||||
    )
 | 
			
		||||
    target_link_libraries(
 | 
			
		||||
        LinearAlgebraTest
 | 
			
		||||
@ -54,9 +63,9 @@ else()
 | 
			
		||||
 | 
			
		||||
    if(MSVC)
 | 
			
		||||
    target_compile_options(LinearAlgebraTest PRIVATE /W4 /WX)
 | 
			
		||||
#   else()
 | 
			
		||||
#     target_compile_options(LinearAlgebraTest PRIVATE -Wall -Wextra -Wpedantic -Werror)
 | 
			
		||||
   endif()
 | 
			
		||||
  else()
 | 
			
		||||
    target_compile_options(LinearAlgebraTest PRIVATE -Wall -Wextra -Wpedantic -Werror)
 | 
			
		||||
  endif()
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
    include(GoogleTest)
 | 
			
		||||
 | 
			
		||||
@ -9,96 +9,46 @@
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
template <typename T>
 | 
			
		||||
DirectionOf<T>::DirectionOf() {
 | 
			
		||||
  this->horizontal = AngleOf<T>();
 | 
			
		||||
  this->vertical = AngleOf<T>();
 | 
			
		||||
Direction<T>::Direction() {
 | 
			
		||||
  this->horizontalAngle = AngleOf<T>(0.0f);
 | 
			
		||||
  this->verticalAngle = AngleOf<T>(0.0f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
DirectionOf<T>::DirectionOf(AngleOf<T> horizontal, AngleOf<T> vertical) {
 | 
			
		||||
  this->horizontal = horizontal;
 | 
			
		||||
  this->vertical = vertical;
 | 
			
		||||
  Normalize();
 | 
			
		||||
Direction<T>::Direction(AngleOf<T> horizontal, AngleOf<T> vertical) {
 | 
			
		||||
  this->horizontalAngle = horizontal;
 | 
			
		||||
  this->verticalAngle = vertical;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
const DirectionOf<T> DirectionOf<T>::forward =
 | 
			
		||||
    DirectionOf<T>(AngleOf<T>(), AngleOf<T>());
 | 
			
		||||
template <typename T>
 | 
			
		||||
const DirectionOf<T> DirectionOf<T>::back =
 | 
			
		||||
    DirectionOf<T>(AngleOf<T>::Degrees(180), AngleOf<T>());
 | 
			
		||||
template <typename T>
 | 
			
		||||
const DirectionOf<T> DirectionOf<T>::up =
 | 
			
		||||
    DirectionOf<T>(AngleOf<T>(), AngleOf<T>::Degrees(90));
 | 
			
		||||
template <typename T>
 | 
			
		||||
const DirectionOf<T> DirectionOf<T>::down =
 | 
			
		||||
    DirectionOf<T>(AngleOf<T>(), AngleOf<T>::Degrees(-90));
 | 
			
		||||
template <typename T>
 | 
			
		||||
const DirectionOf<T> DirectionOf<T>::left =
 | 
			
		||||
    DirectionOf<T>(AngleOf<T>::Degrees(-90), AngleOf<T>());
 | 
			
		||||
template <typename T>
 | 
			
		||||
const DirectionOf<T> DirectionOf<T>::right =
 | 
			
		||||
    DirectionOf<T>(AngleOf<T>::Degrees(90), AngleOf<T>());
 | 
			
		||||
Direction<T>::Direction(Vector3 v) {
 | 
			
		||||
  this->horizontalAngle =
 | 
			
		||||
      atan2f(v.Right(), v.Forward()) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
  this->verticalAngle = 90 - acosf(v.Up()) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
Vector3 DirectionOf<T>::ToVector3() const {
 | 
			
		||||
  Quaternion q = Quaternion::Euler(-this->vertical.InDegrees(),
 | 
			
		||||
                                   this->horizontal.InDegrees(), 0);
 | 
			
		||||
  Vector3 v = q * Vector3::forward;
 | 
			
		||||
const Direction<T> Direction<T>::forward = Direction<T>(0.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const Direction<T> Direction<T>::back = Direction<T>(180.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const Direction<T> Direction<T>::up = Direction<T>(0.0f, 90.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const Direction<T> Direction<T>::down = Direction<T>(0.0f, -90.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const Direction<T> Direction<T>::left = Direction<T>(-90.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const Direction<T> Direction<T>::right = Direction<T>(90.0f, 0.0f);
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
Vector3 Direction<T>::ToVector3() {
 | 
			
		||||
  Vector3 v = Quaternion::Euler(-(this->verticalAngle.ToFloat()),
 | 
			
		||||
                                this->horizontalAngle.ToFloat(), 0) *
 | 
			
		||||
              Vector3::forward;
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
DirectionOf<T> DirectionOf<T>::FromVector3(Vector3 vector) {
 | 
			
		||||
  DirectionOf<T> d;
 | 
			
		||||
  d.horizontal = AngleOf<T>::Atan2(
 | 
			
		||||
      vector.Right(),
 | 
			
		||||
      vector
 | 
			
		||||
          .Forward());  // AngleOf<T>::Radians(atan2f(v.Right(), v.Forward()));
 | 
			
		||||
  d.vertical =
 | 
			
		||||
      AngleOf<T>::Degrees(-90) -
 | 
			
		||||
      AngleOf<T>::Acos(
 | 
			
		||||
          vector.Up());  // AngleOf<T>::Radians(-(0.5f * pi) - acosf(v.Up()));
 | 
			
		||||
  d.Normalize();
 | 
			
		||||
  return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
DirectionOf<T> DirectionOf<T>::Degrees(float horizontal, float vertical) {
 | 
			
		||||
  return DirectionOf<T>(AngleOf<T>::Degrees(horizontal),
 | 
			
		||||
                        AngleOf<T>::Degrees(vertical));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
DirectionOf<T> DirectionOf<T>::Radians(float horizontal, float vertical) {
 | 
			
		||||
  return DirectionOf<T>(AngleOf<T>::Radians(horizontal),
 | 
			
		||||
                        AngleOf<T>::Radians(vertical));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool DirectionOf<T>::operator==(const DirectionOf<T> direction) const {
 | 
			
		||||
  return (this->horizontal == direction.horizontal) &&
 | 
			
		||||
         (this->vertical == direction.vertical);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
DirectionOf<T> DirectionOf<T>::operator-() const {
 | 
			
		||||
  DirectionOf<T> r = DirectionOf<T>(this->horizontal + AngleOf<T>::Degrees(180),
 | 
			
		||||
                                    -this->vertical);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void DirectionOf<T>::Normalize() {
 | 
			
		||||
  if (this->vertical > AngleOf<T>::Degrees(90) ||
 | 
			
		||||
      this->vertical < AngleOf<T>::Degrees(-90)) {
 | 
			
		||||
    this->horizontal += AngleOf<T>::Degrees(180);
 | 
			
		||||
    this->vertical = AngleOf<T>::Degrees(180) - this->vertical;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template class LinearAlgebra::DirectionOf<float>;
 | 
			
		||||
template class LinearAlgebra::DirectionOf<signed short>;
 | 
			
		||||
}
 | 
			
		||||
template class Direction<float>;
 | 
			
		||||
template class Direction<signed short>;
 | 
			
		||||
template class Direction<signed char>;
 | 
			
		||||
@ -7,96 +7,33 @@
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
struct Vector3;
 | 
			
		||||
 | 
			
		||||
/// @brief A direction using angles in various representations
 | 
			
		||||
/// @tparam T The implementation type used for the representation of the angles
 | 
			
		||||
/// A direction is represented using two angles:
 | 
			
		||||
/// * The horizontal angle ranging from -180 (inclusive) to 180 (exclusive)
 | 
			
		||||
/// degrees which is a rotation in the horizontal plane
 | 
			
		||||
/// * A vertical angle ranging from -90 (inclusive) to 90 (exclusive) degrees
 | 
			
		||||
/// which is the rotation in the up/down direction applied after the horizontal
 | 
			
		||||
/// rotation has been applied.
 | 
			
		||||
/// The angles are automatically normalized to stay within the abovenmentioned
 | 
			
		||||
/// ranges.
 | 
			
		||||
template <typename T>
 | 
			
		||||
class DirectionOf {
 | 
			
		||||
class Direction {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief horizontal angle, range= (-180..180]
 | 
			
		||||
  AngleOf<T> horizontal;
 | 
			
		||||
  /// @brief vertical angle, range in degrees = (-90..90]
 | 
			
		||||
  AngleOf<T> vertical;
 | 
			
		||||
  AngleOf<T> horizontalAngle;
 | 
			
		||||
  AngleOf<T> verticalAngle;
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a new direction with zero angles
 | 
			
		||||
  DirectionOf();
 | 
			
		||||
  /// @brief Create a new direction
 | 
			
		||||
  /// @param horizontal The horizontal angle
 | 
			
		||||
  /// @param vertical The vertical angle.
 | 
			
		||||
  DirectionOf(AngleOf<T> horizontal, AngleOf<T> vertical);
 | 
			
		||||
  Direction();
 | 
			
		||||
  Direction(AngleOf<T> horizontal, AngleOf<T> vertical);
 | 
			
		||||
  Direction(Vector3 v);
 | 
			
		||||
 | 
			
		||||
  /// @brief Convert the direction into a carthesian vector
 | 
			
		||||
  /// @return The carthesian vector corresponding to this direction.
 | 
			
		||||
  Vector3 ToVector3() const;
 | 
			
		||||
  /// @brief Convert a carthesian vector into a direction
 | 
			
		||||
  /// @param v The carthesian vector
 | 
			
		||||
  /// @return The direction.
 | 
			
		||||
  /// @note Information about the length of the carthesian vector is not
 | 
			
		||||
  /// included in this transformation.
 | 
			
		||||
  static DirectionOf<T> FromVector3(Vector3 vector);
 | 
			
		||||
  const static Direction forward;
 | 
			
		||||
  const static Direction back;
 | 
			
		||||
  const static Direction up;
 | 
			
		||||
  const static Direction down;
 | 
			
		||||
  const static Direction left;
 | 
			
		||||
  const static Direction right;
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a direction using angle values in degrees
 | 
			
		||||
  /// @param horizontal The horizontal angle in degrees
 | 
			
		||||
  /// @param vertical The vertical angle in degrees
 | 
			
		||||
  /// @return The direction
 | 
			
		||||
  static DirectionOf<T> Degrees(float horizontal, float vertical);
 | 
			
		||||
  /// @brief Create a direction using angle values in radians
 | 
			
		||||
  /// @param horizontal The horizontal angle in radians
 | 
			
		||||
  /// @param vertical The vertical angle in radians
 | 
			
		||||
  /// @return The direction
 | 
			
		||||
  static DirectionOf<T> Radians(float horizontal, float vertical);
 | 
			
		||||
 | 
			
		||||
  /// @brief A forward direction with zero for both angles
 | 
			
		||||
  const static DirectionOf forward;
 | 
			
		||||
  /// @brief A backward direction with horizontal angle -180 and zero vertical
 | 
			
		||||
  /// angle
 | 
			
		||||
  const static DirectionOf back;
 | 
			
		||||
  /// @brief A upward direction with zero horizontal angle and vertical angle 90
 | 
			
		||||
  const static DirectionOf up;
 | 
			
		||||
  /// @brief A downward direction with zero horizontal angle and vertical angle
 | 
			
		||||
  /// -90
 | 
			
		||||
  const static DirectionOf down;
 | 
			
		||||
  /// @brief A left-pointing direction with horizontal angle -90 and zero
 | 
			
		||||
  /// vertical angle
 | 
			
		||||
  const static DirectionOf left;
 | 
			
		||||
  /// @brief A right-pointing direction with horizontal angle 90 and zero
 | 
			
		||||
  /// vertical angle
 | 
			
		||||
  const static DirectionOf right;
 | 
			
		||||
 | 
			
		||||
  /// @brief Test whether this direction is equal to another direction
 | 
			
		||||
  /// @param direction The direction to compare to
 | 
			
		||||
  /// @return True when the direction angles are equal, false otherwise.
 | 
			
		||||
  bool operator==(const DirectionOf<T> direction) const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Negate/reverse the direction
 | 
			
		||||
  /// @return The reversed direction.
 | 
			
		||||
  DirectionOf<T> operator-() const;
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /// @brief Normalize this vector to the specified ranges
 | 
			
		||||
  void Normalize();
 | 
			
		||||
  Vector3 ToVector3();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using DirectionSingle = DirectionOf<float>;
 | 
			
		||||
using Direction16 = DirectionOf<signed short>;
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO)
 | 
			
		||||
using Direction = Direction16;
 | 
			
		||||
#else
 | 
			
		||||
using Direction = DirectionSingle;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,154 +1,420 @@
 | 
			
		||||
warning: source 'images' is not a readable file or directory... skipping.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Quaternion.cpp:100: warning: no uniquely matching class member found for 
 | 
			
		||||
  Quaternion Quaternion::operator*(const Quaternion &r2) const
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_for_dummies.md:566: warning: multiple use of section label 'OrderedCalls' while adding section, (first occurrence: D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md, line 1674)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:411: warning: multiple use of section label 'DefaultValue' while adding section, (first occurrence: D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md, line 2088)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-message.h:62: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-internal.h:158: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-output-test_.cc:47: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest-typed-test_test.cc:43: warning: Found ';' while parsing initializer list! (doxygen could be confused by a macro call without semicolon)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-matchers.h:256: warning: found documented #define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ but ignoring it because ENABLE_PREPROCESSING is NO.
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class testing::internal::FindFirstPrinter< T, E, Printers... >!
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class FindFirstPrinter< T, E, Printers... >!
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class testing::internal::FindFirstPrinter< T, E, Printers... >!
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h:288: warning: Detected potential recursive class relation between class testing::internal::FindFirstPrinter and base class FindFirstPrinter< T, E, Printers... >!
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-cardinalities.cc:129: warning: documented symbol 'void testing::Cardinality::DescribeActualCallCountTo' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:248: warning: documented symbol 'bool testing::internal::MatchMatrix::NextGraph' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:262: warning: documented symbol 'void testing::internal::MatchMatrix::Randomize' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:271: warning: no uniquely matching class member found for 
 | 
			
		||||
  std::string testing::internal::MatchMatrix::DebugString() const
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:284: warning: documented symbol 'void testing::internal::UnorderedElementsAreMatcherImplBase::DescribeToImpl' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:325: warning: documented symbol 'void testing::internal::UnorderedElementsAreMatcherImplBase::DescribeNegationToImpl' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:371: warning: documented symbol 'bool testing::internal::UnorderedElementsAreMatcherImplBase::VerifyMatchMatrix' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-matchers.cc:421: warning: documented symbol 'bool testing::internal::UnorderedElementsAreMatcherImplBase::FindPairing' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:82: warning: documented symbol 'testing::internal::ExpectationBase::ExpectationBase' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:98: warning: documented symbol 'testing::internal::ExpectationBase::~ExpectationBase' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:102: warning: documented symbol 'void testing::internal::ExpectationBase::SpecifyCardinality' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:108: warning: documented symbol 'void testing::internal::ExpectationBase::RetireAllPreRequisites' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:135: warning: documented symbol 'bool testing::internal::ExpectationBase::AllPrerequisitesAreSatisfied' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:155: warning: documented symbol 'void testing::internal::ExpectationBase::FindUnsatisfiedPrerequisites' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:186: warning: documented symbol 'void testing::internal::ExpectationBase::DescribeCallCountTo' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:209: warning: documented symbol 'void testing::internal::ExpectationBase::CheckActionCountIfNotDone' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:261: warning: documented symbol 'void testing::internal::ExpectationBase::UntypedTimes' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:308: warning: documented symbol 'testing::internal::UntypedFunctionMockerBase::UntypedFunctionMockerBase' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:311: warning: documented symbol 'testing::internal::UntypedFunctionMockerBase::~UntypedFunctionMockerBase' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:317: warning: documented symbol 'void testing::internal::UntypedFunctionMockerBase::RegisterOwner' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:329: warning: documented symbol 'void testing::internal::UntypedFunctionMockerBase::SetOwnerAndName' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:341: warning: documented symbol 'const void * testing::internal::UntypedFunctionMockerBase::MockObject' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:358: warning: documented symbol 'const char * testing::internal::UntypedFunctionMockerBase::Name' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:376: warning: documented symbol 'UntypedActionResultHolderBase * testing::internal::UntypedFunctionMockerBase::UntypedInvokeWith' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:505: warning: documented symbol 'Expectation testing::internal::UntypedFunctionMockerBase::GetHandleOf' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:525: warning: documented symbol 'bool testing::internal::UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:685: warning: documented symbol 'void Mock::AllowUninterestingCalls' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:692: warning: documented symbol 'void Mock::WarnUninterestingCalls' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:699: warning: documented symbol 'void Mock::FailUninterestingCalls' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:706: warning: documented symbol 'void Mock::UnregisterCallReaction' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:714: warning: documented symbol 'internal::CallReaction Mock::GetReactionOnUninterestingCalls' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:726: warning: documented symbol 'void Mock::AllowLeak' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:735: warning: documented symbol 'bool Mock::VerifyAndClearExpectations' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:744: warning: documented symbol 'bool Mock::VerifyAndClear' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:754: warning: documented symbol 'bool Mock::VerifyAndClearExpectationsLocked' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:779: warning: documented symbol 'bool Mock::IsNaggy' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:783: warning: documented symbol 'bool Mock::IsNice' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:787: warning: documented symbol 'bool Mock::IsStrict' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:793: warning: no uniquely matching class member found for 
 | 
			
		||||
  void Mock::Register(const void *mock_obj, internal::UntypedFunctionMockerBase *mocker)
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:803: warning: documented symbol 'void Mock::RegisterUseByOnCallOrExpectCall' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:824: warning: documented symbol 'void Mock::UnregisterLocked' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:842: warning: documented symbol 'void Mock::ClearDefaultActionsLocked' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:864: warning: documented symbol 'testing::Expectation::Expectation' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:866: warning: documented symbol 'testing::Expectation::Expectation' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:870: warning: documented symbol 'testing::Expectation::~Expectation' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:873: warning: documented symbol 'void testing::Sequence::AddExpectation' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:884: warning: documented symbol 'testing::InSequence::InSequence' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/src/gmock-spec-builders.cc:895: warning: documented symbol 'testing::InSequence::~InSequence' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-internal.h:111: warning: no matching file member found for 
 | 
			
		||||
std::string testing::PrintToString(const T &value)
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(const AngleOf< T > &angle, float factor)' at line 117 of file d:/PlatformIO/linear-algebra/Angle.h
 | 
			
		||||
  'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(float factor, const AngleOf< T > &angle)' at line 124 of file d:/PlatformIO/linear-algebra/Angle.h
 | 
			
		||||
  'Vector3 Passer::LinearAlgebra::MatrixOf< T >::operator*(const Vector3 v) const' at line 64 of file d:/PlatformIO/linear-algebra/Matrix.h
 | 
			
		||||
  'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(const PolarOf &v, float f)' at line 118 of file d:/PlatformIO/linear-algebra/Polar.h
 | 
			
		||||
  'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(float f, const PolarOf &v)' at line 121 of file d:/PlatformIO/linear-algebra/Polar.h
 | 
			
		||||
  'Vector3 Passer::LinearAlgebra::Quaternion::operator*(const Vector3 &vector) const' at line 98 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
  'Quaternion Passer::LinearAlgebra::Quaternion::operator*(const Quaternion &rotation) const' at line 106 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
  'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(const SphericalOf< T > &v, float f)' at line 111 of file d:/PlatformIO/linear-algebra/Spherical.h
 | 
			
		||||
  'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(float f, const SphericalOf< T > &v)' at line 114 of file d:/PlatformIO/linear-algebra/Spherical.h
 | 
			
		||||
  'SphericalOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SphericalOf< T > &vector) const' at line 46 of file d:/PlatformIO/linear-algebra/SwingTwist.h
 | 
			
		||||
  'SwingTwistOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SwingTwistOf< T > &rotation) const' at line 54 of file d:/PlatformIO/linear-algebra/SwingTwist.h
 | 
			
		||||
  'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(const Vector2 &v, float f)' at line 141 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(float f, const Vector2 &v)' at line 144 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(const Vector3 &v, float f)' at line 149 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
  'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(float f, const Vector3 &v)' at line 152 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Quaternion.cpp:108: warning: no uniquely matching class member found for 
 | 
			
		||||
  Vector3 Quaternion::operator*(const Vector3 &p) const
 | 
			
		||||
 '::std::string PrintToString(const T &value)' at line 1037 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-printers.h
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-internal.h:160: warning: no matching file member found for 
 | 
			
		||||
testing::internal::GTEST_DISABLE_MSC_WARNINGS_PUSH_
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(const AngleOf< T > &angle, float factor)' at line 117 of file d:/PlatformIO/linear-algebra/Angle.h
 | 
			
		||||
  'friend AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator*(float factor, const AngleOf< T > &angle)' at line 124 of file d:/PlatformIO/linear-algebra/Angle.h
 | 
			
		||||
  'Vector3 Passer::LinearAlgebra::MatrixOf< T >::operator*(const Vector3 v) const' at line 64 of file d:/PlatformIO/linear-algebra/Matrix.h
 | 
			
		||||
  'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(const PolarOf &v, float f)' at line 118 of file d:/PlatformIO/linear-algebra/Polar.h
 | 
			
		||||
  'friend PolarOf Passer::LinearAlgebra::PolarOf< T >::operator*(float f, const PolarOf &v)' at line 121 of file d:/PlatformIO/linear-algebra/Polar.h
 | 
			
		||||
  'Vector3 Passer::LinearAlgebra::Quaternion::operator*(const Vector3 &vector) const' at line 98 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
  'Quaternion Passer::LinearAlgebra::Quaternion::operator*(const Quaternion &rotation) const' at line 106 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
  'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(const SphericalOf< T > &v, float f)' at line 111 of file d:/PlatformIO/linear-algebra/Spherical.h
 | 
			
		||||
  'friend SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator*(float f, const SphericalOf< T > &v)' at line 114 of file d:/PlatformIO/linear-algebra/Spherical.h
 | 
			
		||||
  'SphericalOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SphericalOf< T > &vector) const' at line 46 of file d:/PlatformIO/linear-algebra/SwingTwist.h
 | 
			
		||||
  'SwingTwistOf< T > Passer::LinearAlgebra::SwingTwistOf< T >::operator*(const SwingTwistOf< T > &rotation) const' at line 54 of file d:/PlatformIO/linear-algebra/SwingTwist.h
 | 
			
		||||
  'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(const Vector2 &v, float f)' at line 141 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'friend Vector2 Passer::LinearAlgebra::Vector2::operator*(float f, const Vector2 &v)' at line 144 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(const Vector3 &v, float f)' at line 149 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
  'friend Vector3 Passer::LinearAlgebra::Vector3::operator*(float f, const Vector3 &v)' at line 152 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Quaternion.cpp:152: warning: no uniquely matching class member found for 
 | 
			
		||||
  Quaternion Quaternion::LookRotation(const Vector3 &forward, const Vector3 &up)
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 48 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-cardinalities.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 GMOCK_MAYBE_5046_) namespace testing' at line 283 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-matchers.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 84 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googlemock/include/gmock/gmock-spec-builders.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 GTEST_MAYBE_5046_) namespace testing' at line 59 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-matchers.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 38 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-spi.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 42 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest-test-part.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) GTEST_DECLARE_bool_(also_run_disabled_tests)' at line 72 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/gtest.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) class GTEST_API_ DeathTest' at line 60 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-death-test-internal.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) namespace testing' at line 47 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/include/gtest/internal/gtest-filepath.h
 | 
			
		||||
 'GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \) GTEST_DECLARE_bool_(death_test_use_fork)' at line 64 of file D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-internal-inl.h
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-assertion-result.cc:59: warning: documented symbol 'AssertionResult testing::AssertionResult::operator!' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:373: warning: documented symbol 'testing::internal::DeathTest::DeathTest' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:383: warning: no matching class member found for 
 | 
			
		||||
  bool testing::internal::DeathTest::Create(const char *statement, Matcher< const std::string & > matcher, const char *file, int line, DeathTest **test)
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:390: warning: documented symbol 'const char * testing::internal::DeathTest::LastMessage' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:394: warning: documented symbol 'void testing::internal::DeathTest::set_last_death_test_message' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-death-test.cc:398: warning: documented symbol 'std::string testing::internal::DeathTest::last_death_test_message_' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:94: warning: documented symbol 'FilePath testing::internal::FilePath::GetCurrentDir' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:121: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveExtension' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:133: warning: documented symbol 'const char * testing::internal::FilePath::FindLastPathSeparator' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:152: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveDirectoryName' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:163: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveFileName' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:180: warning: documented symbol 'FilePath testing::internal::FilePath::MakeFileName' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:196: warning: documented symbol 'FilePath testing::internal::FilePath::ConcatPaths' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:206: warning: documented symbol 'bool testing::internal::FilePath::FileOrDirectoryExists' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:220: warning: documented symbol 'bool testing::internal::FilePath::DirectoryExists' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:250: warning: documented symbol 'bool testing::internal::FilePath::IsRootDirectory' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:259: warning: documented symbol 'bool testing::internal::FilePath::IsAbsolutePath' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:280: warning: documented symbol 'FilePath testing::internal::FilePath::GenerateUniqueFileName' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:294: warning: documented symbol 'bool testing::internal::FilePath::IsDirectory' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:302: warning: documented symbol 'bool testing::internal::FilePath::CreateDirectoriesRecursively' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:319: warning: documented symbol 'bool testing::internal::FilePath::CreateFolder' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:343: warning: documented symbol 'FilePath testing::internal::FilePath::RemoveTrailingPathSeparator' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-filepath.cc:352: warning: no uniquely matching class member found for 
 | 
			
		||||
  void testing::internal::FilePath::Normalize()
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:45: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:49: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:55: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:59: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:64: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:70: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:76: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:82: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:86: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-matchers.cc:92: warning: documented symbol 'testing::Matcher< typename >::Matcher' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-port.cc:301: warning: no matching class member found for 
 | 
			
		||||
  void testing::internal::AutoHandle::Reset(HANDLE handle)
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'static Quaternion Passer::LinearAlgebra::Quaternion::LookRotation(const Vector3 &forward, const Vector3 &upwards)' at line 132 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
  'static Quaternion Passer::LinearAlgebra::Quaternion::LookRotation(const Vector3 &forward)' at line 143 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Quaternion.cpp:330: warning: no uniquely matching class member found for 
 | 
			
		||||
  Quaternion Quaternion::Euler(Vector3 euler)
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'static Quaternion Passer::LinearAlgebra::Quaternion::Euler(float x, float y, float z)' at line 215 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
  'static Quaternion Passer::LinearAlgebra::Quaternion::Euler(Vector3 eulerAngles)' at line 222 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Quaternion.cpp:362: warning: no uniquely matching class member found for 
 | 
			
		||||
  Quaternion Quaternion::EulerXYZ(Vector3 euler)
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'static Quaternion Passer::LinearAlgebra::Quaternion::EulerXYZ(float x, float y, float z)' at line 232 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
  'static Quaternion Passer::LinearAlgebra::Quaternion::EulerXYZ(Vector3 eulerAngles)' at line 239 of file d:/PlatformIO/linear-algebra/Quaternion.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.cpp:137: warning: no uniquely matching class member found for 
 | 
			
		||||
  template < T >
 | 
			
		||||
  SphericalOf< T > SphericalOf::operator-(const SphericalOf< T > &s2) const
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator-() const' at line 99 of file d:/PlatformIO/linear-algebra/Angle.h
 | 
			
		||||
  'AngleOf< T > Passer::LinearAlgebra::AngleOf< T >::operator-(const AngleOf< T > &angle) const' at line 103 of file d:/PlatformIO/linear-algebra/Angle.h
 | 
			
		||||
  'DirectionOf< T > Passer::LinearAlgebra::DirectionOf< T >::operator-() const' at line 84 of file d:/PlatformIO/linear-algebra/Direction.h
 | 
			
		||||
  'PolarOf Passer::LinearAlgebra::PolarOf< T >::operator-() const' at line 100 of file d:/PlatformIO/linear-algebra/Polar.h
 | 
			
		||||
  'PolarOf Passer::LinearAlgebra::PolarOf< T >::operator-(const PolarOf &v) const' at line 105 of file d:/PlatformIO/linear-algebra/Polar.h
 | 
			
		||||
  'SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator-() const' at line 93 of file d:/PlatformIO/linear-algebra/Spherical.h
 | 
			
		||||
  'SphericalOf< T > Passer::LinearAlgebra::SphericalOf< T >::operator-(const SphericalOf< T > &v) const' at line 98 of file d:/PlatformIO/linear-algebra/Spherical.h
 | 
			
		||||
  'Vector2 Passer::LinearAlgebra::Vector2::operator-()' at line 116 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Vector2 Passer::LinearAlgebra::Vector2::operator-(const Vector2 &v) const' at line 121 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Vector3 Passer::LinearAlgebra::Vector3::operator-() const' at line 124 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
  'Vector3 Passer::LinearAlgebra::Vector3::operator-(const Vector3 &v) const' at line 129 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.cpp:20: warning: no uniquely matching class member found for 
 | 
			
		||||
  Vector2::Vector2(float _x, float _y)
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2()' at line 43 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2(float right, float forward)' at line 47 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2(Vector3 v)' at line 51 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2(PolarOf< float > v)' at line 54 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.cpp:32: warning: no uniquely matching class member found for 
 | 
			
		||||
  Vector2::Vector2(PolarSingle p)
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2()' at line 43 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2(float right, float forward)' at line 47 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2(Vector3 v)' at line 51 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector2::Vector2(PolarOf< float > v)' at line 54 of file d:/PlatformIO/linear-algebra/Vector2.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.cpp:33: warning: no uniquely matching class member found for 
 | 
			
		||||
  Vector3::Vector3(SphericalOf< float > s)
 | 
			
		||||
Possible candidates:
 | 
			
		||||
  'Passer::LinearAlgebra::Vector3::Vector3()' at line 47 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector3::Vector3(float right, float up, float forward)' at line 52 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector3::Vector3(Vector2 v)' at line 55 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
  'Passer::LinearAlgebra::Vector3::Vector3(SphericalOf< float > v)' at line 59 of file d:/PlatformIO/linear-algebra/Vector3.h
 | 
			
		||||
d:/PlatformIO/linear-algebra/Direction.h:43: warning: argument 'v' of command @param is not found in the argument list of Passer::LinearAlgebra::DirectionOf< T >::FromVector3(Vector3 vector)
 | 
			
		||||
d:/PlatformIO/linear-algebra/Direction.h:43: warning: The following parameter of Passer::LinearAlgebra::DirectionOf::FromVector3(Vector3 vector) is not documented:
 | 
			
		||||
  parameter 'vector'
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:12: warning: Member MatrixOf(unsigned int rows, unsigned int cols) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:13: warning: Member MatrixOf(unsigned int rows, unsigned int cols, const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:17: warning: Member MatrixOf(Vector3 v) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:59: warning: Member Multiply(const MatrixOf< T > *m, MatrixOf< T > *r) const (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:64: warning: Member operator*(const Vector3 v) const (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:66: warning: Member Get(unsigned int rowIx, unsigned int colIx) const (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:71: warning: Member Set(unsigned int rowIx, unsigned int colIx, T value) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:77: warning: Member Set(const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:84: warning: Member SetRow(unsigned int rowIx, const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:91: warning: Member SetCol(unsigned int colIx, const T *source) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:98: warning: Member CopyFrom(const MatrixOf< T > *m) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:108: warning: Member RowCount() const (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:109: warning: Member ColCount() const (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:57: warning: Member Multiply(const MatrixOf< T > *m1, const MatrixOf< T > *m2, MatrixOf< T > *r) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Matrix.h:63: warning: Member Multiply(const MatrixOf< T > *m, Vector3 v) (function) of class Passer::LinearAlgebra::MatrixOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:106: warning: Member operator-=(const PolarOf &v) (function) of class Passer::LinearAlgebra::PolarOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:111: warning: Member operator+=(const PolarOf &v) (function) of class Passer::LinearAlgebra::PolarOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:124: warning: Member operator*=(float f) (function) of class Passer::LinearAlgebra::PolarOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:136: warning: Member operator/=(float f) (function) of class Passer::LinearAlgebra::PolarOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:121: warning: Member operator*(float f, const PolarOf &v) (friend) of class Passer::LinearAlgebra::PolarOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:133: warning: Member operator/(float f, const PolarOf &v) (friend) of class Passer::LinearAlgebra::PolarOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:59: warning: argument 's' of command @param is not found in the argument list of Passer::LinearAlgebra::PolarOf< T >::FromSpherical(SphericalOf< T > v)
 | 
			
		||||
d:/PlatformIO/linear-algebra/Polar.h:59: warning: The following parameter of Passer::LinearAlgebra::PolarOf::FromSpherical(SphericalOf< T > v) is not documented:
 | 
			
		||||
  parameter 'v'
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:29: warning: Member SphericalOf(float distance, AngleOf< T > horizontal, AngleOf< T > vertical) (function) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:29: warning: Member SphericalOf(float distance, DirectionOf< T > direction) (function) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:99: warning: Member operator-=(const SphericalOf< T > &v) (function) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:104: warning: Member operator+=(const SphericalOf< T > &v) (function) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:117: warning: Member operator*=(float f) (function) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:129: warning: Member operator/=(float f) (function) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:54: warning: Member Rad (variable) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:114: warning: Member operator*(float f, const SphericalOf< T > &v) (friend) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Spherical.h:126: warning: Member operator/(float f, const SphericalOf< T > &v) (friend) of class Passer::LinearAlgebra::SphericalOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:22: warning: Member SwingTwistOf(DirectionOf< T > swing, AngleOf< T > twist) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:22: warning: Member SwingTwistOf(AngleOf< T > horizontal, AngleOf< T > vertical, AngleOf< T > twist) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:31: warning: Member ToQuaternion() const (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:34: warning: Member ToAngleAxis() const (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:39: warning: Member operator==(const SwingTwistOf< T > d) const (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:55: warning: Member operator*=(const SwingTwistOf< T > &rotation) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:69: warning: Member Normalize() (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:28: warning: Member Degrees(float horizontal, float vertical=0, float twist=0) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:32: warning: Member FromQuaternion(Quaternion q) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:35: warning: Member FromAngleAxis(SphericalOf< T > aa) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:57: warning: Member Inverse(SwingTwistOf< T > rotation) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:67: warning: Member Angle(const SwingTwistOf< T > &r1, const SwingTwistOf< T > &r2) (function) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:21: warning: Member swing (variable) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:22: warning: Member twist (variable) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/SwingTwist.h:37: warning: Member identity (variable) of class Passer::LinearAlgebra::SwingTwistOf is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.h:122: warning: Member operator-=(const Vector2 &v) (function) of struct Passer::LinearAlgebra::Vector2 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.h:127: warning: Member operator+=(const Vector2 &v) (function) of struct Passer::LinearAlgebra::Vector2 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.h:148: warning: Member operator*=(float f) (function) of struct Passer::LinearAlgebra::Vector2 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.h:159: warning: Member operator/=(float f) (function) of struct Passer::LinearAlgebra::Vector2 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.h:144: warning: Member operator*(float f, const Vector2 &v) (friend) of struct Passer::LinearAlgebra::Vector2 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector2.h:156: warning: Member operator/(float f, const Vector2 &v) (friend) of struct Passer::LinearAlgebra::Vector2 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:82: warning: Member Forward() const (function) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:83: warning: Member Up() const (function) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:84: warning: Member Right() const (function) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:130: warning: Member operator-=(const Vector3 &v) (function) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:135: warning: Member operator+=(const Vector3 &v) (function) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:156: warning: Member operator*=(float f) (function) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:168: warning: Member operator/=(float f) (function) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:152: warning: Member operator*(float f, const Vector3 &v) (friend) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
d:/PlatformIO/linear-algebra/Vector3.h:164: warning: Member operator/(float f, const Vector3 &v) (friend) of struct Passer::LinearAlgebra::Vector3 is not documented.
 | 
			
		||||
  'void testing::internal::AutoHandle::Reset()'
 | 
			
		||||
  'void testing::internal::AutoHandle::Reset(Handle handle)'
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:44: warning: documented symbol 'std::string testing::TestPartResult::ExtractSummary' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:66: warning: no uniquely matching class member found for 
 | 
			
		||||
  void testing::TestPartResultArray::Append(const TestPartResult &result)
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:71: warning: no matching class member found for 
 | 
			
		||||
  const TestPartResult & testing::TestPartResultArray::GetTestPartResult(int index) const
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:81: warning: no uniquely matching class member found for 
 | 
			
		||||
  int testing::TestPartResultArray::size() const
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:87: warning: documented symbol 'testing::internal::HasNewFatalFailureHelper::HasNewFatalFailureHelper' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:94: warning: documented symbol 'testing::internal::HasNewFatalFailureHelper::~HasNewFatalFailureHelper' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-test-part.cc:99: warning: no uniquely matching class member found for 
 | 
			
		||||
  void testing::internal::HasNewFatalFailureHelper::ReportTestPartResult(const TestPartResult &result)
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest-typed-test.cc:58: warning: documented symbol 'const char * testing::internal::TypedTestSuitePState::VerifyRegisteredTestNames' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:858: warning: documented symbol 'testing::ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:868: warning: documented symbol 'testing::ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:875: warning: no uniquely matching class member found for 
 | 
			
		||||
  void testing::ScopedFakeTestPartResultReporter::Init()
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:888: warning: documented symbol 'testing::ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:899: warning: no uniquely matching class member found for 
 | 
			
		||||
  void testing::ScopedFakeTestPartResultReporter::ReportTestPartResult(const TestPartResult &result)
 | 
			
		||||
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:965: warning: documented symbol 'testing::internal::SingleFailureChecker::SingleFailureChecker' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:974: warning: documented symbol 'testing::internal::SingleFailureChecker::~SingleFailureChecker' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/src/gtest.cc:2602: warning: documented symbol 'testing::internal::GoogleTestFailureException::GoogleTestFailureException' was not declared or defined.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:52: warning: explicit link request to 'testing::AssertionResult' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:229: warning: explicit link request to 'Bar()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:283: warning: explicit link request to 'testing::Environment' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:283: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:376: warning: explicit link request to 'testing::PrintToString(x)' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:786: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:813: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:850: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:953: warning: explicit link request to 'testing::Environment' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:970: warning: explicit link request to 'testing::AddGlobalTestEnvironment()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1243: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1364: warning: explicit link request to 'testing::Types' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1397: warning: explicit link request to 'including' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1496: warning: explicit link request to 'including' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1538: warning: explicit link request to 'testing::RegisterTest' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1764: warning: explicit link request to 'testing::InitGoogleTest()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1813: warning: found </em> at different nesting level (5) than expected (2)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1822: warning: found </tt> tag while expecting </em>
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1823: warning: found </tt> tag while expecting </em>
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1824: warning: found </tt> tag while expecting </em>
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1986: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1986: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1987: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1987: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1988: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1988: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1989: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1989: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1990: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1990: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1991: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1991: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1992: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1992: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1994: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1994: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1996: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1996: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1997: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1997: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1998: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1998: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1999: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:1999: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:2000: warning: Unsupported xml/html tag <font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:2000: warning: Unsupported xml/html tag </font> found
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/advanced.md:2380: warning: end of comment block while expecting command </em>
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/faq.md:658: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cheat_sheet.md:6: warning: found subsection command (id: 'MockClass') outside of section context!
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:9: warning: explicit link request to 'testing::Foo' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:186: warning: found subsection command (id: 'MockingNonVirtualMethods') outside of section context!
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:1540: warning: explicit link request to 'Set()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:1950: warning: explicit link request to 'testing::ActionInterface' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2045: warning: explicit link request to 'testing::InSequence' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2098: warning: explicit link request to 'testing::DefaultValue' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2223: warning: explicit link request to 'testing::Invoke' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:2309: warning: explicit link request to 'testing::InvokeWithoutArgs' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_cook_book.md:4107: warning: explicit link request to 'testing::ActionInterface' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/gmock_for_dummies.md:524: warning: found subsection command (id: 'MultiExpectations') outside of section context!
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/primer.md:213: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/primer.md:457: warning: explicit link request to 'testing::InitGoogleTest()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/actions.md:5: warning: explicit link request to 'testing' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/assertions.md:529: warning: explicit link request to 'testing::GTEST_FLAG(death_test_style)' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/matchers.md:20: warning: explicit link request to 'testing' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/matchers.md:145: warning: explicit link request to 'std::tuple' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:92: warning: explicit link request to 'EXPECT_CALL.With' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:122: warning: explicit link request to 'EXPECT_CALL.Times' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:129: warning: explicit link request to 'testing' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:151: warning: explicit link request to 'EXPECT_CALL.InSequence' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:181: warning: explicit link request to 'EXPECT_CALL.After' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:222: warning: explicit link request to 'EXPECT_CALL.WillOnce' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:253: warning: explicit link request to 'EXPECT_CALL.WillRepeatedly' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:286: warning: explicit link request to 'EXPECT_CALL.RetiresOnSaturation' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:347: warning: explicit link request to 'ON_CALL.With' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:378: warning: explicit link request to 'ON_CALL.WillByDefault' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:413: warning: explicit link request to 'testing::DefaultValue' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:437: warning: explicit link request to 'testing::NiceMock' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:468: warning: explicit link request to 'testing::NaggyMock' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:495: warning: explicit link request to 'testing::StrictMock' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:527: warning: explicit link request to 'testing::Sequence' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:534: warning: explicit link request to 'testing::InSequence' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:559: warning: explicit link request to 'testing::Expectation' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/mocking.md:574: warning: explicit link request to 'testing::ExpectationSet' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:13: warning: found subsection command (id: 'TEST') outside of section context!
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:100: warning: explicit link request to 'testing' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:389: warning: explicit link request to 'testing::AssertionResult' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:403: warning: explicit link request to 'testing::AssertionException' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:410: warning: explicit link request to 'testing::EmptyTestEventListener' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:418: warning: explicit link request to 'testing::Environment' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:425: warning: explicit link request to 'Environment::SetUp' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:431: warning: explicit link request to 'Environment::TearDown' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:439: warning: explicit link request to 'testing::ScopedTrace' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:466: warning: explicit link request to 'testing::Test' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:472: warning: explicit link request to 'Test::SetUpTestSuite' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:479: warning: explicit link request to 'Test::TearDownTestSuite' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:486: warning: explicit link request to 'Test::HasFatalFailure' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:492: warning: explicit link request to 'Test::HasNonfatalFailure' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:498: warning: explicit link request to 'Test::HasFailure' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:505: warning: explicit link request to 'Test::IsSkipped' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:511: warning: explicit link request to 'Test::RecordProperty' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:538: warning: explicit link request to 'Test::SetUp' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:545: warning: explicit link request to 'Test::TearDown' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:554: warning: explicit link request to 'testing::TestWithParam' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:565: warning: explicit link request to 'TestSuite::name' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:571: warning: explicit link request to 'TestSuite::type_param' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:579: warning: explicit link request to 'TestSuite::should_run' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:585: warning: explicit link request to 'TestSuite::successful_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:591: warning: explicit link request to 'TestSuite::skipped_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:597: warning: explicit link request to 'TestSuite::failed_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:603: warning: explicit link request to 'TestSuite::reportable_disabled_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:609: warning: explicit link request to 'TestSuite::disabled_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:615: warning: explicit link request to 'TestSuite::reportable_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:621: warning: explicit link request to 'TestSuite::test_to_run_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:627: warning: explicit link request to 'TestSuite::total_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:633: warning: explicit link request to 'TestSuite::Passed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:639: warning: explicit link request to 'TestSuite::Failed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:645: warning: explicit link request to 'TestSuite::elapsed_time' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:651: warning: explicit link request to 'TestSuite::start_timestamp' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:657: warning: explicit link request to 'TestSuite::GetTestInfo' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:665: warning: explicit link request to 'TestSuite::ad_hoc_test_result' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:674: warning: explicit link request to 'testing::TestInfo' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:680: warning: explicit link request to 'TestInfo::test_suite_name' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:686: warning: explicit link request to 'TestInfo::name' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:692: warning: explicit link request to 'TestInfo::type_param' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:700: warning: explicit link request to 'TestInfo::value_param' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:708: warning: explicit link request to 'TestInfo::file' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:714: warning: explicit link request to 'TestInfo::line' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:720: warning: explicit link request to 'TestInfo::is_in_another_shard' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:726: warning: explicit link request to 'TestInfo::should_run' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:739: warning: explicit link request to 'TestInfo::is_reportable' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:745: warning: explicit link request to 'TestInfo::result' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:753: warning: explicit link request to 'testing::TestParamInfo' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:763: warning: explicit link request to 'testing::UnitTest' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:774: warning: explicit link request to 'UnitTest::GetInstance' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:782: warning: explicit link request to 'UnitTest::original_working_dir' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:789: warning: explicit link request to 'UnitTest::current_test_suite' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:796: warning: explicit link request to 'UnitTest::current_test_info' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:803: warning: explicit link request to 'UnitTest::random_seed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:809: warning: explicit link request to 'UnitTest::successful_test_suite_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:815: warning: explicit link request to 'UnitTest::failed_test_suite_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:821: warning: explicit link request to 'UnitTest::total_test_suite_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:827: warning: explicit link request to 'UnitTest::test_suite_to_run_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:834: warning: explicit link request to 'UnitTest::successful_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:840: warning: explicit link request to 'UnitTest::skipped_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:846: warning: explicit link request to 'UnitTest::failed_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:852: warning: explicit link request to 'UnitTest::reportable_disabled_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:858: warning: explicit link request to 'UnitTest::disabled_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:864: warning: explicit link request to 'UnitTest::reportable_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:870: warning: explicit link request to 'UnitTest::total_test_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:876: warning: explicit link request to 'UnitTest::test_to_run_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:882: warning: explicit link request to 'UnitTest::start_timestamp' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:888: warning: explicit link request to 'UnitTest::elapsed_time' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:894: warning: explicit link request to 'UnitTest::Passed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:900: warning: explicit link request to 'UnitTest::Failed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:907: warning: explicit link request to 'UnitTest::GetTestSuite' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:915: warning: explicit link request to 'UnitTest::ad_hoc_test_result' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:922: warning: explicit link request to 'UnitTest::listeners' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:931: warning: explicit link request to 'testing::TestEventListener' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:938: warning: explicit link request to 'TestEventListener::OnTestProgramStart' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:944: warning: explicit link request to 'TestEventListener::OnTestIterationStart' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:953: warning: explicit link request to 'TestEventListener::OnEnvironmentsSetUpStart' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:960: warning: explicit link request to 'TestEventListener::OnEnvironmentsSetUpEnd' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:967: warning: explicit link request to 'TestEventListener::OnTestSuiteStart' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:973: warning: explicit link request to 'TestEventListener::OnTestStart' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:979: warning: explicit link request to 'TestEventListener::OnTestPartResult' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:988: warning: explicit link request to 'TestEventListener::OnTestEnd' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:994: warning: explicit link request to 'TestEventListener::OnTestSuiteEnd' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1000: warning: explicit link request to 'TestEventListener::OnEnvironmentsTearDownStart' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1007: warning: explicit link request to 'TestEventListener::OnEnvironmentsTearDownEnd' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1014: warning: explicit link request to 'TestEventListener::OnTestIterationEnd' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1021: warning: explicit link request to 'TestEventListener::OnTestProgramEnd' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1029: warning: explicit link request to 'testing::TestEventListeners' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1035: warning: explicit link request to 'TestEventListeners::Append' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1043: warning: explicit link request to 'TestEventListeners::Release' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1051: warning: explicit link request to 'TestEventListeners::default_result_printer' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1061: warning: explicit link request to 'TestEventListeners::default_xml_generator' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1074: warning: explicit link request to 'testing::TestPartResult' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1081: warning: explicit link request to 'TestPartResult::type' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1098: warning: explicit link request to 'TestPartResult::file_name' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1105: warning: explicit link request to 'TestPartResult::line_number' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1112: warning: explicit link request to 'TestPartResult::summary' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1118: warning: explicit link request to 'TestPartResult::message' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1124: warning: explicit link request to 'TestPartResult::skipped' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1130: warning: explicit link request to 'TestPartResult::passed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1136: warning: explicit link request to 'TestPartResult::nonfatally_failed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1142: warning: explicit link request to 'TestPartResult::fatally_failed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1148: warning: explicit link request to 'TestPartResult::failed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1156: warning: explicit link request to 'testing::TestProperty' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1183: warning: explicit link request to 'testing::TestResult' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1191: warning: explicit link request to 'TestResult::total_part_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1198: warning: explicit link request to 'TestResult::test_property_count' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1204: warning: explicit link request to 'TestResult::Passed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1210: warning: explicit link request to 'TestResult::Skipped' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1216: warning: explicit link request to 'TestResult::Failed' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1222: warning: explicit link request to 'TestResult::HasFatalFailure' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1228: warning: explicit link request to 'TestResult::HasNonfatalFailure' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1234: warning: explicit link request to 'TestResult::elapsed_time' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1240: warning: explicit link request to 'TestResult::start_timestamp' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1246: warning: explicit link request to 'TestResult::GetTestPartResult' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1254: warning: explicit link request to 'TestResult::GetTestProperty' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1264: warning: explicit link request to 'testing::TimeInMillis' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1270: warning: explicit link request to 'testing::Types' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1286: warning: explicit link request to 'testing::WithParamInterface' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1312: warning: explicit link request to 'testing::InitGoogleTest(int* argc, char** argv)' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1313: warning: explicit link request to 'testing::InitGoogleTest(int* argc, wchar_t** argv)' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1314: warning: explicit link request to 'testing::InitGoogleTest()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1331: warning: explicit link request to 'testing::AddGlobalTestEnvironment(Environment* env)' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1383: warning: explicit link request to 'testing::AssertionSuccess()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1390: warning: explicit link request to 'testing::AssertionFailure()' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1403: warning: explicit link request to 'testing::StaticAssertTypeEq' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1412: warning: explicit link request to 'testing::PrintToString(x)' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/docs/reference/testing.md:1422: warning: explicit link request to 'testing::PrintToStringParamName' could not be resolved
 | 
			
		||||
D:/C/VectorAlgebra/include/Vector2.h:233: warning: Member ToFactor(Vector2 a, Vector2 b) (function) of struct Vector2 is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/include/Vector2.h:205: warning: argument 'axis' of command @param is not found in the argument list of Vector2::SignedAngle(Vector2 from, Vector2 to)
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:119: warning: Member testCatchesCxxExceptionsInFixtureConstructor(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:133: warning: Member testCatchesCxxExceptionsInFixtureDestructor(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:143: warning: Member testCatchesCxxExceptionsInSetUpTestCase(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:166: warning: Member testCatchesCxxExceptionsInTearDownTestCase(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:171: warning: Member testCatchesCxxExceptionsInSetUp(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:189: warning: Member testCatchesCxxExceptionsInTearDown(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:200: warning: Member testCatchesCxxExceptionsInTestBody(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:214: warning: Member testCatchesNonStdCxxExceptions(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:219: warning: Member testUnhandledCxxExceptionsAbortTheProgram(self) (function) of class googletest-catch-exceptions-test::CatchCxxExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:85: warning: Member TestSehExceptions(self, test_output) (function) of class googletest-catch-exceptions-test::CatchSehExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:103: warning: Member testCatchesSehExceptionsWithCxxExceptionsEnabled(self) (function) of class googletest-catch-exceptions-test::CatchSehExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-catch-exceptions-test.py:106: warning: Member testCatchesSehExceptionsWithCxxExceptionsDisabled(self) (function) of class googletest-catch-exceptions-test::CatchSehExceptionsTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:122: warning: Member testGoogletestFlag(self) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:187: warning: Member testEventListener(self) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:214: warning: Member assertXmlResultCount(self, result, count, xml) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-failfast-unittest.py:220: warning: Member assertXmlStatusCount(self, status, count, xml) (function) of class googletest-failfast-unittest::GTestFailFastUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-filter-unittest.py:517: warning: Member testNegativeFilters(self) (function) of class googletest-filter-unittest::GTestFilterUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:134: warning: Member setUp(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:142: warning: Member tearDown(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:145: warning: Member DeleteFilesAndDir(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:159: warning: Member testOutfile1(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:162: warning: Member testOutfile2(self) (function) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-json-outfiles-test.py:138: warning: Member output_dir_ (variable) of class googletest-json-outfiles-test::GTestJsonOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:170: warning: Member setUp(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:173: warning: Member testShufflePreservesNumberOfTests(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:179: warning: Member testShuffleChangesTestOrder(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:187: warning: Member testShuffleChangesTestCaseOrder(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:200: warning: Member testShuffleDoesNotRepeatTest(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:214: warning: Member testShuffleDoesNotCreateNewTest(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:224: warning: Member testShuffleIncludesAllTests(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:234: warning: Member testShuffleLeavesDeathTestsAtFront(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:253: warning: Member testShuffleDoesNotInterleaveTestCases(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:259: warning: Member testShuffleRestoresOrderAfterEachIteration(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:291: warning: Member testShuffleGeneratesNewOrderInEachIteration(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/googletest-shuffle-test.py:303: warning: Member testShuffleShardedTestsPreservesPartition(self) (function) of class googletest-shuffle-test::GTestShuffleUnitTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:140: warning: Member testPrintsHelpWithFullFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:143: warning: Member testPrintsHelpWithShortFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:146: warning: Member testPrintsHelpWithQuestionFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:149: warning: Member testPrintsHelpWithWindowsStyleQuestionFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:152: warning: Member testPrintsHelpWithUnrecognizedGoogleTestFlag(self) (function) of class gtest_help_test::GTestHelpTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_help_test.py:155: warning: Member testPrintsHelpWithIncorrectFlagStyle(self) (function) of class gtest_help_test::GTestHelpTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:75: warning: Member setUp(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:83: warning: Member tearDown(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:86: warning: Member DeleteFilesAndDir(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:100: warning: Member testOutfile1(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:103: warning: Member testOutfile2(self) (function) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_outfiles_test.py:79: warning: Member output_dir_ (variable) of class gtest_xml_outfiles_test::GTestXMLOutFilesTest is not documented.
 | 
			
		||||
D:/C/VectorAlgebra/out/build/x64-Debug/_deps/googletest-src/googletest/test/gtest_xml_test_utils.py:103: warning: Member identifying_attribute (variable) of class gtest_xml_test_utils::GTestXMLTestCase is not documented.
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
# Doxyfile 1.9.8
 | 
			
		||||
# Doxyfile 1.9.2
 | 
			
		||||
 | 
			
		||||
# This file describes the settings to be used by the documentation system
 | 
			
		||||
# doxygen (www.doxygen.org) for a project.
 | 
			
		||||
@ -12,16 +12,6 @@
 | 
			
		||||
# For lists, items can also be appended using:
 | 
			
		||||
# TAG += value [value, ...]
 | 
			
		||||
# Values that contain spaces should be placed between quotes (\" \").
 | 
			
		||||
#
 | 
			
		||||
# Note:
 | 
			
		||||
#
 | 
			
		||||
# Use doxygen to compare the used configuration file with the template
 | 
			
		||||
# configuration file:
 | 
			
		||||
# doxygen -x [configFile]
 | 
			
		||||
# Use doxygen to compare the used configuration file with the template
 | 
			
		||||
# configuration file without replacing the environment variables or CMake type
 | 
			
		||||
# replacement variables:
 | 
			
		||||
# doxygen -x_noenv [configFile]
 | 
			
		||||
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
# Project related configuration options
 | 
			
		||||
@ -42,7 +32,7 @@ DOXYFILE_ENCODING      = UTF-8
 | 
			
		||||
# title of most generated pages and in a few other places.
 | 
			
		||||
# The default value is: My Project.
 | 
			
		||||
 | 
			
		||||
PROJECT_NAME           = LinearAlgebra
 | 
			
		||||
PROJECT_NAME           = VectorAlgebra
 | 
			
		||||
 | 
			
		||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
 | 
			
		||||
# could be handy for archiving the generated documentation or if some version
 | 
			
		||||
@ -68,30 +58,18 @@ PROJECT_LOGO           = //intranet/home/Afbeeldingen/PasserVR/Logos/Logo3NameRi
 | 
			
		||||
# entered, it will be relative to the location where doxygen was started. If
 | 
			
		||||
# left blank the current directory will be used.
 | 
			
		||||
 | 
			
		||||
OUTPUT_DIRECTORY       = //intranet/web/passer_life/apis/LinearAlgebra
 | 
			
		||||
OUTPUT_DIRECTORY       = //serrarens.nl/web/apis/VectorAlgebra
 | 
			
		||||
 | 
			
		||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
 | 
			
		||||
# sub-directories (in 2 levels) under the output directory of each output format
 | 
			
		||||
# and will distribute the generated files over these directories. Enabling this
 | 
			
		||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
 | 
			
		||||
# directories (in 2 levels) under the output directory of each output format and
 | 
			
		||||
# will distribute the generated files over these directories. Enabling this
 | 
			
		||||
# option can be useful when feeding doxygen a huge amount of source files, where
 | 
			
		||||
# putting all generated files in the same directory would otherwise causes
 | 
			
		||||
# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
 | 
			
		||||
# control the number of sub-directories.
 | 
			
		||||
# performance problems for the file system.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
 | 
			
		||||
CREATE_SUBDIRS         = NO
 | 
			
		||||
 | 
			
		||||
# Controls the number of sub-directories that will be created when
 | 
			
		||||
# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
 | 
			
		||||
# level increment doubles the number of directories, resulting in 4096
 | 
			
		||||
# directories at level 8 which is the default and also the maximum value. The
 | 
			
		||||
# sub-directories are organized in 2 levels, the first level always has a fixed
 | 
			
		||||
# number of 16 directories.
 | 
			
		||||
# Minimum value: 0, maximum value: 8, default value: 8.
 | 
			
		||||
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
 | 
			
		||||
 | 
			
		||||
CREATE_SUBDIRS_LEVEL   = 8
 | 
			
		||||
 | 
			
		||||
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
 | 
			
		||||
# characters to appear in the names of generated files. If set to NO, non-ASCII
 | 
			
		||||
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
 | 
			
		||||
@ -103,14 +81,14 @@ ALLOW_UNICODE_NAMES    = NO
 | 
			
		||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
 | 
			
		||||
# documentation generated by doxygen is written. Doxygen will use this
 | 
			
		||||
# information to generate all constant output in the proper language.
 | 
			
		||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
 | 
			
		||||
# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
 | 
			
		||||
# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
 | 
			
		||||
# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
 | 
			
		||||
# English messages), Korean, Korean-en (Korean with English messages), Latvian,
 | 
			
		||||
# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
 | 
			
		||||
# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
 | 
			
		||||
# Swedish, Turkish, Ukrainian and Vietnamese.
 | 
			
		||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
 | 
			
		||||
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
 | 
			
		||||
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
 | 
			
		||||
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
 | 
			
		||||
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
 | 
			
		||||
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
 | 
			
		||||
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
 | 
			
		||||
# Ukrainian and Vietnamese.
 | 
			
		||||
# The default value is: English.
 | 
			
		||||
 | 
			
		||||
OUTPUT_LANGUAGE        = English
 | 
			
		||||
@ -363,17 +341,6 @@ MARKDOWN_SUPPORT       = YES
 | 
			
		||||
 | 
			
		||||
TOC_INCLUDE_HEADINGS   = 0
 | 
			
		||||
 | 
			
		||||
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
 | 
			
		||||
# generate identifiers for the Markdown headings. Note: Every identifier is
 | 
			
		||||
# unique.
 | 
			
		||||
# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a
 | 
			
		||||
# sequence number starting at 0 and GITHUB use the lower case version of title
 | 
			
		||||
# with any whitespace replaced by '-' and punctuation characters removed.
 | 
			
		||||
# The default value is: DOXYGEN.
 | 
			
		||||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
 | 
			
		||||
 | 
			
		||||
MARKDOWN_ID_STYLE      = DOXYGEN
 | 
			
		||||
 | 
			
		||||
# When enabled doxygen tries to link words that correspond to documented
 | 
			
		||||
# classes, or namespaces to their corresponding documentation. Such a link can
 | 
			
		||||
# be prevented in individual cases by putting a % sign in front of the word or
 | 
			
		||||
@ -485,7 +452,7 @@ TYPEDEF_HIDES_STRUCT   = NO
 | 
			
		||||
 | 
			
		||||
LOOKUP_CACHE_SIZE      = 0
 | 
			
		||||
 | 
			
		||||
# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
 | 
			
		||||
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
 | 
			
		||||
# during processing. When set to 0 doxygen will based this on the number of
 | 
			
		||||
# cores available in the system. You can set it explicitly to a value larger
 | 
			
		||||
# than 0 to get more control over the balance between CPU load and processing
 | 
			
		||||
@ -498,14 +465,6 @@ LOOKUP_CACHE_SIZE      = 0
 | 
			
		||||
 | 
			
		||||
NUM_PROC_THREADS       = 1
 | 
			
		||||
 | 
			
		||||
# If the TIMESTAMP tag is set different from NO then each generated page will
 | 
			
		||||
# contain the date or date and time when the page was generated. Setting this to
 | 
			
		||||
# NO can help when comparing the output of multiple runs.
 | 
			
		||||
# Possible values are: YES, NO, DATETIME and DATE.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
 | 
			
		||||
TIMESTAMP              = NO
 | 
			
		||||
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
# Build related configuration options
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
@ -587,8 +546,7 @@ HIDE_UNDOC_MEMBERS     = NO
 | 
			
		||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
 | 
			
		||||
# undocumented classes that are normally visible in the class hierarchy. If set
 | 
			
		||||
# to NO, these classes will be included in the various overviews. This option
 | 
			
		||||
# will also hide undocumented C++ concepts if enabled. This option has no effect
 | 
			
		||||
# if EXTRACT_ALL is enabled.
 | 
			
		||||
# has no effect if EXTRACT_ALL is enabled.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
 | 
			
		||||
HIDE_UNDOC_CLASSES     = YES
 | 
			
		||||
@ -619,15 +577,14 @@ INTERNAL_DOCS          = NO
 | 
			
		||||
# filesystem is case sensitive (i.e. it supports files in the same directory
 | 
			
		||||
# whose names only differ in casing), the option must be set to YES to properly
 | 
			
		||||
# deal with such files in case they appear in the input. For filesystems that
 | 
			
		||||
# are not case sensitive the option should be set to NO to properly deal with
 | 
			
		||||
# are not case sensitive the option should be be set to NO to properly deal with
 | 
			
		||||
# output files written for symbols that only differ in casing, such as for two
 | 
			
		||||
# classes, one named CLASS and the other named Class, and to also support
 | 
			
		||||
# references to files without having to specify the exact matching casing. On
 | 
			
		||||
# Windows (including Cygwin) and MacOS, users should typically set this option
 | 
			
		||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
 | 
			
		||||
# YES.
 | 
			
		||||
# Possible values are: SYSTEM, NO and YES.
 | 
			
		||||
# The default value is: SYSTEM.
 | 
			
		||||
# The default value is: system dependent.
 | 
			
		||||
 | 
			
		||||
CASE_SENSE_NAMES       = NO
 | 
			
		||||
 | 
			
		||||
@ -879,26 +836,11 @@ WARN_IF_INCOMPLETE_DOC = YES
 | 
			
		||||
 | 
			
		||||
WARN_NO_PARAMDOC       = NO
 | 
			
		||||
 | 
			
		||||
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
 | 
			
		||||
# undocumented enumeration values. If set to NO, doxygen will accept
 | 
			
		||||
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
 | 
			
		||||
# will automatically be disabled.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
 | 
			
		||||
WARN_IF_UNDOC_ENUM_VAL = NO
 | 
			
		||||
 | 
			
		||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
 | 
			
		||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
 | 
			
		||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
 | 
			
		||||
# at the end of the doxygen process doxygen will return with a non-zero status.
 | 
			
		||||
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
 | 
			
		||||
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
 | 
			
		||||
# write the warning messages in between other messages but write them at the end
 | 
			
		||||
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
 | 
			
		||||
# besides being in the defined file also be shown at the end of a run, unless
 | 
			
		||||
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
 | 
			
		||||
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
 | 
			
		||||
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
 | 
			
		||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
 | 
			
		||||
WARN_AS_ERROR          = NO
 | 
			
		||||
@ -909,27 +851,13 @@ WARN_AS_ERROR          = NO
 | 
			
		||||
# and the warning text. Optionally the format may contain $version, which will
 | 
			
		||||
# be replaced by the version of the file (if it could be obtained via
 | 
			
		||||
# FILE_VERSION_FILTER)
 | 
			
		||||
# See also: WARN_LINE_FORMAT
 | 
			
		||||
# The default value is: $file:$line: $text.
 | 
			
		||||
 | 
			
		||||
WARN_FORMAT            = "$file:$line: $text"
 | 
			
		||||
 | 
			
		||||
# In the $text part of the WARN_FORMAT command it is possible that a reference
 | 
			
		||||
# to a more specific place is given. To make it easier to jump to this place
 | 
			
		||||
# (outside of doxygen) the user can define a custom "cut" / "paste" string.
 | 
			
		||||
# Example:
 | 
			
		||||
# WARN_LINE_FORMAT = "'vi $file +$line'"
 | 
			
		||||
# See also: WARN_FORMAT
 | 
			
		||||
# The default value is: at line $line of file $file.
 | 
			
		||||
 | 
			
		||||
WARN_LINE_FORMAT       = "at line $line of file $file"
 | 
			
		||||
 | 
			
		||||
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
 | 
			
		||||
# messages should be written. If left blank the output is written to standard
 | 
			
		||||
# error (stderr). In case the file specified cannot be opened for writing the
 | 
			
		||||
# warning and error messages are written to standard error. When as file - is
 | 
			
		||||
# specified the warning and error messages are written to standard output
 | 
			
		||||
# (stdout).
 | 
			
		||||
# error (stderr).
 | 
			
		||||
 | 
			
		||||
WARN_LOGFILE           = DoxyWarnLogfile.txt
 | 
			
		||||
 | 
			
		||||
@ -943,7 +871,8 @@ WARN_LOGFILE           = DoxyWarnLogfile.txt
 | 
			
		||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
 | 
			
		||||
# Note: If this tag is empty the current directory is searched.
 | 
			
		||||
 | 
			
		||||
INPUT                  = .. \
 | 
			
		||||
INPUT                  = ../include \
 | 
			
		||||
                         ../src \
 | 
			
		||||
                         ../README.md
 | 
			
		||||
 | 
			
		||||
# This tag can be used to specify the character encoding of the source files
 | 
			
		||||
@ -951,21 +880,10 @@ INPUT                  = .. \
 | 
			
		||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
 | 
			
		||||
# documentation (see:
 | 
			
		||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
 | 
			
		||||
# See also: INPUT_FILE_ENCODING
 | 
			
		||||
# The default value is: UTF-8.
 | 
			
		||||
 | 
			
		||||
INPUT_ENCODING         = UTF-8
 | 
			
		||||
 | 
			
		||||
# This tag can be used to specify the character encoding of the source files
 | 
			
		||||
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
 | 
			
		||||
# character encoding on a per file pattern basis. Doxygen will compare the file
 | 
			
		||||
# name with each pattern and apply the encoding instead of the default
 | 
			
		||||
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
 | 
			
		||||
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
 | 
			
		||||
# "INPUT_ENCODING" for further information on supported encodings.
 | 
			
		||||
 | 
			
		||||
INPUT_FILE_ENCODING    =
 | 
			
		||||
 | 
			
		||||
# If the value of the INPUT tag contains directories, you can use the
 | 
			
		||||
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
 | 
			
		||||
# *.h) to filter out the source-files in the directories.
 | 
			
		||||
@ -977,12 +895,12 @@ INPUT_FILE_ENCODING    =
 | 
			
		||||
# Note the list of default checked file patterns might differ from the list of
 | 
			
		||||
# default file extension mappings.
 | 
			
		||||
#
 | 
			
		||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm,
 | 
			
		||||
# *.cpp, *.cppm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl,
 | 
			
		||||
# *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, *.php,
 | 
			
		||||
# *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be
 | 
			
		||||
# provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
 | 
			
		||||
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
 | 
			
		||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
 | 
			
		||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
 | 
			
		||||
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
 | 
			
		||||
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
 | 
			
		||||
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
 | 
			
		||||
# *.vhdl, *.ucf, *.qsf and *.ice.
 | 
			
		||||
 | 
			
		||||
FILE_PATTERNS          = *.c \
 | 
			
		||||
                         *.cc \
 | 
			
		||||
@ -1060,14 +978,16 @@ EXCLUDE_SYMLINKS       = NO
 | 
			
		||||
# Note that the wildcards are matched against the file with absolute path, so to
 | 
			
		||||
# exclude all test directories for example use the pattern */test/*
 | 
			
		||||
 | 
			
		||||
EXCLUDE_PATTERNS       = gtest* \
 | 
			
		||||
                         googletest*
 | 
			
		||||
EXCLUDE_PATTERNS       =
 | 
			
		||||
 | 
			
		||||
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
 | 
			
		||||
# (namespaces, classes, functions, etc.) that should be excluded from the
 | 
			
		||||
# output. The symbol name can be a fully qualified name, a word, or if the
 | 
			
		||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
 | 
			
		||||
# ANamespace::AClass, ANamespace::*Test
 | 
			
		||||
# AClass::ANamespace, ANamespace::*Test
 | 
			
		||||
#
 | 
			
		||||
# Note that the wildcards are matched against the file with absolute path, so to
 | 
			
		||||
# exclude all test directories use the pattern */test/*
 | 
			
		||||
 | 
			
		||||
EXCLUDE_SYMBOLS        =
 | 
			
		||||
 | 
			
		||||
@ -1113,11 +1033,6 @@ IMAGE_PATH             = images \
 | 
			
		||||
# code is scanned, but not when the output code is generated. If lines are added
 | 
			
		||||
# or removed, the anchors will not be placed correctly.
 | 
			
		||||
#
 | 
			
		||||
# Note that doxygen will use the data processed and written to standard output
 | 
			
		||||
# for further processing, therefore nothing else, like debug statements or used
 | 
			
		||||
# commands (so in case of a Windows batch file always use @echo OFF), should be
 | 
			
		||||
# written to standard output.
 | 
			
		||||
#
 | 
			
		||||
# Note that for custom extensions or not directly supported extensions you also
 | 
			
		||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
 | 
			
		||||
# properly processed by doxygen.
 | 
			
		||||
@ -1159,15 +1074,6 @@ FILTER_SOURCE_PATTERNS =
 | 
			
		||||
 | 
			
		||||
USE_MDFILE_AS_MAINPAGE =
 | 
			
		||||
 | 
			
		||||
# The Fortran standard specifies that for fixed formatted Fortran code all
 | 
			
		||||
# characters from position 72 are to be considered as comment. A common
 | 
			
		||||
# extension is to allow longer lines before the automatic comment starts. The
 | 
			
		||||
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
 | 
			
		||||
# be processed before the automatic comment starts.
 | 
			
		||||
# Minimum value: 7, maximum value: 10000, default value: 72.
 | 
			
		||||
 | 
			
		||||
FORTRAN_COMMENT_AFTER  = 72
 | 
			
		||||
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
# Configuration options related to source browsing
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
@ -1305,11 +1211,10 @@ CLANG_DATABASE_PATH    =
 | 
			
		||||
 | 
			
		||||
ALPHABETICAL_INDEX     = YES
 | 
			
		||||
 | 
			
		||||
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
 | 
			
		||||
# that should be ignored while generating the index headers. The IGNORE_PREFIX
 | 
			
		||||
# tag works for classes, function and member names. The entity will be placed in
 | 
			
		||||
# the alphabetical list under the first letter of the entity name that remains
 | 
			
		||||
# after removing the prefix.
 | 
			
		||||
# In case all classes in a project start with a common prefix, all classes will
 | 
			
		||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
 | 
			
		||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
 | 
			
		||||
# while generating the index headers.
 | 
			
		||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 | 
			
		||||
 | 
			
		||||
IGNORE_PREFIX          =
 | 
			
		||||
@ -1388,12 +1293,7 @@ HTML_STYLESHEET        =
 | 
			
		||||
# Doxygen will copy the style sheet files to the output directory.
 | 
			
		||||
# Note: The order of the extra style sheet files is of importance (e.g. the last
 | 
			
		||||
# style sheet in the list overrules the setting of the previous ones in the
 | 
			
		||||
# list).
 | 
			
		||||
# Note: Since the styling of scrollbars can currently not be overruled in
 | 
			
		||||
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
 | 
			
		||||
# one or more extra stylesheets have been specified. So if scrollbar
 | 
			
		||||
# customization is desired it has to be added explicitly. For an example see the
 | 
			
		||||
# documentation.
 | 
			
		||||
# list). For an example see the documentation.
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
 | 
			
		||||
HTML_EXTRA_STYLESHEET  = custom_doxygen.css
 | 
			
		||||
@ -1408,19 +1308,6 @@ HTML_EXTRA_STYLESHEET  = custom_doxygen.css
 | 
			
		||||
 | 
			
		||||
HTML_EXTRA_FILES       =
 | 
			
		||||
 | 
			
		||||
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
 | 
			
		||||
# should be rendered with a dark or light theme.
 | 
			
		||||
# Possible values are: LIGHT always generate light mode output, DARK always
 | 
			
		||||
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
 | 
			
		||||
# the user preference, use light mode if no preference is set (the default),
 | 
			
		||||
# AUTO_DARK automatically set the mode according to the user preference, use
 | 
			
		||||
# dark mode if no preference is set and TOGGLE allow to user to switch between
 | 
			
		||||
# light and dark mode via a button.
 | 
			
		||||
# The default value is: AUTO_LIGHT.
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
 | 
			
		||||
HTML_COLORSTYLE        = LIGHT
 | 
			
		||||
 | 
			
		||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
 | 
			
		||||
# will adjust the colors in the style sheet and background images according to
 | 
			
		||||
# this color. Hue is specified as an angle on a color-wheel, see
 | 
			
		||||
@ -1451,6 +1338,15 @@ HTML_COLORSTYLE_SAT    = 0
 | 
			
		||||
 | 
			
		||||
HTML_COLORSTYLE_GAMMA  = 103
 | 
			
		||||
 | 
			
		||||
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
 | 
			
		||||
# page will contain the date and time when the page was generated. Setting this
 | 
			
		||||
# to YES can help to show when doxygen was last run and thus if the
 | 
			
		||||
# documentation is up to date.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
 | 
			
		||||
HTML_TIMESTAMP         = NO
 | 
			
		||||
 | 
			
		||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
 | 
			
		||||
# documentation will contain a main index with vertical navigation menus that
 | 
			
		||||
# are dynamically created via JavaScript. If disabled, the navigation index will
 | 
			
		||||
@ -1470,13 +1366,6 @@ HTML_DYNAMIC_MENUS     = YES
 | 
			
		||||
 | 
			
		||||
HTML_DYNAMIC_SECTIONS  = NO
 | 
			
		||||
 | 
			
		||||
# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be
 | 
			
		||||
# dynamically folded and expanded in the generated HTML source code.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
 | 
			
		||||
HTML_CODE_FOLDING      = YES
 | 
			
		||||
 | 
			
		||||
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
 | 
			
		||||
# shown in the various tree structured indices initially; the user can expand
 | 
			
		||||
# and collapse entries dynamically later on. Doxygen will expand the tree to
 | 
			
		||||
@ -1513,13 +1402,6 @@ GENERATE_DOCSET        = NO
 | 
			
		||||
 | 
			
		||||
DOCSET_FEEDNAME        = "Doxygen generated docs"
 | 
			
		||||
 | 
			
		||||
# This tag determines the URL of the docset feed. A documentation feed provides
 | 
			
		||||
# an umbrella under which multiple documentation sets from a single provider
 | 
			
		||||
# (such as a company or product suite) can be grouped.
 | 
			
		||||
# This tag requires that the tag GENERATE_DOCSET is set to YES.
 | 
			
		||||
 | 
			
		||||
DOCSET_FEEDURL         =
 | 
			
		||||
 | 
			
		||||
# This tag specifies a string that should uniquely identify the documentation
 | 
			
		||||
# set bundle. This should be a reverse domain-name style string, e.g.
 | 
			
		||||
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
 | 
			
		||||
@ -1607,16 +1489,6 @@ BINARY_TOC             = NO
 | 
			
		||||
 | 
			
		||||
TOC_EXPAND             = NO
 | 
			
		||||
 | 
			
		||||
# The SITEMAP_URL tag is used to specify the full URL of the place where the
 | 
			
		||||
# generated documentation will be placed on the server by the user during the
 | 
			
		||||
# deployment of the documentation. The generated sitemap is called sitemap.xml
 | 
			
		||||
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
 | 
			
		||||
# is specified no sitemap is generated. For information about the sitemap
 | 
			
		||||
# protocol see https://www.sitemaps.org
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
 | 
			
		||||
SITEMAP_URL            =
 | 
			
		||||
 | 
			
		||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
 | 
			
		||||
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
 | 
			
		||||
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
 | 
			
		||||
@ -1734,7 +1606,7 @@ GENERATE_TREEVIEW      = NO
 | 
			
		||||
# area (value NO) or if it should extend to the full height of the window (value
 | 
			
		||||
# YES). Setting this to YES gives a layout similar to
 | 
			
		||||
# https://docs.readthedocs.io with more room for contents, but less room for the
 | 
			
		||||
# project logo, title, and description. If either GENERATE_TREEVIEW or
 | 
			
		||||
# project logo, title, and description. If either GENERATOR_TREEVIEW or
 | 
			
		||||
# DISABLE_INDEX is set to NO, this option has no effect.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
@ -1765,13 +1637,6 @@ TREEVIEW_WIDTH         = 250
 | 
			
		||||
 | 
			
		||||
EXT_LINKS_IN_WINDOW    = NO
 | 
			
		||||
 | 
			
		||||
# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
 | 
			
		||||
# addresses.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
 | 
			
		||||
OBFUSCATE_EMAILS       = YES
 | 
			
		||||
 | 
			
		||||
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
 | 
			
		||||
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
 | 
			
		||||
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
 | 
			
		||||
@ -1792,6 +1657,17 @@ HTML_FORMULA_FORMAT    = png
 | 
			
		||||
 | 
			
		||||
FORMULA_FONTSIZE       = 10
 | 
			
		||||
 | 
			
		||||
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
 | 
			
		||||
# generated for formulas are transparent PNGs. Transparent PNGs are not
 | 
			
		||||
# supported properly for IE 6.0, but are supported on all modern browsers.
 | 
			
		||||
#
 | 
			
		||||
# Note that when changing this option you need to delete any form_*.png files in
 | 
			
		||||
# the HTML output directory before the changes have effect.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag GENERATE_HTML is set to YES.
 | 
			
		||||
 | 
			
		||||
FORMULA_TRANSPARENT    = YES
 | 
			
		||||
 | 
			
		||||
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
 | 
			
		||||
# to create new LaTeX commands to be used in formulas as building blocks. See
 | 
			
		||||
# the section "Including formulas" for details.
 | 
			
		||||
@ -2105,16 +1981,9 @@ PDF_HYPERLINKS         = YES
 | 
			
		||||
 | 
			
		||||
USE_PDFLATEX           = YES
 | 
			
		||||
 | 
			
		||||
# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error.
 | 
			
		||||
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
 | 
			
		||||
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
 | 
			
		||||
# hit at every error; missing files that TeX tries to input or request from
 | 
			
		||||
# keyboard input (\read on a not open input stream) cause the job to abort,
 | 
			
		||||
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
 | 
			
		||||
# but there is no possibility of user interaction just like in batch mode,
 | 
			
		||||
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
 | 
			
		||||
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
 | 
			
		||||
# each error, asking for user intervention.
 | 
			
		||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
 | 
			
		||||
# command to the generated LaTeX files. This will instruct LaTeX to keep running
 | 
			
		||||
# if errors occur, instead of asking the user for help.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
 | 
			
		||||
 | 
			
		||||
@ -2135,6 +2004,14 @@ LATEX_HIDE_INDICES     = NO
 | 
			
		||||
 | 
			
		||||
LATEX_BIB_STYLE        = plain
 | 
			
		||||
 | 
			
		||||
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
 | 
			
		||||
# page will contain the date and time when the page was generated. Setting this
 | 
			
		||||
# to NO can help when comparing the output of multiple runs.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
 | 
			
		||||
 | 
			
		||||
LATEX_TIMESTAMP        = NO
 | 
			
		||||
 | 
			
		||||
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
 | 
			
		||||
# path from which the emoji images will be read. If a relative path is entered,
 | 
			
		||||
# it will be relative to the LATEX_OUTPUT directory. If left blank the
 | 
			
		||||
@ -2300,7 +2177,7 @@ DOCBOOK_OUTPUT         = docbook
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
 | 
			
		||||
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
 | 
			
		||||
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
 | 
			
		||||
# the structure of the code including all documentation. Note that this feature
 | 
			
		||||
# is still experimental and incomplete at the moment.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
@ -2311,28 +2188,6 @@ GENERATE_AUTOGEN_DEF   = NO
 | 
			
		||||
# Configuration options related to Sqlite3 output
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3
 | 
			
		||||
# database with symbols found by doxygen stored in tables.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
 | 
			
		||||
GENERATE_SQLITE3       = NO
 | 
			
		||||
 | 
			
		||||
# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be
 | 
			
		||||
# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put
 | 
			
		||||
# in front of it.
 | 
			
		||||
# The default directory is: sqlite3.
 | 
			
		||||
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
 | 
			
		||||
 | 
			
		||||
SQLITE3_OUTPUT         = sqlite3
 | 
			
		||||
 | 
			
		||||
# The SQLITE3_OVERWRITE_DB tag is set to YES, the existing doxygen_sqlite3.db
 | 
			
		||||
# database file will be recreated with each doxygen run. If set to NO, doxygen
 | 
			
		||||
# will warn if an a database file is already found and not modify it.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag GENERATE_SQLITE3 is set to YES.
 | 
			
		||||
 | 
			
		||||
SQLITE3_RECREATE_DB    = YES
 | 
			
		||||
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
# Configuration options related to the Perl module output
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
@ -2407,8 +2262,7 @@ SEARCH_INCLUDES        = YES
 | 
			
		||||
 | 
			
		||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
 | 
			
		||||
# contain include files that are not input files but should be processed by the
 | 
			
		||||
# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
 | 
			
		||||
# RECURSIVE has no effect here.
 | 
			
		||||
# preprocessor.
 | 
			
		||||
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
 | 
			
		||||
 | 
			
		||||
INCLUDE_PATH           =
 | 
			
		||||
@ -2475,15 +2329,15 @@ TAGFILES               =
 | 
			
		||||
 | 
			
		||||
GENERATE_TAGFILE       =
 | 
			
		||||
 | 
			
		||||
# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces
 | 
			
		||||
# will be listed in the class and namespace index. If set to NO, only the
 | 
			
		||||
# inherited external classes will be listed.
 | 
			
		||||
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
 | 
			
		||||
# the class index. If set to NO, only the inherited external classes will be
 | 
			
		||||
# listed.
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
 | 
			
		||||
ALLEXTERNALS           = NO
 | 
			
		||||
 | 
			
		||||
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
 | 
			
		||||
# in the topic index. If set to NO, only the current project's groups will be
 | 
			
		||||
# in the modules index. If set to NO, only the current project's groups will be
 | 
			
		||||
# listed.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
 | 
			
		||||
@ -2497,9 +2351,25 @@ EXTERNAL_GROUPS        = YES
 | 
			
		||||
EXTERNAL_PAGES         = YES
 | 
			
		||||
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
# Configuration options related to diagram generator tools
 | 
			
		||||
# Configuration options related to the dot tool
 | 
			
		||||
#---------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
 | 
			
		||||
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
 | 
			
		||||
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
 | 
			
		||||
# disabled, but it is recommended to install and use dot, since it yields more
 | 
			
		||||
# powerful graphs.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
 | 
			
		||||
CLASS_DIAGRAMS         = YES
 | 
			
		||||
 | 
			
		||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
 | 
			
		||||
# then run dia to produce the diagram and insert it in the documentation. The
 | 
			
		||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
 | 
			
		||||
# If left empty dia is assumed to be found in the default search path.
 | 
			
		||||
 | 
			
		||||
DIA_PATH               =
 | 
			
		||||
 | 
			
		||||
# If set to YES the inheritance and collaboration graphs will hide inheritance
 | 
			
		||||
# and usage relations if the target is undocumented or is not a class.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
@ -2508,7 +2378,7 @@ HIDE_UNDOC_RELATIONS   = YES
 | 
			
		||||
 | 
			
		||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
 | 
			
		||||
# available from the path. This tool is part of Graphviz (see:
 | 
			
		||||
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
 | 
			
		||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
 | 
			
		||||
# Bell Labs. The other options in this section have no effect if this option is
 | 
			
		||||
# set to NO
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
@ -2525,73 +2395,49 @@ HAVE_DOT               = NO
 | 
			
		||||
 | 
			
		||||
DOT_NUM_THREADS        = 0
 | 
			
		||||
 | 
			
		||||
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
 | 
			
		||||
# subgraphs. When you want a differently looking font in the dot files that
 | 
			
		||||
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
 | 
			
		||||
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
 | 
			
		||||
# Edge and Graph Attributes specification</a> You need to make sure dot is able
 | 
			
		||||
# to find the font, which can be done by putting it in a standard location or by
 | 
			
		||||
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
 | 
			
		||||
# directory containing the font. Default graphviz fontsize is 14.
 | 
			
		||||
# The default value is: fontname=Helvetica,fontsize=10.
 | 
			
		||||
# When you want a differently looking font in the dot files that doxygen
 | 
			
		||||
# generates you can specify the font name using DOT_FONTNAME. You need to make
 | 
			
		||||
# sure dot is able to find the font, which can be done by putting it in a
 | 
			
		||||
# standard location or by setting the DOTFONTPATH environment variable or by
 | 
			
		||||
# setting DOT_FONTPATH to the directory containing the font.
 | 
			
		||||
# The default value is: Helvetica.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
DOT_COMMON_ATTR        = "fontname=Helvetica,fontsize=10"
 | 
			
		||||
DOT_FONTNAME           = Helvetica
 | 
			
		||||
 | 
			
		||||
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
 | 
			
		||||
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
 | 
			
		||||
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
 | 
			
		||||
# arrows shapes.</a>
 | 
			
		||||
# The default value is: labelfontname=Helvetica,labelfontsize=10.
 | 
			
		||||
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
 | 
			
		||||
# dot graphs.
 | 
			
		||||
# Minimum value: 4, maximum value: 24, default value: 10.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
DOT_EDGE_ATTR          = "labelfontname=Helvetica,labelfontsize=10"
 | 
			
		||||
DOT_FONTSIZE           = 10
 | 
			
		||||
 | 
			
		||||
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
 | 
			
		||||
# around nodes set 'shape=plain' or 'shape=plaintext' <a
 | 
			
		||||
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
 | 
			
		||||
# The default value is: shape=box,height=0.2,width=0.4.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
DOT_NODE_ATTR          = "shape=box,height=0.2,width=0.4"
 | 
			
		||||
 | 
			
		||||
# You can set the path where dot can find font specified with fontname in
 | 
			
		||||
# DOT_COMMON_ATTR and others dot attributes.
 | 
			
		||||
# By default doxygen will tell dot to use the default font as specified with
 | 
			
		||||
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
 | 
			
		||||
# the path where dot can find it using this tag.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
DOT_FONTPATH           =
 | 
			
		||||
 | 
			
		||||
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
 | 
			
		||||
# generate a graph for each documented class showing the direct and indirect
 | 
			
		||||
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
 | 
			
		||||
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
 | 
			
		||||
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
 | 
			
		||||
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
 | 
			
		||||
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
 | 
			
		||||
# relations will be shown as texts / links.
 | 
			
		||||
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
 | 
			
		||||
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
 | 
			
		||||
# each documented class showing the direct and indirect inheritance relations.
 | 
			
		||||
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
CLASS_GRAPH            = YES
 | 
			
		||||
 | 
			
		||||
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
 | 
			
		||||
# graph for each documented class showing the direct and indirect implementation
 | 
			
		||||
# dependencies (inheritance, containment, and class references variables) of the
 | 
			
		||||
# class with other documented classes. Explicit enabling a collaboration graph,
 | 
			
		||||
# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the
 | 
			
		||||
# command \collaborationgraph. Disabling a collaboration graph can be
 | 
			
		||||
# accomplished by means of the command \hidecollaborationgraph.
 | 
			
		||||
# class with other documented classes.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
COLLABORATION_GRAPH    = YES
 | 
			
		||||
 | 
			
		||||
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
 | 
			
		||||
# groups, showing the direct groups dependencies. Explicit enabling a group
 | 
			
		||||
# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means
 | 
			
		||||
# of the command \groupgraph. Disabling a directory graph can be accomplished by
 | 
			
		||||
# means of the command \hidegroupgraph. See also the chapter Grouping in the
 | 
			
		||||
# manual.
 | 
			
		||||
# groups, showing the direct groups dependencies.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
@ -2651,9 +2497,7 @@ TEMPLATE_RELATIONS     = NO
 | 
			
		||||
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
 | 
			
		||||
# YES then doxygen will generate a graph for each documented file showing the
 | 
			
		||||
# direct and indirect include dependencies of the file with other documented
 | 
			
		||||
# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO,
 | 
			
		||||
# can be accomplished by means of the command \includegraph. Disabling an
 | 
			
		||||
# include graph can be accomplished by means of the command \hideincludegraph.
 | 
			
		||||
# files.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
@ -2662,10 +2506,7 @@ INCLUDE_GRAPH          = YES
 | 
			
		||||
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
 | 
			
		||||
# set to YES then doxygen will generate a graph for each documented file showing
 | 
			
		||||
# the direct and indirect include dependencies of the file with other documented
 | 
			
		||||
# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set
 | 
			
		||||
# to NO, can be accomplished by means of the command \includedbygraph. Disabling
 | 
			
		||||
# an included by graph can be accomplished by means of the command
 | 
			
		||||
# \hideincludedbygraph.
 | 
			
		||||
# files.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
@ -2705,26 +2546,16 @@ GRAPHICAL_HIERARCHY    = YES
 | 
			
		||||
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
 | 
			
		||||
# dependencies a directory has on other directories in a graphical way. The
 | 
			
		||||
# dependency relations are determined by the #include relations between the
 | 
			
		||||
# files in the directories. Explicit enabling a directory graph, when
 | 
			
		||||
# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command
 | 
			
		||||
# \directorygraph. Disabling a directory graph can be accomplished by means of
 | 
			
		||||
# the command \hidedirectorygraph.
 | 
			
		||||
# files in the directories.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
DIRECTORY_GRAPH        = YES
 | 
			
		||||
 | 
			
		||||
# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
 | 
			
		||||
# of child directories generated in directory dependency graphs by dot.
 | 
			
		||||
# Minimum value: 1, maximum value: 25, default value: 1.
 | 
			
		||||
# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
 | 
			
		||||
 | 
			
		||||
DIR_GRAPH_MAX_DEPTH    = 1
 | 
			
		||||
 | 
			
		||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
 | 
			
		||||
# generated by dot. For an explanation of the image formats see the section
 | 
			
		||||
# output formats in the documentation of the dot tool (Graphviz (see:
 | 
			
		||||
# https://www.graphviz.org/)).
 | 
			
		||||
# http://www.graphviz.org/)).
 | 
			
		||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
 | 
			
		||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
 | 
			
		||||
# requirement).
 | 
			
		||||
@ -2761,12 +2592,11 @@ DOT_PATH               =
 | 
			
		||||
 | 
			
		||||
DOTFILE_DIRS           =
 | 
			
		||||
 | 
			
		||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
 | 
			
		||||
# then run dia to produce the diagram and insert it in the documentation. The
 | 
			
		||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
 | 
			
		||||
# If left empty dia is assumed to be found in the default search path.
 | 
			
		||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
 | 
			
		||||
# contain msc files that are included in the documentation (see the \mscfile
 | 
			
		||||
# command).
 | 
			
		||||
 | 
			
		||||
DIA_PATH               =
 | 
			
		||||
MSCFILE_DIRS           =
 | 
			
		||||
 | 
			
		||||
# The DIAFILE_DIRS tag can be used to specify one or more directories that
 | 
			
		||||
# contain dia files that are included in the documentation (see the \diafile
 | 
			
		||||
@ -2775,10 +2605,10 @@ DIA_PATH               =
 | 
			
		||||
DIAFILE_DIRS           =
 | 
			
		||||
 | 
			
		||||
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
 | 
			
		||||
# path where java can find the plantuml.jar file or to the filename of jar file
 | 
			
		||||
# to be used. If left blank, it is assumed PlantUML is not used or called during
 | 
			
		||||
# a preprocessing step. Doxygen will generate a warning when it encounters a
 | 
			
		||||
# \startuml command in this case and will not generate output for the diagram.
 | 
			
		||||
# path where java can find the plantuml.jar file. If left blank, it is assumed
 | 
			
		||||
# PlantUML is not used or called during a preprocessing step. Doxygen will
 | 
			
		||||
# generate a warning when it encounters a \startuml command in this case and
 | 
			
		||||
# will not generate output for the diagram.
 | 
			
		||||
 | 
			
		||||
PLANTUML_JAR_PATH      =
 | 
			
		||||
 | 
			
		||||
@ -2816,6 +2646,18 @@ DOT_GRAPH_MAX_NODES    = 50
 | 
			
		||||
 | 
			
		||||
MAX_DOT_GRAPH_DEPTH    = 0
 | 
			
		||||
 | 
			
		||||
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
 | 
			
		||||
# background. This is disabled by default, because dot on Windows does not seem
 | 
			
		||||
# to support this out of the box.
 | 
			
		||||
#
 | 
			
		||||
# Warning: Depending on the platform used, enabling this option may lead to
 | 
			
		||||
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
 | 
			
		||||
# read).
 | 
			
		||||
# The default value is: NO.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
DOT_TRANSPARENT        = NO
 | 
			
		||||
 | 
			
		||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
 | 
			
		||||
# files in one run (i.e. multiple -o and -T options on the command line). This
 | 
			
		||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
 | 
			
		||||
@ -2828,8 +2670,6 @@ DOT_MULTI_TARGETS      = NO
 | 
			
		||||
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
 | 
			
		||||
# explaining the meaning of the various boxes and arrows in the dot generated
 | 
			
		||||
# graphs.
 | 
			
		||||
# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
 | 
			
		||||
# graphical representation for inheritance and collaboration diagrams is used.
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
# This tag requires that the tag HAVE_DOT is set to YES.
 | 
			
		||||
 | 
			
		||||
@ -2843,19 +2683,3 @@ GENERATE_LEGEND        = YES
 | 
			
		||||
# The default value is: YES.
 | 
			
		||||
 | 
			
		||||
DOT_CLEANUP            = YES
 | 
			
		||||
 | 
			
		||||
# You can define message sequence charts within doxygen comments using the \msc
 | 
			
		||||
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
 | 
			
		||||
# use a built-in version of mscgen tool to produce the charts. Alternatively,
 | 
			
		||||
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
 | 
			
		||||
# specifying prog as the value, doxygen will call the tool as prog -T
 | 
			
		||||
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
 | 
			
		||||
# output file formats "png", "eps", "svg", and "ismap".
 | 
			
		||||
 | 
			
		||||
MSCGEN_TOOL            =
 | 
			
		||||
 | 
			
		||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
 | 
			
		||||
# contain msc files that are included in the documentation (see the \mscfile
 | 
			
		||||
# command).
 | 
			
		||||
 | 
			
		||||
MSCFILE_DIRS           =
 | 
			
		||||
 | 
			
		||||
@ -2,18 +2,16 @@
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#include "FloatSingle.h"
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include "FloatSingle.h"
 | 
			
		||||
 | 
			
		||||
const float Float::epsilon = 1e-05f;
 | 
			
		||||
const float Float::sqrEpsilon = 1e-10f;
 | 
			
		||||
 | 
			
		||||
float Float::Clamp(float f, float min, float max) {
 | 
			
		||||
  if (max < min)
 | 
			
		||||
    if (f < min)
 | 
			
		||||
        return min;
 | 
			
		||||
    if (f > max)
 | 
			
		||||
        return max;
 | 
			
		||||
    return f;
 | 
			
		||||
  if (f < min)
 | 
			
		||||
    return min;
 | 
			
		||||
  if (f > max)
 | 
			
		||||
    return max;
 | 
			
		||||
  return f;
 | 
			
		||||
}
 | 
			
		||||
@ -5,18 +5,19 @@
 | 
			
		||||
#ifndef FLOAT_H
 | 
			
		||||
#define FLOAT_H
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
class Float {
 | 
			
		||||
 public:
 | 
			
		||||
public:
 | 
			
		||||
  static const float epsilon;
 | 
			
		||||
  static const float sqrEpsilon;
 | 
			
		||||
 | 
			
		||||
  static float Clamp(float f, float min, float max);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
} // namespace LinearAlgebra
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,290 +1,6 @@
 | 
			
		||||
#include "Matrix.h"
 | 
			
		||||
#if !defined(NO_STD) 
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
#pragma region Matrix1
 | 
			
		||||
 | 
			
		||||
Matrix1::Matrix1(int size) : size(size) {
 | 
			
		||||
  if (this->size == 0)
 | 
			
		||||
    data = nullptr;
 | 
			
		||||
  else {
 | 
			
		||||
    this->data = new float[size]();
 | 
			
		||||
    this->externalData = false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix1::Matrix1(float* data, int size) : data(data), size(size) {
 | 
			
		||||
  this->externalData = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix1 LinearAlgebra::Matrix1::FromQuaternion(Quaternion q) {
 | 
			
		||||
  Matrix1 r = Matrix1(4);
 | 
			
		||||
  float* data = r.data;
 | 
			
		||||
  data[0] = q.x;
 | 
			
		||||
  data[1] = q.y;
 | 
			
		||||
  data[2] = q.z;
 | 
			
		||||
  data[3] = q.w;
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Quaternion LinearAlgebra::Matrix1::ToQuaternion() {
 | 
			
		||||
  return Quaternion(this->data[0], this->data[1], this->data[2], this->data[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Matrix1
 | 
			
		||||
#pragma endregion
 | 
			
		||||
 | 
			
		||||
#pragma region Matrix2
 | 
			
		||||
 | 
			
		||||
Matrix2::Matrix2() {}
 | 
			
		||||
 | 
			
		||||
Matrix2::Matrix2(int nRows, int nCols) : nRows(nRows), nCols(nCols) {
 | 
			
		||||
  this->nValues = nRows * nCols;
 | 
			
		||||
  if (this->nValues == 0)
 | 
			
		||||
    this->data = nullptr;
 | 
			
		||||
  else {
 | 
			
		||||
    this->data = new float[this->nValues];
 | 
			
		||||
    this->externalData = false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2::Matrix2(float* data, int nRows, int nCols)
 | 
			
		||||
    : nRows(nRows), nCols(nCols), data(data) {
 | 
			
		||||
  this->nValues = nRows * nCols;
 | 
			
		||||
  this->externalData = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2::Matrix2(const Matrix2& m)
 | 
			
		||||
    : nRows(m.nRows), nCols(m.nCols), nValues(m.nValues) {
 | 
			
		||||
  if (this->nValues == 0)
 | 
			
		||||
    this->data = nullptr;
 | 
			
		||||
  else {
 | 
			
		||||
    this->data = new float[this->nValues];
 | 
			
		||||
 | 
			
		||||
    for (int ix = 0; ix < this->nValues; ++ix)
 | 
			
		||||
      this->data[ix] = m.data[ix];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2& Matrix2::operator=(const Matrix2& m) {
 | 
			
		||||
  if (this != &m) {
 | 
			
		||||
    delete[] this->data;  // Free the current memory
 | 
			
		||||
 | 
			
		||||
    this->nRows = m.nRows;
 | 
			
		||||
    this->nCols = m.nCols;
 | 
			
		||||
    this->nValues = m.nValues;
 | 
			
		||||
    if (this->nValues == 0)
 | 
			
		||||
      this->data = nullptr;
 | 
			
		||||
    else {
 | 
			
		||||
      this->data = new float[this->nValues];
 | 
			
		||||
      for (int ix = 0; ix < this->nValues; ++ix)
 | 
			
		||||
        this->data[ix] = m.data[ix];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2::~Matrix2() {
 | 
			
		||||
  if (!this->externalData)
 | 
			
		||||
    delete[] data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::Clone() const {
 | 
			
		||||
  Matrix2 r = Matrix2(this->nRows, this->nCols);
 | 
			
		||||
  for (int ix = 0; ix < this->nValues; ++ix)
 | 
			
		||||
    r.data[ix] = this->data[ix];
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Move constructor
 | 
			
		||||
Matrix2::Matrix2(Matrix2&& other) noexcept
 | 
			
		||||
    : nRows(other.nRows),
 | 
			
		||||
      nCols(other.nCols),
 | 
			
		||||
      nValues(other.nValues),
 | 
			
		||||
      data(other.data) {
 | 
			
		||||
  other.data = nullptr;  // Set the other object's pointer to nullptr to avoid
 | 
			
		||||
                         // double deletion
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Move assignment operator
 | 
			
		||||
Matrix2& Matrix2::operator=(Matrix2&& other) noexcept {
 | 
			
		||||
  if (this != &other) {
 | 
			
		||||
    delete[] data;  // Clean up current data
 | 
			
		||||
    nRows = other.nRows;
 | 
			
		||||
    nCols = other.nCols;
 | 
			
		||||
    nValues = other.nValues;
 | 
			
		||||
    data = other.data;
 | 
			
		||||
    other.data = nullptr;  // Avoid double deletion
 | 
			
		||||
  }
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::Zero(int nRows, int nCols) {
 | 
			
		||||
  Matrix2 r = Matrix2(nRows, nCols);
 | 
			
		||||
  for (int ix = 0; ix < r.nValues; ix++)
 | 
			
		||||
    r.data[ix] = 0;
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Matrix2::Clear() {
 | 
			
		||||
  for (int ix = 0; ix < this->nValues; ix++)
 | 
			
		||||
    this->data[ix] = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::Identity(int size) {
 | 
			
		||||
  return Diagonal(1, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::Diagonal(float f, int size) {
 | 
			
		||||
  Matrix2 r = Matrix2::Zero(size, size);
 | 
			
		||||
  float* data = r.data;
 | 
			
		||||
  int valueIx = 0;
 | 
			
		||||
  for (int ix = 0; ix < size; ix++) {
 | 
			
		||||
    data[valueIx] = f;
 | 
			
		||||
    valueIx += size + 1;
 | 
			
		||||
  }
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::SkewMatrix(const Vector3& v) {
 | 
			
		||||
  Matrix2 r = Matrix2(3, 3);
 | 
			
		||||
  float* data = r.data;
 | 
			
		||||
  data[0 * 3 + 1] = -v.z;  // result(0, 1)
 | 
			
		||||
  data[0 * 3 + 2] = v.y;   // result(0, 2)
 | 
			
		||||
  data[1 * 3 + 0] = v.z;   // result(1, 0)
 | 
			
		||||
  data[1 * 3 + 2] = -v.x;  // result(1, 2)
 | 
			
		||||
  data[2 * 3 + 0] = -v.y;  // result(2, 0)
 | 
			
		||||
  data[2 * 3 + 1] = v.x;   // result(2, 1)
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::Transpose() const {
 | 
			
		||||
  Matrix2 r = Matrix2(this->nCols, this->nRows);
 | 
			
		||||
 | 
			
		||||
  for (int rowIx = 0; rowIx < this->nRows; rowIx++) {
 | 
			
		||||
    for (int colIx = 0; colIx < this->nCols; colIx++)
 | 
			
		||||
      r.data[colIx * this->nCols + rowIx] =
 | 
			
		||||
          this->data[rowIx * this->nCols + colIx];
 | 
			
		||||
  }
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 LinearAlgebra::Matrix2::operator-() const {
 | 
			
		||||
  Matrix2 r = Matrix2(this->nRows, this->nCols);
 | 
			
		||||
  for (int ix = 0; ix < r.nValues; ix++)
 | 
			
		||||
    r.data[ix] = -this->data[ix];
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 LinearAlgebra::Matrix2::operator+(const Matrix2& v) const {
 | 
			
		||||
  Matrix2 r = Matrix2(this->nRows, this->nCols);
 | 
			
		||||
  for (int ix = 0; ix < r.nValues; ix++)
 | 
			
		||||
    r.data[ix] = this->data[ix] + v.data[ix];
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::operator+=(const Matrix2& v) {
 | 
			
		||||
  for (int ix = 0; ix < this->nValues; ix++)
 | 
			
		||||
    this->data[ix] += v.data[ix];
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 LinearAlgebra::Matrix2::operator*(const Matrix2& B) const {
 | 
			
		||||
  Matrix2 r = Matrix2(this->nRows, B.nCols);
 | 
			
		||||
 | 
			
		||||
  int ACols = this->nCols;
 | 
			
		||||
  int BCols = B.nCols;
 | 
			
		||||
  int ARows = this->nRows;
 | 
			
		||||
  // int BRows = B.nRows;
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < ARows; ++i) {
 | 
			
		||||
    // Pre-compute row offsets
 | 
			
		||||
    int ARowOffset = i * ACols;  // ARowOffset is constant for each row of A
 | 
			
		||||
    int BColOffset = i * BCols;  // BColOffset is constant for each row of B
 | 
			
		||||
    for (int j = 0; j < BCols; ++j) {
 | 
			
		||||
      float sum = 0;
 | 
			
		||||
      std::cout << " 0";
 | 
			
		||||
      int BIndex = j;
 | 
			
		||||
      for (int k = 0; k < ACols; ++k) {
 | 
			
		||||
        std::cout << " + " << this->data[ARowOffset + k] << " * "
 | 
			
		||||
                  << B.data[BIndex];
 | 
			
		||||
        sum += this->data[ARowOffset + k] * B.data[BIndex];
 | 
			
		||||
        BIndex += BCols;
 | 
			
		||||
      }
 | 
			
		||||
      r.data[BColOffset + j] = sum;
 | 
			
		||||
      std::cout << " = " << sum << " ix: " << BColOffset + j << "\n";
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 Matrix2::Slice(int rowStart, int rowStop, int colStart, int colStop) {
 | 
			
		||||
  Matrix2 r = Matrix2(rowStop - rowStart, colStop - colStart);
 | 
			
		||||
 | 
			
		||||
  int resultRowIx = 0;
 | 
			
		||||
  int resultColIx = 0;
 | 
			
		||||
  for (int i = rowStart; i < rowStop; i++) {
 | 
			
		||||
    for (int j = colStart; j < colStop; j++)
 | 
			
		||||
      r.data[resultRowIx * r.nCols + resultColIx] =
 | 
			
		||||
          this->data[i * this->nCols + j];
 | 
			
		||||
  }
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Matrix2::UpdateSlice(int rowStart,
 | 
			
		||||
                          int rowStop,
 | 
			
		||||
                          int colStart,
 | 
			
		||||
                          int colStop,
 | 
			
		||||
                          const Matrix2& m) const {
 | 
			
		||||
  // for (int i = rowStart; i < rowStop; i++) {
 | 
			
		||||
  //   for (int j = colStart; j < colStop; j++)
 | 
			
		||||
  //     this->data[i * this->nCols + j] =
 | 
			
		||||
  //         m.data[(i - rowStart) * m.nCols + (j - colStart)];
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  int rRowDataIx = rowStart * this->nCols;
 | 
			
		||||
  int mRowDataIx = 0;
 | 
			
		||||
  for (int rowIx = rowStart; rowIx < rowStop; rowIx++) {
 | 
			
		||||
    rRowDataIx = rowIx * this->nCols;
 | 
			
		||||
    // rRowDataIx += this->nCols;
 | 
			
		||||
    mRowDataIx += m.nCols;
 | 
			
		||||
    for (int colIx = colStart; colIx < colStop; colIx++) {
 | 
			
		||||
      this->data[rRowDataIx + colIx] = m.data[mRowDataIx + (colIx - colStart)];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// @brief Compute the Omega matrix of a 3D vector
 | 
			
		||||
/// @param v The vector
 | 
			
		||||
/// @return 4x4 Omega matrix
 | 
			
		||||
Matrix2 LinearAlgebra::Matrix2::Omega(const Vector3& v) {
 | 
			
		||||
  Matrix2 r = Matrix2::Zero(4, 4);
 | 
			
		||||
  r.UpdateSlice(0, 3, 0, 3, -Matrix2::SkewMatrix(v));
 | 
			
		||||
 | 
			
		||||
  // set last row to -v
 | 
			
		||||
  int ix = 3 * 4;
 | 
			
		||||
  r.data[ix++] = -v.x;
 | 
			
		||||
  r.data[ix++] = -v.y;
 | 
			
		||||
  r.data[ix] = -v.z;
 | 
			
		||||
 | 
			
		||||
  // Set last column to v
 | 
			
		||||
  ix = 3;
 | 
			
		||||
  r.data[ix += 4] = v.x;
 | 
			
		||||
  r.data[ix += 4] = v.y;
 | 
			
		||||
  r.data[ix] = v.z;
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Matrix2
 | 
			
		||||
#pragma endregion
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
MatrixOf<float>::MatrixOf(unsigned int rows, unsigned int cols) {
 | 
			
		||||
template <> MatrixOf<float>::MatrixOf(unsigned int rows, unsigned int cols) {
 | 
			
		||||
  if (rows <= 0 || cols <= 0) {
 | 
			
		||||
    this->rows = 0;
 | 
			
		||||
    this->cols = 0;
 | 
			
		||||
@ -298,17 +14,15 @@ MatrixOf<float>::MatrixOf(unsigned int rows, unsigned int cols) {
 | 
			
		||||
  this->data = new float[matrixSize]{0.0f};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
MatrixOf<float>::MatrixOf(Vector3 v) : MatrixOf(3, 1) {
 | 
			
		||||
template <> MatrixOf<float>::MatrixOf(Vector3 v) : MatrixOf(3, 1) {
 | 
			
		||||
  Set(0, 0, v.Right());
 | 
			
		||||
  Set(1, 0, v.Up());
 | 
			
		||||
  Set(2, 0, v.Forward());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
void MatrixOf<float>::Multiply(const MatrixOf<float>* m1,
 | 
			
		||||
                               const MatrixOf<float>* m2,
 | 
			
		||||
                               MatrixOf<float>* r) {
 | 
			
		||||
void MatrixOf<float>::Multiply(const MatrixOf<float> *m1,
 | 
			
		||||
                               const MatrixOf<float> *m2, MatrixOf<float> *r) {
 | 
			
		||||
  for (unsigned int rowIx1 = 0; rowIx1 < m1->rows; rowIx1++) {
 | 
			
		||||
    for (unsigned int colIx2 = 0; colIx2 < m2->cols; colIx2++) {
 | 
			
		||||
      unsigned int rDataIx = colIx2 * m2->cols + rowIx1;
 | 
			
		||||
@ -323,7 +37,7 @@ void MatrixOf<float>::Multiply(const MatrixOf<float>* m1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
Vector3 MatrixOf<float>::Multiply(const MatrixOf<float>* m, Vector3 v) {
 | 
			
		||||
Vector3 MatrixOf<float>::Multiply(const MatrixOf<float> *m, Vector3 v) {
 | 
			
		||||
  MatrixOf<float> v_m = MatrixOf<float>(v);
 | 
			
		||||
  MatrixOf<float> r_m = MatrixOf<float>(3, 1);
 | 
			
		||||
 | 
			
		||||
@ -333,11 +47,10 @@ Vector3 MatrixOf<float>::Multiply(const MatrixOf<float>* m, Vector3 v) {
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
Vector3 MatrixOf<T>::operator*(const Vector3 v) const {
 | 
			
		||||
  float* vData = new float[3]{v.Right(), v.Up(), v.Forward()};
 | 
			
		||||
template <typename T> Vector3 MatrixOf<T>::operator*(const Vector3 v) const {
 | 
			
		||||
  float *vData = new float[3]{v.x, v.y, v.z};
 | 
			
		||||
  MatrixOf<float> v_m = MatrixOf<float>(3, 1, vData);
 | 
			
		||||
  float* rData = new float[3]{};
 | 
			
		||||
  float *rData = new float[3]{};
 | 
			
		||||
  MatrixOf<float> r_m = MatrixOf<float>(3, 1, rData);
 | 
			
		||||
 | 
			
		||||
  Multiply(this, &v_m, &r_m);
 | 
			
		||||
 | 
			
		||||
@ -1,129 +1,20 @@
 | 
			
		||||
#ifndef MATRIX_H
 | 
			
		||||
#define MATRIX_H
 | 
			
		||||
 | 
			
		||||
#include "Quaternion.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
/// @brief A 1-dimensional matrix or vector of arbitrary size
 | 
			
		||||
class Matrix1 {
 | 
			
		||||
 public:
 | 
			
		||||
  float* data = nullptr;
 | 
			
		||||
  int size = 0;
 | 
			
		||||
 | 
			
		||||
  Matrix1(int size);
 | 
			
		||||
  Matrix1(float* data, int size);
 | 
			
		||||
 | 
			
		||||
  static Matrix1 FromQuaternion(Quaternion q);
 | 
			
		||||
  Quaternion ToQuaternion();
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  bool externalData = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// @brief A 2-dimensional matrix of arbitrary size
 | 
			
		||||
class Matrix2 {
 | 
			
		||||
 public:
 | 
			
		||||
  int nRows = 0;
 | 
			
		||||
  int nCols = 0;
 | 
			
		||||
  int nValues = 0;
 | 
			
		||||
  float* data = nullptr;
 | 
			
		||||
 | 
			
		||||
  Matrix2();
 | 
			
		||||
  Matrix2(int nRows, int nCols);
 | 
			
		||||
  Matrix2(float* data, int nRows, int nCols);
 | 
			
		||||
  Matrix2(const Matrix2& m);
 | 
			
		||||
  Matrix2& operator=(const Matrix2& other);
 | 
			
		||||
 | 
			
		||||
  ~Matrix2();
 | 
			
		||||
 | 
			
		||||
  Matrix2 Clone() const;
 | 
			
		||||
 | 
			
		||||
  static Matrix2 Zero(int nRows, int nCols);
 | 
			
		||||
  void Clear();
 | 
			
		||||
 | 
			
		||||
  static Matrix2 Identity(int size);
 | 
			
		||||
 | 
			
		||||
  static Matrix2 Diagonal(float f, int size);
 | 
			
		||||
 | 
			
		||||
  static Matrix2 SkewMatrix(const Vector3& v);
 | 
			
		||||
 | 
			
		||||
  Matrix2 Transpose() const;
 | 
			
		||||
 | 
			
		||||
  Matrix2 operator-() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Add a matrix to this matrix
 | 
			
		||||
  /// @param m The matrix to add to this matrix
 | 
			
		||||
  /// @return The result of the addition
 | 
			
		||||
  Matrix2 operator+(const Matrix2& v) const;
 | 
			
		||||
  Matrix2 operator+=(const Matrix2& v);
 | 
			
		||||
 | 
			
		||||
  Matrix2 operator*(const Matrix2& m) const;
 | 
			
		||||
  friend Matrix2 operator*(const Matrix2& m, float f) {
 | 
			
		||||
    Matrix2 r = Matrix2(m.nRows, m.nCols);
 | 
			
		||||
    for (int ix = 0; ix < r.nValues; ix++)
 | 
			
		||||
      r.data[ix] = m.data[ix] * f;
 | 
			
		||||
    return r;
 | 
			
		||||
  }
 | 
			
		||||
  friend Matrix2 operator*(float f, const Matrix2& m) {
 | 
			
		||||
    Matrix2 r = Matrix2(m.nRows, m.nCols);
 | 
			
		||||
    for (int ix = 0; ix < r.nValues; ix++)
 | 
			
		||||
      r.data[ix] = f * m.data[ix];
 | 
			
		||||
    return r;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  friend Matrix1 operator*(const Matrix2& m, const Matrix1& v) {
 | 
			
		||||
    Matrix1 r = Matrix1(m.nRows);
 | 
			
		||||
    for (int rowIx = 0; rowIx < m.nRows; rowIx++) {
 | 
			
		||||
      int mRowIx = rowIx * m.nCols;
 | 
			
		||||
      for (int colIx = 0; colIx < m.nCols; colIx++)
 | 
			
		||||
        r.data[rowIx] += m.data[mRowIx + colIx] * v.data[rowIx];
 | 
			
		||||
    }
 | 
			
		||||
    return r;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  friend Matrix2 operator/(const Matrix2& m, float f) {
 | 
			
		||||
    Matrix2 r = Matrix2(m.nRows, m.nCols);
 | 
			
		||||
    for (int ix = 0; ix < r.nValues; ix++)
 | 
			
		||||
      r.data[ix] = m.data[ix] / f;
 | 
			
		||||
    return r;
 | 
			
		||||
  }
 | 
			
		||||
  friend Matrix2 operator/(float f, const Matrix2& m) {
 | 
			
		||||
    Matrix2 r = Matrix2(m.nRows, m.nCols);
 | 
			
		||||
    for (int ix = 0; ix < r.nValues; ix++)
 | 
			
		||||
      r.data[ix] = f / m.data[ix];
 | 
			
		||||
    return r;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Matrix2 Slice(int rawStart, int rowStop, int colStart, int colStop);
 | 
			
		||||
 | 
			
		||||
  void UpdateSlice(int rowStart,
 | 
			
		||||
                int rowStop,
 | 
			
		||||
                int colStart,
 | 
			
		||||
                int colStop,
 | 
			
		||||
                const Matrix2& m) const;
 | 
			
		||||
  // private:
 | 
			
		||||
  //  move constructor and move assignment operator
 | 
			
		||||
  Matrix2(Matrix2&& other) noexcept;
 | 
			
		||||
  Matrix2& operator=(Matrix2&& other) noexcept;
 | 
			
		||||
 | 
			
		||||
  static Matrix2 Omega(const Vector3& v);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  bool externalData = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// @brief Single precision float matrix
 | 
			
		||||
template <typename T>
 | 
			
		||||
class MatrixOf {
 | 
			
		||||
 public:
 | 
			
		||||
template <typename T> class MatrixOf {
 | 
			
		||||
public:
 | 
			
		||||
  MatrixOf(unsigned int rows, unsigned int cols);
 | 
			
		||||
  MatrixOf(unsigned int rows, unsigned int cols, const T* source)
 | 
			
		||||
  MatrixOf(unsigned int rows, unsigned int cols, const T *source)
 | 
			
		||||
      : MatrixOf(rows, cols) {
 | 
			
		||||
    Set(source);
 | 
			
		||||
  }
 | 
			
		||||
  MatrixOf(Vector3 v);  // creates a 3,1 matrix
 | 
			
		||||
  MatrixOf(Vector3 v); // creates a 3,1 matrix
 | 
			
		||||
 | 
			
		||||
  ~MatrixOf() {
 | 
			
		||||
    if (this->data == nullptr)
 | 
			
		||||
@ -134,7 +25,7 @@ class MatrixOf {
 | 
			
		||||
 | 
			
		||||
  /// @brief Transpose with result in matrix m
 | 
			
		||||
  /// @param r The matrix in which the transposed matrix is stored
 | 
			
		||||
  void Transpose(MatrixOf<T>* r) const {
 | 
			
		||||
  void Transpose(MatrixOf<T> *r) const {
 | 
			
		||||
    // Check dimensions first
 | 
			
		||||
    // We dont care about the rows and cols (we overwrite them)
 | 
			
		||||
    // but the data size should be equal to avoid problems
 | 
			
		||||
@ -163,14 +54,13 @@ class MatrixOf {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static void Multiply(const MatrixOf<T>* m1,
 | 
			
		||||
                       const MatrixOf<T>* m2,
 | 
			
		||||
                       MatrixOf<T>* r);
 | 
			
		||||
  void Multiply(const MatrixOf<T>* m, MatrixOf<T>* r) const {
 | 
			
		||||
  static void Multiply(const MatrixOf<T> *m1, const MatrixOf<T> *m2,
 | 
			
		||||
                       MatrixOf<T> *r);
 | 
			
		||||
  void Multiply(const MatrixOf<T> *m, MatrixOf<T> *r) const {
 | 
			
		||||
    Multiply(this, m, r);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static Vector3 Multiply(const MatrixOf<T>* m, Vector3 v);
 | 
			
		||||
  static Vector3 Multiply(const MatrixOf<T> *m, Vector3 v);
 | 
			
		||||
  Vector3 operator*(const Vector3 v) const;
 | 
			
		||||
 | 
			
		||||
  T Get(unsigned int rowIx, unsigned int colIx) const {
 | 
			
		||||
@ -184,28 +74,28 @@ class MatrixOf {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // This function does not check on source size!
 | 
			
		||||
  void Set(const T* source) {
 | 
			
		||||
  void Set(const T *source) {
 | 
			
		||||
    unsigned int matrixSize = this->cols * this->rows;
 | 
			
		||||
    for (unsigned int dataIx = 0; dataIx < matrixSize; dataIx++)
 | 
			
		||||
      this->data[dataIx] = source[dataIx];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // This function does not check on source size!
 | 
			
		||||
  void SetRow(unsigned int rowIx, const T* source) {
 | 
			
		||||
  void SetRow(unsigned int rowIx, const T *source) {
 | 
			
		||||
    unsigned int dataIx = rowIx * this->cols;
 | 
			
		||||
    for (unsigned int sourceIx = 0; sourceIx < this->cols; dataIx++, sourceIx++)
 | 
			
		||||
      this->data[dataIx] = source[sourceIx];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // This function does not check on source size!
 | 
			
		||||
  void SetCol(unsigned int colIx, const T* source) {
 | 
			
		||||
  void SetCol(unsigned int colIx, const T *source) {
 | 
			
		||||
    unsigned int dataIx = colIx;
 | 
			
		||||
    for (unsigned int sourceIx = 0; sourceIx < this->cols;
 | 
			
		||||
         dataIx += this->cols, sourceIx++)
 | 
			
		||||
      this->data[dataIx] = source[sourceIx];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void CopyFrom(const MatrixOf<T>* m) {
 | 
			
		||||
  void CopyFrom(const MatrixOf<T> *m) {
 | 
			
		||||
    unsigned int thisMatrixSize = this->cols * this->rows;
 | 
			
		||||
    unsigned int mMatrixSize = m->cols * m->rows;
 | 
			
		||||
    if (mMatrixSize != thisMatrixSize)
 | 
			
		||||
@ -218,13 +108,14 @@ class MatrixOf {
 | 
			
		||||
  unsigned int RowCount() const { return rows; }
 | 
			
		||||
  unsigned int ColCount() const { return cols; }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
private:
 | 
			
		||||
  unsigned int rows;
 | 
			
		||||
  unsigned int cols;
 | 
			
		||||
  T* data;
 | 
			
		||||
  T *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
// using namespace LinearAlgebra;
 | 
			
		||||
} // namespace LinearAlgebra
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,73 +1,59 @@
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#include "Polar.h"
 | 
			
		||||
#include "Vector2.h"
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T>::PolarOf() {
 | 
			
		||||
  this->distance = 0.0f;
 | 
			
		||||
  this->angle = AngleOf<T>();
 | 
			
		||||
  this->angle = 0.0f;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T>::PolarOf(float distance, AngleOf<T> angle) {
 | 
			
		||||
  // distance should always be 0 or greater
 | 
			
		||||
  if (distance < 0.0f) {
 | 
			
		||||
    this->distance = -distance;
 | 
			
		||||
    this->angle = AngleOf<T>::Normalize(angle - AngleOf<T>::Degrees(180));
 | 
			
		||||
    this->angle = AngleOf<T>::Normalize(angle.ToFloat() - 180.0f);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->distance = distance;
 | 
			
		||||
    if (this->distance == 0.0f)
 | 
			
		||||
      // angle is always 0 if distance is 0
 | 
			
		||||
      this->angle = AngleOf<T>();
 | 
			
		||||
      this->angle = 0.0f;
 | 
			
		||||
    else
 | 
			
		||||
      this->angle = AngleOf<T>::Normalize(angle);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T> PolarOf<T>::Degrees(float distance, float degrees) {
 | 
			
		||||
  AngleOf<T> angle = AngleOf<T>::Degrees(degrees);
 | 
			
		||||
  PolarOf<T> r = PolarOf<T>(distance, angle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T> PolarOf<T>::Radians(float distance, float radians) {
 | 
			
		||||
  return PolarOf<T>(distance, AngleOf<T>::Radians(radians));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T> PolarOf<T>::FromVector2(Vector2 v) {
 | 
			
		||||
  float distance = v.magnitude();
 | 
			
		||||
  AngleOf<T> angle =
 | 
			
		||||
      AngleOf<T>::Degrees(Vector2::SignedAngle(Vector2::forward, v));
 | 
			
		||||
  AngleOf<T> angle = Vector2::SignedAngle(Vector2::forward, v);
 | 
			
		||||
  PolarOf<T> p = PolarOf(distance, angle);
 | 
			
		||||
  return p;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T> PolarOf<T>::FromSpherical(SphericalOf<T> v) {
 | 
			
		||||
  float distance =
 | 
			
		||||
      v.distance * cosf(v.direction.vertical.InDegrees() * Deg2Rad);
 | 
			
		||||
  AngleOf<T> angle = v.direction.horizontal;
 | 
			
		||||
      v.distance * cosf(v.vertical.ToFloat() * Passer::LinearAlgebra::Deg2Rad);
 | 
			
		||||
  AngleOf<T> angle = v.horizontal;
 | 
			
		||||
  PolarOf<T> p = PolarOf(distance, angle);
 | 
			
		||||
  return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
const PolarOf<T> PolarOf<T>::zero = PolarOf(0.0f, AngleOf<T>());
 | 
			
		||||
const PolarOf<T> PolarOf<T>::zero = PolarOf(0.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const PolarOf<T> PolarOf<T>::forward = PolarOf(1.0f, AngleOf<T>());
 | 
			
		||||
const PolarOf<T> PolarOf<T>::forward = PolarOf(1.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const PolarOf<T> PolarOf<T>::back = PolarOf(1.0, AngleOf<T>::Degrees(180));
 | 
			
		||||
const PolarOf<T> PolarOf<T>::back = PolarOf(1.0, 180.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const PolarOf<T> PolarOf<T>::right = PolarOf(1.0, AngleOf<T>::Degrees(90));
 | 
			
		||||
const PolarOf<T> PolarOf<T>::right = PolarOf(1.0, 90.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const PolarOf<T> PolarOf<T>::left = PolarOf(1.0, AngleOf<T>::Degrees(-90));
 | 
			
		||||
const PolarOf<T> PolarOf<T>::left = PolarOf(1.0, -90.0f);
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool PolarOf<T>::operator==(const PolarOf& v) const {
 | 
			
		||||
  return (this->distance == v.distance &&
 | 
			
		||||
          this->angle.InDegrees() == v.angle.InDegrees());
 | 
			
		||||
          this->angle.ToFloat() == v.angle.ToFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
@ -83,8 +69,7 @@ PolarOf<T> PolarOf<T>::normalized() const {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T> PolarOf<T>::operator-() const {
 | 
			
		||||
  PolarOf<T> v =
 | 
			
		||||
      PolarOf(this->distance, this->angle + AngleOf<T>::Degrees(180));
 | 
			
		||||
  PolarOf<T> v = PolarOf(this->distance, this->angle + AngleOf<T>(180));
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -97,24 +82,8 @@ template <typename T>
 | 
			
		||||
PolarOf<T> PolarOf<T>::operator-=(const PolarOf& v) {
 | 
			
		||||
  *this = *this - v;
 | 
			
		||||
  return *this;
 | 
			
		||||
  // angle = AngleOf<T>::Normalize(newAngle);
 | 
			
		||||
  // distance = newDistance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Polar::Polar(Vector2 v) {
 | 
			
		||||
//   float signY = (v.y >= 0) - (v.y < 0);
 | 
			
		||||
//   angle = atan2(v.y, signY * sqrt(v.y * v.y + v.x * v.x)) * Angle::Rad2Deg;
 | 
			
		||||
//   distance = v.magnitude();
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// const Polar Polar::zero = Polar(0, 0);
 | 
			
		||||
 | 
			
		||||
// float Polar::Distance(const Polar &v1, const Polar &v2) {
 | 
			
		||||
//   float d =
 | 
			
		||||
//       Angle::CosineRuleSide(v1.distance, v2.distance, v2.angle - v1.angle);
 | 
			
		||||
//   return d;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
PolarOf<T> PolarOf<T>::operator+(const PolarOf& v) const {
 | 
			
		||||
  if (v.distance == 0)
 | 
			
		||||
@ -122,7 +91,8 @@ PolarOf<T> PolarOf<T>::operator+(const PolarOf& v) const {
 | 
			
		||||
  if (this->distance == 0.0f)
 | 
			
		||||
    return v;
 | 
			
		||||
 | 
			
		||||
  float deltaAngle = AngleOf<T>::Normalize(v.angle - this->angle).InDegrees();
 | 
			
		||||
  float deltaAngle =
 | 
			
		||||
      Angle::Normalize(v.angle.ToFloat() - this->angle.ToFloat()).ToFloat();
 | 
			
		||||
  float rotation =
 | 
			
		||||
      deltaAngle < 0.0f ? 180.0f + deltaAngle : 180.0f - deltaAngle;
 | 
			
		||||
 | 
			
		||||
@ -131,17 +101,16 @@ PolarOf<T> PolarOf<T>::operator+(const PolarOf& v) const {
 | 
			
		||||
    return PolarOf(this->distance + v.distance, this->angle);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  float newDistance = AngleOf<T>::CosineRuleSide(v.distance, this->distance,
 | 
			
		||||
                                                 AngleOf<T>::Degrees(rotation));
 | 
			
		||||
  float newDistance =
 | 
			
		||||
      Angle::CosineRuleSide(v.distance, this->distance, rotation).ToFloat();
 | 
			
		||||
 | 
			
		||||
  float angle =
 | 
			
		||||
      AngleSingle::CosineRuleAngle(newDistance, this->distance, v.distance)
 | 
			
		||||
          .InDegrees();
 | 
			
		||||
      Angle::CosineRuleAngle(newDistance, this->distance, v.distance).ToFloat();
 | 
			
		||||
 | 
			
		||||
  float newAngle = deltaAngle < 0.0f ? this->angle.InDegrees() - angle
 | 
			
		||||
                                     : this->angle.InDegrees() + angle;
 | 
			
		||||
  AngleOf<T> newAngleA = AngleOf<T>::Normalize(AngleOf<T>::Degrees(newAngle));
 | 
			
		||||
  PolarOf vector = PolarOf(newDistance, newAngleA);
 | 
			
		||||
  float newAngle = deltaAngle < 0.0f ? this->angle.ToFloat() - angle
 | 
			
		||||
                                     : this->angle.ToFloat() + angle;
 | 
			
		||||
  newAngle = Angle::Normalize(newAngle).ToFloat();
 | 
			
		||||
  PolarOf vector = PolarOf(newDistance, newAngle);
 | 
			
		||||
  return vector;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
@ -163,8 +132,9 @@ PolarOf<T> PolarOf<T>::operator/=(float f) {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
float PolarOf<T>::Distance(const PolarOf& v1, const PolarOf& v2) {
 | 
			
		||||
  float d =
 | 
			
		||||
      AngleOf<T>::CosineRuleSide(v1.distance, v2.distance, v2.angle - v1.angle);
 | 
			
		||||
  float d = Angle::CosineRuleSide(v1.distance, v2.distance,
 | 
			
		||||
                                  v2.angle.ToFloat() - v1.angle.ToFloat())
 | 
			
		||||
                .ToFloat();
 | 
			
		||||
  return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -175,5 +145,137 @@ PolarOf<T> PolarOf<T>::Rotate(const PolarOf& v, AngleOf<T> angle) {
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template class LinearAlgebra::PolarOf<float>;
 | 
			
		||||
template class LinearAlgebra::PolarOf<signed short>;
 | 
			
		||||
template class PolarOf<float>;
 | 
			
		||||
template class PolarOf<signed short>;
 | 
			
		||||
 | 
			
		||||
//=====================================
 | 
			
		||||
/*
 | 
			
		||||
Polar::Polar() {
 | 
			
		||||
  this->distance = 0.0f;
 | 
			
		||||
  this->angle = 0.0f;
 | 
			
		||||
}
 | 
			
		||||
Polar::Polar(float distance, Angle angle) {
 | 
			
		||||
  // distance should always be 0 or greater
 | 
			
		||||
  if (distance < 0.0f) {
 | 
			
		||||
    this->distance = -distance;
 | 
			
		||||
    this->angle = Angle::Normalize(angle.ToFloat() - 180.0f);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->distance = distance;
 | 
			
		||||
    if (this->distance == 0.0f)
 | 
			
		||||
      // angle is always 0 if distance is 0
 | 
			
		||||
      this->angle = 0.0f;
 | 
			
		||||
    else
 | 
			
		||||
      this->angle = Angle::Normalize(angle);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
Polar::Polar(Vector2 v) {
 | 
			
		||||
  this->distance = v.magnitude();
 | 
			
		||||
  this->angle = Vector2::SignedAngle(Vector2::forward, v);
 | 
			
		||||
}
 | 
			
		||||
Polar::Polar(Spherical v) {
 | 
			
		||||
  this->distance = v.distance * cosf(v.verticalAngle.ToFloat() *
 | 
			
		||||
                                     Passer::LinearAlgebra::Deg2Rad);
 | 
			
		||||
  this->angle = v.horizontalAngle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Polar Polar::zero = Polar(0.0f, 0.0f);
 | 
			
		||||
const Polar Polar::forward = Polar(1.0f, 0.0f);
 | 
			
		||||
const Polar Polar::back = Polar(1.0, 180.0f);
 | 
			
		||||
const Polar Polar::right = Polar(1.0, 90.0f);
 | 
			
		||||
const Polar Polar::left = Polar(1.0, -90.0f);
 | 
			
		||||
 | 
			
		||||
bool Polar::operator==(const Polar& v) const {
 | 
			
		||||
  return (this->distance == v.distance &&
 | 
			
		||||
          this->angle.ToFloat() == v.angle.ToFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Polar Polar::Normalize(const Polar& v) {
 | 
			
		||||
  Polar r = Polar(1, v.angle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Polar Polar::normalized() const {
 | 
			
		||||
  Polar r = Polar(1, this->angle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Polar Polar::operator-() const {
 | 
			
		||||
  Polar v = Polar(this->distance, this->angle.ToFloat() + 180.0f);
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Polar Polar::operator-(const Polar& v) const {
 | 
			
		||||
  Polar r = -v;
 | 
			
		||||
  return *this + r;
 | 
			
		||||
}
 | 
			
		||||
Polar Polar::operator-=(const Polar& v) {
 | 
			
		||||
  *this = *this - v;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
Polar Polar::operator+(const Polar& v) const {
 | 
			
		||||
  if (v.distance == 0)
 | 
			
		||||
    return Polar(this->distance, this->angle);
 | 
			
		||||
  if (this->distance == 0.0f)
 | 
			
		||||
    return v;
 | 
			
		||||
 | 
			
		||||
  float deltaAngle =
 | 
			
		||||
      Angle::Normalize(v.angle.ToFloat() - this->angle.ToFloat()).ToFloat();
 | 
			
		||||
  float rotation =
 | 
			
		||||
      deltaAngle < 0.0f ? 180.0f + deltaAngle : 180.0f - deltaAngle;
 | 
			
		||||
 | 
			
		||||
  if (rotation == 180.0f && v.distance > 0.0f) {
 | 
			
		||||
    //  angle is too small, take this angle and add the distances
 | 
			
		||||
    return Polar(this->distance + v.distance, this->angle);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  float newDistance =
 | 
			
		||||
      Angle::CosineRuleSide(v.distance, this->distance, rotation).ToFloat();
 | 
			
		||||
 | 
			
		||||
  float angle =
 | 
			
		||||
      Angle::CosineRuleAngle(newDistance, this->distance,
 | 
			
		||||
v.distance).ToFloat();
 | 
			
		||||
 | 
			
		||||
  float newAngle = deltaAngle < 0.0f ? this->angle.ToFloat() - angle
 | 
			
		||||
                                     : this->angle.ToFloat() + angle;
 | 
			
		||||
  newAngle = Angle::Normalize(newAngle).ToFloat();
 | 
			
		||||
  Polar vector = Polar(newDistance, newAngle);
 | 
			
		||||
  return vector;
 | 
			
		||||
}
 | 
			
		||||
Polar Polar::operator+=(const Polar& v) {
 | 
			
		||||
  *this = *this + v;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Polar Passer::LinearAlgebra::operator*(const Polar &v, float f) {
 | 
			
		||||
//   return Polar(v.distance * f, v.angle);
 | 
			
		||||
// }
 | 
			
		||||
// Polar Passer::LinearAlgebra::operator*(float f, const Polar &v) {
 | 
			
		||||
//   return Polar(v.distance * f, v.angle);
 | 
			
		||||
// }
 | 
			
		||||
Polar Polar::operator*=(float f) {
 | 
			
		||||
  this->distance *= f;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
// Polar Passer::LinearAlgebra::operator/(const Polar& v, float f) {
 | 
			
		||||
//   return Polar(v.distance / f, v.angle);
 | 
			
		||||
// }
 | 
			
		||||
// Polar Passer::LinearAlgebra::operator/(float f, const Polar& v) {
 | 
			
		||||
//   return Polar(v.distance / f, v.angle);
 | 
			
		||||
// }
 | 
			
		||||
Polar Polar::operator/=(float f) {
 | 
			
		||||
  this->distance /= f;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float Polar::Distance(const Polar& v1, const Polar& v2) {
 | 
			
		||||
  float d = Angle::CosineRuleSide(v1.distance, v2.distance,
 | 
			
		||||
                                  v2.angle.ToFloat() - v1.angle.ToFloat())
 | 
			
		||||
                .ToFloat();
 | 
			
		||||
  return d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Polar Polar::Rotate(const Polar& v, Angle angle) {
 | 
			
		||||
  Angle a = Angle::Normalize(v.angle.ToFloat() + angle.ToFloat());
 | 
			
		||||
  Polar r = Polar(v.distance, a);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -7,14 +7,13 @@
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
struct Vector2;
 | 
			
		||||
template <typename T>
 | 
			
		||||
class SphericalOf;
 | 
			
		||||
 | 
			
		||||
/// @brief A polar vector using an angle in various representations
 | 
			
		||||
/// @tparam T The implementation type used for the representation of the angle
 | 
			
		||||
template <typename T>
 | 
			
		||||
class PolarOf {
 | 
			
		||||
 public:
 | 
			
		||||
@ -34,24 +33,6 @@ class PolarOf {
 | 
			
		||||
  /// @note The distance is automatically converted to a positive value.
 | 
			
		||||
  /// @note The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  PolarOf(float distance, AngleOf<T> angle);
 | 
			
		||||
 | 
			
		||||
  /// @brief Create polar vector without using AngleOf type. All given angles
 | 
			
		||||
  /// are in degrees
 | 
			
		||||
  /// @param distance The distance in meters
 | 
			
		||||
  /// @param degrees The angle in degrees
 | 
			
		||||
  /// @return The polar vector
 | 
			
		||||
  static PolarOf<T> Degrees(float distance, float degrees);
 | 
			
		||||
  /// @brief Short-hand Deg alias for the Degrees function
 | 
			
		||||
  constexpr static auto Deg = Degrees;
 | 
			
		||||
  /// @brief Create polar vector without using AngleOf type. All given angles
 | 
			
		||||
  /// are in radians.
 | 
			
		||||
  /// @param distance The distance in meters
 | 
			
		||||
  /// @param radians The angle in radians
 | 
			
		||||
  /// @return The polar vector
 | 
			
		||||
  static PolarOf<T> Radians(float distance, float radians);
 | 
			
		||||
  /// @brief Short-hand Rad alias for the Radians function
 | 
			
		||||
  constexpr static auto Rad = Radians;
 | 
			
		||||
 | 
			
		||||
  /// @brief Convert a vector from 2D carthesian coordinates to polar
 | 
			
		||||
  /// coordinates
 | 
			
		||||
  /// @param v The vector to convert
 | 
			
		||||
@ -151,10 +132,131 @@ class PolarOf {
 | 
			
		||||
 | 
			
		||||
using PolarSingle = PolarOf<float>;
 | 
			
		||||
using Polar16 = PolarOf<signed short>;
 | 
			
		||||
// using Polar = PolarSingle;
 | 
			
		||||
using Polar = PolarSingle;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
/// @brief A polar vector
 | 
			
		||||
/// @details This will use the polar coordinate system consisting of a angle
 | 
			
		||||
/// from a reference direction and a distance.
 | 
			
		||||
struct Polar {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief The distance in meters
 | 
			
		||||
  /// @remark The distance shall never be negative
 | 
			
		||||
  float distance;
 | 
			
		||||
  /// @brief The angle in degrees clockwise rotation
 | 
			
		||||
  /// @remark The angle shall be between -180 .. 180
 | 
			
		||||
  Angle angle;
 | 
			
		||||
 | 
			
		||||
  /// @brief A new vector with polar coordinates with zero degrees and
 | 
			
		||||
  /// distance
 | 
			
		||||
  Polar();
 | 
			
		||||
  /// @brief A new vector with polar coordinates
 | 
			
		||||
  /// @param distance The distance in meters
 | 
			
		||||
  /// @param angle The angle in degrees, clockwise rotation
 | 
			
		||||
  /// @note The distance is automatically converted to a positive value.
 | 
			
		||||
  /// @note The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  Polar(float distance, Angle angle);
 | 
			
		||||
  /// @brief Convert a vector from 2D carthesian coordinates to polar
 | 
			
		||||
  /// coordinates
 | 
			
		||||
  /// @param v The vector to convert
 | 
			
		||||
  Polar(Vector2 v);
 | 
			
		||||
  /// @brief Convert a vector from spherical coordinates to polar coordinates
 | 
			
		||||
  /// @param s The vector to convert
 | 
			
		||||
  /// @note The resulting vector will be projected on the horizontal plane
 | 
			
		||||
  Polar(Spherical s);
 | 
			
		||||
 | 
			
		||||
  /// @brief A polar vector with zero degrees and distance
 | 
			
		||||
  const static Polar zero;
 | 
			
		||||
  /// @brief A normalized forward-oriented vector
 | 
			
		||||
  const static Polar forward;
 | 
			
		||||
  /// @brief A normalized back-oriented vector
 | 
			
		||||
  const static Polar back;
 | 
			
		||||
  /// @brief A normalized right-oriented vector
 | 
			
		||||
  const static Polar right;
 | 
			
		||||
  /// @brief A normalized left-oriented vector
 | 
			
		||||
  const static Polar left;
 | 
			
		||||
 | 
			
		||||
  /// @brief Equality test to another vector
 | 
			
		||||
  /// @param v The vector to check against
 | 
			
		||||
  /// @return true: if it is identical to the given vector
 | 
			
		||||
  /// @note This uses float comparison to check equality which may have
 | 
			
		||||
  /// strange effects. Equality on floats should be avoided.
 | 
			
		||||
  bool operator==(const Polar& v) const;
 | 
			
		||||
 | 
			
		||||
  /// @brief The vector length
 | 
			
		||||
  /// @param v The vector for which you need the length
 | 
			
		||||
  /// @return The vector length;
 | 
			
		||||
  inline static float Magnitude(const Polar& v) { return v.distance; }
 | 
			
		||||
  /// @brief The vector length
 | 
			
		||||
  /// @return The vector length
 | 
			
		||||
  inline float magnitude() const { return this->distance; }
 | 
			
		||||
 | 
			
		||||
  /// @brief Convert the vector to a length of 1
 | 
			
		||||
  /// @param v The vector to convert
 | 
			
		||||
  /// @return The vector normalized to a length of 1
 | 
			
		||||
  static Polar Normalize(const Polar& v);
 | 
			
		||||
  /// @brief Convert the vector to a length of a
 | 
			
		||||
  /// @return The vector normalized to a length of 1
 | 
			
		||||
  Polar normalized() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Negate the vector
 | 
			
		||||
  /// @return The negated vector
 | 
			
		||||
  /// This will rotate the vector by 180 degrees. Distance will stay the same.
 | 
			
		||||
  Polar operator-() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Subtract a polar vector from this vector
 | 
			
		||||
  /// @param v The vector to subtract
 | 
			
		||||
  /// @return The result of the subtraction
 | 
			
		||||
  Polar operator-(const Polar& v) const;
 | 
			
		||||
  Polar operator-=(const Polar& v);
 | 
			
		||||
  /// @brief Add a polar vector to this vector
 | 
			
		||||
  /// @param v The vector to add
 | 
			
		||||
  /// @return The result of the addition
 | 
			
		||||
  Polar operator+(const Polar& v) const;
 | 
			
		||||
  Polar operator+=(const Polar& v);
 | 
			
		||||
 | 
			
		||||
  /// @brief Scale the vector uniformly up
 | 
			
		||||
  /// @param f The scaling factor
 | 
			
		||||
  /// @return The scaled vector
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend Polar operator*(const Polar& v, float f) {
 | 
			
		||||
    return Polar(v.distance * f, v.angle);
 | 
			
		||||
  }
 | 
			
		||||
  friend Polar operator*(float f, const Polar& v) {
 | 
			
		||||
    return Polar(f * v.distance, v.angle);
 | 
			
		||||
  }
 | 
			
		||||
  Polar operator*=(float f);
 | 
			
		||||
  /// @brief Scale the vector uniformly down
 | 
			
		||||
  /// @param f The scaling factor
 | 
			
		||||
  /// @return The scaled factor
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend Polar operator/(const Polar& v, float f) {
 | 
			
		||||
    return Polar(v.distance / f, v.angle);
 | 
			
		||||
  }
 | 
			
		||||
  friend Polar operator/(float f, const Polar& v) {
 | 
			
		||||
    return Polar(f / v.distance, v.angle);
 | 
			
		||||
  }
 | 
			
		||||
  Polar operator/=(float f);
 | 
			
		||||
 | 
			
		||||
  /// @brief The distance between two vectors
 | 
			
		||||
  /// @param v1 The first vector
 | 
			
		||||
  /// @param v2 The second vector
 | 
			
		||||
  /// @return The distance between the two vectors
 | 
			
		||||
  static float Distance(const Polar& v1, const Polar& v2);
 | 
			
		||||
 | 
			
		||||
  /// @brief Rotate a vector
 | 
			
		||||
  /// @param v The vector to rotate
 | 
			
		||||
  /// @param a The angle in degreesto rotate
 | 
			
		||||
  /// @return The rotated vector
 | 
			
		||||
  static Polar Rotate(const Polar& v, Angle a);
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
#include "Vector2.h"
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@
 | 
			
		||||
#include <float.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
#include "Matrix.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
void CopyQuat(const Quat& q1, Quat& q2) {
 | 
			
		||||
@ -98,28 +97,6 @@ Vector3 Quaternion::ToAngles(const Quaternion& q1) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Matrix2 LinearAlgebra::Quaternion::ToRotationMatrix() {
 | 
			
		||||
  Matrix2 r = Matrix2(3, 3);
 | 
			
		||||
 | 
			
		||||
  float x = this->x;
 | 
			
		||||
  float y = this->y;
 | 
			
		||||
  float z = this->z;
 | 
			
		||||
  float w = this->w;
 | 
			
		||||
 | 
			
		||||
  float* data = r.data;
 | 
			
		||||
  data[0 * 3 + 0] = 1 - 2 * (y * y + z * z);
 | 
			
		||||
  data[0 * 3 + 1] = 2 * (x * y - w * z);
 | 
			
		||||
  data[0 * 3 + 2] = 2 * (x * z + w * y);
 | 
			
		||||
  data[1 * 3 + 0] = 2 * (x * y + w * z);
 | 
			
		||||
  data[1 * 3 + 1] = 1 - 2 * (x * x + z * z);
 | 
			
		||||
  data[1 * 3 + 2] = 2 * (y * z - w * x);
 | 
			
		||||
  data[2 * 3 + 0] = 2 * (x * z - w * y);
 | 
			
		||||
  data[2 * 3 + 1] = 2 * (y * z + w * x);
 | 
			
		||||
  data[2 * 3 + 2] = 1 - 2 * (x * x + y * y);
 | 
			
		||||
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Quaternion Quaternion::operator*(const Quaternion& r2) const {
 | 
			
		||||
  return Quaternion(
 | 
			
		||||
      this->x * r2.w + this->y * r2.z - this->z * r2.y + this->w * r2.x,
 | 
			
		||||
@ -159,7 +136,7 @@ Vector3 Quaternion::operator*(const Vector3& p) const {
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Quaternion::operator==(const Quaternion& q) const {
 | 
			
		||||
bool Quaternion::operator==(const Quaternion& q) {
 | 
			
		||||
  return (this->x == q.x && this->y == q.y && this->z == q.z && this->w == q.w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -229,7 +206,7 @@ Quaternion Quaternion::FromToRotation(Vector3 fromDirection,
 | 
			
		||||
  Vector3 axis = Vector3::Cross(fromDirection, toDirection);
 | 
			
		||||
  axis = Vector3::Normalize(axis);
 | 
			
		||||
  AngleOf<float> angle = Vector3::SignedAngle(fromDirection, toDirection, axis);
 | 
			
		||||
  Quaternion rotation = Quaternion::AngleAxis(angle.InDegrees(), axis);
 | 
			
		||||
  Quaternion rotation = Quaternion::AngleAxis(angle.ToFloat(), axis);
 | 
			
		||||
  return rotation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,9 +7,12 @@
 | 
			
		||||
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// A quaternion (C-style)
 | 
			
		||||
/// A quaternion
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// This is a C-style implementation
 | 
			
		||||
typedef struct Quat {
 | 
			
		||||
@ -32,15 +35,11 @@ typedef struct Quat {
 | 
			
		||||
} Quat;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
class Matrix2;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// A quaternion
 | 
			
		||||
/// </summary>
 | 
			
		||||
struct Quaternion : Quat {
 | 
			
		||||
 public:
 | 
			
		||||
public:
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Create a new identity quaternion
 | 
			
		||||
  /// </summary>
 | 
			
		||||
@ -81,7 +80,7 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <returns>A unit quaternion</returns>
 | 
			
		||||
  /// This will preserve the orientation,
 | 
			
		||||
  /// but ensures that it is a unit quaternion.
 | 
			
		||||
  static Quaternion Normalize(const Quaternion& q);
 | 
			
		||||
  static Quaternion Normalize(const Quaternion &q);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Convert to euler angles
 | 
			
		||||
@ -89,16 +88,14 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <param name="q">The quaternion to convert</param>
 | 
			
		||||
  /// <returns>A vector containing euler angles</returns>
 | 
			
		||||
  /// The euler angles performed in the order: Z, X, Y
 | 
			
		||||
  static Vector3 ToAngles(const Quaternion& q);
 | 
			
		||||
 | 
			
		||||
  Matrix2 ToRotationMatrix();
 | 
			
		||||
  static Vector3 ToAngles(const Quaternion &q);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Rotate a vector using this quaterion
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="vector">The vector to rotate</param>
 | 
			
		||||
  /// <returns>The rotated vector</returns>
 | 
			
		||||
  Vector3 operator*(const Vector3& vector) const;
 | 
			
		||||
  Vector3 operator*(const Vector3 &vector) const;
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Multiply this quaternion with another quaternion
 | 
			
		||||
  /// </summary>
 | 
			
		||||
@ -106,7 +103,7 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <returns>The resulting rotation</returns>
 | 
			
		||||
  /// The result will be this quaternion rotated according to
 | 
			
		||||
  /// the give rotation.
 | 
			
		||||
  Quaternion operator*(const Quaternion& rotation) const;
 | 
			
		||||
  Quaternion operator*(const Quaternion &rotation) const;
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Check the equality of two quaternions
 | 
			
		||||
@ -117,7 +114,7 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// themselves. Two quaternions with the same rotational effect may have
 | 
			
		||||
  /// different components. Use Quaternion::Angle to check if the rotations are
 | 
			
		||||
  /// the same.
 | 
			
		||||
  bool operator==(const Quaternion& quaternion) const;
 | 
			
		||||
  bool operator==(const Quaternion &quaternion);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// The inverse of quaterion
 | 
			
		||||
@ -132,8 +129,8 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <param name="forward">The look direction</param>
 | 
			
		||||
  /// <param name="upwards">The up direction</param>
 | 
			
		||||
  /// <returns>The look rotation</returns>
 | 
			
		||||
  static Quaternion LookRotation(const Vector3& forward,
 | 
			
		||||
                                 const Vector3& upwards);
 | 
			
		||||
  static Quaternion LookRotation(const Vector3 &forward,
 | 
			
		||||
                                 const Vector3 &upwards);
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Creates a quaternion with the given forward direction with up =
 | 
			
		||||
  /// Vector3::up
 | 
			
		||||
@ -143,7 +140,7 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// For the rotation, Vector::up is used for the up direction.
 | 
			
		||||
  /// Note: if the forward direction == Vector3::up, the result is
 | 
			
		||||
  /// Quaternion::identity
 | 
			
		||||
  static Quaternion LookRotation(const Vector3& forward);
 | 
			
		||||
  static Quaternion LookRotation(const Vector3 &forward);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Calculat the rotation from on vector to another
 | 
			
		||||
@ -160,8 +157,7 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <param name="to">The destination rotation</param>
 | 
			
		||||
  /// <param name="maxDegreesDelta">The maximum amount of degrees to
 | 
			
		||||
  /// rotate</param> <returns>The possibly limited rotation</returns>
 | 
			
		||||
  static Quaternion RotateTowards(const Quaternion& from,
 | 
			
		||||
                                  const Quaternion& to,
 | 
			
		||||
  static Quaternion RotateTowards(const Quaternion &from, const Quaternion &to,
 | 
			
		||||
                                  float maxDegreesDelta);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
@ -170,13 +166,13 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <param name="angle">The angle</param>
 | 
			
		||||
  /// <param name="axis">The axis</param>
 | 
			
		||||
  /// <returns>The resulting quaternion</returns>
 | 
			
		||||
  static Quaternion AngleAxis(float angle, const Vector3& axis);
 | 
			
		||||
  static Quaternion AngleAxis(float angle, const Vector3 &axis);
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Convert this quaternion to angle/axis representation
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="angle">A pointer to the angle for the result</param>
 | 
			
		||||
  /// <param name="axis">A pointer to the axis for the result</param>
 | 
			
		||||
  void ToAngleAxis(float* angle, Vector3* axis);
 | 
			
		||||
  void ToAngleAxis(float *angle, Vector3 *axis);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Get the angle between two orientations
 | 
			
		||||
@ -194,9 +190,8 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <param name="factor">The factor between 0 and 1.</param>
 | 
			
		||||
  /// <returns>The resulting rotation</returns>
 | 
			
		||||
  /// A factor 0 returns rotation1, factor1 returns rotation2.
 | 
			
		||||
  static Quaternion Slerp(const Quaternion& rotation1,
 | 
			
		||||
                          const Quaternion& rotation2,
 | 
			
		||||
                          float factor);
 | 
			
		||||
  static Quaternion Slerp(const Quaternion &rotation1,
 | 
			
		||||
                          const Quaternion &rotation2, float factor);
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Unclamped sherical lerp between two rotations
 | 
			
		||||
  /// </summary>
 | 
			
		||||
@ -206,9 +201,8 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <returns>The resulting rotation</returns>
 | 
			
		||||
  /// A factor 0 returns rotation1, factor1 returns rotation2.
 | 
			
		||||
  /// Values outside the 0..1 range will result in extrapolated rotations
 | 
			
		||||
  static Quaternion SlerpUnclamped(const Quaternion& rotation1,
 | 
			
		||||
                                   const Quaternion& rotation2,
 | 
			
		||||
                                   float factor);
 | 
			
		||||
  static Quaternion SlerpUnclamped(const Quaternion &rotation1,
 | 
			
		||||
                                   const Quaternion &rotation2, float factor);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Create a rotation from euler angles
 | 
			
		||||
@ -266,10 +260,8 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <param name="swing">A pointer to the quaternion for the swing
 | 
			
		||||
  /// result</param> <param name="twist">A pointer to the quaternion for the
 | 
			
		||||
  /// twist result</param>
 | 
			
		||||
  static void GetSwingTwist(Vector3 axis,
 | 
			
		||||
                            Quaternion rotation,
 | 
			
		||||
                            Quaternion* swing,
 | 
			
		||||
                            Quaternion* twist);
 | 
			
		||||
  static void GetSwingTwist(Vector3 axis, Quaternion rotation,
 | 
			
		||||
                            Quaternion *swing, Quaternion *twist);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Calculate the dot product of two quaternions
 | 
			
		||||
@ -279,19 +271,20 @@ struct Quaternion : Quat {
 | 
			
		||||
  /// <returns></returns>
 | 
			
		||||
  static float Dot(Quaternion rotation1, Quaternion rotation2);
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
private:
 | 
			
		||||
  float GetLength() const;
 | 
			
		||||
  float GetLengthSquared() const;
 | 
			
		||||
  static float GetLengthSquared(const Quaternion& q);
 | 
			
		||||
  static float GetLengthSquared(const Quaternion &q);
 | 
			
		||||
 | 
			
		||||
  void ToAxisAngleRad(const Quaternion& q, Vector3* const axis, float* angle);
 | 
			
		||||
  void ToAxisAngleRad(const Quaternion &q, Vector3 *const axis, float *angle);
 | 
			
		||||
  static Quaternion FromEulerRad(Vector3 euler);
 | 
			
		||||
  static Quaternion FromEulerRadXYZ(Vector3 euler);
 | 
			
		||||
 | 
			
		||||
  Vector3 xyz() const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
} // namespace LinearAlgebra
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,21 +1,12 @@
 | 
			
		||||
\mainpage Linear Algebra
 | 
			
		||||
\mainpage Vector Algebra
 | 
			
		||||
 | 
			
		||||
Linear algebra library
 | 
			
		||||
Vector algebra library
 | 
			
		||||
 | 
			
		||||
Main components
 | 
			
		||||
---------------
 | 
			
		||||
Carthesian coordinate systems
 | 
			
		||||
* [Vector3](#Passer::LinearAlgebra::Vector3): A 3D carthesian vector
 | 
			
		||||
* [Vector2](#Passer::LinearAlgebra::Vector2): A 2D carthesian vector
 | 
			
		||||
* [Vector3](https://passervr.com/apis/VectorAlgebra/struct_vector3.html)
 | 
			
		||||
* [Quaternion](https://passervr.com/apis/VectorAlgebra/struct_quaternion.html)
 | 
			
		||||
 | 
			
		||||
Other coodinate systems
 | 
			
		||||
* [Polar](#Passer::LinearAlgebra::PolarOf): A 2D polar vector
 | 
			
		||||
* [Spherical](#Passer::LinearAlgebra::SphericalOf): A 3D spherical vector
 | 
			
		||||
* [Vector2](https://passervr.com/apis/VectorAlgebra/struct_vector2.html)
 | 
			
		||||
 | 
			
		||||
Rotations
 | 
			
		||||
* [Quaternion](#Passer::LinearAlgebra::Quaternion): A quaternion rotation
 | 
			
		||||
* [SwingTwist](#Passer::LinearAlgebra::SwingTwistOf): A swing/twist angular rotation
 | 
			
		||||
 | 
			
		||||
Basics
 | 
			
		||||
* [Angle](#Passer::LinearAlgebra::AngleOf): An angle
 | 
			
		||||
* [Direction](#Passer::LinearAlgebra::DirectionOf): A direction using angles
 | 
			
		||||
* [Polar](https://passervr.com/apis/VectorAlgebra/struct_polar.html)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										48
									
								
								LinearAlgebra/Range.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								LinearAlgebra/Range.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
#include "Range.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Range16::Range16() { this->range = 0; }
 | 
			
		||||
 | 
			
		||||
Range16::Range16(float f) {
 | 
			
		||||
  // clamp the float range to -1..1
 | 
			
		||||
  if (f < -1.0F)
 | 
			
		||||
    f = -1.0F;
 | 
			
		||||
  else if (f > 1.0F)
 | 
			
		||||
    f = 1.0F;
 | 
			
		||||
 | 
			
		||||
  // map -1..1 to 0..65535
 | 
			
		||||
  this->range = (unsigned short)((f + 1.0F) * 65535.0F);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Range16::Range16(short s) {
 | 
			
		||||
  // clamp the range to -32767..32767
 | 
			
		||||
  // This is needed because the representation can support +/-32768 (like 2s
 | 
			
		||||
  // complement)
 | 
			
		||||
  if (s < -32767)
 | 
			
		||||
    s = -32767;
 | 
			
		||||
  else if (s > 32767)
 | 
			
		||||
    s = 32767;
 | 
			
		||||
 | 
			
		||||
  this->range = (unsigned short)(s + 32767);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Range16 Range16::operator-(Range16 a) { this->range - a.range; };
 | 
			
		||||
Range16 Range16::operator+(Range16 a) { this->range + a.range; };
 | 
			
		||||
 | 
			
		||||
Range16 &Range16::operator-() { -this->range; }
 | 
			
		||||
 | 
			
		||||
bool Range16::operator==(Range16 a) { this->range == a.range; }
 | 
			
		||||
bool Range16::operator!=(Range16 a) { return (this->range != a.range); }
 | 
			
		||||
 | 
			
		||||
bool Range16::operator<(Range16 a) { return (this->range < a.range); }
 | 
			
		||||
bool Range16::operator>(Range16 a) { return (this->range > a.range); }
 | 
			
		||||
bool Range16::operator<=(Range16 a) { return (this->range <= a.range); }
 | 
			
		||||
bool Range16::operator>=(Range16 a) { return (this->range >= a.range); }
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
template <> RangeUsing<unsigned char>::RangeUsing(float f) {
 | 
			
		||||
  this->value = (unsigned char)((f + 1.0f) * 127.0F);
 | 
			
		||||
}
 | 
			
		||||
template <> RangeUsing<unsigned short>::RangeUsing(float f) {
 | 
			
		||||
  this->value = (unsigned short)((f + 1.0F) * 32767.0F);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								LinearAlgebra/Range.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								LinearAlgebra/Range.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
#ifndef RANGE_H
 | 
			
		||||
#define RANGE_H
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
/// @brief Signed range. May be renamed to SignedRange later
 | 
			
		||||
class Range16 {
 | 
			
		||||
public:
 | 
			
		||||
  Range16();
 | 
			
		||||
  Range16(float range); // range -1..1
 | 
			
		||||
  Range16(short range); // range -32768..32767
 | 
			
		||||
 | 
			
		||||
  inline Range16 operator-(Range16 a);
 | 
			
		||||
  inline Range16 operator+(Range16 a);
 | 
			
		||||
  inline virtual Range16 &operator-();
 | 
			
		||||
 | 
			
		||||
  inline bool operator==(Range16 a);
 | 
			
		||||
  inline bool operator!=(Range16 a);
 | 
			
		||||
 | 
			
		||||
  inline bool operator<(Range16 a);
 | 
			
		||||
  inline bool operator>(Range16 a);
 | 
			
		||||
  inline bool operator<=(Range16 a);
 | 
			
		||||
  inline bool operator>=(Range16 a);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
  // How do we make sure we have 16 bit range on every platform?
 | 
			
		||||
  // uint16_t range; // 16-bit range
 | 
			
		||||
  unsigned short range; // 16-bit range
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
template <typename T> class RangeUsing {
 | 
			
		||||
public:
 | 
			
		||||
  RangeUsing<T>(float range); // range -1..1
 | 
			
		||||
 | 
			
		||||
  inline RangeUsing<T> operator-(RangeUsing<T> a) { this->value - a.value; }
 | 
			
		||||
  inline RangeUsing<T> operator+(RangeUsing<T> a) { this->value + a.value; }
 | 
			
		||||
  inline RangeUsing<T> operator-() { this->value = -this.value; }
 | 
			
		||||
  inline T GetValue() { return value; }
 | 
			
		||||
 | 
			
		||||
  T value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace LinearAlgebra
 | 
			
		||||
} // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -5,60 +5,51 @@
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T>::SphericalOf() {
 | 
			
		||||
  this->distance = 0.0f;
 | 
			
		||||
  this->direction = DirectionOf<T>();
 | 
			
		||||
  this->horizontal = AngleOf<T>(0);
 | 
			
		||||
  this->vertical = AngleOf<T>(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// template <>
 | 
			
		||||
// SphericalOf<signed short>::SphericalOf() {
 | 
			
		||||
//   this->distance = 0.0f;
 | 
			
		||||
//   this->horizontal = AngleOf<signed short>(0);
 | 
			
		||||
//   this->vertical = AngleOf<signed short>(0);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T>::SphericalOf(float distance,
 | 
			
		||||
                            AngleOf<T> horizontal,
 | 
			
		||||
                            AngleOf<T> vertical) {
 | 
			
		||||
  if (distance < 0) {
 | 
			
		||||
    this->distance = -distance;
 | 
			
		||||
    this->direction = -DirectionOf<T>(horizontal, vertical);
 | 
			
		||||
  } else {
 | 
			
		||||
    this->distance = distance;
 | 
			
		||||
    this->direction = DirectionOf<T>(horizontal, vertical);
 | 
			
		||||
  }
 | 
			
		||||
  this->distance = distance;
 | 
			
		||||
  this->horizontal = horizontal;
 | 
			
		||||
  this->vertical = vertical;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T>::SphericalOf(float distance, DirectionOf<T> direction) {
 | 
			
		||||
  if (distance < 0) {
 | 
			
		||||
    this->distance = -distance;
 | 
			
		||||
    this->direction = -direction;
 | 
			
		||||
  } else {
 | 
			
		||||
    this->distance = distance;
 | 
			
		||||
    this->direction = direction;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
// template <>
 | 
			
		||||
// SphericalOf<float>::SphericalOf(float distance,
 | 
			
		||||
//                                 AngleOf<float> horizontal,
 | 
			
		||||
//                                 AngleOf<float> vertical) {
 | 
			
		||||
//   this->distance = distance;
 | 
			
		||||
//   this->horizontal = horizontal;
 | 
			
		||||
//   this->vertical = vertical;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::Degrees(float distance,
 | 
			
		||||
                                       float horizontal,
 | 
			
		||||
                                       float vertical) {
 | 
			
		||||
  AngleOf<T> horizontalAngle = AngleOf<T>::Degrees(horizontal);
 | 
			
		||||
  AngleOf<T> verticalAngle = AngleOf<T>::Degrees(vertical);
 | 
			
		||||
  SphericalOf<T> r = SphericalOf<T>(distance, horizontalAngle, verticalAngle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::Radians(float distance,
 | 
			
		||||
                                       float horizontal,
 | 
			
		||||
                                       float vertical) {
 | 
			
		||||
  return SphericalOf<T>(distance, AngleOf<T>::Radians(horizontal),
 | 
			
		||||
                        AngleOf<T>::Radians(vertical));
 | 
			
		||||
}
 | 
			
		||||
// template <>
 | 
			
		||||
// SphericalOf<signed short>::SphericalOf(float distance,
 | 
			
		||||
//                                        AngleOf<signed short> horizontal,
 | 
			
		||||
//                                        AngleOf<signed short> vertical) {
 | 
			
		||||
//   this->distance = distance;
 | 
			
		||||
//   this->horizontal = horizontal;
 | 
			
		||||
//   this->vertical = vertical;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::FromPolar(PolarOf<T> polar) {
 | 
			
		||||
  AngleOf<T> horizontal = polar.angle;
 | 
			
		||||
  AngleOf<T> vertical = AngleOf<T>();
 | 
			
		||||
  AngleOf<T> vertical = AngleOf<T>(0);
 | 
			
		||||
  SphericalOf<T> r = SphericalOf(polar.distance, horizontal, vertical);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
@ -67,32 +58,22 @@ template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::FromVector3(Vector3 v) {
 | 
			
		||||
  float distance = v.magnitude();
 | 
			
		||||
  if (distance == 0.0f) {
 | 
			
		||||
    return SphericalOf(distance, AngleOf<T>(), AngleOf<T>());
 | 
			
		||||
    return SphericalOf(distance, 0, 0);
 | 
			
		||||
  } else {
 | 
			
		||||
    AngleOf<T> verticalAngle =
 | 
			
		||||
        AngleOf<T>::Radians((pi / 2 - acosf(v.Up() / distance)));
 | 
			
		||||
    AngleOf<T> horizontalAngle =
 | 
			
		||||
        AngleOf<T>::Radians(atan2f(v.Right(), v.Forward()));
 | 
			
		||||
    float verticalAngle =
 | 
			
		||||
        (90.0f - acosf(v.Up() / distance) * Passer::LinearAlgebra::Rad2Deg);
 | 
			
		||||
    float horizontalAngle =
 | 
			
		||||
        atan2f(v.Right(), v.Forward()) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
    return SphericalOf(distance, horizontalAngle, verticalAngle);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Converts spherical coordinates to a 3D vector.
 | 
			
		||||
 *
 | 
			
		||||
 * This function converts the spherical coordinates represented by the
 | 
			
		||||
 * SphericalOf object to a 3D vector (Vector3). The conversion is based
 | 
			
		||||
 * on the distance and direction (vertical and horizontal angles) of the
 | 
			
		||||
 * spherical coordinates.
 | 
			
		||||
 *
 | 
			
		||||
 * @tparam T The type of the distance and direction values.
 | 
			
		||||
 * @return Vector3 The 3D vector representation of the spherical coordinates.
 | 
			
		||||
 */
 | 
			
		||||
template <typename T>
 | 
			
		||||
Vector3 SphericalOf<T>::ToVector3() const {
 | 
			
		||||
  float verticalRad = (pi / 2) - this->direction.vertical.InRadians();
 | 
			
		||||
  float horizontalRad = this->direction.horizontal.InRadians();
 | 
			
		||||
 | 
			
		||||
  float verticalRad =
 | 
			
		||||
      (90.0f - this->vertical.ToFloat()) * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
  float horizontalRad =
 | 
			
		||||
      this->horizontal.ToFloat() * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
  float cosVertical = cosf(verticalRad);
 | 
			
		||||
  float sinVertical = sinf(verticalRad);
 | 
			
		||||
  float cosHorizontal = cosf(horizontalRad);
 | 
			
		||||
@ -108,37 +89,29 @@ Vector3 SphericalOf<T>::ToVector3() const {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::zero =
 | 
			
		||||
    SphericalOf<T>(0.0f, AngleOf<T>(), AngleOf<T>());
 | 
			
		||||
    SphericalOf<T>(0.0f, AngleOf<T>(0), AngleOf<T>(0));
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::forward =
 | 
			
		||||
    SphericalOf<T>(1.0f, AngleOf<T>(), AngleOf<T>());
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::forward = SphericalOf<T>(1.0f, 0.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::back =
 | 
			
		||||
    SphericalOf<T>(1.0f, AngleOf<T>::Degrees(180), AngleOf<T>());
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::back = SphericalOf<T>(1.0f, 180.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::right =
 | 
			
		||||
    SphericalOf<T>(1.0f, AngleOf<T>::Degrees(90), AngleOf<T>());
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::right = SphericalOf<T>(1.0f, 90.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::left =
 | 
			
		||||
    SphericalOf<T>(1.0f, AngleOf<T>::Degrees(-90), AngleOf<T>());
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::left = SphericalOf<T>(1.0f, -90.0f, 0.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::up =
 | 
			
		||||
    SphericalOf<T>(1.0f, AngleOf<T>(), AngleOf<T>::Degrees(90));
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::up = SphericalOf<T>(1.0f, 0.0f, 90.0f);
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::down =
 | 
			
		||||
    SphericalOf<T>(1.0f, AngleOf<T>(), AngleOf<T>::Degrees(-90));
 | 
			
		||||
const SphericalOf<T> SphericalOf<T>::down = SphericalOf<T>(1.0f, 0.0f, -90.0f);
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::WithDistance(float distance) {
 | 
			
		||||
  SphericalOf<T> v = SphericalOf<T>(distance, this->direction);
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
template <>
 | 
			
		||||
const SphericalOf<signed short> SphericalOf<signed short>::zero =
 | 
			
		||||
    SphericalOf(0.0f, AngleOf<signed short>(0), AngleOf<signed short>(0));
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::operator-() const {
 | 
			
		||||
  SphericalOf<T> v = SphericalOf<T>(
 | 
			
		||||
      this->distance, this->direction.horizontal + AngleOf<T>::Degrees(180),
 | 
			
		||||
      this->direction.vertical + AngleOf<T>::Degrees(180));
 | 
			
		||||
  SphericalOf<T> v =
 | 
			
		||||
      SphericalOf<T>(this->distance, this->horizontal.ToFloat() + 180.0f,
 | 
			
		||||
                     this->vertical.ToFloat() + 180.0f);
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -235,17 +208,6 @@ SphericalOf<T> SphericalOf<T>::operator/=(float f) {
 | 
			
		||||
 | 
			
		||||
const float epsilon = 1E-05f;
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
float SphericalOf<T>::DistanceBetween(const SphericalOf<T>& v1,
 | 
			
		||||
                                      const SphericalOf<T>& v2) {
 | 
			
		||||
  // SphericalOf<T> difference = v1 - v2;
 | 
			
		||||
  // return difference.distance;
 | 
			
		||||
  Vector3 vec1 = v1.ToVector3();
 | 
			
		||||
  Vector3 vec2 = v2.ToVector3();
 | 
			
		||||
  float distance = Vector3::Distance(vec1, vec2);
 | 
			
		||||
  return distance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> SphericalOf<T>::AngleBetween(const SphericalOf& v1,
 | 
			
		||||
                                        const SphericalOf& v2) {
 | 
			
		||||
@ -262,46 +224,255 @@ AngleOf<T> SphericalOf<T>::AngleBetween(const SphericalOf& v1,
 | 
			
		||||
 | 
			
		||||
  // float cdot = Float::Clamp(fraction, -1.0, 1.0);
 | 
			
		||||
  // float r = ((float)acos(cdot)) * Rad2Deg;
 | 
			
		||||
  AngleSingle r = Vector3::Angle(v1_3, v2_3);
 | 
			
		||||
  return AngleOf<T>::Degrees(r.InDegrees());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> SphericalOf<T>::SignedAngleBetween(const SphericalOf<T>& v1,
 | 
			
		||||
                                              const SphericalOf<T>& v2,
 | 
			
		||||
                                              const SphericalOf<T>& axis) {
 | 
			
		||||
  Vector3 v1_vector = v1.ToVector3();
 | 
			
		||||
  Vector3 v2_vector = v2.ToVector3();
 | 
			
		||||
  Vector3 axis_vector = axis.ToVector3();
 | 
			
		||||
  AngleSingle r = Vector3::SignedAngle(v1_vector, v2_vector, axis_vector);
 | 
			
		||||
  return AngleOf<T>::Degrees(r.InDegrees());
 | 
			
		||||
  Angle r = Vector3::Angle(v1_3, v2_3);
 | 
			
		||||
  return AngleOf<T>(r.ToFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::Rotate(const SphericalOf<T>& v,
 | 
			
		||||
                                      AngleOf<T> horizontalAngle,
 | 
			
		||||
                                      AngleOf<T> verticalAngle) {
 | 
			
		||||
  SphericalOf<T> r =
 | 
			
		||||
      SphericalOf(v.distance, v.direction.horizontal + horizontalAngle,
 | 
			
		||||
                  v.direction.vertical + verticalAngle);
 | 
			
		||||
  SphericalOf<T> r = SphericalOf(v.distance, v.horizontal + horizontalAngle,
 | 
			
		||||
                                 v.vertical + verticalAngle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::RotateHorizontal(const SphericalOf<T>& v,
 | 
			
		||||
                                                AngleOf<T> a) {
 | 
			
		||||
  SphericalOf<T> r =
 | 
			
		||||
      SphericalOf(v.distance, v.direction.horizontal + a, v.direction.vertical);
 | 
			
		||||
  SphericalOf<T> r = SphericalOf(v.distance, v.horizontal + a, v.vertical);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SphericalOf<T>::RotateVertical(const SphericalOf<T>& v,
 | 
			
		||||
                                              AngleOf<T> a) {
 | 
			
		||||
  SphericalOf<T> r =
 | 
			
		||||
      SphericalOf(v.distance, v.direction.horizontal, v.direction.vertical + a);
 | 
			
		||||
  SphericalOf<T> r = SphericalOf(v.distance, v.horizontal, v.vertical + a);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template class SphericalOf<float>;
 | 
			
		||||
template class SphericalOf<signed short>;
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
//---------------------------------------
 | 
			
		||||
/*
 | 
			
		||||
Spherical::Spherical() {
 | 
			
		||||
  this->distance = 0.0f;
 | 
			
		||||
  this->horizontalAngle = 0.0f;
 | 
			
		||||
  this->verticalAngle = 0.0f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Spherical::Spherical(Polar polar) {
 | 
			
		||||
//   this->distance = polar.distance;
 | 
			
		||||
//   this->horizontalAngle = polar.angle;
 | 
			
		||||
//   this->verticalAngle = 0.0f;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
Spherical::Spherical(float distance,
 | 
			
		||||
                     Angle horizontalAngle,
 | 
			
		||||
                     Angle verticalAngle) {
 | 
			
		||||
  if (distance < 0) {
 | 
			
		||||
    this->distance = -distance;
 | 
			
		||||
    this->horizontalAngle =
 | 
			
		||||
        Angle::Normalize(horizontalAngle.ToFloat() - 180.0f);
 | 
			
		||||
    this->verticalAngle = verticalAngle;
 | 
			
		||||
  } else {
 | 
			
		||||
    this->distance = distance;
 | 
			
		||||
    this->horizontalAngle = Angle::Normalize(horizontalAngle);
 | 
			
		||||
    this->verticalAngle = Angle::Normalize(verticalAngle);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical::Spherical(Vector3 v) {
 | 
			
		||||
  this->distance = v.magnitude();
 | 
			
		||||
  if (distance == 0.0f) {
 | 
			
		||||
    this->verticalAngle = 0.0f;
 | 
			
		||||
    this->horizontalAngle = 0.0f;
 | 
			
		||||
  } else {
 | 
			
		||||
    this->verticalAngle = (90.0f - acosf(v.Up() / this->distance) *
 | 
			
		||||
                                       Passer::LinearAlgebra::Rad2Deg);
 | 
			
		||||
    this->horizontalAngle =
 | 
			
		||||
        atan2f(v.Right(), v.Forward()) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Spherical Spherical::zero = Spherical(0.0f, 0.0f, 0.0f);
 | 
			
		||||
const Spherical Spherical::forward = Spherical(1.0f, 0.0f, 0.0f);
 | 
			
		||||
const Spherical Spherical::back = Spherical(1.0f, 180.0f, 0.0f);
 | 
			
		||||
const Spherical Spherical::right = Spherical(1.0f, 90.0f, 0.0f);
 | 
			
		||||
const Spherical Spherical::left = Spherical(1.0f, -90.0f, 0.0f);
 | 
			
		||||
const Spherical Spherical::up = Spherical(1.0f, 0.0f, 90.0f);
 | 
			
		||||
const Spherical Spherical::down = Spherical(1.0f, 0.0f, -90.0f);
 | 
			
		||||
 | 
			
		||||
bool Spherical::operator==(const Spherical& v) const {
 | 
			
		||||
  return (this->distance == v.distance &&
 | 
			
		||||
          this->horizontalAngle.ToFloat() == v.horizontalAngle.ToFloat() &&
 | 
			
		||||
          this->verticalAngle.ToFloat() == v.verticalAngle.ToFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical Spherical::Normalize(const Spherical& v) {
 | 
			
		||||
  Spherical r = Spherical(1, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical Spherical::normalized() const {
 | 
			
		||||
  Spherical r = Spherical(1, this->horizontalAngle, this->verticalAngle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical Spherical::operator-() const {
 | 
			
		||||
  Spherical v =
 | 
			
		||||
      Spherical(this->distance, this->horizontalAngle.ToFloat() + 180.0f,
 | 
			
		||||
                this->verticalAngle.ToFloat() + 180.0f);
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical Spherical::operator-(const Spherical& s2) const {
 | 
			
		||||
  // let's do it the easy way...
 | 
			
		||||
  Vector3 v1 = Vector3(*this);
 | 
			
		||||
  Vector3 v2 = Vector3(s2);
 | 
			
		||||
  Vector3 v = v1 - v2;
 | 
			
		||||
  Spherical r = Spherical(v);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical Spherical::operator-=(const Spherical& v) {
 | 
			
		||||
  *this = *this - v;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical Spherical::operator+(const Spherical& s2) const {
 | 
			
		||||
  // let's do it the easy way...
 | 
			
		||||
  Vector3 v1 = Vector3(*this);
 | 
			
		||||
  Vector3 v2 = Vector3(s2);
 | 
			
		||||
  Vector3 v = v1 + v2;
 | 
			
		||||
  Spherical r = Spherical(v);
 | 
			
		||||
  return r;
 | 
			
		||||
 | 
			
		||||
  // This is the hard way...
 | 
			
		||||
  // if (v2.distance <= 0)
 | 
			
		||||
  //   return Spherical(this->distance, this->horizontalAngle,
 | 
			
		||||
  //                    this->verticalAngle);
 | 
			
		||||
  // if (this->distance <= 0)
 | 
			
		||||
  //   return v2;
 | 
			
		||||
 | 
			
		||||
  // float deltaHorizontalAngle =
 | 
			
		||||
  //     (float)Angle::Normalize(v2.horizontalAngle - this->horizontalAngle);
 | 
			
		||||
  // float horizontalRotation = deltaHorizontalAngle < 0
 | 
			
		||||
  //                                ? 180 + deltaHorizontalAngle
 | 
			
		||||
  //                                : 180 - deltaHorizontalAngle;
 | 
			
		||||
  // float deltaVerticalAngle =
 | 
			
		||||
  //     Angle::Normalize(v2.verticalAngle - this->verticalAngle);
 | 
			
		||||
  // float verticalRotation = deltaVerticalAngle < 0 ? 180 + deltaVerticalAngle
 | 
			
		||||
  //                                                 : 180 - deltaVerticalAngle;
 | 
			
		||||
 | 
			
		||||
  // if (horizontalRotation == 180 && verticalRotation == 180)
 | 
			
		||||
  //   // angle is too small, take this angle and add the distances
 | 
			
		||||
  //   return Spherical(this->distance + v2.distance, this->horizontalAngle,
 | 
			
		||||
  //                    this->verticalAngle);
 | 
			
		||||
 | 
			
		||||
  // Angle rotation = AngleBetween(*this, v2);
 | 
			
		||||
  // float newDistance =
 | 
			
		||||
  //     Angle::CosineRuleSide(v2.distance, this->distance, rotation);
 | 
			
		||||
  // float angle =
 | 
			
		||||
  //     Angle::CosineRuleAngle(newDistance, this->distance, v2.distance);
 | 
			
		||||
 | 
			
		||||
  // // Now we have to project the angle to the horizontal and vertical
 | 
			
		||||
planes...
 | 
			
		||||
  // // The axis for the angle is the cross product of the two spherical vectors
 | 
			
		||||
  // // (which function we do not have either...)
 | 
			
		||||
  // float horizontalAngle = 0;
 | 
			
		||||
  // float verticalAngle = 0;
 | 
			
		||||
 | 
			
		||||
  // float newHorizontalAngle =
 | 
			
		||||
  //     deltaHorizontalAngle < 0
 | 
			
		||||
  //         ? Angle::Normalize(this->horizontalAngle - horizontalAngle)
 | 
			
		||||
  //         : Angle::Normalize(this->horizontalAngle + horizontalAngle);
 | 
			
		||||
  // float newVerticalAngle =
 | 
			
		||||
  //     deltaVerticalAngle < 0
 | 
			
		||||
  //         ? Angle::Normalize(this->verticalAngle - verticalAngle)
 | 
			
		||||
  //         : Angle::Normalize(this->verticalAngle + verticalAngle);
 | 
			
		||||
 | 
			
		||||
  // Spherical v = Spherical(newDistance, newHorizontalAngle, newVerticalAngle);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
Spherical Spherical::operator+=(const Spherical& v) {
 | 
			
		||||
  *this = *this + v;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator*(const Spherical &v, float f) {
 | 
			
		||||
//   return Spherical(v.distance * f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator*(float f, const Spherical &v) {
 | 
			
		||||
//   return Spherical(v.distance * f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
Spherical Spherical::operator*=(float f) {
 | 
			
		||||
  this->distance *= f;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator/(const Spherical &v, float f) {
 | 
			
		||||
//   return Spherical(v.distance / f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator/(float f, const Spherical &v) {
 | 
			
		||||
//   return Spherical(v.distance / f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
Spherical Spherical::operator/=(float f) {
 | 
			
		||||
  this->distance /= f;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// float Spherical::GetSwing() {
 | 
			
		||||
//   // Not sure if this is correct
 | 
			
		||||
//   return sqrtf(horizontalAngle * horizontalAngle +
 | 
			
		||||
//                verticalAngle * verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// float Spherical::Distance(const Spherical &s1, const Spherical &s2) {
 | 
			
		||||
//   float d = 0;
 | 
			
		||||
//   return d;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
#include "AngleUsing.h"
 | 
			
		||||
#include "FloatSingle.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
const float epsilon = 1E-05f;
 | 
			
		||||
const float Rad2Deg = 57.29578F;
 | 
			
		||||
 | 
			
		||||
Angle Spherical::AngleBetween(const Spherical& v1, const Spherical& v2) {
 | 
			
		||||
  // float denominator = sqrtf(v1_3.sqrMagnitude() * v2_3.sqrMagnitude());
 | 
			
		||||
  float denominator =
 | 
			
		||||
      v1.distance * v2.distance;  // sqrtf(v1.distance * v1.distance *
 | 
			
		||||
                                  // v2.distance * v2.distance);
 | 
			
		||||
  if (denominator < epsilon)
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
 | 
			
		||||
  Vector3 v1_3 = Vector3(v1);
 | 
			
		||||
  Vector3 v2_3 = Vector3(v2);
 | 
			
		||||
  float dot = Vector3::Dot(v1_3, v2_3);
 | 
			
		||||
  float fraction = dot / denominator;
 | 
			
		||||
  if (isnan(fraction))
 | 
			
		||||
    return fraction;  // short cut to returning NaN universally
 | 
			
		||||
 | 
			
		||||
  float cdot = Float::Clamp(fraction, -1.0, 1.0);
 | 
			
		||||
  float r = ((float)acos(cdot)) * Rad2Deg;
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical Spherical::Rotate(const Spherical& v,
 | 
			
		||||
                            Angle horizontalAngle,
 | 
			
		||||
                            Angle verticalAngle) {
 | 
			
		||||
  Spherical r = Spherical(
 | 
			
		||||
      v.distance, v.horizontalAngle.ToFloat() + horizontalAngle.ToFloat(),
 | 
			
		||||
      v.verticalAngle.ToFloat() + verticalAngle.ToFloat());
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical Spherical::RotateHorizontal(const Spherical& v, Angle a) {
 | 
			
		||||
  Spherical r = Spherical(v.distance, v.horizontalAngle.ToFloat() + a.ToFloat(),
 | 
			
		||||
                          v.verticalAngle.ToFloat());
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical Spherical::RotateVertical(const Spherical& v, Angle a) {
 | 
			
		||||
  Spherical r = Spherical(v.distance, v.horizontalAngle.ToFloat(),
 | 
			
		||||
                          v.verticalAngle.ToFloat() + a.ToFloat());
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -5,63 +5,35 @@
 | 
			
		||||
#ifndef SPHERICAL_H
 | 
			
		||||
#define SPHERICAL_H
 | 
			
		||||
 | 
			
		||||
#include "Direction.h"
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
// #include "Polar.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
struct Vector3;
 | 
			
		||||
template <typename T>
 | 
			
		||||
class PolarOf;
 | 
			
		||||
 | 
			
		||||
/// @brief A spherical vector using angles in various representations
 | 
			
		||||
/// @tparam T The implementation type used for the representations of the agles
 | 
			
		||||
template <typename T>
 | 
			
		||||
class SphericalOf {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief The distance in meters
 | 
			
		||||
  /// @remark The distance should never be negative
 | 
			
		||||
  float distance;
 | 
			
		||||
  /// @brief The direction of the vector
 | 
			
		||||
  DirectionOf<T> direction;
 | 
			
		||||
  /// @brief The angle in the horizontal plane in degrees, clockwise rotation
 | 
			
		||||
  /// @details The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  AngleOf<T> horizontal;
 | 
			
		||||
  /// @brief The angle in the vertical plane in degrees. Positive is upward.
 | 
			
		||||
  /// @details The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  AngleOf<T> vertical;
 | 
			
		||||
 | 
			
		||||
  SphericalOf();
 | 
			
		||||
  SphericalOf(float distance, AngleOf<T> horizontal, AngleOf<T> vertical);
 | 
			
		||||
  SphericalOf(float distance, DirectionOf<T> direction);
 | 
			
		||||
  SphericalOf<T>();
 | 
			
		||||
  SphericalOf<T>(float distance, AngleOf<T> horizontal, AngleOf<T> vertical);
 | 
			
		||||
 | 
			
		||||
  /// @brief Create spherical vector without using AngleOf type. All given
 | 
			
		||||
  /// angles are in degrees
 | 
			
		||||
  /// @param distance The distance in meters
 | 
			
		||||
  /// @param horizontal The horizontal angle in degrees
 | 
			
		||||
  /// @param vertical The vertical angle in degrees
 | 
			
		||||
  /// @return The spherical vector
 | 
			
		||||
  static SphericalOf<T> Degrees(float distance,
 | 
			
		||||
                                float horizontal,
 | 
			
		||||
                                float vertical);
 | 
			
		||||
  /// @brief Short-hand Deg alias for the Degrees function
 | 
			
		||||
  constexpr static auto Deg = Degrees;
 | 
			
		||||
  /// @brief Create sperical vector without using the AngleOf type. All given
 | 
			
		||||
  /// angles are in radians
 | 
			
		||||
  /// @param distance The distance in meters
 | 
			
		||||
  /// @param horizontal The horizontal angle in radians
 | 
			
		||||
  /// @param vertical The vertical angle in radians
 | 
			
		||||
  /// @return The spherical vectpr
 | 
			
		||||
  static SphericalOf<T> Radians(float distance,
 | 
			
		||||
                                float horizontal,
 | 
			
		||||
                                float vertical);
 | 
			
		||||
  // Short-hand Rad alias for the Radians function
 | 
			
		||||
  constexpr static auto Rad = Radians;
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a Spherical coordinate from a Polar coordinate
 | 
			
		||||
  /// @param v The polar coordinate
 | 
			
		||||
  /// @return The spherical coordinate with the vertical angle set to zero.
 | 
			
		||||
  static SphericalOf<T> FromPolar(PolarOf<T> v);
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a Spherical coordinate from a Vector3 coordinate
 | 
			
		||||
  /// @param v The vector coordinate
 | 
			
		||||
  /// @return The spherical coordinate
 | 
			
		||||
  static SphericalOf<T> FromVector3(Vector3 v);
 | 
			
		||||
  /// @brief Convert the spherical coordinate to a Vector3 coordinate
 | 
			
		||||
  /// @return The vector coordinate
 | 
			
		||||
  Vector3 ToVector3() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief A spherical vector with zero degree angles and distance
 | 
			
		||||
@ -79,11 +51,6 @@ class SphericalOf {
 | 
			
		||||
  /// @brief A normalized down-oriented vector
 | 
			
		||||
  const static SphericalOf<T> down;
 | 
			
		||||
 | 
			
		||||
  /// @brief Update the distance component of the spherical coordinate
 | 
			
		||||
  /// @param distance The new distance
 | 
			
		||||
  /// @return The updated coordinate
 | 
			
		||||
  SphericalOf<T> WithDistance(float distance);
 | 
			
		||||
 | 
			
		||||
  /// @brief Negate the vector
 | 
			
		||||
  /// @return The negated vector
 | 
			
		||||
  /// This will rotate the vector by 180 degrees horizontally and
 | 
			
		||||
@ -107,10 +74,11 @@ class SphericalOf {
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend SphericalOf<T> operator*(const SphericalOf<T>& v, float f) {
 | 
			
		||||
    return SphericalOf<T>(v.distance * f, v.direction);
 | 
			
		||||
    return SphericalOf<T>(v.distance * f, v.horizontal, v.vertical);
 | 
			
		||||
  }
 | 
			
		||||
  friend SphericalOf<T> operator*(float f, const SphericalOf<T>& v) {
 | 
			
		||||
    return SphericalOf<T>(f * v.distance, v.direction);
 | 
			
		||||
    return SphericalOf<T>(v.distance * f, v.horizontal,
 | 
			
		||||
                          v.vertical);  // not correct, should be f * v.distance
 | 
			
		||||
  }
 | 
			
		||||
  SphericalOf<T> operator*=(float f);
 | 
			
		||||
  /// @brief Scale the vector uniformly down
 | 
			
		||||
@ -119,73 +87,174 @@ class SphericalOf {
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend SphericalOf<T> operator/(const SphericalOf<T>& v, float f) {
 | 
			
		||||
    return SphericalOf<T>(v.distance / f, v.direction);
 | 
			
		||||
    return SphericalOf<T>(v.distance / f, v.horizontal, v.vertical);
 | 
			
		||||
  }
 | 
			
		||||
  friend SphericalOf<T> operator/(float f, const SphericalOf<T>& v) {
 | 
			
		||||
    return SphericalOf<T>(f / v.distance, v.direction);
 | 
			
		||||
    return SphericalOf<T>(v.distance / f, v.horizontal,
 | 
			
		||||
                          v.vertical);  // not correct, should be f / v.distance
 | 
			
		||||
  }
 | 
			
		||||
  SphericalOf<T> operator/=(float f);
 | 
			
		||||
 | 
			
		||||
  /// @brief Calculate the distance between two spherical coordinates
 | 
			
		||||
  /// @param v1 The first coordinate
 | 
			
		||||
  /// @param v2 The second coordinate
 | 
			
		||||
  /// @return The distance between the coordinates in meters
 | 
			
		||||
  static float DistanceBetween(const SphericalOf<T>& v1,
 | 
			
		||||
                               const SphericalOf<T>& v2);
 | 
			
		||||
  /// @brief Calculate the unsigned angle between two spherical vectors
 | 
			
		||||
  /// @param v1 The first vector
 | 
			
		||||
  /// @param v2 The second vector
 | 
			
		||||
  /// @return The unsigned angle between the vectors
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// The distance between two vectors
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="v1">The first vector</param>
 | 
			
		||||
  /// <param name="v2">The second vector</param>
 | 
			
		||||
  /// <returns>The distance between the two vectors</returns>
 | 
			
		||||
  // static float Distance(const Spherical &s1, const Spherical &s2);
 | 
			
		||||
 | 
			
		||||
  static AngleOf<T> AngleBetween(const SphericalOf<T>& v1,
 | 
			
		||||
                                 const SphericalOf<T>& v2);
 | 
			
		||||
  /// @brief Calculate the signed angle between two spherical vectors
 | 
			
		||||
  /// @param v1 The first vector
 | 
			
		||||
  /// @param v2 The second vector
 | 
			
		||||
  /// @param axis The axis are which the angle is calculated
 | 
			
		||||
  /// @return The signed angle between the vectors
 | 
			
		||||
  static AngleOf<T> SignedAngleBetween(const SphericalOf<T>& v1,
 | 
			
		||||
                                       const SphericalOf<T>& v2,
 | 
			
		||||
                                       const SphericalOf<T>& axis);
 | 
			
		||||
 | 
			
		||||
  /// @brief Rotate a spherical vector
 | 
			
		||||
  /// @param v The vector to rotate
 | 
			
		||||
  /// @param horizontalAngle The horizontal rotation angle in local space
 | 
			
		||||
  /// @param verticalAngle The vertical rotation angle in local space
 | 
			
		||||
  /// @return The rotated vector
 | 
			
		||||
  static SphericalOf<T> Rotate(const SphericalOf& v,
 | 
			
		||||
                               AngleOf<T> horizontalAngle,
 | 
			
		||||
                               AngleOf<T> verticalAngle);
 | 
			
		||||
  /// @brief Rotate a spherical vector horizontally
 | 
			
		||||
  /// @param v The vector to rotate
 | 
			
		||||
  /// @param angle The horizontal rotation angle in local space
 | 
			
		||||
  /// @return The rotated vector
 | 
			
		||||
  static SphericalOf<T> RotateHorizontal(const SphericalOf<T>& v,
 | 
			
		||||
                                         AngleOf<T> angle);
 | 
			
		||||
  /// @brief Rotate a spherical vector vertically
 | 
			
		||||
  /// @param v The vector to rotate
 | 
			
		||||
  /// @param angle The vertical rotation angle in local space
 | 
			
		||||
  /// @return The rotated vector
 | 
			
		||||
  static SphericalOf<T> RotateVertical(const SphericalOf<T>& v,
 | 
			
		||||
                                       AngleOf<T> angle);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// @brief Shorthand notation for a spherical vector using single precision
 | 
			
		||||
/// floats for the angles This is the fastest implementation on devices with
 | 
			
		||||
/// floating point harware
 | 
			
		||||
using SphericalSingle = SphericalOf<float>;
 | 
			
		||||
/// @brief Shorthand notation for a spherical vector using signed 16-bit words
 | 
			
		||||
/// for the angles
 | 
			
		||||
/// @note This is the fastest implementation on devices without floating point
 | 
			
		||||
/// hardware
 | 
			
		||||
using Spherical16 = SphericalOf<signed short>;
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO)
 | 
			
		||||
using Spherical = Spherical16;
 | 
			
		||||
#else
 | 
			
		||||
using Spherical = SphericalSingle;
 | 
			
		||||
#endif
 | 
			
		||||
/*
 | 
			
		||||
/// @brief A spherical vector
 | 
			
		||||
/// @details This is a vector in 3D space using a spherical coordinate system.
 | 
			
		||||
/// It consists of a distance and the polar and elevation angles from a
 | 
			
		||||
/// reference direction. The reference direction is typically thought of
 | 
			
		||||
/// as a forward direction.
 | 
			
		||||
struct Spherical {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief The distance in meters
 | 
			
		||||
  /// @remark The distance should never be negative
 | 
			
		||||
  float distance;
 | 
			
		||||
  /// @brief The angle in the horizontal plane in degrees, clockwise rotation
 | 
			
		||||
  /// @details The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  Angle horizontalAngle;
 | 
			
		||||
  /// @brief The angle in the vertical plane in degrees. Positive is upward.
 | 
			
		||||
  /// @details The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  Angle verticalAngle;
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a new spherical vector with zero degrees and distance
 | 
			
		||||
  Spherical();
 | 
			
		||||
  /// @brief Create a new spherical vector
 | 
			
		||||
  /// @param distance The distance in meters
 | 
			
		||||
  /// @param horizontalAngle The angle in the horizontal plane in degrees,
 | 
			
		||||
  /// clockwise rotation
 | 
			
		||||
  /// @param verticalAngle The angle in the vertical plan in degrees,
 | 
			
		||||
  /// zero is forward, positive is upward
 | 
			
		||||
  Spherical(float distance, Angle horizontalAngle, Angle verticalAngle);
 | 
			
		||||
  /// @brief Convert polar coordinates to spherical coordinates
 | 
			
		||||
  /// @param polar The polar coordinate
 | 
			
		||||
  // Spherical(Polar polar);
 | 
			
		||||
  /// @brief Convert 3D carthesian coordinates to spherical coordinates
 | 
			
		||||
  /// @param v Vector in 3D carthesian coordinates;
 | 
			
		||||
  Spherical(Vector3 v);
 | 
			
		||||
 | 
			
		||||
  /// @brief A spherical vector with zero degree angles and distance
 | 
			
		||||
  const static Spherical zero;
 | 
			
		||||
  /// @brief A normalized forward-oriented vector
 | 
			
		||||
  const static Spherical forward;
 | 
			
		||||
  /// @brief A normalized back-oriented vector
 | 
			
		||||
  const static Spherical back;
 | 
			
		||||
  /// @brief A normalized right-oriented vector
 | 
			
		||||
  const static Spherical right;
 | 
			
		||||
  /// @brief A normalized left-oriented vector
 | 
			
		||||
  const static Spherical left;
 | 
			
		||||
  /// @brief A normalized up-oriented vector
 | 
			
		||||
  const static Spherical up;
 | 
			
		||||
  /// @brief A normalized down-oriented vector
 | 
			
		||||
  const static Spherical down;
 | 
			
		||||
 | 
			
		||||
  /// @brief Equality test to another vector
 | 
			
		||||
  /// @param v The vector to check against
 | 
			
		||||
  /// @return true: if it is identical to the given vector
 | 
			
		||||
  /// @note This uses float comparison to check equality which may have strange
 | 
			
		||||
  /// effects. Equality on floats should be avoided.
 | 
			
		||||
  bool operator==(const Spherical& v) const;
 | 
			
		||||
 | 
			
		||||
  /// @brief The vector length
 | 
			
		||||
  /// @param v The vector for which you need the length
 | 
			
		||||
  /// @return The vector length;
 | 
			
		||||
  inline static float Magnitude(const Spherical& v) { return v.distance; }
 | 
			
		||||
  /// @brief The vector length
 | 
			
		||||
  /// @return The vector length
 | 
			
		||||
  inline float magnitude() const { return this->distance; }
 | 
			
		||||
 | 
			
		||||
  /// @brief Convert the vector to a length of 1
 | 
			
		||||
  /// @param v The vector to convert
 | 
			
		||||
  /// @return The vector normalized to a length of 1
 | 
			
		||||
  static Spherical Normalize(const Spherical& v);
 | 
			
		||||
  /// @brief Convert the vector to a length of a
 | 
			
		||||
  /// @return The vector normalized to a length of 1
 | 
			
		||||
  Spherical normalized() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Negate the vector
 | 
			
		||||
  /// @return The negated vector
 | 
			
		||||
  /// This will rotate the vector by 180 degrees horizontally and
 | 
			
		||||
  /// vertically. Distance will stay the same.
 | 
			
		||||
  Spherical operator-() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Subtract a spherical vector from this vector
 | 
			
		||||
  /// @param v The vector to subtract
 | 
			
		||||
  /// @return The result of the subtraction
 | 
			
		||||
  Spherical operator-(const Spherical& v) const;
 | 
			
		||||
  Spherical operator-=(const Spherical& v);
 | 
			
		||||
  /// @brief Add a spherical vector to this vector
 | 
			
		||||
  /// @param v The vector to add
 | 
			
		||||
  /// @return The result of the addition
 | 
			
		||||
  Spherical operator+(const Spherical& v) const;
 | 
			
		||||
  Spherical operator+=(const Spherical& v);
 | 
			
		||||
 | 
			
		||||
  /// @brief Scale the vector uniformly up
 | 
			
		||||
  /// @param f The scaling factor
 | 
			
		||||
  /// @return The scaled vector
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend Spherical operator*(const Spherical& v, float f) {
 | 
			
		||||
    return Spherical(v.distance * f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
  }
 | 
			
		||||
  friend Spherical operator*(float f, const Spherical& v) {
 | 
			
		||||
    return Spherical(v.distance * f, v.horizontalAngle,
 | 
			
		||||
                     v.verticalAngle);  // not correct, should be f * v.distance
 | 
			
		||||
  }
 | 
			
		||||
  Spherical operator*=(float f);
 | 
			
		||||
  /// @brief Scale the vector uniformly down
 | 
			
		||||
  /// @param f The scaling factor
 | 
			
		||||
  /// @return The scaled factor
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend Spherical operator/(const Spherical& v, float f) {
 | 
			
		||||
    return Spherical(v.distance / f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
  }
 | 
			
		||||
  friend Spherical operator/(float f, const Spherical& v) {
 | 
			
		||||
    return Spherical(v.distance / f, v.horizontalAngle,
 | 
			
		||||
                     v.verticalAngle);  // not correct, should be f / v.distance
 | 
			
		||||
  }
 | 
			
		||||
  Spherical operator/=(float f);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// The distance between two vectors
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="v1">The first vector</param>
 | 
			
		||||
  /// <param name="v2">The second vector</param>
 | 
			
		||||
  /// <returns>The distance between the two vectors</returns>
 | 
			
		||||
  // static float Distance(const Spherical &s1, const Spherical &s2);
 | 
			
		||||
 | 
			
		||||
  static Angle AngleBetween(const Spherical& v1, const Spherical& v2);
 | 
			
		||||
 | 
			
		||||
  static Spherical Rotate(const Spherical& v,
 | 
			
		||||
                          Angle horizontalAngle,
 | 
			
		||||
                          Angle verticalAngle);
 | 
			
		||||
  static Spherical RotateHorizontal(const Spherical& v, Angle angle);
 | 
			
		||||
  static Spherical RotateVertical(const Spherical& v, Angle angle);
 | 
			
		||||
};
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#include "Polar.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										257
									
								
								LinearAlgebra/Spherical16.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								LinearAlgebra/Spherical16.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,257 @@
 | 
			
		||||
/*
 | 
			
		||||
#include "Spherical16.h"
 | 
			
		||||
 | 
			
		||||
#include "Quaternion.h"
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
Spherical16::Spherical16() {
 | 
			
		||||
  this->distance = 0.0f;
 | 
			
		||||
  this->horizontalAngle = Angle16(0);
 | 
			
		||||
  this->verticalAngle = Angle16(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16::Spherical16(Polar polar) {
 | 
			
		||||
  this->distance = polar.distance;
 | 
			
		||||
  this->horizontalAngle = Angle16(polar.angle.ToFloat());
 | 
			
		||||
  this->verticalAngle = Angle16(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16::Spherical16(float distance,
 | 
			
		||||
                         Angle16 horizontalAngle,
 | 
			
		||||
                         Angle16 verticalAngle) {
 | 
			
		||||
  if (distance < 0) {
 | 
			
		||||
    this->distance = -distance;
 | 
			
		||||
    this->horizontalAngle = horizontalAngle.ToFloat() - Angle16(180).ToFloat();
 | 
			
		||||
    this->verticalAngle = verticalAngle;
 | 
			
		||||
  } else {
 | 
			
		||||
    this->distance = distance;
 | 
			
		||||
    this->horizontalAngle = horizontalAngle;
 | 
			
		||||
    this->verticalAngle = verticalAngle;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16::Spherical16(Vector3 v) {
 | 
			
		||||
  this->distance = v.magnitude();
 | 
			
		||||
  if (distance == 0.0f) {
 | 
			
		||||
    this->verticalAngle = 0.0f;
 | 
			
		||||
    this->horizontalAngle = 0.0f;
 | 
			
		||||
  } else {
 | 
			
		||||
    this->verticalAngle = (90.0f - acosf(v.Up() / this->distance) *
 | 
			
		||||
                                       Passer::LinearAlgebra::Rad2Deg);
 | 
			
		||||
    this->horizontalAngle =
 | 
			
		||||
        atan2f(v.Right(), v.Forward()) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vector3 Passer::LinearAlgebra::Spherical16::ToVector3() {
 | 
			
		||||
  float verticalRad =
 | 
			
		||||
      (90.0f - this->verticalAngle.ToFloat()) * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
  float horizontalRad =
 | 
			
		||||
      this->horizontalAngle.ToFloat() * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
  float cosVertical = cosf(verticalRad);
 | 
			
		||||
  float sinVertical = sinf(verticalRad);
 | 
			
		||||
  float cosHorizontal = cosf(horizontalRad);
 | 
			
		||||
  float sinHorizontal = sinf(horizontalRad);
 | 
			
		||||
 | 
			
		||||
  float x = this->distance * sinVertical * sinHorizontal;
 | 
			
		||||
  float y = this->distance * cosVertical;
 | 
			
		||||
  float z = this->distance * sinVertical * cosHorizontal;
 | 
			
		||||
 | 
			
		||||
  Vector3 v = Vector3(x, y, z);
 | 
			
		||||
  return Vector3();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Spherical16 Spherical16::zero = Spherical16(0.0f, 0.0f, 0.0f);
 | 
			
		||||
const Spherical16 Spherical16::forward = Spherical16(1.0f, 0.0f, 0.0f);
 | 
			
		||||
const Spherical16 Spherical16::back = Spherical16(1.0f, 180.0f, 0.0f);
 | 
			
		||||
const Spherical16 Spherical16::right = Spherical16(1.0f, 90.0f, 0.0f);
 | 
			
		||||
const Spherical16 Spherical16::left = Spherical16(1.0f, -90.0f, 0.0f);
 | 
			
		||||
const Spherical16 Spherical16::up = Spherical16(1.0f, 0.0f, 90.0f);
 | 
			
		||||
const Spherical16 Spherical16::down = Spherical16(1.0f, 0.0f, -90.0f);
 | 
			
		||||
 | 
			
		||||
bool Spherical16::operator==(const Spherical16& v) const {
 | 
			
		||||
  return (this->distance == v.distance &&
 | 
			
		||||
          this->horizontalAngle.ToFloat() == v.horizontalAngle.ToFloat() &&
 | 
			
		||||
          this->verticalAngle.ToFloat() == v.verticalAngle.ToFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16 Spherical16::Normalize(const Spherical16& v) {
 | 
			
		||||
  Spherical16 r = Spherical16(1, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical16 Spherical16::normalized() const {
 | 
			
		||||
  Spherical16 r = Spherical16(1, this->horizontalAngle, this->verticalAngle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16 Spherical16::operator-() const {
 | 
			
		||||
  Spherical16 v =
 | 
			
		||||
      Spherical16(this->distance, this->horizontalAngle.ToFloat() + 180.0f,
 | 
			
		||||
                  this->verticalAngle.ToFloat() + 180.0f);
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16 Spherical16::operator-(const Spherical16& s2) const {
 | 
			
		||||
  Spherical thisSpherical =
 | 
			
		||||
      Spherical(this->distance, this->horizontalAngle.ToFloat(),
 | 
			
		||||
                this->verticalAngle.ToFloat());
 | 
			
		||||
  Spherical spherical2 = Spherical(s2.distance, s2.horizontalAngle.ToFloat(),
 | 
			
		||||
                                   s2.verticalAngle.ToFloat());
 | 
			
		||||
 | 
			
		||||
  // let's do it the easy way...
 | 
			
		||||
  Vector3 v1 = Vector3(thisSpherical);
 | 
			
		||||
  Vector3 v2 = Vector3(spherical2);
 | 
			
		||||
  Vector3 v = v1 - v2;
 | 
			
		||||
  Spherical16 r = Spherical16(v);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical16 Spherical16::operator-=(const Spherical16& v) {
 | 
			
		||||
  *this = *this - v;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16 Spherical16::operator+(const Spherical16& s2) const {
 | 
			
		||||
  // let's do it the easy way...
 | 
			
		||||
  Vector3 v1 =
 | 
			
		||||
      Vector3(Spherical(this->distance, this->horizontalAngle.ToFloat(),
 | 
			
		||||
                        this->verticalAngle.ToFloat()));
 | 
			
		||||
  Vector3 v2 = Vector3(Spherical(s2.distance, s2.horizontalAngle.ToFloat(),
 | 
			
		||||
                                 s2.verticalAngle.ToFloat()));
 | 
			
		||||
  Vector3 v = v1 + v2;
 | 
			
		||||
  Spherical16 r = Spherical16(v);
 | 
			
		||||
  return r;
 | 
			
		||||
 | 
			
		||||
  // This is the hard way...
 | 
			
		||||
  if (v2.distance <= 0)
 | 
			
		||||
    return Spherical(this->distance, this->horizontalAngle,
 | 
			
		||||
                     this->verticalAngle);
 | 
			
		||||
  if (this->distance <= 0)
 | 
			
		||||
    return v2;
 | 
			
		||||
 | 
			
		||||
  float deltaHorizontalAngle =
 | 
			
		||||
      (float)Angle::Normalize(v2.horizontalAngle - this->horizontalAngle);
 | 
			
		||||
  float horizontalRotation = deltaHorizontalAngle < 0
 | 
			
		||||
                                 ? 180 + deltaHorizontalAngle
 | 
			
		||||
                                 : 180 - deltaHorizontalAngle;
 | 
			
		||||
  float deltaVerticalAngle =
 | 
			
		||||
      Angle::Normalize(v2.verticalAngle - this->verticalAngle);
 | 
			
		||||
  float verticalRotation = deltaVerticalAngle < 0 ? 180 + deltaVerticalAngle
 | 
			
		||||
                                                  : 180 - deltaVerticalAngle;
 | 
			
		||||
 | 
			
		||||
  if (horizontalRotation == 180 && verticalRotation == 180)
 | 
			
		||||
    // angle is too small, take this angle and add the distances
 | 
			
		||||
    return Spherical(this->distance + v2.distance, this->horizontalAngle,
 | 
			
		||||
                     this->verticalAngle);
 | 
			
		||||
 | 
			
		||||
  Angle rotation = AngleBetween(*this, v2);
 | 
			
		||||
  float newDistance =
 | 
			
		||||
      Angle::CosineRuleSide(v2.distance, this->distance, rotation);
 | 
			
		||||
  float angle =
 | 
			
		||||
      Angle::CosineRuleAngle(newDistance, this->distance, v2.distance);
 | 
			
		||||
 | 
			
		||||
  // Now we have to project the angle to the horizontal and vertical planes...
 | 
			
		||||
  // The axis for the angle is the cross product of the two spherical vectors
 | 
			
		||||
  // (which function we do not have either...)
 | 
			
		||||
  float horizontalAngle = 0;
 | 
			
		||||
  float verticalAngle = 0;
 | 
			
		||||
 | 
			
		||||
  float newHorizontalAngle =
 | 
			
		||||
      deltaHorizontalAngle < 0
 | 
			
		||||
          ? Angle::Normalize(this->horizontalAngle - horizontalAngle)
 | 
			
		||||
          : Angle::Normalize(this->horizontalAngle + horizontalAngle);
 | 
			
		||||
  float newVerticalAngle =
 | 
			
		||||
      deltaVerticalAngle < 0
 | 
			
		||||
          ? Angle::Normalize(this->verticalAngle - verticalAngle)
 | 
			
		||||
          : Angle::Normalize(this->verticalAngle + verticalAngle);
 | 
			
		||||
 | 
			
		||||
  Spherical v = Spherical(newDistance, newHorizontalAngle, newVerticalAngle);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
Spherical16 Spherical16::operator+=(const Spherical16& v) {
 | 
			
		||||
  *this = *this + v;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator*(const Spherical &v, float f) {
 | 
			
		||||
//   return Spherical(v.distance * f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator*(float f, const Spherical &v) {
 | 
			
		||||
//   return Spherical(v.distance * f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
Spherical16 Spherical16::operator*=(float f) {
 | 
			
		||||
  this->distance *= f;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator/(const Spherical &v, float f) {
 | 
			
		||||
//   return Spherical(v.distance / f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
// Spherical Passer::LinearAlgebra::operator/(float f, const Spherical &v) {
 | 
			
		||||
//   return Spherical(v.distance / f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
Spherical16 Spherical16::operator/=(float f) {
 | 
			
		||||
  this->distance /= f;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// float Spherical::GetSwing() {
 | 
			
		||||
//   // Not sure if this is correct
 | 
			
		||||
//   return sqrtf(horizontalAngle * horizontalAngle +
 | 
			
		||||
//                verticalAngle * verticalAngle);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
// float Spherical::Distance(const Spherical &s1, const Spherical &s2) {
 | 
			
		||||
//   float d = 0;
 | 
			
		||||
//   return d;
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
#include "AngleUsing.h"
 | 
			
		||||
#include "FloatSingle.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
const float epsilon = 1E-05f;
 | 
			
		||||
const float Rad2Deg = 57.29578F;
 | 
			
		||||
 | 
			
		||||
Angle Spherical16::AngleBetween(const Spherical16& v1, const Spherical16& v2) {
 | 
			
		||||
  // float denominator = sqrtf(v1_3.sqrMagnitude() * v2_3.sqrMagnitude());
 | 
			
		||||
  float denominator =
 | 
			
		||||
      v1.distance * v2.distance;  // sqrtf(v1.distance * v1.distance *
 | 
			
		||||
                                  // v2.distance * v2.distance);
 | 
			
		||||
  if (denominator < epsilon)
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
 | 
			
		||||
  Vector3 v1_3 = Vector3(Spherical(v1.distance, v1.horizontalAngle.ToFloat(),
 | 
			
		||||
                                   v1.verticalAngle.ToFloat()));
 | 
			
		||||
  Vector3 v2_3 = Vector3(Spherical(v2.distance, v2.horizontalAngle.ToFloat(),
 | 
			
		||||
                                   v2.verticalAngle.ToFloat()));
 | 
			
		||||
  float dot = Vector3::Dot(v1_3, v2_3);
 | 
			
		||||
  float fraction = dot / denominator;
 | 
			
		||||
  if (isnan(fraction))
 | 
			
		||||
    return fraction;  // short cut to returning NaN universally
 | 
			
		||||
 | 
			
		||||
  float cdot = Float::Clamp(fraction, -1.0, 1.0);
 | 
			
		||||
  float r = ((float)acos(cdot)) * Rad2Deg;
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Spherical16 Spherical16::Rotate(const Spherical16& v,
 | 
			
		||||
                                Angle horizontalAngle,
 | 
			
		||||
                                Angle verticalAngle) {
 | 
			
		||||
  Spherical16 r = Spherical16(
 | 
			
		||||
      v.distance, v.horizontalAngle.ToFloat() + horizontalAngle.ToFloat(),
 | 
			
		||||
      v.verticalAngle.ToFloat() + verticalAngle.ToFloat());
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical16 Spherical16::RotateHorizontal(const Spherical16& v, Angle a) {
 | 
			
		||||
  Spherical16 r = Spherical16(
 | 
			
		||||
      v.distance, v.horizontalAngle.ToFloat() + a.ToFloat(), v.verticalAngle);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
Spherical16 Spherical16::RotateVertical(const Spherical16& v, Angle a) {
 | 
			
		||||
  Spherical16 r = Spherical16(v.distance, v.horizontalAngle,
 | 
			
		||||
                              v.verticalAngle.ToFloat() + a.ToFloat());
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
							
								
								
									
										162
									
								
								LinearAlgebra/Spherical16.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								LinearAlgebra/Spherical16.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,162 @@
 | 
			
		||||
/*
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#ifndef SPHERICAL16_H
 | 
			
		||||
#define SPHERICAL16_H
 | 
			
		||||
 | 
			
		||||
#include "Angle16.h"
 | 
			
		||||
#include "Polar.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
struct Vector3;
 | 
			
		||||
 | 
			
		||||
/// @brief A spherical vector
 | 
			
		||||
/// @details This is a vector in 3D space using a spherical coordinate system.
 | 
			
		||||
/// It consists of a distance and the polar and elevation angles from a
 | 
			
		||||
/// reference direction. The reference direction is typically thought of
 | 
			
		||||
/// as a forward direction.
 | 
			
		||||
/// In contrast to the normal Spherical type, this version uses 16 bit integers
 | 
			
		||||
/// for the angles
 | 
			
		||||
struct Spherical16 {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief The distance in meters
 | 
			
		||||
  /// @remark The distance should never be negative
 | 
			
		||||
  float distance;
 | 
			
		||||
  /// @brief The angle in the horizontal plane in degrees, clockwise rotation
 | 
			
		||||
  /// @details The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  Angle16 horizontalAngle;
 | 
			
		||||
  /// @brief The angle in the vertical plane in degrees. Positive is upward.
 | 
			
		||||
  /// @details The angle is automatically normalized to -180 .. 180
 | 
			
		||||
  Angle16 verticalAngle;
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a new spherical vector with zero degrees and distance
 | 
			
		||||
  Spherical16();
 | 
			
		||||
  /// @brief Create a new spherical vector
 | 
			
		||||
  /// @param distance The distance in meters
 | 
			
		||||
  /// @param horizontalAngle The angle in the horizontal plane in degrees,
 | 
			
		||||
  /// clockwise rotation
 | 
			
		||||
  /// @param verticalAngle The angle in the vertical plan in degrees,
 | 
			
		||||
  /// zero is forward, positive is upward
 | 
			
		||||
  Spherical16(float distance, Angle16 horizontalAngle, Angle16 verticalAngle);
 | 
			
		||||
  /// @brief Convert polar coordinates to spherical coordinates
 | 
			
		||||
  /// @param polar The polar coordinate
 | 
			
		||||
  Spherical16(Polar polar);
 | 
			
		||||
  /// @brief Convert 3D carthesian coordinates to spherical coordinates
 | 
			
		||||
  /// @param v Vector in 3D carthesian coordinates;
 | 
			
		||||
  Spherical16(Vector3 v);
 | 
			
		||||
 | 
			
		||||
  Vector3 ToVector3();
 | 
			
		||||
 | 
			
		||||
  /// @brief A spherical vector with zero degree angles and distance
 | 
			
		||||
  const static Spherical16 zero;
 | 
			
		||||
  /// @brief A normalized forward-oriented vector
 | 
			
		||||
  const static Spherical16 forward;
 | 
			
		||||
  /// @brief A normalized back-oriented vector
 | 
			
		||||
  const static Spherical16 back;
 | 
			
		||||
  /// @brief A normalized right-oriented vector
 | 
			
		||||
  const static Spherical16 right;
 | 
			
		||||
  /// @brief A normalized left-oriented vector
 | 
			
		||||
  const static Spherical16 left;
 | 
			
		||||
  /// @brief A normalized up-oriented vector
 | 
			
		||||
  const static Spherical16 up;
 | 
			
		||||
  /// @brief A normalized down-oriented vector
 | 
			
		||||
  const static Spherical16 down;
 | 
			
		||||
 | 
			
		||||
  /// @brief Equality test to another vector
 | 
			
		||||
  /// @param v The vector to check against
 | 
			
		||||
  /// @return true: if it is identical to the given vector
 | 
			
		||||
  /// @note This uses float comparison to check equality which may have strange
 | 
			
		||||
  /// effects. Equality on floats should be avoided.
 | 
			
		||||
  bool operator==(const Spherical16& v) const;
 | 
			
		||||
 | 
			
		||||
  /// @brief The vector length
 | 
			
		||||
  /// @param v The vector for which you need the length
 | 
			
		||||
  /// @return The vector length;
 | 
			
		||||
  inline static float Magnitude(const Spherical16& v) { return v.distance; }
 | 
			
		||||
  /// @brief The vector length
 | 
			
		||||
  /// @return The vector length
 | 
			
		||||
  inline float magnitude() const { return this->distance; }
 | 
			
		||||
 | 
			
		||||
  /// @brief Convert the vector to a length of 1
 | 
			
		||||
  /// @param v The vector to convert
 | 
			
		||||
  /// @return The vector normalized to a length of 1
 | 
			
		||||
  static Spherical16 Normalize(const Spherical16& v);
 | 
			
		||||
  /// @brief Convert the vector to a length of a
 | 
			
		||||
  /// @return The vector normalized to a length of 1
 | 
			
		||||
  Spherical16 normalized() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Negate the vector
 | 
			
		||||
  /// @return The negated vector
 | 
			
		||||
  /// This will rotate the vector by 180 degrees horizontally and
 | 
			
		||||
  /// vertically. Distance will stay the same.
 | 
			
		||||
  Spherical16 operator-() const;
 | 
			
		||||
 | 
			
		||||
  /// @brief Subtract a spherical vector from this vector
 | 
			
		||||
  /// @param v The vector to subtract
 | 
			
		||||
  /// @return The result of the subtraction
 | 
			
		||||
  Spherical16 operator-(const Spherical16& v) const;
 | 
			
		||||
  Spherical16 operator-=(const Spherical16& v);
 | 
			
		||||
  /// @brief Add a spherical vector to this vector
 | 
			
		||||
  /// @param v The vector to add
 | 
			
		||||
  /// @return The result of the addition
 | 
			
		||||
  Spherical16 operator+(const Spherical16& v) const;
 | 
			
		||||
  Spherical16 operator+=(const Spherical16& v);
 | 
			
		||||
 | 
			
		||||
  /// @brief Scale the vector uniformly up
 | 
			
		||||
  /// @param f The scaling factor
 | 
			
		||||
  /// @return The scaled vector
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend Spherical16 operator*(const Spherical16& v, float f) {
 | 
			
		||||
    return Spherical16(v.distance * f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
  }
 | 
			
		||||
  friend Spherical16 operator*(float f, const Spherical16& v) {
 | 
			
		||||
    return Spherical16(
 | 
			
		||||
        v.distance * f, v.horizontalAngle,
 | 
			
		||||
        v.verticalAngle);  // not correct, should be f * v.distance
 | 
			
		||||
  }
 | 
			
		||||
  Spherical16 operator*=(float f);
 | 
			
		||||
  /// @brief Scale the vector uniformly down
 | 
			
		||||
  /// @param f The scaling factor
 | 
			
		||||
  /// @return The scaled factor
 | 
			
		||||
  /// @remark This operation will scale the distance of the vector. The angle
 | 
			
		||||
  /// will be unaffected.
 | 
			
		||||
  friend Spherical16 operator/(const Spherical16& v, float f) {
 | 
			
		||||
    return Spherical16(v.distance / f, v.horizontalAngle, v.verticalAngle);
 | 
			
		||||
  }
 | 
			
		||||
  friend Spherical16 operator/(float f, const Spherical16& v) {
 | 
			
		||||
    return Spherical16(
 | 
			
		||||
        v.distance / f, v.horizontalAngle,
 | 
			
		||||
        v.verticalAngle);  // not correct, should be f / v.distance
 | 
			
		||||
  }
 | 
			
		||||
  Spherical16 operator/=(float f);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// The distance between two vectors
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="v1">The first vector</param>
 | 
			
		||||
  /// <param name="v2">The second vector</param>
 | 
			
		||||
  /// <returns>The distance between the two vectors</returns>
 | 
			
		||||
  // static float Distance(const Spherical16 &s1, const Spherical16 &s2);
 | 
			
		||||
 | 
			
		||||
  static Angle AngleBetween(const Spherical16& v1, const Spherical16& v2);
 | 
			
		||||
 | 
			
		||||
  static Spherical16 Rotate(const Spherical16& v,
 | 
			
		||||
                            Angle horizontalAngle,
 | 
			
		||||
                            Angle verticalAngle);
 | 
			
		||||
  static Spherical16 RotateHorizontal(const Spherical16& v, Angle angle);
 | 
			
		||||
  static Spherical16 RotateVertical(const Spherical16& v, Angle angle);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
*/
 | 
			
		||||
@ -1,172 +0,0 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#include "SwingTwist.h"
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T>::SwingTwistOf() {
 | 
			
		||||
  this->swing = DirectionOf<T>(AngleOf<T>(), AngleOf<T>());
 | 
			
		||||
  this->twist = AngleOf<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T>::SwingTwistOf(DirectionOf<T> swing, AngleOf<T> twist) {
 | 
			
		||||
  // Normalize angles
 | 
			
		||||
  AngleOf<T> deg90 = AngleOf<T>::Degrees(90);
 | 
			
		||||
  AngleOf<T> deg180 = AngleOf<T>::Degrees(180);
 | 
			
		||||
 | 
			
		||||
  if (swing.vertical > deg90 || swing.vertical < -deg90) {
 | 
			
		||||
    swing.horizontal += deg180;
 | 
			
		||||
    swing.vertical = deg180 - swing.vertical;
 | 
			
		||||
    twist += deg180;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->swing = swing;
 | 
			
		||||
  this->twist = twist;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T>::SwingTwistOf(AngleOf<T> horizontal,
 | 
			
		||||
                              AngleOf<T> vertical,
 | 
			
		||||
                              AngleOf<T> twist) {
 | 
			
		||||
  // Normalize angles
 | 
			
		||||
  AngleOf<T> deg90 = AngleOf<T>::Degrees(90);
 | 
			
		||||
  AngleOf<T> deg180 = AngleOf<T>::Degrees(180);
 | 
			
		||||
 | 
			
		||||
  if (vertical > deg90 || vertical < -deg90) {
 | 
			
		||||
    horizontal += deg180;
 | 
			
		||||
    vertical = deg180 - vertical;
 | 
			
		||||
    twist += deg180;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  this->swing = DirectionOf<T>(horizontal, vertical);
 | 
			
		||||
  this->twist = twist;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T> SwingTwistOf<T>::Degrees(float horizontal,
 | 
			
		||||
                                         float vertical,
 | 
			
		||||
                                         float twist) {
 | 
			
		||||
  SwingTwistOf<T> orientation = SwingTwistOf<T>(AngleOf<T>::Degrees(horizontal),
 | 
			
		||||
                                                -AngleOf<T>::Degrees(vertical),
 | 
			
		||||
                                                AngleOf<T>::Degrees(twist));
 | 
			
		||||
  // DirectionOf<T> swing = DirectionOf<T>::Degrees(horizontal, vertical);
 | 
			
		||||
  // AngleOf<T> twistAngle = AngleOf<T>::Degrees(twist);
 | 
			
		||||
  // SwingTwistOf<T> orientation = SwingTwistOf(swing, twistAngle);
 | 
			
		||||
  return orientation;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
Quaternion SwingTwistOf<T>::ToQuaternion() const {
 | 
			
		||||
  Quaternion q = Quaternion::Euler(-this->swing.vertical.InDegrees(),
 | 
			
		||||
                                   this->swing.horizontal.InDegrees(),
 | 
			
		||||
                                   this->twist.InDegrees());
 | 
			
		||||
  return q;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T> SwingTwistOf<T>::FromQuaternion(Quaternion q) {
 | 
			
		||||
  Vector3 angles = Quaternion::ToAngles(q);
 | 
			
		||||
  SwingTwistOf<T> r =
 | 
			
		||||
      SwingTwistOf<T>::Degrees(angles.Up(), angles.Right(), angles.Forward());
 | 
			
		||||
  r.Normalize();
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SwingTwistOf<T>::ToAngleAxis() const {
 | 
			
		||||
  Quaternion q = this->ToQuaternion();
 | 
			
		||||
  float angle;
 | 
			
		||||
  Vector3 axis;
 | 
			
		||||
  q.ToAngleAxis(&angle, &axis);
 | 
			
		||||
  DirectionOf<T> direction = DirectionOf<T>::FromVector3(axis);
 | 
			
		||||
 | 
			
		||||
  SphericalOf<T> aa = SphericalOf<T>(angle, direction);
 | 
			
		||||
  return aa;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T> SwingTwistOf<T>::FromAngleAxis(SphericalOf<T> aa) {
 | 
			
		||||
  Vector3 vectorAxis = aa.direction.ToVector3();
 | 
			
		||||
  Quaternion q = Quaternion::AngleAxis(aa.distance, vectorAxis);
 | 
			
		||||
  return SwingTwistOf<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
bool SwingTwistOf<T>::operator==(const SwingTwistOf<T> s) const {
 | 
			
		||||
  return (this->swing == s.swing) && (this->twist == s.twist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
const SwingTwistOf<T> SwingTwistOf<T>::identity = SwingTwistOf();
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SphericalOf<T> SwingTwistOf<T>::operator*(const SphericalOf<T>& vector) const {
 | 
			
		||||
  SphericalOf<T> v = SphericalOf<T>(
 | 
			
		||||
      vector.distance, vector.direction.horizontal + this->swing.horizontal,
 | 
			
		||||
      vector.direction.vertical + this->swing.vertical);
 | 
			
		||||
  return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T> SwingTwistOf<T>::operator*(
 | 
			
		||||
    const SwingTwistOf<T>& rotation) const {
 | 
			
		||||
  SwingTwistOf<T> r =
 | 
			
		||||
      SwingTwistOf(this->swing.horizontal + rotation.swing.horizontal,
 | 
			
		||||
                   this->swing.vertical + rotation.swing.vertical,
 | 
			
		||||
                   this->twist + rotation.twist);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T> SwingTwistOf<T>::operator*=(const SwingTwistOf<T>& rotation) {
 | 
			
		||||
  this->swing.horizontal += rotation.swing.horizontal;
 | 
			
		||||
  this->swing.vertical += rotation.swing.vertical;
 | 
			
		||||
  this->twist += rotation.twist;
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T> SwingTwistOf<T>::Inverse(SwingTwistOf<T> rotation) {
 | 
			
		||||
  SwingTwistOf<T> r = SwingTwistOf<T>(
 | 
			
		||||
      -rotation.swing.horizontal, -rotation.swing.vertical, -rotation.twist);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
SwingTwistOf<T> SwingTwistOf<T>::AngleAxis(float angle,
 | 
			
		||||
                                           const DirectionOf<T>& axis) {
 | 
			
		||||
  Vector3 axis_vector = axis.ToVector3();
 | 
			
		||||
  Quaternion q = Quaternion::AngleAxis(angle, axis_vector);
 | 
			
		||||
  SwingTwistOf<T> r = SwingTwistOf<T>::FromQuaternion(q);
 | 
			
		||||
  return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
AngleOf<T> SwingTwistOf<T>::Angle(const SwingTwistOf<T>& r1,
 | 
			
		||||
                                  const SwingTwistOf<T>& r2) {
 | 
			
		||||
  Quaternion q1 = r1.ToQuaternion();
 | 
			
		||||
  Quaternion q2 = r2.ToQuaternion();
 | 
			
		||||
  float angle = Quaternion::Angle(q1, q2);
 | 
			
		||||
  return AngleOf<T>::Degrees(angle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void SwingTwistOf<T>::Normalize() {
 | 
			
		||||
  AngleOf<T> deg90 = AngleOf<T>::Degrees(90);
 | 
			
		||||
  AngleOf<T> deg180 = AngleOf<T>::Degrees(180);
 | 
			
		||||
 | 
			
		||||
  if (this->swing.vertical > deg90 || this->swing.vertical < -deg90) {
 | 
			
		||||
    this->swing.horizontal += deg180;
 | 
			
		||||
    this->swing.vertical = deg180 - this->swing.vertical;
 | 
			
		||||
    this->twist += deg180;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template class SwingTwistOf<float>;
 | 
			
		||||
template class SwingTwistOf<signed short>;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,85 +0,0 @@
 | 
			
		||||
// This Source Code Form is subject to the terms of the Mozilla Public
 | 
			
		||||
// License, v. 2.0.If a copy of the MPL was not distributed with this
 | 
			
		||||
// file, You can obtain one at https ://mozilla.org/MPL/2.0/.
 | 
			
		||||
 | 
			
		||||
#ifndef SWINGTWIST_H
 | 
			
		||||
#define SWINGTWIST_H
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
#include "Direction.h"
 | 
			
		||||
#include "Quaternion.h"
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
/// @brief An orientation using swing and twist angles in various
 | 
			
		||||
/// representations
 | 
			
		||||
/// @tparam T The implmentation type used for the representation of the angles
 | 
			
		||||
template <typename T>
 | 
			
		||||
class SwingTwistOf {
 | 
			
		||||
 public:
 | 
			
		||||
  DirectionOf<T> swing;
 | 
			
		||||
  AngleOf<T> twist;
 | 
			
		||||
 | 
			
		||||
  SwingTwistOf();
 | 
			
		||||
  SwingTwistOf(DirectionOf<T> swing, AngleOf<T> twist);
 | 
			
		||||
  SwingTwistOf(AngleOf<T> horizontal, AngleOf<T> vertical, AngleOf<T> twist);
 | 
			
		||||
 | 
			
		||||
  static SwingTwistOf<T> Degrees(float horizontal,
 | 
			
		||||
                                 float vertical = 0,
 | 
			
		||||
                                 float twist = 0);
 | 
			
		||||
 | 
			
		||||
  Quaternion ToQuaternion() const;
 | 
			
		||||
  static SwingTwistOf<T> FromQuaternion(Quaternion q);
 | 
			
		||||
 | 
			
		||||
  SphericalOf<T> ToAngleAxis() const;
 | 
			
		||||
  static SwingTwistOf<T> FromAngleAxis(SphericalOf<T> aa);
 | 
			
		||||
 | 
			
		||||
  const static SwingTwistOf<T> identity;
 | 
			
		||||
 | 
			
		||||
  bool operator==(const SwingTwistOf<T> d) const;
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Rotate a vector using this rotation
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="vector">The vector to rotate</param>
 | 
			
		||||
  /// <returns>The rotated vector</returns>
 | 
			
		||||
  SphericalOf<T> operator*(const SphericalOf<T>& vector) const;
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Multiply this rotation with another rotation
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="rotation">The swing/twist rotation to multiply with</param>
 | 
			
		||||
  /// <returns>The resulting swing/twist rotation</returns>
 | 
			
		||||
  /// The result will be this rotation rotated according to
 | 
			
		||||
  /// the give rotation.
 | 
			
		||||
  SwingTwistOf<T> operator*(const SwingTwistOf<T>& rotation) const;
 | 
			
		||||
  SwingTwistOf<T> operator*=(const SwingTwistOf<T>& rotation);
 | 
			
		||||
 | 
			
		||||
  static SwingTwistOf<T> Inverse(SwingTwistOf<T> rotation);
 | 
			
		||||
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// Convert an angle/axis representation to a swingt
 | 
			
		||||
  /// </summary>
 | 
			
		||||
  /// <param name="angle">The angle</param>
 | 
			
		||||
  /// <param name="axis">The axis</param>
 | 
			
		||||
  /// <returns>The resulting quaternion</returns>
 | 
			
		||||
  static SwingTwistOf<T> AngleAxis(float angle, const DirectionOf<T>& axis);
 | 
			
		||||
 | 
			
		||||
  static AngleOf<T> Angle(const SwingTwistOf<T>& r1, const SwingTwistOf<T>& r2);
 | 
			
		||||
 | 
			
		||||
  void Normalize();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using SwingTwistSingle = SwingTwistOf<float>;
 | 
			
		||||
using SwingTwist16 = SwingTwistOf<signed short>;
 | 
			
		||||
 | 
			
		||||
#if defined(ARDUINO)
 | 
			
		||||
using SwingTwist = SwingTwist16;
 | 
			
		||||
#else
 | 
			
		||||
using SwingTwist = SwingTwistSingle;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -7,11 +7,11 @@
 | 
			
		||||
#include "FloatSingle.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
// #if defined(AVR)
 | 
			
		||||
// #include <Arduino.h>
 | 
			
		||||
// #else
 | 
			
		||||
#if defined(AVR)
 | 
			
		||||
#include <Arduino.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <math.h>
 | 
			
		||||
// #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
Vector2::Vector2() {
 | 
			
		||||
  x = 0;
 | 
			
		||||
@ -29,8 +29,8 @@ Vector2::Vector2(Vector3 v) {
 | 
			
		||||
  x = v.Right();    // x;
 | 
			
		||||
  y = v.Forward();  // z;
 | 
			
		||||
}
 | 
			
		||||
Vector2::Vector2(PolarSingle p) {
 | 
			
		||||
  float horizontalRad = p.angle.InDegrees() * Deg2Rad;
 | 
			
		||||
Vector2::Vector2(Polar p) {
 | 
			
		||||
  float horizontalRad = p.angle.ToFloat() * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
  float cosHorizontal = cosf(horizontalRad);
 | 
			
		||||
  float sinHorizontal = sinf(horizontalRad);
 | 
			
		||||
 | 
			
		||||
@ -156,11 +156,11 @@ float Vector2::SignedAngle(const Vector2& v1, const Vector2& v2) {
 | 
			
		||||
 | 
			
		||||
  float angleFrom = atan2f(v1.y, v1.x);
 | 
			
		||||
  float angleTo = atan2f(v2.y, v2.x);
 | 
			
		||||
  return -(angleTo - angleFrom) * Rad2Deg;
 | 
			
		||||
  return -(angleTo - angleFrom) * Passer::LinearAlgebra::Rad2Deg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vector2 Vector2::Rotate(const Vector2& v, AngleSingle a) {
 | 
			
		||||
  float angleRad = a.InDegrees() * Deg2Rad;
 | 
			
		||||
Vector2 Vector2::Rotate(const Vector2& v, Passer::LinearAlgebra::Angle a) {
 | 
			
		||||
  float angleRad = a.ToFloat() * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
#if defined(AVR)
 | 
			
		||||
  float sinValue = sin(angleRad);
 | 
			
		||||
  float cosValue = cos(angleRad);  // * Angle::Deg2Rad);
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 2-dimensional Vector representation (C-style)
 | 
			
		||||
/// 2-dimensional Vector representation
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// This is a C-style implementation
 | 
			
		||||
/// This uses the right-handed coordinate system.
 | 
			
		||||
@ -26,13 +26,15 @@ typedef struct Vec2 {
 | 
			
		||||
} Vec2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
struct Vector3;
 | 
			
		||||
template <typename T>
 | 
			
		||||
class PolarOf;
 | 
			
		||||
// using Polar = PolarOf<float>
 | 
			
		||||
 | 
			
		||||
/// @brief A 2-dimensional vector
 | 
			
		||||
/// @brief A 2=dimensional vector
 | 
			
		||||
/// @remark This uses the right=handed carthesian coordinate system.
 | 
			
		||||
/// @note This implementation intentionally avoids the use of x and y
 | 
			
		||||
struct Vector2 : Vec2 {
 | 
			
		||||
@ -188,7 +190,7 @@ struct Vector2 : Vec2 {
 | 
			
		||||
  /// @param v The vector to rotate
 | 
			
		||||
  /// @param a The angle in degrees to rotate
 | 
			
		||||
  /// @return The rotated vector
 | 
			
		||||
  static Vector2 Rotate(const Vector2& v, AngleSingle a);
 | 
			
		||||
  static Vector2 Rotate(const Vector2& v, Passer::LinearAlgebra::Angle a);
 | 
			
		||||
 | 
			
		||||
  /// @brief Lerp (linear interpolation) between two vectors
 | 
			
		||||
  /// @param v1 The starting vector
 | 
			
		||||
@ -202,7 +204,8 @@ struct Vector2 : Vec2 {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#include "Polar.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -30,9 +30,10 @@ Vector3::Vector3(Vector2 v) {
 | 
			
		||||
  this->z = v.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vector3::Vector3(SphericalOf<float> s) {
 | 
			
		||||
  float verticalRad = (90.0f - s.direction.vertical.InDegrees()) * Deg2Rad;
 | 
			
		||||
  float horizontalRad = s.direction.horizontal.InDegrees() * Deg2Rad;
 | 
			
		||||
Vector3::Vector3(Spherical s) {
 | 
			
		||||
  float verticalRad =
 | 
			
		||||
      (90.0f - s.vertical.ToFloat()) * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
  float horizontalRad = s.horizontal.ToFloat() * Passer::LinearAlgebra::Deg2Rad;
 | 
			
		||||
  float cosVertical = cosf(verticalRad);
 | 
			
		||||
  float sinVertical = sinf(verticalRad);
 | 
			
		||||
  float cosHorizontal = cosf(horizontalRad);
 | 
			
		||||
@ -151,7 +152,7 @@ float Vector3::Dot(const Vector3& v1, const Vector3& v2) {
 | 
			
		||||
  return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Vector3::operator==(const Vector3& v) const {
 | 
			
		||||
bool Vector3::operator==(const Vector3& v) {
 | 
			
		||||
  return (this->x == v.x && this->y == v.y && this->z == v.z);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -189,17 +190,16 @@ float clamp(float x, float lower, float upper) {
 | 
			
		||||
AngleOf<float> Vector3::Angle(const Vector3& v1, const Vector3& v2) {
 | 
			
		||||
  float denominator = sqrtf(v1.sqrMagnitude() * v2.sqrMagnitude());
 | 
			
		||||
  if (denominator < epsilon)
 | 
			
		||||
    return AngleOf<float>();
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
  float dot = Vector3::Dot(v1, v2);
 | 
			
		||||
  float fraction = dot / denominator;
 | 
			
		||||
  if (isnan(fraction))
 | 
			
		||||
    return AngleOf<float>::Degrees(
 | 
			
		||||
        fraction);  // short cut to returning NaN universally
 | 
			
		||||
    return fraction;  // short cut to returning NaN universally
 | 
			
		||||
 | 
			
		||||
  float cdot = clamp(fraction, -1.0, 1.0);
 | 
			
		||||
  float r = ((float)acos(cdot));
 | 
			
		||||
  return AngleOf<float>::Radians(r);
 | 
			
		||||
  float r = ((float)acos(cdot)) * Rad2Deg;
 | 
			
		||||
  return AngleOf<float>(r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AngleOf<float> Vector3::SignedAngle(const Vector3& v1,
 | 
			
		||||
 | 
			
		||||
@ -7,14 +7,21 @@
 | 
			
		||||
 | 
			
		||||
#include "Vector2.h"
 | 
			
		||||
 | 
			
		||||
namespace Passer {
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
// struct Spherical;
 | 
			
		||||
template <typename T>
 | 
			
		||||
class SphericalOf;
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// 3-dimensional Vector representation (C-style)
 | 
			
		||||
/// 3-dimensional Vector representation
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// This is a C-style implementation
 | 
			
		||||
/// This uses the right-handed coordinate system.
 | 
			
		||||
typedef struct Vec3 {
 | 
			
		||||
 public:
 | 
			
		||||
 protected:
 | 
			
		||||
  /// <summary>
 | 
			
		||||
  /// The right axis of the vector
 | 
			
		||||
  /// </summary>
 | 
			
		||||
@ -31,11 +38,6 @@ typedef struct Vec3 {
 | 
			
		||||
} Vec3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace LinearAlgebra {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class SphericalOf;
 | 
			
		||||
 | 
			
		||||
/// @brief A 3-dimensional vector
 | 
			
		||||
/// @remark This uses a right-handed carthesian coordinate system.
 | 
			
		||||
/// @note This implementation intentionally avoids the use of x, y and z values.
 | 
			
		||||
@ -88,7 +90,7 @@ struct Vector3 : Vec3 {
 | 
			
		||||
  /// @return true if it is identical to the given vector
 | 
			
		||||
  /// @note This uses float comparison to check equality which may have strange
 | 
			
		||||
  /// effects. Equality on floats should be avoided.
 | 
			
		||||
  bool operator==(const Vector3& v) const;
 | 
			
		||||
  bool operator==(const Vector3& v);
 | 
			
		||||
 | 
			
		||||
  /// @brief The vector length
 | 
			
		||||
  /// @param v The vector for which you need the length
 | 
			
		||||
@ -226,7 +228,8 @@ struct Vector3 : Vec3 {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace LinearAlgebra
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
}  // namespace Passer
 | 
			
		||||
using namespace Passer::LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,250 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//    FILE: float16.cpp
 | 
			
		||||
//  AUTHOR: Rob Tillaart
 | 
			
		||||
// VERSION: 0.1.8
 | 
			
		||||
// PURPOSE: library for Float16s for Arduino
 | 
			
		||||
//     URL: http://en.wikipedia.org/wiki/Half-precision_floating-point_format
 | 
			
		||||
 | 
			
		||||
#include "float16.h"
 | 
			
		||||
// #include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
//  CONSTRUCTOR
 | 
			
		||||
float16::float16(float f) { _value = f32tof16(f); }
 | 
			
		||||
 | 
			
		||||
//  PRINTING
 | 
			
		||||
// size_t float16::printTo(Print& p) const
 | 
			
		||||
// {
 | 
			
		||||
//   double d = this->f16tof32(_value);
 | 
			
		||||
//   return p.print(d, _decimals);
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
float float16::toFloat() const { return f16tof32(_value); }
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//  EQUALITIES
 | 
			
		||||
//
 | 
			
		||||
bool float16::operator==(const float16 &f) { return (_value == f._value); }
 | 
			
		||||
 | 
			
		||||
bool float16::operator!=(const float16 &f) { return (_value != f._value); }
 | 
			
		||||
 | 
			
		||||
bool float16::operator>(const float16 &f) {
 | 
			
		||||
  if ((_value & 0x8000) && (f._value & 0x8000))
 | 
			
		||||
    return _value < f._value;
 | 
			
		||||
  if (_value & 0x8000)
 | 
			
		||||
    return false;
 | 
			
		||||
  if (f._value & 0x8000)
 | 
			
		||||
    return true;
 | 
			
		||||
  return _value > f._value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool float16::operator>=(const float16 &f) {
 | 
			
		||||
  if ((_value & 0x8000) && (f._value & 0x8000))
 | 
			
		||||
    return _value <= f._value;
 | 
			
		||||
  if (_value & 0x8000)
 | 
			
		||||
    return false;
 | 
			
		||||
  if (f._value & 0x8000)
 | 
			
		||||
    return true;
 | 
			
		||||
  return _value >= f._value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool float16::operator<(const float16 &f) {
 | 
			
		||||
  if ((_value & 0x8000) && (f._value & 0x8000))
 | 
			
		||||
    return _value > f._value;
 | 
			
		||||
  if (_value & 0x8000)
 | 
			
		||||
    return true;
 | 
			
		||||
  if (f._value & 0x8000)
 | 
			
		||||
    return false;
 | 
			
		||||
  return _value < f._value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool float16::operator<=(const float16 &f) {
 | 
			
		||||
  if ((_value & (uint16_t)0x8000) && (f._value & (uint16_t)0x8000))
 | 
			
		||||
    return _value >= f._value;
 | 
			
		||||
  if (_value & 0x8000)
 | 
			
		||||
    return true;
 | 
			
		||||
  if (f._value & 0x8000)
 | 
			
		||||
    return false;
 | 
			
		||||
  return _value <= f._value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//  NEGATION
 | 
			
		||||
//
 | 
			
		||||
float16 float16::operator-() {
 | 
			
		||||
  float16 f16;
 | 
			
		||||
  f16.setBinary(_value ^ 0x8000);
 | 
			
		||||
  return f16;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//  MATH
 | 
			
		||||
//
 | 
			
		||||
float16 float16::operator+(const float16 &f) {
 | 
			
		||||
  return float16(this->toFloat() + f.toFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float16 float16::operator-(const float16 &f) {
 | 
			
		||||
  return float16(this->toFloat() - f.toFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float16 float16::operator*(const float16 &f) {
 | 
			
		||||
  return float16(this->toFloat() * f.toFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float16 float16::operator/(const float16 &f) {
 | 
			
		||||
  return float16(this->toFloat() / f.toFloat());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float16 &float16::operator+=(const float16 &f) {
 | 
			
		||||
  *this = this->toFloat() + f.toFloat();
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float16 &float16::operator-=(const float16 &f) {
 | 
			
		||||
  *this = this->toFloat() - f.toFloat();
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float16 &float16::operator*=(const float16 &f) {
 | 
			
		||||
  *this = this->toFloat() * f.toFloat();
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float16 &float16::operator/=(const float16 &f) {
 | 
			
		||||
  *this = this->toFloat() / f.toFloat();
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//  MATH HELPER FUNCTIONS
 | 
			
		||||
//
 | 
			
		||||
int float16::sign() {
 | 
			
		||||
  if (_value & 0x8000)
 | 
			
		||||
    return -1;
 | 
			
		||||
  if (_value & 0xFFFF)
 | 
			
		||||
    return 1;
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool float16::isZero() { return ((_value & 0x7FFF) == 0x0000); }
 | 
			
		||||
 | 
			
		||||
bool float16::isNaN() {
 | 
			
		||||
  if ((_value & 0x7C00) != 0x7C00)
 | 
			
		||||
    return false;
 | 
			
		||||
  if ((_value & 0x03FF) == 0x0000)
 | 
			
		||||
    return false;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool float16::isInf() { return ((_value == 0x7C00) || (_value == 0xFC00)); }
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
//  CORE CONVERSION
 | 
			
		||||
//
 | 
			
		||||
float float16::f16tof32(uint16_t _value) const {
 | 
			
		||||
  uint16_t sgn, man;
 | 
			
		||||
  int exp;
 | 
			
		||||
  float f;
 | 
			
		||||
 | 
			
		||||
  sgn = (_value & 0x8000) > 0;
 | 
			
		||||
  exp = (_value & 0x7C00) >> 10;
 | 
			
		||||
  man = (_value & 0x03FF);
 | 
			
		||||
 | 
			
		||||
  //  ZERO
 | 
			
		||||
  if ((_value & 0x7FFF) == 0) {
 | 
			
		||||
    return sgn ? -0.0f : 0.0f;
 | 
			
		||||
  }
 | 
			
		||||
  //  NAN & INF
 | 
			
		||||
  if (exp == 0x001F) {
 | 
			
		||||
    if (man == 0)
 | 
			
		||||
      return sgn ? -INFINITY : INFINITY;
 | 
			
		||||
    else
 | 
			
		||||
      return NAN;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //  SUBNORMAL/NORMAL
 | 
			
		||||
  if (exp == 0)
 | 
			
		||||
    f = 0;
 | 
			
		||||
  else
 | 
			
		||||
    f = 1;
 | 
			
		||||
 | 
			
		||||
  //  PROCESS MANTISSE
 | 
			
		||||
  for (int i = 9; i >= 0; i--) {
 | 
			
		||||
    f *= 2;
 | 
			
		||||
    if (man & (1 << i))
 | 
			
		||||
      f = f + 1;
 | 
			
		||||
  }
 | 
			
		||||
  f = f * powf(2.0f, (float)(exp - 25));
 | 
			
		||||
  if (exp == 0) {
 | 
			
		||||
    f = f * powf(2.0f, -13); // 5.96046447754e-8;
 | 
			
		||||
  }
 | 
			
		||||
  return sgn ? -f : f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t float16::f32tof16(float f) const {
 | 
			
		||||
  // untested code, but will avoid strict aliasing warning
 | 
			
		||||
  // union {
 | 
			
		||||
  //   float f;
 | 
			
		||||
  //   uint32_t t;
 | 
			
		||||
  // } u;
 | 
			
		||||
  // u.f = f;
 | 
			
		||||
  // uint32_t t = u.t;
 | 
			
		||||
  uint32_t t = *(uint32_t *)&f;
 | 
			
		||||
  //  man bits = 10; but we keep 11 for rounding
 | 
			
		||||
  uint16_t man = (t & 0x007FFFFF) >> 12;
 | 
			
		||||
  int16_t exp = (t & 0x7F800000) >> 23;
 | 
			
		||||
  bool sgn = (t & 0x80000000);
 | 
			
		||||
 | 
			
		||||
  //  handle 0
 | 
			
		||||
  if ((t & 0x7FFFFFFF) == 0) {
 | 
			
		||||
    return sgn ? 0x8000 : 0x0000;
 | 
			
		||||
  }
 | 
			
		||||
  //  denormalized float32 does not fit in float16
 | 
			
		||||
  if (exp == 0x00) {
 | 
			
		||||
    return sgn ? 0x8000 : 0x0000;
 | 
			
		||||
  }
 | 
			
		||||
  //  handle infinity & NAN
 | 
			
		||||
  if (exp == 0x00FF) {
 | 
			
		||||
    if (man)
 | 
			
		||||
      return 0xFE00;              //  NAN
 | 
			
		||||
    return sgn ? 0xFC00 : 0x7C00; //  -INF : INF
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //  normal numbers
 | 
			
		||||
  exp = exp - 127 + 15;
 | 
			
		||||
  //  overflow does not fit => INF
 | 
			
		||||
  if (exp > 30) {
 | 
			
		||||
    return sgn ? 0xFC00 : 0x7C00; //  -INF : INF
 | 
			
		||||
  }
 | 
			
		||||
  //  subnormal numbers
 | 
			
		||||
  if (exp < -38) {
 | 
			
		||||
    return sgn ? 0x8000 : 0x0000; //  -0 or 0  ?   just 0 ?
 | 
			
		||||
  }
 | 
			
		||||
  if (exp <= 0) //  subnormal
 | 
			
		||||
  {
 | 
			
		||||
    man >>= (exp + 14);
 | 
			
		||||
    //  rounding
 | 
			
		||||
    man++;
 | 
			
		||||
    man >>= 1;
 | 
			
		||||
    if (sgn)
 | 
			
		||||
      return 0x8000 | man;
 | 
			
		||||
    return man;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //  normal
 | 
			
		||||
  //  TODO rounding
 | 
			
		||||
  exp <<= 10;
 | 
			
		||||
  man++;
 | 
			
		||||
  man >>= 1;
 | 
			
		||||
  if (sgn)
 | 
			
		||||
    return 0x8000 | exp | man;
 | 
			
		||||
  return exp | man;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  -- END OF FILE --
 | 
			
		||||
@ -1,74 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
//
 | 
			
		||||
//    FILE: float16.h
 | 
			
		||||
//  AUTHOR: Rob Tillaart
 | 
			
		||||
// VERSION: 0.1.8
 | 
			
		||||
// PURPOSE: Arduino library to implement float16 data type.
 | 
			
		||||
//          half-precision floating point format,
 | 
			
		||||
//          used for efficient storage and transport.
 | 
			
		||||
//     URL: https://github.com/RobTillaart/float16
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#define FLOAT16_LIB_VERSION (F("0.1.8"))
 | 
			
		||||
 | 
			
		||||
// typedef uint16_t _fp16;
 | 
			
		||||
 | 
			
		||||
class float16 {
 | 
			
		||||
public:
 | 
			
		||||
  //  Constructors
 | 
			
		||||
  float16(void) { _value = 0x0000; };
 | 
			
		||||
  float16(float f);
 | 
			
		||||
  float16(const float16 &f) { _value = f._value; };
 | 
			
		||||
 | 
			
		||||
  //  Conversion
 | 
			
		||||
  float toFloat(void) const;
 | 
			
		||||
  //  access the 2 byte representation.
 | 
			
		||||
  uint16_t getBinary() { return _value; };
 | 
			
		||||
  void setBinary(uint16_t u) { _value = u; };
 | 
			
		||||
 | 
			
		||||
  //  Printable
 | 
			
		||||
  // size_t printTo(Print &p) const;
 | 
			
		||||
  void setDecimals(uint8_t d) { _decimals = d; };
 | 
			
		||||
  uint8_t getDecimals() { return _decimals; };
 | 
			
		||||
 | 
			
		||||
  //  equalities
 | 
			
		||||
  bool operator==(const float16 &f);
 | 
			
		||||
  bool operator!=(const float16 &f);
 | 
			
		||||
 | 
			
		||||
  bool operator>(const float16 &f);
 | 
			
		||||
  bool operator>=(const float16 &f);
 | 
			
		||||
  bool operator<(const float16 &f);
 | 
			
		||||
  bool operator<=(const float16 &f);
 | 
			
		||||
 | 
			
		||||
  //  negation
 | 
			
		||||
  float16 operator-();
 | 
			
		||||
 | 
			
		||||
  //  basic math
 | 
			
		||||
  float16 operator+(const float16 &f);
 | 
			
		||||
  float16 operator-(const float16 &f);
 | 
			
		||||
  float16 operator*(const float16 &f);
 | 
			
		||||
  float16 operator/(const float16 &f);
 | 
			
		||||
 | 
			
		||||
  float16 &operator+=(const float16 &f);
 | 
			
		||||
  float16 &operator-=(const float16 &f);
 | 
			
		||||
  float16 &operator*=(const float16 &f);
 | 
			
		||||
  float16 &operator/=(const float16 &f);
 | 
			
		||||
 | 
			
		||||
  //  math helper functions
 | 
			
		||||
  int sign(); //  1 = positive   0 = zero   -1 = negative.
 | 
			
		||||
  bool isZero();
 | 
			
		||||
  bool isNaN();
 | 
			
		||||
  bool isInf();
 | 
			
		||||
 | 
			
		||||
  //  CORE CONVERSION
 | 
			
		||||
  //  should be private but for testing...
 | 
			
		||||
  float f16tof32(uint16_t) const;
 | 
			
		||||
  uint16_t f32tof16(float) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  uint8_t _decimals = 4;
 | 
			
		||||
  uint16_t _value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//  -- END OF FILE --
 | 
			
		||||
@ -1,241 +0,0 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include "gtest/gtest.h"
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Construct) {
 | 
			
		||||
  float angle = 0.0F;
 | 
			
		||||
  Angle16 a = Angle16::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = -180.0F;
 | 
			
		||||
  a = Angle16::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 270.0F;
 | 
			
		||||
  a = Angle16::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -90);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Negate) {
 | 
			
		||||
  float angle = 0;
 | 
			
		||||
  Angle16 a = Angle16::Degrees(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 90.0F;
 | 
			
		||||
  a = Angle16::Degrees(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -angle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Subtract) {
 | 
			
		||||
  Angle16 a = Angle16::Degrees(0);
 | 
			
		||||
  Angle16 b = Angle16::Degrees(45.0F);
 | 
			
		||||
  Angle16 r = a - b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -45);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Add) {
 | 
			
		||||
  Angle16 a = Angle16::Degrees(-45);
 | 
			
		||||
  Angle16 b = Angle16::Degrees(45.0F);
 | 
			
		||||
  Angle16 r = a + b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Compare) {
 | 
			
		||||
  Angle16 a = Angle16::Degrees(45);
 | 
			
		||||
  bool r = false;
 | 
			
		||||
 | 
			
		||||
  r = a > Angle16::Degrees(0);
 | 
			
		||||
  EXPECT_TRUE(r) << "45 > 0";
 | 
			
		||||
 | 
			
		||||
  r = a > Angle16::Degrees(90);
 | 
			
		||||
  EXPECT_FALSE(r) << "45 > 90";
 | 
			
		||||
 | 
			
		||||
  r = a > Angle16::Degrees(-90);
 | 
			
		||||
  EXPECT_TRUE(r) << "45 > -90";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Normalize) {
 | 
			
		||||
  Angle16 r = Angle16();
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Normalize(Angle16::Degrees(90.0f));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Normalize(Angle16::Degrees(-90));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Normalize(Angle16::Degrees(270));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Normalize(Angle16::Degrees(270 + 360));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Normalize(Angle16::Degrees(-270));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Normalize(Angle16::Degrees(-270 - 360));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Normalize(Angle16::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0";
 | 
			
		||||
 | 
			
		||||
  if (false) {  // std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    // Infinites are not supported
 | 
			
		||||
    r = Angle16::Normalize(Angle16::Degrees(FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle16::Normalize(Angle16::Degrees(-FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Clamp) {
 | 
			
		||||
  Angle16 r = Angle16();
 | 
			
		||||
 | 
			
		||||
  // Clamp(1, 0, 2) will fail because Angle16 does not have enough resolution
 | 
			
		||||
  // for this. Instead we use Clamp(10, 0, 20) etc.
 | 
			
		||||
  r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(0),
 | 
			
		||||
                     Angle16::Degrees(20));
 | 
			
		||||
  EXPECT_NEAR(r.InDegrees(), 10, 1.0e-2) << "Clamp 10 0 20";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Clamp(Angle16::Degrees(-10), Angle16::Degrees(0),
 | 
			
		||||
                     Angle16::Degrees(20));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -10 0 20";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Clamp(Angle16::Degrees(30), Angle16::Degrees(0),
 | 
			
		||||
                     Angle16::Degrees(20));
 | 
			
		||||
  EXPECT_NEAR(r.InDegrees(), 20, 1.0e-2) << "Clamp 30 0 20";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(0),
 | 
			
		||||
                     Angle16::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 10 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Clamp(Angle16::Degrees(0), Angle16::Degrees(0),
 | 
			
		||||
                     Angle16::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::Clamp(Angle16::Degrees(0), Angle16::Degrees(10),
 | 
			
		||||
                     Angle16::Degrees(-10));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 10 -10";
 | 
			
		||||
 | 
			
		||||
  if (false) {  // std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    // Infinites are not supported
 | 
			
		||||
    r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(0),
 | 
			
		||||
                       Angle16::Degrees(FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_NEAR(r.InDegrees(), 10, 1.0e-2) << "Clamp 1 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle16::Clamp(Angle16::Degrees(10), Angle16::Degrees(-FLOAT_INFINITY),
 | 
			
		||||
                       Angle16::Degrees(10));
 | 
			
		||||
    EXPECT_NEAR(r.InDegrees(), 10, 1.0e-2) << "Clamp 1 -INFINITY 1";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TEST(Angle16, Difference) {
 | 
			
		||||
//   Angle16 r = 0;
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(0, 90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90";
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(0, -90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90";
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(0, 270);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270";
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(0, -270);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270";
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(90, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0";
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(-90, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0";
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(0, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0";
 | 
			
		||||
 | 
			
		||||
//   r = Angle16::Difference(90, 90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90";
 | 
			
		||||
 | 
			
		||||
//   if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
//     r = Angle16::Difference(0, INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
//     r = Angle16::Difference(0, -INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY";
 | 
			
		||||
 | 
			
		||||
//     r = Angle16::Difference(-INFINITY, INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY
 | 
			
		||||
//     INFINITY";
 | 
			
		||||
//   }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, MoveTowards) {
 | 
			
		||||
  Angle16 r = Angle16();
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 30);
 | 
			
		||||
  EXPECT_NEAR(r.InDegrees(), 30, 1.0e-2) << "MoveTowards 0 90 30";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), 180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 -90 -180";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90), -270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90), 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(0), 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(0), 30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30";
 | 
			
		||||
 | 
			
		||||
  if (false) {  // std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    // infinites are not supported
 | 
			
		||||
    r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(90),
 | 
			
		||||
                             FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle16::MoveTowards(Angle16::Degrees(0),
 | 
			
		||||
                             Angle16::Degrees(FLOAT_INFINITY), 30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30";
 | 
			
		||||
 | 
			
		||||
    r = Angle16::MoveTowards(Angle16::Degrees(0), Angle16::Degrees(-90),
 | 
			
		||||
                             -FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY)
 | 
			
		||||
        << "MoveTowards 0 -90 -FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle16::MoveTowards(Angle16::Degrees(0),
 | 
			
		||||
                             Angle16::Degrees(-FLOAT_INFINITY), -30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,241 +0,0 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Construct) {
 | 
			
		||||
  float angle = 0.0F;
 | 
			
		||||
  Angle8 a = Angle8::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = -180.0F;
 | 
			
		||||
  a = Angle8::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 270.0F;
 | 
			
		||||
  a = Angle8::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -90);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Negate) {
 | 
			
		||||
  float angle = 0;
 | 
			
		||||
  Angle8 a = Angle8::Degrees(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 90.0F;
 | 
			
		||||
  a = Angle8::Degrees(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -angle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Add) {
 | 
			
		||||
  Angle8 a = Angle8::Degrees(-45);
 | 
			
		||||
  Angle8 b = Angle8::Degrees(45.0F);
 | 
			
		||||
  Angle8 r = a + b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Subtract) {
 | 
			
		||||
  Angle8 a = Angle8::Degrees(0);
 | 
			
		||||
  Angle8 b = Angle8::Degrees(45.0F);
 | 
			
		||||
  Angle8 r = a - b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -45);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Compare) {
 | 
			
		||||
  Angle8 a = Angle8::Degrees(45);
 | 
			
		||||
  bool r = false;
 | 
			
		||||
 | 
			
		||||
  r = a > Angle8::Degrees(0);
 | 
			
		||||
  EXPECT_TRUE(r) << "45 > 0";
 | 
			
		||||
 | 
			
		||||
  r = a > Angle8::Degrees(90);
 | 
			
		||||
  EXPECT_FALSE(r) << "45 > 90";
 | 
			
		||||
 | 
			
		||||
  r = a > Angle8::Degrees(-90);
 | 
			
		||||
  EXPECT_TRUE(r) << "45 > -90";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Normalize) {
 | 
			
		||||
  Angle8 r = Angle8();
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Normalize(Angle8::Degrees(90.0f));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Normalize(Angle8::Degrees(-90));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Normalize(Angle8::Degrees(270));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Normalize(Angle8::Degrees(270 + 360));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Normalize(Angle8::Degrees(-270));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Normalize(Angle8::Degrees(-270 - 360));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Normalize(Angle8::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0";
 | 
			
		||||
 | 
			
		||||
  if (false) {  // std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    // Infinites are not supported
 | 
			
		||||
    r = Angle8::Normalize(Angle8::Degrees(FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle8::Normalize(Angle8::Degrees(-FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Clamp) {
 | 
			
		||||
  Angle8 r = Angle8();
 | 
			
		||||
 | 
			
		||||
  // Clamp(1, 0, 2) will fail because Angle8 does not have enough resolution for
 | 
			
		||||
  // this. Instead we use Clamp(10, 0, 20) etc.
 | 
			
		||||
  r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0),
 | 
			
		||||
                    Angle8::Degrees(20));
 | 
			
		||||
  EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 10 0 20";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Clamp(Angle8::Degrees(-10), Angle8::Degrees(0),
 | 
			
		||||
                    Angle8::Degrees(20));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -10 0 20";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Clamp(Angle8::Degrees(30), Angle8::Degrees(0),
 | 
			
		||||
                    Angle8::Degrees(20));
 | 
			
		||||
  EXPECT_NEAR(r.InDegrees(), 20, 1.0e-0) << "Clamp 30 0 20";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0),
 | 
			
		||||
                    Angle8::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 10 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(0), Angle8::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::Clamp(Angle8::Degrees(0), Angle8::Degrees(10),
 | 
			
		||||
                    Angle8::Degrees(-10));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 10 -10";
 | 
			
		||||
 | 
			
		||||
  if (false) {  // std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    // Infinites are not supported
 | 
			
		||||
    r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(0),
 | 
			
		||||
                      Angle8::Degrees(FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle8::Clamp(Angle8::Degrees(10), Angle8::Degrees(-FLOAT_INFINITY),
 | 
			
		||||
                      Angle8::Degrees(10));
 | 
			
		||||
    EXPECT_NEAR(r.InDegrees(), 10, 1.0e-0) << "Clamp 1 -INFINITY 1";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TEST(Angle8, Difference) {
 | 
			
		||||
//   Angle8 r = 0;
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(0, 90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90";
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(0, -90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90";
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(0, 270);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270";
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(0, -270);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270";
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(90, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0";
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(-90, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0";
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(0, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0";
 | 
			
		||||
 | 
			
		||||
//   r = Angle8::Difference(90, 90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90";
 | 
			
		||||
 | 
			
		||||
//   if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
//     r = Angle8::Difference(0, INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
//     r = Angle8::Difference(0, -INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY";
 | 
			
		||||
 | 
			
		||||
//     r = Angle8::Difference(-INFINITY, INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY
 | 
			
		||||
//     INFINITY";
 | 
			
		||||
//   }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, MoveTowards) {
 | 
			
		||||
  Angle8 r = Angle8();
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 30);
 | 
			
		||||
  EXPECT_NEAR(r.InDegrees(), 30, 1.0e-0) << "MoveTowards 0 90 30";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), 180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 -90 -180";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90), -270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90), 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(0), 30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30";
 | 
			
		||||
 | 
			
		||||
  if (false) {  // std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    // infinites are not supported
 | 
			
		||||
    r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(90),
 | 
			
		||||
                            FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(FLOAT_INFINITY),
 | 
			
		||||
                            30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30";
 | 
			
		||||
 | 
			
		||||
    r = Angle8::MoveTowards(Angle8::Degrees(0), Angle8::Degrees(-90),
 | 
			
		||||
                            -FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY)
 | 
			
		||||
        << "MoveTowards 0 -90 -FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle8::MoveTowards(Angle8::Degrees(0),
 | 
			
		||||
                            Angle8::Degrees(-FLOAT_INFINITY), -30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,249 +0,0 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, Construct) {
 | 
			
		||||
  float angle = 0.0F;
 | 
			
		||||
  AngleSingle a = AngleSingle::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = -180.0F;
 | 
			
		||||
  a = AngleSingle::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 270.0F;
 | 
			
		||||
  a = AngleSingle::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -90);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, Negate) {
 | 
			
		||||
  float angle = 0;
 | 
			
		||||
  AngleSingle a = AngleSingle::Degrees(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 90.0F;
 | 
			
		||||
  a = AngleSingle::Degrees(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -angle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, Add) {
 | 
			
		||||
  AngleSingle a = AngleSingle::Degrees(-45);
 | 
			
		||||
  AngleSingle b = AngleSingle::Degrees(45.0F);
 | 
			
		||||
  AngleSingle r = a + b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, Subtract) {
 | 
			
		||||
  AngleSingle a = AngleSingle::Degrees(0);
 | 
			
		||||
  AngleSingle b = AngleSingle::Degrees(45.0F);
 | 
			
		||||
  AngleSingle r = a - b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -45);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, Compare) {
 | 
			
		||||
  AngleSingle a = AngleSingle::Degrees(45);
 | 
			
		||||
  bool r = false;
 | 
			
		||||
 | 
			
		||||
  r = a > AngleSingle::Degrees(0);
 | 
			
		||||
  EXPECT_TRUE(r) << "45 > 0";
 | 
			
		||||
 | 
			
		||||
  r = a > AngleSingle::Degrees(90);
 | 
			
		||||
  EXPECT_FALSE(r) << "45 > 90";
 | 
			
		||||
 | 
			
		||||
  r = a > AngleSingle::Degrees(-90);
 | 
			
		||||
  EXPECT_TRUE(r) << "45 > -90";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, Normalize) {
 | 
			
		||||
  AngleSingle r = AngleSingle();
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Normalize(AngleSingle::Degrees(90.0f));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize 90";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Normalize(AngleSingle::Degrees(-90));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize -90";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Normalize(AngleSingle::Degrees(270));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Normalize(AngleSingle::Degrees(270 + 360));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Normalize 270+360";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Normalize(AngleSingle::Degrees(-270));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Normalize(AngleSingle::Degrees(-270 - 360));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Normalize -270-360";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Normalize(AngleSingle::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Normalize 0";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = AngleSingle::Normalize(AngleSingle::Degrees(FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = AngleSingle::Normalize(AngleSingle::Degrees(-FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), -FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, Clamp) {
 | 
			
		||||
  AngleSingle r = AngleSingle();
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Clamp(AngleSingle::Degrees(1), AngleSingle::Degrees(0),
 | 
			
		||||
                         AngleSingle::Degrees(2));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 1) << "Clamp 1 0 2";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Clamp(AngleSingle::Degrees(-1), AngleSingle::Degrees(0),
 | 
			
		||||
                         AngleSingle::Degrees(2));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp -1 0 2";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Clamp(AngleSingle::Degrees(3), AngleSingle::Degrees(0),
 | 
			
		||||
                         AngleSingle::Degrees(2));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 2) << "Clamp 3 0 2";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Clamp(AngleSingle::Degrees(1), AngleSingle::Degrees(0),
 | 
			
		||||
                         AngleSingle::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 1 0 0";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Clamp(AngleSingle::Degrees(0), AngleSingle::Degrees(0),
 | 
			
		||||
                         AngleSingle::Degrees(0));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::Clamp(AngleSingle::Degrees(0), AngleSingle::Degrees(1),
 | 
			
		||||
                         AngleSingle::Degrees(-1));
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Clamp 0 1 -1";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = AngleSingle::Clamp(AngleSingle::Degrees(1), AngleSingle::Degrees(0),
 | 
			
		||||
                           AngleSingle::Degrees(FLOAT_INFINITY));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 1) << "Clamp 1 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = AngleSingle::Clamp(AngleSingle::Degrees(1),
 | 
			
		||||
                           AngleSingle::Degrees(-FLOAT_INFINITY),
 | 
			
		||||
                           AngleSingle::Degrees(1));
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 1) << "Clamp 1 -INFINITY 1";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TEST(AngleSingle, Difference) {
 | 
			
		||||
//   AngleSingle r = 0;
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(0, 90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 90";
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(0, -90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 -90";
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(0, 270);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 0 270";
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(0, -270);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference 0 -270";
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(90, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), -90) << "Difference 90 0";
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(-90, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "Difference -90 0";
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(0, 0);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 0 0";
 | 
			
		||||
 | 
			
		||||
//   r = AngleSingle::Difference(90, 90);
 | 
			
		||||
//   EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "Difference 90 90";
 | 
			
		||||
 | 
			
		||||
//   if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
//     r = AngleSingle::Difference(0, INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
//     r = AngleSingle::Difference(0, -INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), -INFINITY) << "Difference 0 -INFINITY";
 | 
			
		||||
 | 
			
		||||
//     r = AngleSingle::Difference(-INFINITY, INFINITY);
 | 
			
		||||
//     EXPECT_FLOAT_EQ(r.InDegrees(), INFINITY) << "Difference -INFINITY
 | 
			
		||||
//     INFINITY";
 | 
			
		||||
//   }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
TEST(AngleSingle, MoveTowards) {
 | 
			
		||||
  AngleSingle r = AngleSingle();
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(90), 30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 90 30";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(90), 90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 90";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(90), 180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 180";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(90), 270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 270";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(90), -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 -30";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(-90), -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -30";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(-90), -90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -90";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(-90), -180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -180";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(-90), -270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -270";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                               AngleSingle::Degrees(90), 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 90 0";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), AngleSingle::Degrees(0),
 | 
			
		||||
                               0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = AngleSingle::MoveTowards(AngleSingle::Degrees(0), AngleSingle::Degrees(0),
 | 
			
		||||
                               30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 0 30";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                                 AngleSingle::Degrees(90), FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 90) << "MoveTowards 0 90 FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                                 AngleSingle::Degrees(FLOAT_INFINITY), 30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 30) << "MoveTowards 0 FLOAT_INFINITY 30";
 | 
			
		||||
 | 
			
		||||
    r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                                 AngleSingle::Degrees(-90), -FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -90 -FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = AngleSingle::MoveTowards(AngleSingle::Degrees(0),
 | 
			
		||||
                                 AngleSingle::Degrees(-FLOAT_INFINITY), -30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.InDegrees(), 0) << "MoveTowards 0 -FLOAT_INFINITY -30";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										168
									
								
								LinearAlgebra/test/Angle_test.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								LinearAlgebra/test/Angle_test.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,168 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(Angle, Normalize) {
 | 
			
		||||
  Angle r = 0;
 | 
			
		||||
 | 
			
		||||
  r = Angle::Normalize(90.0f);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "Normalize 90";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Normalize(-90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -90) << "Normalize -90";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Normalize(270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -90) << "Normalize 270";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Normalize(270 + 360);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -90) << "Normalize 270+360";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Normalize(-270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "Normalize -270";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Normalize(-270 - 360);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "Normalize -270-360";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Normalize(0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "Normalize 0";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = Angle::Normalize(FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle::Normalize(-FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), -FLOAT_INFINITY) << "Normalize INFINITY";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle, Clamp) {
 | 
			
		||||
  Angle r = 0;
 | 
			
		||||
 | 
			
		||||
  r = Angle::Clamp(1, 0, 2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 1) << "Clamp 1 0 2";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Clamp(-1, 0, 2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "Clamp -1 0 2";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Clamp(3, 0, 2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 2) << "Clamp 3 0 2";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Clamp(1, 0, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "Clamp 1 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Clamp(0, 0, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "Clamp 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Clamp(0, 1, -1);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 1) << "Clamp 0 1 -1";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = Angle::Clamp(1, 0, FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), 1) << "Clamp 1 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle::Clamp(1, -FLOAT_INFINITY, 1);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), 1) << "Clamp 1 -INFINITY 1";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle, Difference) {
 | 
			
		||||
  Angle r = 0;
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(0, 90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "Difference 0 90";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(0, -90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -90) << "Difference 0 -90";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(0, 270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -90) << "Difference 0 270";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(0, -270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "Difference 0 -270";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(90, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -90) << "Difference 90 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(-90, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "Difference -90 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(0, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "Difference 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle::Difference(90, 90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "Difference 90 90";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = Angle::Difference(0, INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), INFINITY) << "Difference 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle::Difference(0, -INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), -INFINITY) << "Difference 0 -INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle::Difference(-INFINITY, INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), INFINITY) << "Difference -INFINITY INFINITY";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle, MoveTowards) {
 | 
			
		||||
  Angle r = 0;
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 90, 30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 30) << "MoveTowards 0 90 30";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 90, 90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "MoveTowards 0 90 90";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 90, 180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "MoveTowards 0 90 180";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 90, 270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "MoveTowards 0 90 270";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 90, -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -30) << "MoveTowards 0 90 -30";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, -90, -30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 30) << "MoveTowards 0 -90 -30";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, -90, -90);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "MoveTowards 0 -90 -90";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, -90, -180);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 180) << "MoveTowards 0 -90 -180";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, -90, -270);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 270) << "MoveTowards 0 -90 -270";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 90, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "MoveTowards 0 90 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 0, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "MoveTowards 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Angle::MoveTowards(0, 0, 30);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0) << "MoveTowards 0 0 30";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = Angle::MoveTowards(0, 90, FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), 90) << "MoveTowards 0 90 FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle::MoveTowards(0, FLOAT_INFINITY, 30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), 30) << "MoveTowards 0 FLOAT_INFINITY 30";
 | 
			
		||||
 | 
			
		||||
    r = Angle::MoveTowards(0, -90, -FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), FLOAT_INFINITY)
 | 
			
		||||
        << "MoveTowards 0 -90 -FLOAT_INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Angle::MoveTowards(0, -FLOAT_INFINITY, -30);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r.ToFloat(), 30) << "MoveTowards 0 -FLOAT_INFINITY -30";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,58 +0,0 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Direction.h"
 | 
			
		||||
 | 
			
		||||
using namespace LinearAlgebra;
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(Direction16, Compare) {
 | 
			
		||||
  Direction16 d = Direction16::Degrees(45, 135);
 | 
			
		||||
  bool r;
 | 
			
		||||
  r = (d == Direction16(Angle16::Degrees(45), Angle16::Degrees(135)));
 | 
			
		||||
  EXPECT_TRUE(r) << "45,135 == 45, 135";
 | 
			
		||||
 | 
			
		||||
  r = (d ==
 | 
			
		||||
       Direction16(Angle16::Degrees(45 + 360), Angle16::Degrees(135 - 360)));
 | 
			
		||||
  EXPECT_TRUE(r) << "45+360, 135-360 == 45, 135";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Direction16, Inverse) {
 | 
			
		||||
  Direction16 d;
 | 
			
		||||
  Direction16 r;
 | 
			
		||||
 | 
			
		||||
  d = Direction16::Degrees(45, 135);
 | 
			
		||||
  r = -d;
 | 
			
		||||
  EXPECT_EQ(r, Direction16::Degrees(-135, -135)) << "-(45, 135)";
 | 
			
		||||
 | 
			
		||||
  d = Direction16::Degrees(-45, -135);
 | 
			
		||||
  r = -d;
 | 
			
		||||
  EXPECT_EQ(r, Direction16::Degrees(135, 135)) << "-(-45, -135)";
 | 
			
		||||
 | 
			
		||||
  d = Direction16::Degrees(0, 0);
 | 
			
		||||
  r = -d;
 | 
			
		||||
  EXPECT_EQ(r, Direction16::Degrees(180, 0)) << "-(0, 0)";
 | 
			
		||||
 | 
			
		||||
  d = Direction16::Degrees(0, 45);
 | 
			
		||||
  r = -d;
 | 
			
		||||
  EXPECT_EQ(r, Direction16::Degrees(180, -45)) << "-(0, 45)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Direction16, Equality) {
 | 
			
		||||
  Direction16 d;
 | 
			
		||||
  d = Direction16::Degrees(135, 45);
 | 
			
		||||
  EXPECT_EQ(d, Direction16::Degrees(135, 45)) << "(135, 45) == (135, 45)";
 | 
			
		||||
  EXPECT_EQ(d, Direction16::Degrees(135 + 360, 45))
 | 
			
		||||
      << "(135, 45) == (135 + 360, 45) ";
 | 
			
		||||
  EXPECT_EQ(d, Direction16::Degrees(135 - 360, 45))
 | 
			
		||||
      << "(135, 135) == (135 - 360, 45) ";
 | 
			
		||||
 | 
			
		||||
  d = Direction16::Degrees(0, 45 + 180);
 | 
			
		||||
  EXPECT_EQ(d, Direction16::Degrees(180, -45)) << "(0, 45+180) == (180, -45)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,82 +1,79 @@
 | 
			
		||||
/*
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Angle.h"
 | 
			
		||||
// #include "Angle16.h"
 | 
			
		||||
// #include "Angle8.h"
 | 
			
		||||
#include "Angle16.h"
 | 
			
		||||
#include "Angle8.h"
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Construct) {
 | 
			
		||||
  float angle = 0.0F;
 | 
			
		||||
  Angle8 a = Angle8::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
  Angle8 a = Angle8(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.ToFloat(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = -180.0F;
 | 
			
		||||
  a = Angle8::Degrees(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
  a = Angle8(angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.ToFloat(), angle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Negate) {
 | 
			
		||||
  float angle = 0;
 | 
			
		||||
  Angle8 a = Angle8::Degrees(angle);
 | 
			
		||||
  Angle8 a = Angle8(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.ToFloat(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 90.0F;
 | 
			
		||||
  a = Angle8::Degrees(angle);
 | 
			
		||||
  a = Angle8(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.ToFloat(), -angle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Add) {
 | 
			
		||||
  Angle8 a = Angle8::Degrees(-45);
 | 
			
		||||
  Angle8 b = Angle8::Degrees(45.0F);
 | 
			
		||||
  Angle8 a = Angle8(-45);
 | 
			
		||||
  Angle8 b = Angle8(45.0F);
 | 
			
		||||
  Angle8 r = a + b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle8, Subtract) {
 | 
			
		||||
  Angle8 a = Angle8::Degrees(0);
 | 
			
		||||
  Angle8 b = Angle8::Degrees(45.0F);
 | 
			
		||||
  Angle8 a = Angle8(0);
 | 
			
		||||
  Angle8 b = Angle8(45.0F);
 | 
			
		||||
  Angle8 r = a - b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -45);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -45);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Construct) {
 | 
			
		||||
  Angle16 a = Angle16::Degrees(0.0F);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), 0);
 | 
			
		||||
  Angle16 a = Angle16(0.0F);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.ToFloat(), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Negate) {
 | 
			
		||||
  float angle = 0;
 | 
			
		||||
  Angle16 a = Angle16::Degrees(angle);
 | 
			
		||||
  Angle16 a = Angle16(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.ToFloat(), angle);
 | 
			
		||||
 | 
			
		||||
  angle = 90.0F;
 | 
			
		||||
  a = Angle16::Degrees(angle);
 | 
			
		||||
  a = Angle16(angle);
 | 
			
		||||
  a = -a;
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.InDegrees(), -angle);
 | 
			
		||||
  EXPECT_FLOAT_EQ(a.ToFloat(), -angle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Subtract) {
 | 
			
		||||
  Angle16 a = Angle16::Degrees(0);
 | 
			
		||||
  Angle16 b = Angle16::Degrees(45.0F);
 | 
			
		||||
  Angle16 a = Angle16(0);
 | 
			
		||||
  Angle16 b = Angle16(45.0F);
 | 
			
		||||
  Angle16 r = a - b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), -45);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), -45);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Angle16, Add) {
 | 
			
		||||
  Angle16 a = Angle16::Degrees(-45);
 | 
			
		||||
  Angle16 b = Angle16::Degrees(45.0F);
 | 
			
		||||
  Angle16 a = Angle16(-45);
 | 
			
		||||
  Angle16 b = Angle16(45.0F);
 | 
			
		||||
  Angle16 r = a + b;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.InDegrees(), 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.ToFloat(), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
*/
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,41 +1,41 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "FloatSingle.h"
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(FloatC, Clamp) {
 | 
			
		||||
  float r = 0;
 | 
			
		||||
	float r = 0;
 | 
			
		||||
 | 
			
		||||
  r = Float::Clamp(1, 0, 2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 2";
 | 
			
		||||
	r = Float::Clamp(1, 0, 2);
 | 
			
		||||
	EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 2";
 | 
			
		||||
 | 
			
		||||
  r = Float::Clamp(-1, 0, 2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r, 0) << "Clamp -1 0 2";
 | 
			
		||||
	r = Float::Clamp(-1, 0, 2);
 | 
			
		||||
	EXPECT_FLOAT_EQ(r, 0) << "Clamp -1 0 2";
 | 
			
		||||
 | 
			
		||||
  r = Float::Clamp(3, 0, 2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r, 2) << "Clamp 3 0 2";
 | 
			
		||||
	r = Float::Clamp(3, 0, 2);
 | 
			
		||||
	EXPECT_FLOAT_EQ(r, 2) << "Clamp 3 0 2";
 | 
			
		||||
 | 
			
		||||
  r = Float::Clamp(1, 0, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r, 0) << "Clamp 1 0 0";
 | 
			
		||||
	r = Float::Clamp(1, 0, 0);
 | 
			
		||||
	EXPECT_FLOAT_EQ(r, 0) << "Clamp 1 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Float::Clamp(0, 0, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r, 0) << "Clamp 0 0 0";
 | 
			
		||||
	r = Float::Clamp(0, 0, 0);
 | 
			
		||||
	EXPECT_FLOAT_EQ(r, 0) << "Clamp 0 0 0";
 | 
			
		||||
 | 
			
		||||
  r = Float::Clamp(0, 1, -1);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r, 0) << "Clamp 0 1 -1";
 | 
			
		||||
	r = Float::Clamp(0, 1, -1);
 | 
			
		||||
	EXPECT_FLOAT_EQ(r, 1) << "Clamp 0 1 -1";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    r = Float::Clamp(1, 0, FLOAT_INFINITY);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 INFINITY";
 | 
			
		||||
	if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
		r = Float::Clamp(1, 0, FLOAT_INFINITY);
 | 
			
		||||
		EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 0 INFINITY";
 | 
			
		||||
 | 
			
		||||
    r = Float::Clamp(1, -FLOAT_INFINITY, 1);
 | 
			
		||||
    EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 -INFINITY 1";
 | 
			
		||||
  }
 | 
			
		||||
		r = Float::Clamp(1, -FLOAT_INFINITY, 1);
 | 
			
		||||
		EXPECT_FLOAT_EQ(r, 1) << "Clamp 1 -INFINITY 1";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,90 +1,10 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#include "Matrix.h"
 | 
			
		||||
 | 
			
		||||
TEST(Matrix2, Zero) {
 | 
			
		||||
      // Test case 1: 2x2 zero matrix
 | 
			
		||||
      Matrix2 zeroMatrix = Matrix2::Zero(2, 2);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nRows == 2);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nCols == 2);
 | 
			
		||||
      for (int i = 0; i < zeroMatrix.nValues; ++i) {
 | 
			
		||||
        EXPECT_TRUE(zeroMatrix.data[i] == 0.0f);
 | 
			
		||||
      }
 | 
			
		||||
      std::cout << "Test case 1 passed: 2x2 zero matrix\n";
 | 
			
		||||
  
 | 
			
		||||
      // Test case 2: 3x3 zero matrix
 | 
			
		||||
      zeroMatrix = Matrix2::Zero(3, 3);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nRows == 3);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nCols == 3);
 | 
			
		||||
      for (int i = 0; i < zeroMatrix.nValues; ++i) {
 | 
			
		||||
        EXPECT_TRUE(zeroMatrix.data[i] == 0.0f);
 | 
			
		||||
      }
 | 
			
		||||
      std::cout << "Test case 2 passed: 3x3 zero matrix\n";
 | 
			
		||||
  
 | 
			
		||||
      // Test case 3: 1x1 zero matrix
 | 
			
		||||
      zeroMatrix = Matrix2::Zero(1, 1);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nRows == 1);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nCols == 1);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.data[0] == 0.0f);
 | 
			
		||||
      std::cout << "Test case 3 passed: 1x1 zero matrix\n";
 | 
			
		||||
  
 | 
			
		||||
      // Test case 4: 0x0 matrix (edge case)
 | 
			
		||||
      zeroMatrix = Matrix2::Zero(0, 0);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nRows == 0);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.nCols == 0);
 | 
			
		||||
      EXPECT_TRUE(zeroMatrix.data == nullptr);
 | 
			
		||||
      std::cout << "Test case 4 passed: 0x0 matrix\n";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Matrix2, Multiplication) {
 | 
			
		||||
  // Test 1: Multiplying two 2x2 matrices
 | 
			
		||||
  float dataA[] = {1, 2, 3, 4};
 | 
			
		||||
  float dataB[] = {5, 6, 7, 8};
 | 
			
		||||
  Matrix2 A(dataA, 2, 2);
 | 
			
		||||
  Matrix2 B(dataB, 2, 2);
 | 
			
		||||
 | 
			
		||||
  Matrix2 result = A * B;
 | 
			
		||||
 | 
			
		||||
  float expectedData[] = {19, 22, 43, 50};
 | 
			
		||||
  for (int i = 0; i < 4; ++i) 
 | 
			
		||||
    EXPECT_TRUE(result.data[i] == expectedData[i]);  
 | 
			
		||||
  std::cout << "Test 1 passed: 2x2 matrix multiplication.\n";
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
  // Test 2: Multiplying a 3x2 matrix with a 2x3 matrix
 | 
			
		||||
  float dataC[] = {1, 2, 3, 4, 5, 6};
 | 
			
		||||
  float dataD[] = {7, 8, 9, 10, 11, 12};
 | 
			
		||||
  Matrix2 C(dataC, 3, 2);
 | 
			
		||||
  Matrix2 D(dataD, 2, 3);
 | 
			
		||||
 | 
			
		||||
  Matrix2 result2 = C * D;
 | 
			
		||||
 | 
			
		||||
  float expectedData2[] = {27, 30, 33, 61, 68, 75, 95, 106, 117};
 | 
			
		||||
  for (int i = 0; i < 9; ++i)
 | 
			
		||||
    EXPECT_TRUE(result2.data[i] == expectedData2[i]);
 | 
			
		||||
  std::cout << "Test 2 passed: 3x2 * 2x3 matrix multiplication.\n";
 | 
			
		||||
  
 | 
			
		||||
  // Test 3: Multiplying with a zero matrix
 | 
			
		||||
  Matrix2 zeroMatrix = Matrix2::Zero(2, 2);
 | 
			
		||||
  Matrix2 result3 = A * zeroMatrix;
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < 4; ++i)
 | 
			
		||||
    EXPECT_TRUE(result3.data[i] == 0);
 | 
			
		||||
  std::cout << "Test 3 passed: Multiplication with zero matrix.\n";
 | 
			
		||||
  
 | 
			
		||||
  // Test 4: Multiplying with an identity matrix
 | 
			
		||||
  Matrix2 identityMatrix = Matrix2::Identity(2);
 | 
			
		||||
  Matrix2 result4 = A * identityMatrix;
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < 4; ++i)
 | 
			
		||||
    EXPECT_TRUE(result4.data[i] == A.data[i]);
 | 
			
		||||
  std::cout << "Test 4 passed: Multiplication with identity matrix.\n";
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(MatrixSingle, Init) {
 | 
			
		||||
  // zero
 | 
			
		||||
  MatrixOf<float> m0 = MatrixOf<float>(0, 0);
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Polar.h"
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
@ -11,116 +10,112 @@
 | 
			
		||||
 | 
			
		||||
TEST(Polar, FromVector2) {
 | 
			
		||||
  Vector2 v = Vector2(0, 1);
 | 
			
		||||
  PolarSingle p = PolarSingle::FromVector2(v);
 | 
			
		||||
  Polar p = Polar::FromVector2(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "s.angle 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), 0.0F) << "s.angle 0 0 1";
 | 
			
		||||
 | 
			
		||||
  v = Vector2(1, 0);
 | 
			
		||||
  p = PolarSingle::FromVector2(v);
 | 
			
		||||
  p = Polar::FromVector2(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), 90.0F) << "s.angle 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), 90.0F) << "s.angle 1 0";
 | 
			
		||||
 | 
			
		||||
  v = Vector2(-1, 1);
 | 
			
		||||
  p = PolarSingle::FromVector2(v);
 | 
			
		||||
  p = Polar::FromVector2(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, sqrt(2.0F)) << "p.distance -1 1";
 | 
			
		||||
  EXPECT_NEAR(p.angle.InDegrees(), -45.0F, 1.0e-05) << "s.angle -1 1";
 | 
			
		||||
  EXPECT_NEAR(p.angle.ToFloat(), -45.0F, 1.0e-05) << "s.angle -1 1";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, FromSpherical) {
 | 
			
		||||
  SphericalSingle s;
 | 
			
		||||
  PolarSingle p;
 | 
			
		||||
  Spherical s;
 | 
			
		||||
  Polar p;
 | 
			
		||||
 | 
			
		||||
  s = SphericalSingle(1, DirectionSingle::forward);
 | 
			
		||||
  p = PolarSingle::FromSpherical(s);
 | 
			
		||||
  s = Spherical(1, 0, 0);
 | 
			
		||||
  p = Polar::FromSpherical(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(1 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), 0.0F) << "p.angle FromSpherical(1 0 0)";
 | 
			
		||||
 | 
			
		||||
  s = SphericalSingle(1, AngleSingle::Degrees(45), AngleSingle::Degrees(0));
 | 
			
		||||
  p = PolarSingle::FromSpherical(s);
 | 
			
		||||
  s = Spherical(1, 45, 0);
 | 
			
		||||
  p = Polar::FromSpherical(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), 45.0F)
 | 
			
		||||
      << "p.angle FromSpherical(1 45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), 45.0F) << "p.angle FromSpherical(1 45 0)";
 | 
			
		||||
 | 
			
		||||
  s = SphericalSingle(1, AngleSingle::Degrees(-45), AngleSingle::Degrees(0));
 | 
			
		||||
  p = PolarSingle::FromSpherical(s);
 | 
			
		||||
  s = Spherical(1, -45, 0);
 | 
			
		||||
  p = Polar::FromSpherical(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), -45.0F)
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), -45.0F)
 | 
			
		||||
      << "p.angle FromSpherical(1 -45 0)";
 | 
			
		||||
 | 
			
		||||
  s = SphericalSingle(0, AngleSingle::Degrees(0), AngleSingle::Degrees(0));
 | 
			
		||||
  p = PolarSingle::FromSpherical(s);
 | 
			
		||||
  s = Spherical(0, 0, 0);
 | 
			
		||||
  p = Polar::FromSpherical(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 0.0F) << "p.distance FromSpherical(0 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(0 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), 0.0F) << "p.angle FromSpherical(0 0 0)";
 | 
			
		||||
 | 
			
		||||
  s = SphericalSingle(-1, AngleSingle::Degrees(0), AngleSingle::Degrees(0));
 | 
			
		||||
  p = PolarSingle::FromSpherical(s);
 | 
			
		||||
  s = Spherical(-1, 0, 0);
 | 
			
		||||
  p = Polar::FromSpherical(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 1.0F) << "p.distance FromSpherical(-1 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), -180.0F)
 | 
			
		||||
      << "p.angle FromSpherical(-1 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), 180.0F) << "p.angle FromSpherical(-1 0 0)";
 | 
			
		||||
 | 
			
		||||
  s = SphericalSingle(0, AngleSingle::Degrees(0), AngleSingle::Degrees(90));
 | 
			
		||||
  p = PolarSingle::FromSpherical(s);
 | 
			
		||||
  s = Spherical(0, 0, 90);
 | 
			
		||||
  p = Polar::FromSpherical(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.distance, 0.0F) << "p.distance FromSpherical(0 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.InDegrees(), 0.0F) << "p.angle FromSpherical(0 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(p.angle.ToFloat(), 0.0F) << "p.angle FromSpherical(0 0 90)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, Negation) {
 | 
			
		||||
  PolarSingle v = PolarSingle(2, AngleSingle::Degrees(45));
 | 
			
		||||
  PolarSingle r = PolarSingle::zero;
 | 
			
		||||
  Polar v = Polar(2, 45);
 | 
			
		||||
  Polar r = Polar::zero;
 | 
			
		||||
 | 
			
		||||
  r = -v;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, 2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.InDegrees(), -135);
 | 
			
		||||
  EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(-135)))
 | 
			
		||||
      << "Negate(2 45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.ToFloat(), -135);
 | 
			
		||||
  EXPECT_TRUE(r == Polar(2, -135)) << "Negate(2 45)";
 | 
			
		||||
 | 
			
		||||
  v = PolarSingle::Deg(2, -45);
 | 
			
		||||
  v = Polar(2, -45);
 | 
			
		||||
  r = -v;
 | 
			
		||||
  EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(135)))
 | 
			
		||||
      << "Negate(2 -45)";
 | 
			
		||||
  EXPECT_TRUE(r == Polar(2, 135)) << "Negate(2 -45)";
 | 
			
		||||
 | 
			
		||||
  v = PolarSingle::Degrees(2, 0);
 | 
			
		||||
  v = Polar(2, 0);
 | 
			
		||||
  r = -v;
 | 
			
		||||
  EXPECT_TRUE(r == PolarSingle(2, AngleSingle::Degrees(180))) << "Negate(2 0)";
 | 
			
		||||
  EXPECT_TRUE(r == Polar(2, 180)) << "Negate(2 0)";
 | 
			
		||||
 | 
			
		||||
  v = PolarSingle(0, AngleSingle::Degrees(0));
 | 
			
		||||
  v = Polar(0, 0);
 | 
			
		||||
  r = -v;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, 0.0f);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.InDegrees(), 0.0f);
 | 
			
		||||
  EXPECT_TRUE(r == PolarSingle(0, AngleSingle::Degrees(0))) << "Negate(0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.ToFloat(), 0.0f);
 | 
			
		||||
  EXPECT_TRUE(r == Polar(0, 0)) << "Negate(0 0)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, Subtraction) {
 | 
			
		||||
  PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
 | 
			
		||||
  PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90));
 | 
			
		||||
  PolarSingle r = PolarSingle::zero;
 | 
			
		||||
  Polar v1 = Polar(4, 45);
 | 
			
		||||
  Polar v2 = Polar(1, -90);
 | 
			
		||||
  Polar r = Polar::zero;
 | 
			
		||||
 | 
			
		||||
  r = v1 - v2;
 | 
			
		||||
  // don't know what to expect yet
 | 
			
		||||
 | 
			
		||||
  v2 = PolarSingle::zero;
 | 
			
		||||
  v2 = Polar::zero;
 | 
			
		||||
  r = v1 - v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Subtraction(0 0)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, Addition) {
 | 
			
		||||
  PolarSingle v1 = PolarSingle(1, AngleSingle::Degrees(45));
 | 
			
		||||
  PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90));
 | 
			
		||||
  PolarSingle r = PolarSingle::zero;
 | 
			
		||||
  Polar v1 = Polar(1, 45);
 | 
			
		||||
  Polar v2 = Polar(1, -90);
 | 
			
		||||
  Polar r = Polar::zero;
 | 
			
		||||
 | 
			
		||||
  r = v1 - v2;
 | 
			
		||||
  // don't know what to expect yet
 | 
			
		||||
 | 
			
		||||
  v2 = PolarSingle::zero;
 | 
			
		||||
  v2 = Polar::zero;
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0)";
 | 
			
		||||
 | 
			
		||||
@ -128,106 +123,51 @@ TEST(Polar, Addition) {
 | 
			
		||||
  r += v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0)";
 | 
			
		||||
 | 
			
		||||
  v2 = PolarSingle(1, AngleSingle::Degrees(-45));
 | 
			
		||||
  v2 = Polar(1, -45);
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(0 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.InDegrees(), 0) << "Addition(0 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.ToFloat(), 0) << "Addition(0 0 0)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, Scale_Multiply) {
 | 
			
		||||
  PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
 | 
			
		||||
  PolarSingle r = PolarSingle::zero;
 | 
			
		||||
  Polar v1 = Polar(4, 45);
 | 
			
		||||
  Polar r = Polar::zero;
 | 
			
		||||
 | 
			
		||||
  r = v1 * 2.0f;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance * 2) << "ScaleMult(4 45, 2)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.InDegrees(), v1.angle.InDegrees())
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.ToFloat(), v1.angle.ToFloat())
 | 
			
		||||
      << "ScaleMult(4 45, 2)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, Scale_Divide) {
 | 
			
		||||
  PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
 | 
			
		||||
  PolarSingle r = PolarSingle::zero;
 | 
			
		||||
  Polar v1 = Polar(4, 45);
 | 
			
		||||
  Polar r = Polar::zero;
 | 
			
		||||
 | 
			
		||||
  r = v1 / 2.0f;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance / 2) << "ScaleDiv(4 45, 2)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.InDegrees(), v1.angle.InDegrees())
 | 
			
		||||
      << "ScaleDiv(4 45, 2)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.ToFloat(), v1.angle.ToFloat()) << "ScaleDiv(4 45, 2)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, Distance) {
 | 
			
		||||
  PolarSingle v1 = PolarSingle(4, AngleSingle::Degrees(45));
 | 
			
		||||
  PolarSingle v2 = PolarSingle(1, AngleSingle::Degrees(-90));
 | 
			
		||||
  Polar v1 = Polar(4, 45);
 | 
			
		||||
  Polar v2 = Polar(1, -90);
 | 
			
		||||
  float d = 0;
 | 
			
		||||
 | 
			
		||||
  d = PolarSingle::Distance(v1, v2);
 | 
			
		||||
  d = Polar::Distance(v1, v2);
 | 
			
		||||
  // don't know what to expect yet
 | 
			
		||||
 | 
			
		||||
  v2 = PolarSingle::zero;
 | 
			
		||||
  d = PolarSingle::Distance(v1, v2);
 | 
			
		||||
  v2 = Polar::zero;
 | 
			
		||||
  d = Polar::Distance(v1, v2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(d, v1.distance) << "Distance(4 45, zero)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Polar, Rotate) {
 | 
			
		||||
  PolarSingle v = PolarSingle(4, AngleSingle::Degrees(45));
 | 
			
		||||
  PolarSingle r = PolarSingle::zero;
 | 
			
		||||
  Polar v = Polar(4, 45);
 | 
			
		||||
  Polar r = Polar::zero;
 | 
			
		||||
 | 
			
		||||
  r = PolarSingle::Rotate(v, AngleSingle::Degrees(45));
 | 
			
		||||
  r = Polar::Rotate(v, 45);
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v.distance) << "Rotate(4 45, 45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.InDegrees(), 90.0f) << "Rotate(4 45, 45)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Performance Test
 | 
			
		||||
TEST(PolarOfTest, PerformanceTest) {
 | 
			
		||||
  const int numIterations = 1000000; // Number of instances to test
 | 
			
		||||
  std::vector<PolarOf<float>> polarObjects;
 | 
			
		||||
 | 
			
		||||
  // Measure time for creating a large number of PolarOf objects
 | 
			
		||||
  auto start = std::chrono::high_resolution_clock::now();
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < numIterations; ++i) {
 | 
			
		||||
    float distance =
 | 
			
		||||
        static_cast<float>(rand() % 100); // Random distance from 0 to 100
 | 
			
		||||
    AngleOf<float> angle = AngleOf<float>::Degrees(
 | 
			
		||||
        static_cast<float>(rand() % 360)); // Random angle from 0 to 360 degrees
 | 
			
		||||
    PolarOf<float> p = PolarOf<float>(distance, angle);
 | 
			
		||||
    polarObjects.emplace_back(p); // Create and store the object
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto end = std::chrono::high_resolution_clock::now();
 | 
			
		||||
  std::chrono::duration<double> duration = end - start;
 | 
			
		||||
  std::cout << "Time to construct " << numIterations
 | 
			
		||||
            << " PolarOf objects: " << duration.count() << " seconds."
 | 
			
		||||
            << std::endl;
 | 
			
		||||
 | 
			
		||||
  // Test completion with a message
 | 
			
		||||
  ASSERT_GE(duration.count(), 0); // Ensure duration is non-negative
 | 
			
		||||
 | 
			
		||||
  // Assert that the duration is less than or equal to 1 second
 | 
			
		||||
  ASSERT_LE(duration.count(), 1.0)
 | 
			
		||||
      << "Performance test failed: Construction took longer than 1 second.";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Edge Case 1: Testing with distance = 0 and angle = 45
 | 
			
		||||
TEST(PolarOfTest, TestDistanceZero) {
 | 
			
		||||
  PolarOf<float> p1(0.0f, AngleOf<float>::Degrees(45.0f));
 | 
			
		||||
  EXPECT_EQ(p1.distance, 0.0f);          // Ensure distance is 0
 | 
			
		||||
  EXPECT_EQ(p1.angle.InDegrees(), 0.0f); // Ensure angle is 0 when distance is 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Edge Case 2: Testing with negative distance, angle should be adjusted
 | 
			
		||||
TEST(PolarOfTest, TestNegativeDistance) {
 | 
			
		||||
  PolarOf<float> p2(-10.0f, AngleOf<float>::Degrees(90.0f));
 | 
			
		||||
  EXPECT_EQ(p2.distance, 10.0f); // Ensure distance is positive
 | 
			
		||||
  EXPECT_NEAR(p2.angle.InDegrees(), -90.0f,
 | 
			
		||||
              0.0001f); // Ensure angle is normalized to 270 degrees (180 + 90)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Edge Case 3: Testing with positive distance and angle = 180
 | 
			
		||||
TEST(PolarOfTest, TestPositiveDistance) {
 | 
			
		||||
  PolarOf<float> p3(100.0f, AngleOf<float>::Degrees(180.0f));
 | 
			
		||||
  EXPECT_EQ(p3.distance, 100.0f); // Ensure distance is correct
 | 
			
		||||
  EXPECT_NEAR(p3.angle.InDegrees(), -180.0f,
 | 
			
		||||
              0.0001f); // Ensure angle is correct
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.angle.ToFloat(), 90.0f) << "Rotate(4 45, 45)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -36,8 +36,7 @@ TEST(Quaternion, ToAngles) {
 | 
			
		||||
	q1 = Quaternion(1, 0, 0, 0);
 | 
			
		||||
	v = Quaternion::ToAngles(q1);
 | 
			
		||||
	r = v == Vector3(180, 0, 0);
 | 
			
		||||
	// EXPECT_TRUE(r) << "Quaternion::ToAngles 1 0 0 0";
 | 
			
		||||
	// fails on MacOS?
 | 
			
		||||
	EXPECT_TRUE(r) << "Quaternion::ToAngles 1 0 0 0";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Quaternion, Multiplication) {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
@ -14,36 +13,22 @@ TEST(Spherical16, FromVector3) {
 | 
			
		||||
  Spherical16 s = Spherical16::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ((float)s.direction.horizontal.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.hor 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ((float)s.direction.vertical.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.vert 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ((float)s.horizontal.ToFloat(), 0.0F) << "s.hor 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ((float)s.vertical.ToFloat(), 0.0F) << "s.vert 0 0 1";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(0, 1, 0);
 | 
			
		||||
  s = Spherical16::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 90.0F) << "s.vert 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 0.0F) << "s.hor 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 90.0F) << "s.vert 0 1 0";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1, 0, 0);
 | 
			
		||||
  s = Spherical16::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 90.0F) << "s.hor 1 0 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 1 0 0";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Spherical16, Vector3) {
 | 
			
		||||
  Vector3 v = Vector3(1, 2, 3);
 | 
			
		||||
  Spherical16 rd = Spherical16::FromVector3(v);
 | 
			
		||||
  Vector3 rv = rd.ToVector3();
 | 
			
		||||
  EXPECT_LT(Vector3::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1, 2, -3);
 | 
			
		||||
  rd = Spherical16::FromVector3(v);
 | 
			
		||||
  rv = rd.ToVector3();
 | 
			
		||||
  EXPECT_LT(Vector3::Distance(v, rv), 10e-4) << " 1 2 3 <-> spherical";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 90.0F) << "s.hor 1 0 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert 1 0 0";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TEST(Spherical16, FromPolar) {
 | 
			
		||||
@ -51,53 +36,48 @@ TEST(Spherical16, Vector3) {
 | 
			
		||||
//   Spherical16 s = Spherical16::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 0.0F) << "s.hor Polar(1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 0.0F) << "s.hor Polar(1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(1 0)";
 | 
			
		||||
 | 
			
		||||
//   p = Polar(1, 45);
 | 
			
		||||
//   s = Spherical16::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 45.0F) << "s.hor Polar(1 45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 45.0F) << "s.hor Polar(1 45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(1 45)";
 | 
			
		||||
 | 
			
		||||
//   p = Polar(1, -45);
 | 
			
		||||
//   s = Spherical16::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), -45.0F) << "s.hor Polar(1 -45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(1 -45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), -45.0F) << "s.hor Polar(1 -45)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(1 -45)";
 | 
			
		||||
 | 
			
		||||
//   p = Polar(0, 0);
 | 
			
		||||
//   s = Spherical16::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), 0.0F) << "s.hor Polar(0 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(0 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 0.0F) << "s.hor Polar(0 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(0 0)";
 | 
			
		||||
 | 
			
		||||
//   p = Polar(-1, 0);
 | 
			
		||||
//   s = Spherical16::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.InDegrees(), -180.0F) << "s.hor Polar(-1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.InDegrees(), 0.0F) << "s.vert Polar(-1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), -180.0F) << "s.hor Polar(-1 0)";
 | 
			
		||||
//   EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(-1 0)";
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
TEST(Spherical16, Incident1) {
 | 
			
		||||
  Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f);
 | 
			
		||||
  Spherical16 s = Spherical16::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  Spherical16 sr =
 | 
			
		||||
      Spherical16(2.49F, Angle16::Degrees(98.18f), Angle16::Degrees(24.4F));
 | 
			
		||||
  Spherical16 sr = Spherical16(2.49F, 98.18f, 24.4F);
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-01);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(),
 | 
			
		||||
              sr.direction.horizontal.InDegrees(), 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(),
 | 
			
		||||
              sr.direction.vertical.InDegrees(), 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), sr.horizontal.ToFloat(), 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), sr.vertical.ToFloat(), 1.0e-02);
 | 
			
		||||
 | 
			
		||||
  Vector3 r =
 | 
			
		||||
      Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical)
 | 
			
		||||
          .ToVector3();
 | 
			
		||||
  Vector3 r = Spherical16(sr.distance, sr.horizontal, sr.vertical).ToVector3();
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0";
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0";
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0";
 | 
			
		||||
@ -107,17 +87,12 @@ TEST(Spherical16, Incident2) {
 | 
			
		||||
  Vector3 v = Vector3(1.0f, 0.0f, 1.0f);
 | 
			
		||||
  Spherical16 s = Spherical16::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  Spherical16 sr = Spherical16(1.4142135623F, Angle16::Degrees(45.0f),
 | 
			
		||||
                               Angle16::Degrees(0.0F));
 | 
			
		||||
  Spherical16 sr = Spherical16(1.4142135623F, 45.0f, 0.0F);
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(),
 | 
			
		||||
              sr.direction.horizontal.InDegrees(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(),
 | 
			
		||||
              sr.direction.vertical.InDegrees(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), sr.horizontal.ToFloat(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), sr.vertical.ToFloat(), 1.0e-05);
 | 
			
		||||
 | 
			
		||||
  Vector3 r =
 | 
			
		||||
      Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical)
 | 
			
		||||
          .ToVector3();
 | 
			
		||||
  Vector3 r = Spherical16(sr.distance, sr.horizontal, sr.vertical).ToVector3();
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
@ -125,27 +100,23 @@ TEST(Spherical16, Incident2) {
 | 
			
		||||
  v = Vector3(0.0f, 1.0f, 1.0f);
 | 
			
		||||
  s = Spherical16::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  sr = Spherical16(1.4142135623F, Angle16::Degrees(0), Angle16::Degrees(45));
 | 
			
		||||
  sr = Spherical16(1.4142135623F, 0.0f, 45.0F);
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(),
 | 
			
		||||
              sr.direction.horizontal.InDegrees(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(),
 | 
			
		||||
              sr.direction.vertical.InDegrees(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), sr.horizontal.ToFloat(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), sr.vertical.ToFloat(), 1.0e-05);
 | 
			
		||||
 | 
			
		||||
  r = Spherical16(sr.distance, sr.direction.horizontal, sr.direction.vertical)
 | 
			
		||||
          .ToVector3();
 | 
			
		||||
  r = Spherical16(sr.distance, sr.horizontal, sr.vertical).ToVector3();
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1.0f, 1.0f, 1.0f);
 | 
			
		||||
  s = Spherical16::FromVector3(v);
 | 
			
		||||
  r = Spherical16(s.distance, s.direction.horizontal, s.direction.vertical)
 | 
			
		||||
          .ToVector3();
 | 
			
		||||
  r = Spherical16(s.distance, s.horizontal, s.vertical).ToVector3();
 | 
			
		||||
 | 
			
		||||
  EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(), 45.0F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(), 35.26F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), 45.0F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), 35.26F, 1.0e-02);
 | 
			
		||||
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-04);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-04);
 | 
			
		||||
@ -159,7 +130,7 @@ TEST(Spherical16, Incident2) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Spherical16, Addition) {
 | 
			
		||||
  Spherical16 v1 = Spherical16(1, Angle16::Degrees(45), Angle16::Degrees(0));
 | 
			
		||||
  Spherical16 v1 = Spherical16(1, 45, 0);
 | 
			
		||||
  Spherical16 v2 = Spherical16::zero;
 | 
			
		||||
  Spherical16 r = Spherical16::zero;
 | 
			
		||||
 | 
			
		||||
@ -170,54 +141,17 @@ TEST(Spherical16, Addition) {
 | 
			
		||||
  r += v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
 | 
			
		||||
 | 
			
		||||
  v2 = Spherical16(1, Angle16::Degrees(-45), Angle16::Degrees(0));
 | 
			
		||||
  v2 = Spherical16(1, -45, 0);
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.horizontal.ToFloat(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.vertical.ToFloat(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
 | 
			
		||||
  v2 = Spherical16(1, Angle16::Degrees(0), Angle16::Degrees(90));
 | 
			
		||||
  v2 = Spherical16(1, 0, 90);
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 45) << "Addition(1 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 45) << "Addition(1 0 90)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Spherical16, AdditionPerformance) {
 | 
			
		||||
  const int numIterations = 1000000; // Number of additions to test
 | 
			
		||||
  std::vector<Spherical16> sphericalObjects;
 | 
			
		||||
 | 
			
		||||
  // Populate the vector with random SphericalOf objects
 | 
			
		||||
  for (int i = 0; i < numIterations; ++i) {
 | 
			
		||||
    float distance = (float)(rand() % 100);
 | 
			
		||||
    float horizontal = (float)(rand() % 180);
 | 
			
		||||
    float vertical = (float)(rand() % 360);
 | 
			
		||||
    Spherical16 s = Spherical16::Deg(distance, horizontal, vertical);
 | 
			
		||||
    sphericalObjects.push_back(s);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Measure the time to perform multiple additions
 | 
			
		||||
  auto start = std::chrono::high_resolution_clock::now();
 | 
			
		||||
 | 
			
		||||
  Spherical16 result = Spherical16::zero; // Start with a
 | 
			
		||||
                                          // zero-initialized object
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < numIterations - 1; ++i) {
 | 
			
		||||
    result = result + sphericalObjects[i]; // Add objects
 | 
			
		||||
                                           // together
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto end = std::chrono::high_resolution_clock::now();
 | 
			
		||||
  std::chrono::duration<double> duration = end - start;
 | 
			
		||||
  std::cout << "Time to perform " << numIterations - 1
 | 
			
		||||
            << " additions: " << duration.count() << " seconds." << std::endl;
 | 
			
		||||
 | 
			
		||||
  // Assert that the time taken is less than
 | 
			
		||||
  // 1 second (or any other performance
 | 
			
		||||
  // requirement)
 | 
			
		||||
  ASSERT_LE(duration.count(), 2.0) << "Performance test failed: "
 | 
			
		||||
                                      "Additions took longer than 1 "
 | 
			
		||||
                                      "second.";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.horizontal.ToFloat(), 45) << "Addition(1 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.vertical.ToFloat(), 45) << "Addition(1 0 90)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,214 +0,0 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(SphericalSingle, FromVector3) {
 | 
			
		||||
  Vector3 v = Vector3(0, 0, 1);
 | 
			
		||||
  SphericalSingle s = SphericalSingle ::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 0 0 1";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(0, 1, 0);
 | 
			
		||||
  s = SphericalSingle ::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F) << "s.hor 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 90.0F) << "s.vert 0 1 0";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1, 0, 0);
 | 
			
		||||
  s = SphericalSingle ::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 90.0F) << "s.hor 1 0 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F) << "s.vert 1 0 0";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SphericalSingle, FromPolar) {
 | 
			
		||||
  PolarSingle p = PolarSingle(1, AngleSingle::Degrees(0));
 | 
			
		||||
  SphericalSingle s = SphericalSingle ::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.hor Polar(1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.vert Polar(1 0)";
 | 
			
		||||
 | 
			
		||||
  p = PolarSingle(1, AngleSingle::Degrees(45));
 | 
			
		||||
  s = SphericalSingle ::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 45.0F)
 | 
			
		||||
      << "s.hor Polar(1 45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.vert Polar(1 45)";
 | 
			
		||||
 | 
			
		||||
  p = PolarSingle(1, AngleSingle::Degrees(-45));
 | 
			
		||||
  s = SphericalSingle ::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), -45.0F)
 | 
			
		||||
      << "s.hor Polar(1 -45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.vert Polar(1 -45)";
 | 
			
		||||
 | 
			
		||||
  p = PolarSingle(0, AngleSingle::Degrees(0));
 | 
			
		||||
  s = SphericalSingle ::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.hor Polar(0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.vert Polar(0 0)";
 | 
			
		||||
 | 
			
		||||
  p = PolarSingle(-1, AngleSingle::Degrees(0));
 | 
			
		||||
  s = SphericalSingle ::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.horizontal.InDegrees(), -180.0F)
 | 
			
		||||
      << "s.hor Polar(-1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.direction.vertical.InDegrees(), 0.0F)
 | 
			
		||||
      << "s.vert Polar(-1 0)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SphericalSingle, Incident1) {
 | 
			
		||||
  Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f);
 | 
			
		||||
  SphericalSingle s = SphericalSingle ::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  SphericalSingle sr = SphericalSingle(2.49F, AngleSingle::Degrees(98.18f),
 | 
			
		||||
                                       AngleSingle::Degrees(24.4F));
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-01);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(),
 | 
			
		||||
              sr.direction.horizontal.InDegrees(), 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(),
 | 
			
		||||
              sr.direction.vertical.InDegrees(), 1.0e-02);
 | 
			
		||||
 | 
			
		||||
  Vector3 r = Vector3(sr);
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0";
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0";
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SphericalSingle, Incident2) {
 | 
			
		||||
  Vector3 v = Vector3(1.0f, 0.0f, 1.0f);
 | 
			
		||||
  SphericalSingle s = SphericalSingle ::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  SphericalSingle sr = SphericalSingle(
 | 
			
		||||
      1.4142135623F, AngleSingle::Degrees(45.0f), AngleSingle::Degrees(0.0F));
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(),
 | 
			
		||||
              sr.direction.horizontal.InDegrees(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(),
 | 
			
		||||
              sr.direction.vertical.InDegrees(), 1.0e-05);
 | 
			
		||||
 | 
			
		||||
  Vector3 r = Vector3(sr);
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  v = Vector3(0.0f, 1.0f, 1.0f);
 | 
			
		||||
  s = SphericalSingle ::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  sr = SphericalSingle(1.4142135623F, AngleSingle::Degrees(0.0f),
 | 
			
		||||
                       AngleSingle::Degrees(45.0F));
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(),
 | 
			
		||||
              sr.direction.horizontal.InDegrees(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(),
 | 
			
		||||
              sr.direction.vertical.InDegrees(), 1.0e-05);
 | 
			
		||||
 | 
			
		||||
  r = Vector3(sr);
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1.0f, 1.0f, 1.0f);
 | 
			
		||||
  s = SphericalSingle ::FromVector3(v);
 | 
			
		||||
  r = Vector3(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.direction.horizontal.InDegrees(), 45.0F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.direction.vertical.InDegrees(), 35.26F, 1.0e-02);
 | 
			
		||||
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  // s = SphericalSingle(10, 45, 45);
 | 
			
		||||
  // r = s.ToVector3();
 | 
			
		||||
  // EXPECT_NEAR(r.x, 5, 1.0e-06);
 | 
			
		||||
  // EXPECT_NEAR(r.y, 7.07, 1.0e-06);
 | 
			
		||||
  // EXPECT_NEAR(r.z, 5, 1.0e-06);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SphericalSingle, Addition) {
 | 
			
		||||
  SphericalSingle v1 =
 | 
			
		||||
      SphericalSingle(1, AngleSingle::Degrees(45), AngleSingle::Degrees(0));
 | 
			
		||||
  SphericalSingle v2 = SphericalSingle ::zero;
 | 
			
		||||
  SphericalSingle r = SphericalSingle ::zero;
 | 
			
		||||
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
 | 
			
		||||
 | 
			
		||||
  r = v1;
 | 
			
		||||
  r += v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
 | 
			
		||||
 | 
			
		||||
  v2 = SphericalSingle(1, AngleSingle::Degrees(-45), AngleSingle::Degrees(0));
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
 | 
			
		||||
  v2 = SphericalSingle(1, AngleSingle::Degrees(0), AngleSingle::Degrees(90));
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.horizontal.InDegrees(), 45) << "Addition(1 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.direction.vertical.InDegrees(), 45) << "Addition(1 0 90)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SphericalSingle, AdditionPerformance) {
 | 
			
		||||
  const int numIterations = 1000000; // Number of additions to test
 | 
			
		||||
  std::vector<SphericalSingle> sphericalObjects;
 | 
			
		||||
 | 
			
		||||
  // Populate the vector with random SphericalOf objects
 | 
			
		||||
  for (int i = 0; i < numIterations; ++i) {
 | 
			
		||||
    float distance = (float)(rand() % 100);
 | 
			
		||||
    float horizontal = (float)(rand() % 180);
 | 
			
		||||
    float vertical = (float)(rand() % 360);
 | 
			
		||||
    SphericalSingle s = SphericalSingle::Deg(distance, horizontal, vertical);
 | 
			
		||||
    sphericalObjects.push_back(s);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Measure the time to perform multiple additions
 | 
			
		||||
  auto start = std::chrono::high_resolution_clock::now();
 | 
			
		||||
 | 
			
		||||
  SphericalSingle result = SphericalSingle::zero; // Start with a
 | 
			
		||||
                                                  // zero-initialized object
 | 
			
		||||
 | 
			
		||||
  for (int i = 0; i < numIterations - 1; ++i) {
 | 
			
		||||
    result = result + sphericalObjects[i]; // Add objects
 | 
			
		||||
                                           // together
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto end = std::chrono::high_resolution_clock::now();
 | 
			
		||||
  std::chrono::duration<double> duration = end - start;
 | 
			
		||||
  std::cout << "Time to perform " << numIterations - 1
 | 
			
		||||
            << " additions: " << duration.count() << " seconds." << std::endl;
 | 
			
		||||
 | 
			
		||||
  // Assert that the time taken is less than
 | 
			
		||||
  // 1 second (or any other performance
 | 
			
		||||
  // requirement)
 | 
			
		||||
  ASSERT_LE(duration.count(), 1.0) << "Performance test failed: "
 | 
			
		||||
                                      "Additions took longer than 1 "
 | 
			
		||||
                                      "second.";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										156
									
								
								LinearAlgebra/test/Spherical_test.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								LinearAlgebra/test/Spherical_test.cc
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,156 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Spherical.h"
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(Spherical, FromVector3) {
 | 
			
		||||
  Vector3 v = Vector3(0, 0, 1);
 | 
			
		||||
  Spherical s = Spherical::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 0.0F) << "s.hor 0 0 1";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert 0 0 1";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(0, 1, 0);
 | 
			
		||||
  s = Spherical::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 0.0F) << "s.hor 0 1 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 90.0F) << "s.vert 0 1 0";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1, 0, 0);
 | 
			
		||||
  s = Spherical::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance 1 0 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 90.0F) << "s.hor 1 0 0";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert 1 0 0";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Spherical, FromPolar) {
 | 
			
		||||
  Polar p = Polar(1, 0);
 | 
			
		||||
  Spherical s = Spherical::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 0.0F) << "s.hor Polar(1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(1 0)";
 | 
			
		||||
 | 
			
		||||
  p = Polar(1, 45);
 | 
			
		||||
  s = Spherical::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 45.0F) << "s.hor Polar(1 45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(1 45)";
 | 
			
		||||
 | 
			
		||||
  p = Polar(1, -45);
 | 
			
		||||
  s = Spherical::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(1 -45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), -45.0F) << "s.hor Polar(1 -45)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(1 -45)";
 | 
			
		||||
 | 
			
		||||
  p = Polar(0, 0);
 | 
			
		||||
  s = Spherical::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 0.0F) << "s.distance Polar(0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 0.0F) << "s.hor Polar(0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(0 0)";
 | 
			
		||||
 | 
			
		||||
  p = Polar(-1, 0);
 | 
			
		||||
  s = Spherical::FromPolar(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.distance, 1.0F) << "s.distance Polar(-1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.horizontal.ToFloat(), 180.0F) << "s.hor Polar(-1 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(s.vertical.ToFloat(), 0.0F) << "s.vert Polar(-1 0)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Spherical, Incident1) {
 | 
			
		||||
  Vector3 v = Vector3(2.242557f, 1.027884f, -0.322347f);
 | 
			
		||||
  Spherical s = Spherical::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  Spherical sr = Spherical(2.49F, 98.18f, 24.4F);
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-01);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), sr.horizontal.ToFloat(), 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), sr.vertical.ToFloat(), 1.0e-02);
 | 
			
		||||
 | 
			
		||||
  Vector3 r = Vector3(sr);
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-02) << "toVector3.x 1 0 0";
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-02) << "toVector3.y 1 0 0";
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-02) << "toVector3.z 1 0 0";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Spherical, Incident2) {
 | 
			
		||||
  Vector3 v = Vector3(1.0f, 0.0f, 1.0f);
 | 
			
		||||
  Spherical s = Spherical::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  Spherical sr = Spherical(1.4142135623F, 45.0f, 0.0F);
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), sr.horizontal.ToFloat(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), sr.vertical.ToFloat(), 1.0e-05);
 | 
			
		||||
 | 
			
		||||
  Vector3 r = Vector3(sr);
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  v = Vector3(0.0f, 1.0f, 1.0f);
 | 
			
		||||
  s = Spherical::FromVector3(v);
 | 
			
		||||
 | 
			
		||||
  sr = Spherical(1.4142135623F, 0.0f, 45.0F);
 | 
			
		||||
  EXPECT_NEAR(s.distance, sr.distance, 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), sr.horizontal.ToFloat(), 1.0e-05);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), sr.vertical.ToFloat(), 1.0e-05);
 | 
			
		||||
 | 
			
		||||
  r = Vector3(sr);
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1.0f, 1.0f, 1.0f);
 | 
			
		||||
  s = Spherical::FromVector3(v);
 | 
			
		||||
  r = Vector3(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_NEAR(s.distance, 1.73205080F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.horizontal.ToFloat(), 45.0F, 1.0e-02);
 | 
			
		||||
  EXPECT_NEAR(s.vertical.ToFloat(), 35.26F, 1.0e-02);
 | 
			
		||||
 | 
			
		||||
  EXPECT_NEAR(r.Right(), v.Right(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Up(), v.Up(), 1.0e-06);
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), v.Forward(), 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  // s = Spherical(10, 45, 45);
 | 
			
		||||
  // r = s.ToVector3();
 | 
			
		||||
  // EXPECT_NEAR(r.x, 5, 1.0e-06);
 | 
			
		||||
  // EXPECT_NEAR(r.y, 7.07, 1.0e-06);
 | 
			
		||||
  // EXPECT_NEAR(r.z, 5, 1.0e-06);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(Spherical, Addition) {
 | 
			
		||||
  Spherical v1 = Spherical(1, 45, 0);
 | 
			
		||||
  Spherical v2 = Spherical::zero;
 | 
			
		||||
  Spherical r = Spherical::zero;
 | 
			
		||||
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
 | 
			
		||||
 | 
			
		||||
  r = v1;
 | 
			
		||||
  r += v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, v1.distance) << "Addition(0 0 0)";
 | 
			
		||||
 | 
			
		||||
  v2 = Spherical(1, -45, 0);
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.horizontal.ToFloat(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.vertical.ToFloat(), 0) << "Addition(1 -45 0)";
 | 
			
		||||
 | 
			
		||||
  v2 = Spherical(1, 0, 90);
 | 
			
		||||
  r = v1 + v2;
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.distance, sqrtf(2)) << "Addition(1 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.horizontal.ToFloat(), 45) << "Addition(1 0 90)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.vertical.ToFloat(), 45) << "Addition(1 0 90)";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,131 +0,0 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "SwingTwist.h"
 | 
			
		||||
 | 
			
		||||
#define FLOAT_INFINITY std::numeric_limits<float>::infinity()
 | 
			
		||||
 | 
			
		||||
TEST(SwingTwistSingle, Quaternion) {
 | 
			
		||||
  Quaternion q;
 | 
			
		||||
  SwingTwistSingle s;
 | 
			
		||||
  Quaternion rq;
 | 
			
		||||
 | 
			
		||||
  q = Quaternion::identity;
 | 
			
		||||
  s = SwingTwistSingle::FromQuaternion(q);
 | 
			
		||||
  rq = s.ToQuaternion();
 | 
			
		||||
  EXPECT_EQ(q, rq) << " 0 0 0 1 <-> SwingTwist";
 | 
			
		||||
 | 
			
		||||
  q = Quaternion::Euler(90, 0, 0);
 | 
			
		||||
  s = SwingTwistSingle::FromQuaternion(q);
 | 
			
		||||
  rq = s.ToQuaternion();
 | 
			
		||||
  EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 90 0 0 <-> SwingTwist";
 | 
			
		||||
 | 
			
		||||
  q = Quaternion::Euler(0, 90, 0);
 | 
			
		||||
  s = SwingTwistSingle::FromQuaternion(q);
 | 
			
		||||
  rq = s.ToQuaternion();
 | 
			
		||||
  EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist";
 | 
			
		||||
 | 
			
		||||
  q = Quaternion::Euler(0, 0, 90);
 | 
			
		||||
  s = SwingTwistSingle::FromQuaternion(q);
 | 
			
		||||
  rq = s.ToQuaternion();
 | 
			
		||||
  EXPECT_EQ(q, rq) << " Euler 0 0 90 <-> SwingTwist";
 | 
			
		||||
 | 
			
		||||
  q = Quaternion::Euler(0, 180, 0);  // ==> spherical S(180 0)T0
 | 
			
		||||
  s = SwingTwistSingle::FromQuaternion(q);
 | 
			
		||||
  rq = s.ToQuaternion();
 | 
			
		||||
  EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist";
 | 
			
		||||
 | 
			
		||||
  q = Quaternion::Euler(0, 135, 0);  // ==> spherical S(180 45)T0
 | 
			
		||||
  s = SwingTwistSingle::FromQuaternion(q);
 | 
			
		||||
  rq = s.ToQuaternion();
 | 
			
		||||
  EXPECT_LT(Quaternion::Angle(q, rq), 10e-2) << " Euler 0 90 0 <-> SwingTwist";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SwingTwistSingle, AngleAxis) {
 | 
			
		||||
  SwingTwistSingle s;
 | 
			
		||||
  SwingTwistSingle r;
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::AngleAxis(0, DirectionSingle::up);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(0, 0, 0)) << "0 up";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(90, DirectionSingle::up);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(90, 0, 0);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "90 up";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(180, DirectionSingle::up);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(180, 0, 0);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "180 up";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(270, DirectionSingle::up);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(-90, 0, 0);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "270 up";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(90, DirectionSingle::right);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 90, 0);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "90 right";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(180, DirectionSingle::right);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 180, 0);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "180 right";
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(270, DirectionSingle::right);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, -90, 0);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "270 right";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(90, DirectionSingle::forward);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 0, 90);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "90 up";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(180, DirectionSingle::forward);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 0, 180);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "180 up";
 | 
			
		||||
 | 
			
		||||
  r = SwingTwistSingle::AngleAxis(270, DirectionSingle::forward);
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 0, -90);
 | 
			
		||||
  EXPECT_LT(SwingTwistSingle::Angle(r, s), AngleSingle::Degrees(10e-2f))
 | 
			
		||||
      << "270 up";
 | 
			
		||||
 | 
			
		||||
  auto r16 = SwingTwist16::AngleAxis(13, Direction16::down);
 | 
			
		||||
  auto s16 = SwingTwist16::Degrees(-13, 0, 0);
 | 
			
		||||
  EXPECT_LT(SwingTwist16::Angle(r16, s16), Angle16::Degrees(10e-2f))
 | 
			
		||||
      << "270 up";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(SwingTwistSingle, Normalize) {
 | 
			
		||||
  SwingTwistSingle s;
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 0, 0);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(0, 0, 0)) << "0 0 0 Normalized";
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 180, 0);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(180, 0, 180)) << "0 180 0 Normalized";
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::Degrees(0, 180, 180);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(180, 0, 0)) << "0 180 180 Normalized";
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::Degrees(270, 90, 0);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, 90, 0)) << "270 90 0 Normalized";
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::Degrees(270, 270, 0);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, -90, 0))
 | 
			
		||||
      << "270 270 0 Normalized";
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::Degrees(270, 225, 0);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(90, -45, -180))
 | 
			
		||||
      << "270 225 0 Normalized";
 | 
			
		||||
 | 
			
		||||
  s = SwingTwistSingle::Degrees(270, 0, 225);
 | 
			
		||||
  EXPECT_EQ(s, SwingTwistSingle::Degrees(-90, 0, -135))
 | 
			
		||||
      << "270 0 225 Normalized";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Vector2.h"
 | 
			
		||||
 | 
			
		||||
@ -9,25 +9,25 @@
 | 
			
		||||
 | 
			
		||||
TEST(Vector2, FromPolar) {
 | 
			
		||||
  Vector2 v;
 | 
			
		||||
  PolarSingle p;
 | 
			
		||||
  Polar p;
 | 
			
		||||
  Vector2 r;
 | 
			
		||||
 | 
			
		||||
  v = Vector2(0, 1);
 | 
			
		||||
  p = PolarSingle::FromVector2(v);
 | 
			
		||||
  p = Polar::FromVector2(v);
 | 
			
		||||
  r = Vector2(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.x, 0.0F) << "FromPolar(0 1)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.y, 1.0F) << "FromPolar(0 1)";
 | 
			
		||||
 | 
			
		||||
  v = Vector2(1, 0);
 | 
			
		||||
  p = PolarSingle::FromVector2(v);
 | 
			
		||||
  p = Polar::FromVector2(v);
 | 
			
		||||
  r = Vector2(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.x, 1.0F) << "FromPolar(1 0)";
 | 
			
		||||
  EXPECT_NEAR(r.y, 0.0F, 1.0e-07) << "FromPolar(1 0)";
 | 
			
		||||
 | 
			
		||||
  v = Vector2(0, 0);
 | 
			
		||||
  p = PolarSingle::FromVector2(v);
 | 
			
		||||
  p = Polar::FromVector2(v);
 | 
			
		||||
  r = Vector2(p);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.x, 0.0F) << "FromPolar(0 0)";
 | 
			
		||||
@ -462,16 +462,16 @@ TEST(Vector2, Rotate) {
 | 
			
		||||
  Vector2 v1 = Vector2(1, 2);
 | 
			
		||||
  Vector2 r = Vector2(0, 0);
 | 
			
		||||
 | 
			
		||||
  r = Vector2::Rotate(v1, AngleSingle::Degrees(0));
 | 
			
		||||
  r = Vector2::Rotate(v1, 0);
 | 
			
		||||
  EXPECT_FLOAT_EQ(Vector2::Distance(r, v1), 0);
 | 
			
		||||
 | 
			
		||||
  r = Vector2::Rotate(v1, AngleSingle::Degrees(180));
 | 
			
		||||
  r = Vector2::Rotate(v1, 180);
 | 
			
		||||
  EXPECT_NEAR(Vector2::Distance(r, Vector2(-1, -2)), 0, 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  r = Vector2::Rotate(v1, AngleSingle::Degrees(-90));
 | 
			
		||||
  r = Vector2::Rotate(v1, -90);
 | 
			
		||||
  EXPECT_NEAR(Vector2::Distance(r, Vector2(2, -1)), 0, 1.0e-06);
 | 
			
		||||
 | 
			
		||||
  r = Vector2::Rotate(v1, AngleSingle::Degrees(270));
 | 
			
		||||
  r = Vector2::Rotate(v1, 270);
 | 
			
		||||
  EXPECT_NEAR(Vector2::Distance(r, Vector2(2, -1)), 0, 1.0e-06);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#if GTEST
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <limits>
 | 
			
		||||
 | 
			
		||||
#include "Vector3.h"
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
 | 
			
		||||
TEST(Vector3, FromSpherical) {
 | 
			
		||||
  Vector3 v = Vector3(0, 0, 1);
 | 
			
		||||
  SphericalOf<float> s = SphericalOf<float>::FromVector3(v);
 | 
			
		||||
  Spherical s = Spherical::FromVector3(v);
 | 
			
		||||
  Vector3 r = Vector3(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.Right(), 0.0F) << "toVector3.x 0 0 1";
 | 
			
		||||
@ -17,7 +17,7 @@ TEST(Vector3, FromSpherical) {
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.Forward(), 1.0F) << "toVector3.z 0 0 1";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(0, 1, 0);
 | 
			
		||||
  s = SphericalOf<float>::FromVector3(v);
 | 
			
		||||
  s = Spherical::FromVector3(v);
 | 
			
		||||
  r = Vector3(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.Right(), 0.0F) << "toVector3.x 0 1 0";
 | 
			
		||||
@ -25,7 +25,7 @@ TEST(Vector3, FromSpherical) {
 | 
			
		||||
  EXPECT_NEAR(r.Forward(), 0.0F, 1.0e-06) << "toVector3.z 0 1 0";
 | 
			
		||||
 | 
			
		||||
  v = Vector3(1, 0, 0);
 | 
			
		||||
  s = SphericalOf<float>::FromVector3(v);
 | 
			
		||||
  s = Spherical::FromVector3(v);
 | 
			
		||||
  r = Vector3(s);
 | 
			
		||||
 | 
			
		||||
  EXPECT_FLOAT_EQ(r.Right(), 1.0F) << "toVector3.x 1 0 0";
 | 
			
		||||
@ -488,29 +488,29 @@ TEST(Vector3, ProjectOnPlane) {
 | 
			
		||||
TEST(Vector3, Angle) {
 | 
			
		||||
  Vector3 v1 = Vector3(4, 5, 6);
 | 
			
		||||
  Vector3 v2 = Vector3(1, 2, 3);
 | 
			
		||||
  AngleOf<float> f = AngleOf<float>::Degrees(0);
 | 
			
		||||
  AngleOf<float> f = 0;
 | 
			
		||||
  bool r = false;
 | 
			
		||||
 | 
			
		||||
  f = Vector3::Angle(v1, v2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), 12.9331388F) << "Angle(4 5 6, 1 2 3)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), 12.9331388F) << "Angle(4 5 6, 1 2 3)";
 | 
			
		||||
 | 
			
		||||
  v2 = Vector3(-1, -2, -3);
 | 
			
		||||
  f = Vector3::Angle(v1, v2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), 167.066864F) << "Angle(4 5 6, -1 -2 -3)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), 167.066864F) << "Angle(4 5 6, -1 -2 -3)";
 | 
			
		||||
 | 
			
		||||
  v2 = Vector3(0, 0, 0);
 | 
			
		||||
  f = Vector3::Angle(v1, v2);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "Angle(4 5 6, 0 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), 0) << "Angle(4 5 6, 0 0 0)";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
 | 
			
		||||
    f = Vector3::Angle(v1, v2);
 | 
			
		||||
    r = isnan(f.InDegrees());
 | 
			
		||||
    r = isnan(f.ToFloat());
 | 
			
		||||
    EXPECT_TRUE(r) << "Angle(4 5 6, INFINITY INFINITY INFINITY)";
 | 
			
		||||
 | 
			
		||||
    v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
 | 
			
		||||
    f = Vector3::Angle(v1, v2);
 | 
			
		||||
    r = isnan(f.InDegrees());
 | 
			
		||||
    r = isnan(f.ToFloat());
 | 
			
		||||
    EXPECT_TRUE(r) << "Angle(4 5 6, -INFINITY -INFINITY -INFINITY)";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -519,42 +519,42 @@ TEST(Vector3, SignedAngle) {
 | 
			
		||||
  Vector3 v1 = Vector3(4, 5, 6);
 | 
			
		||||
  Vector3 v2 = Vector3(1, 2, 3);
 | 
			
		||||
  Vector3 v3 = Vector3(7, 8, -9);
 | 
			
		||||
  AngleOf<float> f = AngleOf<float>::Degrees(0);
 | 
			
		||||
  AngleOf<float> f = 0;
 | 
			
		||||
  bool r = false;
 | 
			
		||||
 | 
			
		||||
  f = Vector3::SignedAngle(v1, v2, v3);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), -12.9331388F)
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), -12.9331388F)
 | 
			
		||||
      << "SignedAngle(4 5 6, 1 2 3, 7 8 -9)";
 | 
			
		||||
 | 
			
		||||
  v2 = Vector3(-1, -2, -3);
 | 
			
		||||
  f = Vector3::SignedAngle(v1, v2, v3);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), 167.066864F)
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), 167.066864F)
 | 
			
		||||
      << "SignedAngle(4 5 6, -1 -2 -3, 7 8 -9)";
 | 
			
		||||
 | 
			
		||||
  v2 = Vector3(0, 0, 0);
 | 
			
		||||
  f = Vector3::SignedAngle(v1, v2, v3);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "SignedAngle(4 5 6, 0 0 0, 7 8 -9 )";
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), 0) << "SignedAngle(4 5 6, 0 0 0, 7 8 -9 )";
 | 
			
		||||
 | 
			
		||||
  v2 = Vector3(1, 2, 3);
 | 
			
		||||
 | 
			
		||||
  v3 = Vector3(-7, -8, 9);
 | 
			
		||||
  f = Vector3::SignedAngle(v1, v2, v3);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), 12.9331388F)
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), 12.9331388F)
 | 
			
		||||
      << "SignedAngle(4 5 6, 1 2 3, -7 -8 9)";
 | 
			
		||||
 | 
			
		||||
  v3 = Vector3(0, 0, 0);
 | 
			
		||||
  f = Vector3::SignedAngle(v1, v2, v3);
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.InDegrees(), 0) << "SignedAngle(4 5 6, 1 2 3, 0 0 0)";
 | 
			
		||||
  EXPECT_FLOAT_EQ(f.ToFloat(), 0) << "SignedAngle(4 5 6, 1 2 3, 0 0 0)";
 | 
			
		||||
 | 
			
		||||
  if (std::numeric_limits<float>::is_iec559) {
 | 
			
		||||
    v2 = Vector3(FLOAT_INFINITY, FLOAT_INFINITY, FLOAT_INFINITY);
 | 
			
		||||
    f = Vector3::SignedAngle(v1, v2, v3);
 | 
			
		||||
    r = isnan(f.InDegrees());
 | 
			
		||||
    r = isnan(f.ToFloat());
 | 
			
		||||
    EXPECT_TRUE(r) << "SignedAngle(4 5 6, INFINITY INFINITY INFINITY)";
 | 
			
		||||
 | 
			
		||||
    v2 = Vector3(-FLOAT_INFINITY, -FLOAT_INFINITY, -FLOAT_INFINITY);
 | 
			
		||||
    f = Vector3::SignedAngle(v1, v2, v3);
 | 
			
		||||
    r = isnan(f.InDegrees());
 | 
			
		||||
    r = isnan(f.ToFloat());
 | 
			
		||||
    EXPECT_TRUE(r) << "SignedAngle(4 5 6, -INFINITY -INFINITY -INFINITY)";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										78
									
								
								MessageFormat.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								MessageFormat.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
			
		||||
 | 
			
		||||
Message Format
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
## Data type
 | 
			
		||||
 | 
			
		||||
The datatype consists of 4-bit (nibble) 2 parts: the most significant nibble is the syntax, while the least significant nibble is the sematics. 
 | 
			
		||||
 | 
			
		||||
| 7 . 6 | 5 . 4| 3. 2. 1. 0 |
 | 
			
		||||
|-|-|-|
 | 
			
		||||
| angular | linear | semantics |
 | 
			
		||||
 | 
			
		||||
When the Data type is 0x00, this indicates that a second byte will follow which defines further syntax options. Currently, this has not been defined yet, but can be used to define high-resolution angles using 2 bytes per dimension.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Syntax
 | 
			
		||||
 | 
			
		||||
The syntax defines the format of the data sent and makes it possible to parse or skip parts of the message. Every value can consist of two parts: the angular and linear part, each represented by 2 bits.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| Angular part | |
 | 
			
		||||
|-|-|
 | 
			
		||||
| 00 (0x0) | No angle | 
 | 
			
		||||
| 01 (0x4) | 1-byte, 1D angle |
 | 
			
		||||
| 10 (0x8) | 2-byte, 2D angle |
 | 
			
		||||
| 11 (0xC) | 3-byte, 3D angle |
 | 
			
		||||
 | 
			
		||||
| Linear part | |
 | 
			
		||||
|-|-|
 | 
			
		||||
| 00 (0x0) | No magnitude |
 | 
			
		||||
| 01 (0x1) | 1 byte magnitude |
 | 
			
		||||
| 10 (0x2) | 2 byte magnitude |
 | 
			
		||||
| 11 (0x3) | 4 byte magnitude |
 | 
			
		||||
 | 
			
		||||
Note that these values do not actually say how the angular and linear values are encoded. A 4-byte magnitude may be a 32-bit unsigned int or a single precision float for example. This depends on the semantics.
 | 
			
		||||
 | 
			
		||||
When the angular and linear parts are combined, the size of the message can be determined. A few examples:
 | 
			
		||||
 | 
			
		||||
| Data type | Size | Description |
 | 
			
		||||
|-|-|-|
 | 
			
		||||
| 0001 (0x1) | 1 byte | A single byte of linear data, like an intensity value |
 | 
			
		||||
| 0100 (0x4) | 1 byte | An angle, like an angle between 0 and 360 degrees |
 | 
			
		||||
| 0101 (0x5) | 2 bytes | An angle with a distance, like a polar coordinate |
 | 
			
		||||
| 1101 (0xD) | 4 bytes | For example a quaternion, where the x,y,z = angular and w = linear part |
 | 
			
		||||
| 0002 (0x2) | 2 bytes | A 16-bit value, like a single short int |
 | 
			
		||||
| 1011 (0xB) | 6 bytes | 2D angles and a 32-bit distance, for example a spherical coordinate |
 | 
			
		||||
 | 
			
		||||
### Semantics
 | 
			
		||||
 | 
			
		||||
The semantics defines how the data should be interpreted. The following are defined:
 | 
			
		||||
 | 
			
		||||
| Semantics | |
 | 
			
		||||
|-|-|
 | 
			
		||||
| 0b0001 (0x1) | Position |
 | 
			
		||||
| 0b0010 (0x2) | Linear velocity |
 | 
			
		||||
| 0b0011 (0x3) | Linear acceleration |
 | 
			
		||||
| 0b0101 (0x5) | Orientation or rotation |
 | 
			
		||||
| ob0110 (0x6) | Angular velocity |
 | 
			
		||||
| 0b0111 (0x7) | Angular acceleration |
 | 
			
		||||
| 0b1000 (0x8) | Direction |
 | 
			
		||||
 | 
			
		||||
## Currently implemented data types
 | 
			
		||||
 | 
			
		||||
| Data type | Message |
 | 
			
		||||
|-|-|
 | 
			
		||||
| 0x62 | Polar velocity with 2-byte distance |
 | 
			
		||||
 | 
			
		||||
## Typical data types
 | 
			
		||||
 | 
			
		||||
| Data type | Interpretation |
 | 
			
		||||
| 0x48 | A direction in 2D space, represented by an angle. |
 | 
			
		||||
| 0x88 | A direction in 3D space, represented by 2 angles. |
 | 
			
		||||
| 0x83 | A position in 3D space, using Spherical coordinates |
 | 
			
		||||
| 0xD4 | An orientation represented by a quaternion |
 | 
			
		||||
| 0xE5 | Angular verlocity, represented in Angle-axis format |
 | 
			
		||||
| 0xF5 | Angular verlocity, represented in Angle-axis format using a float for the magnitude |
 | 
			
		||||
 | 
			
		||||
Note that a 2D or 3D vector is not directly supported. In alignment to the coordinate sytem of Roboid controle, these need to be converted to Polar or Spherical coordinates before they can be sent.
 | 
			
		||||
@ -1,49 +0,0 @@
 | 
			
		||||
#include "BinaryMsg.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
BinaryMsg::BinaryMsg(unsigned char networkId, Thing* thing) {
 | 
			
		||||
  this->networkId = networkId;
 | 
			
		||||
  this->thingId = thing->id;
 | 
			
		||||
  this->thing = thing;
 | 
			
		||||
  unsigned char ix = 0; //BinaryMsg::length;
 | 
			
		||||
  this->data = new char[255];
 | 
			
		||||
  this->dataLength = this->thing->GenerateBinary(this->data, &ix);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BinaryMsg::BinaryMsg(char* buffer) {
 | 
			
		||||
  unsigned char ix = 1;
 | 
			
		||||
  this->networkId = buffer[ix++];
 | 
			
		||||
  this->thingId = buffer[ix++];
 | 
			
		||||
  this->dataLength = buffer[ix++];
 | 
			
		||||
  char* data = new char[this->dataLength];
 | 
			
		||||
  for (int i = 0; i < this->dataLength; i++)
 | 
			
		||||
    data[i] = buffer[ix++];
 | 
			
		||||
  this->data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BinaryMsg::~BinaryMsg() {
 | 
			
		||||
  delete[] this->data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned char BinaryMsg::Serialize(char* buffer) {
 | 
			
		||||
  // unsigned char ix = this->length;
 | 
			
		||||
  //  this->dataLength = this->thing->GenerateBinary(buffer, &ix);
 | 
			
		||||
  if (this->dataLength <= 0)  // in this case, no data is actually sent
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
#if defined(DEBUG)
 | 
			
		||||
  std::cout << "Send BinaryMsg [" << (int)this->networkId << "/" << (int)this->thingId
 | 
			
		||||
            << "] " << (int)this->dataLength << std::endl;
 | 
			
		||||
#endif
 | 
			
		||||
  unsigned char ix = 0;
 | 
			
		||||
  buffer[ix++] = this->id;
 | 
			
		||||
  buffer[ix++] = this->networkId;
 | 
			
		||||
  buffer[ix++] = this->thingId;
 | 
			
		||||
  buffer[ix++] = this->dataLength;
 | 
			
		||||
  for (int dataIx = 0; dataIx < this->dataLength; dataIx++)
 | 
			
		||||
    buffer[ix++] = this->data[dataIx];
 | 
			
		||||
  return this->length + this->dataLength;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,41 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IMessage.h"
 | 
			
		||||
#include "Thing.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief A message containing binary data for custom communication
 | 
			
		||||
class BinaryMsg : public IMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief The message ID
 | 
			
		||||
  static const unsigned char id = 0xB1;
 | 
			
		||||
  /// @brief The length of the message in bytes, excluding the binary data
 | 
			
		||||
  /// For the total size of the message this.bytes.Length should be added to this value.
 | 
			
		||||
  static const unsigned length = 4;
 | 
			
		||||
 | 
			
		||||
  /// @brief The network ID of the thing
 | 
			
		||||
  unsigned char networkId;
 | 
			
		||||
  /// @brief The ID of the thing
 | 
			
		||||
  unsigned char thingId;
 | 
			
		||||
  /// @brief The thing for which the binary data is communicated
 | 
			
		||||
  Thing* thing;
 | 
			
		||||
 | 
			
		||||
  unsigned char dataLength;
 | 
			
		||||
  /// @brief The binary data which is communicated
 | 
			
		||||
  char* data = nullptr;
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a BinaryMsg
 | 
			
		||||
  /// @param networkId The network ID of the thing
 | 
			
		||||
  /// @param thing The thing for which binary data is sent
 | 
			
		||||
  BinaryMsg(unsigned char networkId, Thing* thing);
 | 
			
		||||
  /// @copydoc RoboidControl::IMessage::IMessage(char*)
 | 
			
		||||
  BinaryMsg(char* buffer);
 | 
			
		||||
  /// @brief Destructor for the message
 | 
			
		||||
  virtual ~BinaryMsg();
 | 
			
		||||
 | 
			
		||||
    /// @copydoc RoboidControl::IMessage::Serialize
 | 
			
		||||
  virtual unsigned char Serialize(char* buffer) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,29 +0,0 @@
 | 
			
		||||
#include "DestroyMsg.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
DestroyMsg::DestroyMsg(unsigned char networkId, Thing* thing) {
 | 
			
		||||
  this->networkId = networkId;
 | 
			
		||||
  this->thingId = thing->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DestroyMsg::DestroyMsg(char* buffer) {
 | 
			
		||||
  this->networkId = buffer[1];
 | 
			
		||||
  this->thingId = buffer[2];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DestroyMsg::~DestroyMsg() {}
 | 
			
		||||
 | 
			
		||||
unsigned char DestroyMsg::Serialize(char* buffer) {
 | 
			
		||||
#if defined(DEBUG)
 | 
			
		||||
  std::cout << "Send DestroyMsg [" << (int)this->networkId << "/"
 | 
			
		||||
            << (int)this->thingId << "] " << std::endl;
 | 
			
		||||
#endif
 | 
			
		||||
  unsigned char ix = 0;
 | 
			
		||||
  buffer[ix++] = this->id;
 | 
			
		||||
  buffer[ix++] = this->networkId;
 | 
			
		||||
  buffer[ix++] = this->thingId;
 | 
			
		||||
  return ix;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,33 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "IMessage.h"
 | 
			
		||||
#include "Thing.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief A Message notifiying that a Thing no longer exists
 | 
			
		||||
class DestroyMsg : public IMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  /// @brief The message ID
 | 
			
		||||
  static const unsigned char id = 0x20;
 | 
			
		||||
  /// @brief The length of the message in bytes
 | 
			
		||||
  static const unsigned length = 3;
 | 
			
		||||
  /// @brief The network ID of the thing
 | 
			
		||||
  unsigned char networkId;
 | 
			
		||||
  /// @brief The ID of the thing
 | 
			
		||||
  unsigned char thingId;
 | 
			
		||||
 | 
			
		||||
  /// @brief Create a message for sending
 | 
			
		||||
  /// @param networkId The network ID of the thing
 | 
			
		||||
  /// @param thing The ID of the thing
 | 
			
		||||
  DestroyMsg(unsigned char networkId, Thing* thing);
 | 
			
		||||
  /// @copydoc RoboidControl::IMessage::IMessage(char*)
 | 
			
		||||
  DestroyMsg(char* buffer);
 | 
			
		||||
  /// @brief Destructor for the message
 | 
			
		||||
  virtual ~DestroyMsg();
 | 
			
		||||
 | 
			
		||||
  /// @copydoc RoboidControl::IMessage::Serialize
 | 
			
		||||
  virtual unsigned char Serialize(char* buffer) override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
#include "IMessage.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
#pragma region IMessage
 | 
			
		||||
 | 
			
		||||
IMessage::IMessage() {}
 | 
			
		||||
 | 
			
		||||
unsigned char IMessage::Serialize(char* buffer) {
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IMessage
 | 
			
		||||
#pragma endregion
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,16 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
/// @brief Root structure for all communcation messages
 | 
			
		||||
class IMessage {
 | 
			
		||||
 public:
 | 
			
		||||
  IMessage();
 | 
			
		||||
  /// @brief Serialize the message into a byte array for sending
 | 
			
		||||
  /// @param buffer The buffer to serilize into
 | 
			
		||||
  /// @return The length of the message in the buffer
 | 
			
		||||
  virtual unsigned char Serialize(char* buffer);
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
@ -1,28 +0,0 @@
 | 
			
		||||
#include "InvestigateMsg.h"
 | 
			
		||||
 | 
			
		||||
namespace RoboidControl {
 | 
			
		||||
 | 
			
		||||
InvestigateMsg::InvestigateMsg(char* buffer) {
 | 
			
		||||
  unsigned ix = 1;  // first byte is msgId
 | 
			
		||||
  this->networkId = buffer[ix++];
 | 
			
		||||
  this->thingId = buffer[ix++];
 | 
			
		||||
}
 | 
			
		||||
InvestigateMsg::InvestigateMsg(unsigned char networkId, Thing* thing) {
 | 
			
		||||
  this->networkId = networkId;
 | 
			
		||||
  this->thingId = thing->id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InvestigateMsg::~InvestigateMsg() {}
 | 
			
		||||
unsigned char InvestigateMsg::Serialize(char* buffer) {
 | 
			
		||||
  #if defined(DEBUG)
 | 
			
		||||
  std::cout << "Send InvestigateMsg [" << (int)this->networkId << "/" << (int)this->thingId
 | 
			
		||||
            << "] " << std::endl;
 | 
			
		||||
#endif
 | 
			
		||||
  unsigned char ix = 0;
 | 
			
		||||
  buffer[ix++] = this->id;
 | 
			
		||||
  buffer[ix++] = this->networkId;
 | 
			
		||||
  buffer[ix++] = this->thingId;
 | 
			
		||||
  return ix;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace RoboidControl
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user