Skip to content

Instantly share code, notes, and snippets.

@Alynva
Last active June 27, 2017 18:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Alynva/92ee52f733e9e311e61efab4b49d6ee5 to your computer and use it in GitHub Desktop.
Save Alynva/92ee52f733e9e311e61efab4b49d6ee5 to your computer and use it in GitHub Desktop.
Uma biblioteca de geometria, adaptada da p5.js (JavaScript) para C++.
#ifndef __Geometria_Alynva__
#define __Geometria_Alynva__
namespace GeoA {
const double TWO_PI = 6.28318530717958647693;
const double PI = 3.14159265358979323846;
const double HALF_PI = 1.57079632679489661923;
const double QUARTER_PI = 0.7853982;
double random(); // [0.0 .. 1.0]
double random(double); // [0.0 .. double]
double random(double, double); // [double .. double]
double map(double, double, double, double, double);
struct Ponto {
double x; // Número do componente x do vetor
double y; // Número do componente y do vetor
Ponto(double px, double py):x(px), y(py) {};
Ponto(Ponto* pp):x(pp->x), y(pp->y) {};
Ponto():x(), y() {};
};
struct Vetor : public Ponto { // Uma classe para descrever um vetor de duas ou três dimensões, especificamente um vetor euclidiano (também conhecido como geométrico).
double z; // Número do componente z do vetor
Vetor(double px, double py, double pz):Ponto(px, py), z(pz) {}; // Construtores para a passagem direta ou indireta dos componentes ou para o vetor nulo.
Vetor(Vetor* pv):Ponto(pv->x, pv->y), z(pv->z) {};
Vetor():Ponto(0, 0), z(0) {};
char* toString() const; // Retorna uma representação em sequência de caracteres de um vetor v ao chamar v.toString(). Esse método é útil para registrar vetores no console.
Vetor* set(double, double, double); // Definem o componente x, y e z do vetor usando três variáveis ​​separadas ou os dados de um Vetor.
Vetor* set(Vetor*);
Vetor* copy() const; // Obtém uma cópia do vetor, retorna um objeto Vetor.
Vetor* add(double, double, double); // Adiciona componentes x, y e z a um vetor, adiciona um vetor a outro ou adiciona dois vetores independentes juntos. A versão do método que adiciona dois vetores juntos é um método estático e retorna um objeto Vetor, os outros atuam diretamente no vetor.
Vetor* add(const Vetor*);
static Vetor* add(Vetor*, Vetor*);
Vetor* sub(double, double, double); // Subtrai componentes x, y e z de um vetor, subtrai um vetor de outro, ou subtrai dois vetores independentes. A versão do método que subtrai dois vetores é um método estático e retorna um objeto Vetor, os outros atuam diretamente no vetor.
Vetor* sub(const Vetor*);
static Vetor* sub(const Vetor*, const Vetor*);
Vetor* mult(double); // Multiplique o vetor por um escalar.
Vetor* div(double); // Divida o vetor por um escalar.
double mag(); // Calcula a magnitude (comprimento) do vetor e retorna o resultado como um double.
double magSq(); // Calcula a magnitude quadrada do vetor e retorna o resultado como um double. Mais rápido se o comprimento real não for necessário no caso de comparar vetores, etc.
double dot(Vetor*) const; // Calcula o produto interno de dois vetores. A versão do método que calcula o produto ponto de dois vetores independentes é um método estático.
static double dot(Vetor*, Vetor*);
Vetor* cross(Vetor*) const; // Calcula e retorna um vetor composto do produto cruzado entre dois vetores. Ambos os métodos estático e não estático retornam um novo objeto Vetor.
static Vetor* cross(Vetor*, Vetor*);
double dist(const Vetor*) const; // Calcula a distância euclidiana entre dois pontos (considerando ponto como um objeto vetorial). A versão do método que calcula a distância de dois pontos independentes é um método estático.
static double dist(const Vetor*, const Vetor*);
Vetor* normalize(); // Normaliza o vetor para o comprimento 1 (faça dele um vetor unitário).
Vetor* limit(double); // Limita a magnitude desse vetor ao valor usado no parâmetro.
Vetor* setMag(double); // Define a magnitude desse vetor para o valor usado no parâmetro.
double heading() const; // Calcula e retorna o ângulo de rotação para este vetor (apenas vetores 2D)
Vetor* rotate(double); // Gira o vetor por um ângulo (apenas vetores 2D), a magnitude permanece a mesma.
static double angleBetween(Vetor*, Vetor*); // Calcula e retorna o ângulo (em radianos) entre dois vetores.
static Vetor* lerp(Vetor*, Vetor*, double = 0); // Interpolar linearmente o vetor para outro vetor.
double* array() const; // Retorna uma representação deste vetor como um array de double. Isso é apenas para uso temporário. Se for necessário usar de qualquer outra forma, o conteúdo deve ser copiado usando o método Vetor::copy() para copiar para sua própria matriz.
static bool equals(Vetor*, Vetor*); // Checa a igualdade entre dois vetores.
static Vetor* fromAngle(double); // Cria um novo vetor 2D unitário a partir de um ângulo.
static Vetor* random2D(); // Cria um novo vetor 2D unitário a partir de um ângulo aleatório.
static Vetor* random3D(); // Cria um novo vetor 3D unitário a partir de um ângulo aleatório.
};
class Objeto {
Vetor pos;
Vetor target;
Vetor vel;
Vetor acc;
double max_speed;
double max_force;
public:
Objeto() {
this->max_speed = 10;
this->max_force = 1;
}
Objeto* update();
Objeto* behaviors();
Objeto* applyForce(const Vetor*);
Vetor* arrive(const Vetor*);
Vetor* flee(const Vetor*);
};
}
#endif
#include "GeoA.h"
double GeoA::map(double value, double start1, double stop1, double start2, double stop2) {
return ((value - start1) / (stop1 - start1)) * (stop2 - start2) + start2;
}
#include "GeoA.h"
GeoA::Objeto* GeoA::Objeto::update() {
this->pos.add(&this->vel);
this->vel.add(&this->acc);
this->acc.mult(0);
return this;
}
GeoA::Objeto* GeoA::Objeto::behaviors() {
return this->applyForce(this->arrive(&this->target));
}
GeoA::Objeto* GeoA::Objeto::applyForce(const Vetor* force) {
this->acc.add(force);
return this;
}
GeoA::Vetor* GeoA::Objeto::arrive(const Vetor* target) {
GeoA::Vetor* desired = GeoA::Vetor::sub(target, &this->pos);
int d = desired->mag();
double speed = this->max_speed;
if (d < 100)
speed = GeoA::map(d, 0, 100, 0, this->max_speed);
desired->setMag(this->max_speed);
GeoA::Vetor* steer = GeoA::Vetor::sub(desired, &this->vel);
steer->limit(this->max_force);
return steer;
}
GeoA::Vetor* GeoA::Objeto::flee(const Vetor* target) {
GeoA::Vetor* desired = GeoA::Vetor::sub(target, &this->pos);
if (desired->mag() < 50) {
desired->setMag(this->max_speed);
desired->mult(-1);
GeoA::Vetor* steer = GeoA::Vetor::sub(desired, &this->vel);
steer->limit(this->max_force);
return steer;
}
return new Vetor();
}
#include "GeoA.h"
#include <cstdlib> // srand, rand
#include <ctime> // time
double GeoA::random() {
srand (static_cast <unsigned> (time(NULL)));
return static_cast <double> (rand()) / static_cast <double> (RAND_MAX);
}
double GeoA::random(double X) {
srand (static_cast <unsigned> (time(NULL)));
return static_cast <double> (rand()) / (static_cast <double> (RAND_MAX/X));
}
double GeoA::random(double LO, double HI) {
srand (static_cast <unsigned> (time(NULL)));
return LO + static_cast <double> (rand()) /( static_cast <double> (RAND_MAX/(HI-LO)));
}
#include "GeoA.h"
#include <string> // string
#include <cstring> // strcpy
#include <cmath> // mathematical functions
#include <iostream> // std
char* GeoA::Vetor::toString() const {
std::string str = "Objeto GeoA::Vetor : [";
str += std::to_string(this->x);
str += ",";
str += std::to_string(this->y);
str += ",";
str += std::to_string(this->z);
str += "]";
char* temp = new char[str.size()+1];
strcpy(temp, str.c_str());
return temp;
}
GeoA::Vetor* GeoA::Vetor::set(double px, double py, double pz) {
this->x = px;
this->y = py;
this->z = pz;
return this;
}
GeoA::Vetor* GeoA::Vetor::set(GeoA::Vetor* pv) {
this->x = pv->x;
this->y = pv->y;
this->z = pv->z;
return this;
}
GeoA::Vetor* GeoA::Vetor::copy() const {
return new GeoA::Vetor(this->x, this->y, this->z);
}
GeoA::Vetor* GeoA::Vetor::add(double px, double py, double pz) {
this->x += px;
this->y += py;
this->z += pz;
return this;
}
GeoA::Vetor* GeoA::Vetor::add(const GeoA::Vetor* pv) {
this->x += pv->x;
this->y += pv->y;
this->z += pv->z;
return this;
}
GeoA::Vetor* GeoA::Vetor::add(GeoA::Vetor* pv1, GeoA::Vetor* pv2) {
return new GeoA::Vetor(pv1->x + pv2->y, pv1->y + pv2->y, pv1->z + pv2->z);
}
GeoA::Vetor* GeoA::Vetor::sub(double px, double py, double pz) {
this->x -= px;
this->y -= py;
this->z -= pz;
return this;
}
GeoA::Vetor* GeoA::Vetor::sub(const GeoA::Vetor* pv) {
this->x -= pv->x;
this->y -= pv->y;
this->z -= pv->z;
return this;
}
GeoA::Vetor* GeoA::Vetor::sub(const GeoA::Vetor* pv1, const GeoA::Vetor* pv2) {
double x = pv2->x - pv1->x;
double y = pv2->y - pv1->y;
double z = pv2->z - pv1->z;
return new Vetor(x, y, z);
}
GeoA::Vetor* GeoA::Vetor::mult(double scl) {
this->x *= scl;
this->y *= scl;
this->z *= scl;
return this;
}
GeoA::Vetor* GeoA::Vetor::div(double scl) {
this->x /= scl;
this->y /= scl;
this->z /= scl;
return this;
}
double GeoA::Vetor::mag() {
return sqrt(this->magSq());
}
double GeoA::Vetor::magSq() {
return (this->x * this->x + this->y * this->y + this->z * this->z);
}
double GeoA::Vetor::dot(GeoA::Vetor* pv1, GeoA::Vetor* pv2) {
return (pv1->x * pv2->x + pv1->y * pv2->y + pv1->z * pv2->z);
}
GeoA::Vetor* GeoA::Vetor::cross(GeoA::Vetor* pv) const {
double x = this->y * pv->z - this->z * pv->y;
double y = this->z * pv->x - this->x * pv->z;
double z = this->x * pv->y - this->y * pv->x;
return new GeoA::Vetor(x, y, z);
}
double GeoA::Vetor::dist(const GeoA::Vetor* pv) const {
GeoA::Vetor* temp = pv->copy()->sub(this);
return temp->mag();
}
GeoA::Vetor* GeoA::Vetor::normalize() {
return this->mag() == 0 || this->mag() == 1 ? this : this->div(this->mag());
}
GeoA::Vetor* GeoA::Vetor::limit(double max) {
double aSq = this->magSq();
if (aSq > max * max) {
this->div(sqrt(aSq)); // normalize it
this->mult(max);
}
return this;
}
GeoA::Vetor* GeoA::Vetor::setMag(double mag) {
return this->normalize()->mult(mag);
}
double GeoA::Vetor::heading() const {
return atan2(this->y, this->x);
}
GeoA::Vetor* GeoA::Vetor::rotate(double a) {
double newHeading = this->heading() + a;
double mag = this->mag();
this->x = cos(newHeading) * mag;
this->y = sin(newHeading) * mag;
return this;
}
double GeoA::Vetor::angleBetween(GeoA::Vetor* pv1, GeoA::Vetor* pv2) {
return acos(GeoA::Vetor::dot(pv1, pv2) / (pv1->mag() * pv2->mag()));
}
GeoA::Vetor* GeoA::Vetor::lerp(GeoA::Vetor* pv1, GeoA::Vetor* pv2, double amt) {
Vetor* target = pv1->copy();
target->x += (pv2->x - pv1->x) * amt;
target->y += (pv2->y - pv1->y) * amt;
target->z += (pv2->z - pv1->z) * amt;
return target;
}
double* GeoA::Vetor::array() const {
double* data = new double[3];
data[0] = this->x;
data[1] = this->y;
data[2] = this->z;
return data;
}
bool GeoA::Vetor::equals(GeoA::Vetor* pv1, GeoA::Vetor* pv2) {
return (pv1->x == pv2->x && pv1->y == pv2->y && pv1->z == pv2->z);
}
GeoA::Vetor* GeoA::Vetor::fromAngle(double angle) {
return new GeoA::Vetor(cos(angle), sin(angle), 0);
}
GeoA::Vetor* GeoA::Vetor::random2D() {
return GeoA::Vetor::fromAngle(GeoA::random() * GeoA::PI * 2);;
}
GeoA::Vetor* GeoA::Vetor::random3D() {
double angle = GeoA::random() * GeoA::PI * 2;
double vz = GeoA::random() * 2 - 1;
double vx = sqrt(1 - vz * vz) * cos(angle);
double vy = sqrt(1 - vz * vz) * sin(angle);
return new GeoA::Vetor(vx, vy, vz);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment