json serialization beginnings, but still much to do
This commit is contained in:
+2
-2
@@ -4,12 +4,12 @@
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
|
||||
inline bool ViButton(Vec2D<float> mp, float x, float y, float radius, Color color){
|
||||
inline bool ViButton(Vec2Df mp, float x, float y, float radius, Color color){
|
||||
DrawCircle(x,y,radius, color);
|
||||
return (Vector2Distance(mp, (Vector2){x,y}) < radius && IsMouseButtonPressed(MOUSE_BUTTON_LEFT));
|
||||
}
|
||||
|
||||
inline bool ViSegButton(Vec2D<float> mp, float x, float y, float start_angle, float end_angle, float radius, Color color){
|
||||
inline bool ViSegButton(Vec2Df mp, float x, float y, float start_angle, float end_angle, float radius, Color color){
|
||||
DrawCircleSector((Vector2){x,y},radius, start_angle, end_angle, 5, color);
|
||||
return (Vector2Distance(mp, (Vector2){x,y}) < radius && IsMouseButtonPressed(MOUSE_BUTTON_LEFT));
|
||||
}
|
||||
|
||||
+33
-136
@@ -18,10 +18,14 @@
|
||||
#define VS_COLOR_BROWN (Color){84, 75, 61, 255}
|
||||
#define VS_COLOR_SUN (Color){214, 170, 21, 255}
|
||||
|
||||
#include "vmath.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
using json = nlohmann::json;
|
||||
|
||||
#include <cmath>
|
||||
#include <math.h>
|
||||
#include "libremidi/libremidi.hpp"
|
||||
#include "raylib.h"
|
||||
|
||||
enum Distribution {GEOMETRIC, ROUNDROBIN, RANDOM};
|
||||
|
||||
@@ -45,146 +49,36 @@ typedef std::vector<SPTR_Node> VEC_SPTR_Node;
|
||||
typedef std::vector<SPTR_Edge> VEC_SPTR_Edge;
|
||||
typedef std::vector<SPTR_Signal> VEC_SPTR_Signal;
|
||||
|
||||
using Vec2Df = VMath::Vec2D<float>;
|
||||
|
||||
// 2D Vectors
|
||||
|
||||
template<typename T>
|
||||
class Vec2D{
|
||||
public:
|
||||
|
||||
Vec2D() {};
|
||||
Vec2D(T x, T y) : x(x), y(y) {}
|
||||
T x = 0;
|
||||
T y = 0;
|
||||
T dist(Vec2D* v) { return sqrt(pow((v->x - x), 2) + pow((v->y - y), 2));};
|
||||
T dist(Vec2D v) { return sqrt(pow((v.x - x), 2) + pow((v.y - y), 2));};
|
||||
|
||||
T length() { return (T)sqrt(pow(x, 2) + pow(y, 2));};
|
||||
|
||||
T angle(Vec2D v){
|
||||
T angle = atan2(v.y, v.x) - atan2(y,x);
|
||||
if(angle > M_PI) angle -= M_PI_2;
|
||||
if(angle < -M_PI) angle += M_PI_2;
|
||||
return angle;
|
||||
//return acos(dot(v));
|
||||
};
|
||||
|
||||
T angleDeg(Vec2D v){
|
||||
return angle(v) * 180 / M_PI;
|
||||
};
|
||||
|
||||
T dot(Vec2D &v){
|
||||
return (x*v.x) + (y*v.y);
|
||||
};
|
||||
|
||||
T dot(Vec2D v){
|
||||
return (x*v.x) + (y*v.y);
|
||||
};
|
||||
|
||||
operator Vector2() const {
|
||||
return (Vector2){x,y};
|
||||
}
|
||||
|
||||
Vec2D orth(Vec2D &v){
|
||||
return Vec2D(-v.y, v.x);
|
||||
};
|
||||
|
||||
Vec2D orth(){
|
||||
return Vec2D(-y, x);
|
||||
};
|
||||
|
||||
Vec2D norm() { return *this / length();};
|
||||
|
||||
Vec2D center(Vec2D v){
|
||||
return Vec2D<T>{x,y} - (Vec2D<T>{x,y} - v)*0.5f;
|
||||
}
|
||||
|
||||
Vec2D& operator=(const Vec2D& vec){
|
||||
if (this == &vec){
|
||||
return *this;
|
||||
namespace nlohmann {
|
||||
template <typename T>
|
||||
struct adl_serializer<std::shared_ptr<T>> {
|
||||
static void to_json(json& j, const std::shared_ptr<T>& opt){
|
||||
if (opt)
|
||||
{
|
||||
j = *opt;
|
||||
}
|
||||
x = vec.x;
|
||||
y = vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator+=(const Vec2D& vec){
|
||||
this->x += vec.x;
|
||||
this->y += vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator-=(const Vec2D& vec){
|
||||
this->x -= vec.x;
|
||||
this->y -= vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator*=(const Vec2D& vec){
|
||||
this->x *= vec.x;
|
||||
this->y *= vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator/=(const Vec2D& vec){
|
||||
this->x /= vec.x;
|
||||
this->y /= vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator*=(T scalar){
|
||||
this->x *= scalar;
|
||||
this->y *= scalar;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator/=(T scalar){
|
||||
this->x /= scalar;
|
||||
this->y /= scalar;
|
||||
return *this;
|
||||
};
|
||||
|
||||
};
|
||||
else
|
||||
{
|
||||
j = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator+(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x + right.x, left.y + right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator-(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x - right.x, left.y - right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator*(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x * right.x, left.y * right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator/(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x / right.x, left.y / right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator/(const Vec2D<T> left, T scalar){
|
||||
return Vec2D<T>(left.x / scalar, left.y / scalar);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator*(const Vec2D<T> left, T scalar){
|
||||
return Vec2D<T>(left.x * scalar, left.y * scalar);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> cartesianToPolar(T x, T y) {
|
||||
return Vec2D<T>{sqrt(x * x + y * y), atan(y / x)}; // r,theta
|
||||
static void from_json(const json& j, std::shared_ptr<T>& opt){
|
||||
if (j.is_null())
|
||||
{
|
||||
opt = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
opt.reset(new T(j.get<T>()));
|
||||
//opt = j.get<T>();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> polarToCartesian(T r, T q) {
|
||||
return Vec2D<T>{r * cos(q), r * sin(q)};
|
||||
}
|
||||
|
||||
// App Settings
|
||||
struct AppSettings{
|
||||
@@ -217,6 +111,9 @@ struct MidiOut{
|
||||
int number;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiOut, number)
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiOutPort, number, enabled)
|
||||
|
||||
namespace MIDI{
|
||||
inline std::vector<std::string> Fractions = {"1/32","1/16","3/32","1/8","5/32","3/16","7/32","1/4","9/32","5/16","11/32","3/8","13/32","7/16","15/32","1/2","17/32","9/16","19/32","5/8","21/32","11/16","23/32","3/4","25/32","13/16","27/32","7/8","29/32","15/16","31/32","1/1"};
|
||||
inline std::vector<std::string> Notes = {
|
||||
|
||||
+3
-1
@@ -28,7 +28,9 @@ class Edge : public GraphItem{
|
||||
return start == origin ? end : start;
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> mouse_pos, Camera2D cam) {
|
||||
void draw(Vec2Df mouse_pos, Camera2D cam) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Edge, id, start, end, pass_forward, pass_backward)
|
||||
|
||||
+10
-2
@@ -8,11 +8,19 @@
|
||||
class GraphItem{
|
||||
|
||||
public:
|
||||
GraphItem() {static int _id; id=_id++;}
|
||||
std::vector<std::shared_ptr<GraphItem>> neighbors;
|
||||
|
||||
int id = 0;
|
||||
GraphItemType graphItemType;
|
||||
|
||||
virtual void draw(Vec2D<float> mouse, Camera2D cam) = 0;
|
||||
virtual void draw(Vec2Df mouse, Camera2D cam) {};
|
||||
virtual GraphItemType getType() {return graphItemType;}
|
||||
virtual ~GraphItem() = default;
|
||||
|
||||
/*void to_json(json& j, const GraphItem& G){*/
|
||||
/* j = json{{"id",id},{"graphItemType",graphItemType},{"neighbors",neighbors}};*/
|
||||
/*}*/
|
||||
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GraphItem, id, graphItemType, neighbors)
|
||||
|
||||
+50
-28
@@ -5,8 +5,9 @@
|
||||
#include "raylib.h"
|
||||
#include "raymath.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "button.h"
|
||||
#include "graph-item.h"
|
||||
#include "midi-node.h"
|
||||
#include "node.h"
|
||||
#include "edge.h"
|
||||
@@ -21,6 +22,8 @@
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
class GraphManager{
|
||||
|
||||
public:
|
||||
@@ -35,6 +38,14 @@ class GraphManager{
|
||||
|
||||
std::map<SPTR_Node, int> counter;
|
||||
|
||||
/*void to_json(json& j, const GraphManager& G){*/
|
||||
/* j = json{{"nodes", G.nodes}, {"edges", G.edges}};*/
|
||||
/*}*/
|
||||
/**/
|
||||
/*void from_json(const json& j, GraphManager& G){*/
|
||||
/**/
|
||||
/*}*/
|
||||
|
||||
SPTR_Node getRandomNode(){
|
||||
VEC_SPTR_GraphItem o;
|
||||
std::ranges::sample(nodes, std::back_inserter(o), 1, std::mt19937{std::random_device{}()});
|
||||
@@ -47,7 +58,7 @@ class GraphManager{
|
||||
return std::dynamic_pointer_cast<Edge>(o.front());
|
||||
}
|
||||
|
||||
void copyNodes(VEC_SPTR_Node _nodes, Vec2D<float> position){
|
||||
void copyNodes(VEC_SPTR_Node _nodes, Vec2Df position){
|
||||
for(auto n: _nodes){
|
||||
nodes.insert(nodes.end(), std::make_shared<Node>(*n));
|
||||
nodes.back()->setPosition(position + nodes.back()->drag_offset);
|
||||
@@ -55,7 +66,7 @@ class GraphManager{
|
||||
}
|
||||
}
|
||||
|
||||
void copyNodes(std::vector<std::shared_ptr<MidiNode>> _nodes, Vec2D<float> position){
|
||||
void copyNodes(std::vector<std::shared_ptr<MidiNode>> _nodes, Vec2Df position){
|
||||
for(auto n: _nodes){
|
||||
nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));
|
||||
nodes.back()->setPosition(position + nodes.back()->drag_offset);
|
||||
@@ -63,21 +74,21 @@ class GraphManager{
|
||||
}
|
||||
}
|
||||
|
||||
SPTR_Node copyNode(SPTR_Node n, Vec2D<float> position){
|
||||
SPTR_Node copyNode(SPTR_Node n, Vec2Df position){
|
||||
std::cout << "copy basenode" << std::endl;
|
||||
nodes.insert(nodes.end(), std::make_shared<Node>(*n));
|
||||
nodes.back()->setPosition(position);
|
||||
return nodes.back();
|
||||
}
|
||||
|
||||
SPTR_Node copyNode(std::shared_ptr<MidiNode> n, Vec2D<float> position){
|
||||
SPTR_Node copyNode(std::shared_ptr<MidiNode> n, Vec2Df position){
|
||||
std::cout << "copy midinode" << std::endl;
|
||||
nodes.insert(nodes.end(), std::make_shared<MidiNode>(*n));
|
||||
nodes.back()->setPosition(position);
|
||||
return nodes.back();
|
||||
}
|
||||
|
||||
SPTR_Node addMidiNode(Vec2D<float> position){
|
||||
SPTR_Node addMidiNode(Vec2Df position){
|
||||
nodes.emplace_back(std::make_shared<MidiNode>(position));
|
||||
return nodes.back();
|
||||
}
|
||||
@@ -102,7 +113,7 @@ class GraphManager{
|
||||
int return_path = 0;
|
||||
float angle = -1;
|
||||
if(current->distributionMode == Distribution::GEOMETRIC){
|
||||
Vec2D<float> coming_from = (current->position - last->position).norm();
|
||||
Vec2Df coming_from = (current->position - last->position).norm();
|
||||
int i = 0;
|
||||
for(auto n : possible_connections){
|
||||
SPTR_Node next_node = n->getNextNode(current);
|
||||
@@ -148,7 +159,7 @@ class GraphManager{
|
||||
|
||||
void splitEdges(){
|
||||
for(auto s : split_edges){
|
||||
Vec2D<float> center = s->end->position.center(s->start->position);
|
||||
Vec2Df center = s->end->position.center(s->start->position);
|
||||
SPTR_Node cn = addMidiNode(center);
|
||||
addConnection(s->start, cn);
|
||||
addConnection(cn, s->end);
|
||||
@@ -170,12 +181,12 @@ class GraphManager{
|
||||
remove_edges.clear();
|
||||
}
|
||||
|
||||
void drawEdges(Vec2D<float> mouse_pos, Camera2D cam){
|
||||
void drawEdges(Vec2Df mouse_pos, Camera2D cam){
|
||||
if(!remove_edges.empty()) removeEdges();
|
||||
if(!split_edges.empty()) splitEdges();
|
||||
for(auto c : edges){
|
||||
Vec2D<float> v1_position = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->connector_offset);
|
||||
Vec2D<float> v2_position = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->connector_offset);
|
||||
Vec2Df v1_position = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->connector_offset);
|
||||
Vec2Df v2_position = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->connector_offset);
|
||||
float v1_v2_distance = v1_position.dist(&v2_position);
|
||||
|
||||
float midi_gate_v1 = Clamp((4.f / 1000.f) * c->start->GGate(), 1.f, 4.f);
|
||||
@@ -194,12 +205,12 @@ class GraphManager{
|
||||
DrawCircle(v2_position.x, v2_position.y, midi_gate_v2, col);
|
||||
|
||||
if(v1_v2_distance < 100) c->switches_offset = v1_v2_distance/2.3f;
|
||||
Vec2D<float> from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->switches_offset);
|
||||
Vec2D<float> to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->switches_offset);
|
||||
Vec2D<float> middle_handle = c->end->position - ((c->end->position - c->start->position))*0.4f;
|
||||
Vec2D<float> middle_handle_2 = c->end->position - ((c->end->position - c->start->position))*0.6f;
|
||||
Vec2D<float> flip_handle = middle_handle + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*0.2, 0.f, 20.f) : 1.0f);
|
||||
Vec2D<float> flip_handle_2 = middle_handle_2 + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*-0.2, -20.f, 0.f) : 1.0f);
|
||||
Vec2Df from_to_handle = c->start->position - ((c->start->position - c->end->position)).norm() * (c->start->radius + c->switches_offset);
|
||||
Vec2Df to_from_handle = c->end->position - ((c->end->position - c->start->position)).norm() * (c->end->radius + c->switches_offset);
|
||||
Vec2Df middle_handle = c->end->position - ((c->end->position - c->start->position))*0.4f;
|
||||
Vec2Df middle_handle_2 = c->end->position - ((c->end->position - c->start->position))*0.6f;
|
||||
Vec2Df flip_handle = middle_handle + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*0.2, 0.f, 20.f) : 1.0f);
|
||||
Vec2Df flip_handle_2 = middle_handle_2 + (v1_position - v2_position).norm().orth() * (v1_v2_distance < 120.0f ? Clamp((120.0f - v1_v2_distance)*-0.2, -20.f, 0.f) : 1.0f);
|
||||
|
||||
// Dynamic opacity by distance to mouse
|
||||
unsigned char opacity = 150.0f - Clamp(middle_handle.dist(mouse_pos), 0.0f, 150.0f);
|
||||
@@ -212,14 +223,14 @@ class GraphManager{
|
||||
if(ViButton(mouse_pos, to_from_handle.x, to_from_handle.y, 8.0f, c->pass_backward ? (Color){120, 210, 115, opacity_to} : (Color){232, 50, 32, opacity_to} )) c->pass_backward = !c->pass_backward;
|
||||
|
||||
if(!c->pass_forward){
|
||||
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle;
|
||||
Vec2D<float> block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle;
|
||||
Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + from_to_handle;
|
||||
Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + from_to_handle;
|
||||
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_from});
|
||||
}
|
||||
|
||||
if(!c->pass_backward){
|
||||
Vec2D<float> block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle;
|
||||
Vec2D<float> block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle;
|
||||
Vec2Df block_point1 = (v1_position - v2_position).norm().orth()*4.0f + to_from_handle;
|
||||
Vec2Df block_point2 = (v1_position - v2_position).norm().orth()*-4.0f + to_from_handle;
|
||||
DrawLineEx(block_point1, block_point2, 2.0f, (Color){232,232,232,opacity_to});
|
||||
}
|
||||
|
||||
@@ -229,7 +240,7 @@ class GraphManager{
|
||||
}
|
||||
}
|
||||
|
||||
void drawNodes(Vec2D<float> mouse_pos, Camera2D camera){
|
||||
void drawNodes(Vec2Df mouse_pos, Camera2D camera){
|
||||
auto neighbors = nodes | RANGE_FILTER([](SPTR_Node n){ return !n->dragging && !n->selected;}) | std::ranges::to<VEC_SPTR_Node>();
|
||||
float min_d = 480;
|
||||
for(auto n : nodes){
|
||||
@@ -247,16 +258,16 @@ class GraphManager{
|
||||
Vector2 text_length = MeasureTextEx(GetFontDefault(), std::format("{:.1f}",dn).c_str(), 10.0f, 2.0f);
|
||||
Vector2 text_length_frac = MeasureTextEx(GetFontDefault(), frac.c_str(), 10.0f, 2.0f);
|
||||
|
||||
Vec2D<float> middle_handle = nb->position + (n->position - nb->position) * ((dn - text_length.x)*0.5f)/dn;
|
||||
Vec2D<float> middle_handle_frac = nb->position + (n->position - nb->position) * ((dn - text_length_frac.x)*0.5f)/dn;
|
||||
Vec2D<float> text_position = middle_handle + (nb->position - n->position).norm().orth() * 12.0f;
|
||||
Vec2D<float> text_position_frac = middle_handle_frac - (nb->position - n->position).norm().orth() * 4.0f;
|
||||
Vec2Df middle_handle = nb->position + (n->position - nb->position) * ((dn - text_length.x)*0.5f)/dn;
|
||||
Vec2Df middle_handle_frac = nb->position + (n->position - nb->position) * ((dn - text_length_frac.x)*0.5f)/dn;
|
||||
Vec2Df text_position = middle_handle + (nb->position - n->position).norm().orth() * 12.0f;
|
||||
Vec2Df text_position_frac = middle_handle_frac - (nb->position - n->position).norm().orth() * 4.0f;
|
||||
|
||||
float rotation = Vector2Angle((Vector2){1,0}, (n->position - nb->position)) * RAD2DEG;
|
||||
DrawTextPro(GetFontDefault(), std::format("{:.1f}",dn).c_str(), text_position, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
|
||||
if(nb == neighbors.front() && IsKeyDown(KEY_LEFT_SHIFT)) DrawTextPro(GetFontDefault(), frac.c_str(), text_position_frac, (Vector2){0,0}, rotation, 10.0f, 2.0f, VS_COLOR_PINK);
|
||||
Vec2D<float> n_position = n->position - ((n->position - nb->position)).norm() * 20.0f;
|
||||
Vec2D<float> nb_position = nb->position - ((nb->position - n->position)).norm() * 20.0f;
|
||||
Vec2Df n_position = n->position - ((n->position - nb->position)).norm() * 20.0f;
|
||||
Vec2Df nb_position = nb->position - ((nb->position - n->position)).norm() * 20.0f;
|
||||
DrawLineV(n_position, nb_position, VS_COLOR_PINK);
|
||||
}
|
||||
|
||||
@@ -269,3 +280,14 @@ class GraphManager{
|
||||
|
||||
};
|
||||
|
||||
inline void to_json(json& j, const Node& N) {
|
||||
std::vector<int> conns;
|
||||
std::ranges::transform(N.connections.begin(), N.connections.end(), std::back_inserter(conns), [](SPTR_Edge e){ return e->id;});
|
||||
j = json{{"neighbor", N.neighbor}, {"nodeType", N.nodeType}, {"distributionMode", N.distributionMode}, {"connections", conns}};
|
||||
|
||||
}
|
||||
inline void from_json(const json& j, Node& N) {
|
||||
|
||||
}
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(GraphManager, nodes, edges)
|
||||
|
||||
+28
-26
@@ -6,28 +6,30 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "midi-node.h"
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#define RAYGUI_IMPLEMENTATION
|
||||
|
||||
#include "datatypes.h"
|
||||
#include <ranges>
|
||||
#include <raylib.h>
|
||||
#include <raymath.h>
|
||||
|
||||
#include "state-manager.h"
|
||||
#include "datatypes.h"
|
||||
#include "midi-node.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
#include <cmath>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#include "state-manager.h"
|
||||
using json = nlohmann::json;
|
||||
|
||||
AppState app;
|
||||
|
||||
Vec2D<float> mouse_pos;
|
||||
Vec2D<float> drag_start;
|
||||
Vec2Df mouse_pos;
|
||||
Vec2Df drag_start;
|
||||
|
||||
Camera2D camera = { {0} };
|
||||
|
||||
@@ -71,25 +73,25 @@ int main(){
|
||||
camera.zoom = 1.0f;
|
||||
|
||||
for(int i = 0; i < 4; ++i){
|
||||
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 2 * app.settings.grid*4});
|
||||
app.gm.addMidiNode(Vec2Df{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 2 * app.settings.grid*4});
|
||||
}
|
||||
for(int i = 3; i >= 0; --i){
|
||||
app.gm.addMidiNode(Vec2D<float>{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 3 * app.settings.grid*4});
|
||||
app.gm.addMidiNode(Vec2Df{(float)i * app.settings.grid*4 + 7 * app.settings.grid, 3 * app.settings.grid*4});
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; ++i){
|
||||
app.gm.addConnection(app.gm.nodes[i], app.gm.nodes[(i+1) % 8]);
|
||||
}
|
||||
|
||||
std::cout << app.gm.nodes[0]->getNodeType() << std::endl;
|
||||
std::cout << std::setw(2) << json(app.gm) << std::endl;
|
||||
|
||||
app.sm.addSignalAtNode(app.gm.nodes.front());
|
||||
app.sm.addSignalAtNode(app.gm.nodes.front());
|
||||
app.sm.startSignalThread();
|
||||
|
||||
enum InteractionState {HOVER_CANVAS, HOVER_NODE, HOVER_CONNECTOR, DRAG_NODE, CONNECT_NODE, DRAW_SELECTION, DELETE_SELECTED_NODES, COPY_SELECTED_NODES, PASTE_SELECTED_NODES};
|
||||
InteractionState istate = HOVER_CANVAS;
|
||||
|
||||
Vec2D<float> select_start;
|
||||
Vec2Df select_start;
|
||||
Rectangle selection;
|
||||
|
||||
VEC_SPTR_Node copied_nodes;
|
||||
@@ -103,8 +105,8 @@ int main(){
|
||||
app.settings.speed = (app.settings.grid * 16.0f) * (app.settings.bpm / 120.f);
|
||||
|
||||
Vector2 mp = GetScreenToWorld2D(GetMousePosition(), camera);
|
||||
Vec2D<float> mouse_pos = {(float)mp.x, (float)mp.y};
|
||||
Vec2D<float> cam_pos = {camera.offset.x, camera.offset.y};
|
||||
Vec2Df mouse_pos = {(float)mp.x, (float)mp.y};
|
||||
Vec2Df cam_pos = {camera.offset.x, camera.offset.y};
|
||||
|
||||
bool mouse_down = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
|
||||
bool mouse_clicked = IsMouseButtonPressed(MOUSE_BUTTON_LEFT);
|
||||
@@ -114,8 +116,8 @@ int main(){
|
||||
bool mouse_right_clicked = IsMouseButtonPressed(MOUSE_BUTTON_RIGHT);
|
||||
bool mouse_right_released = IsMouseButtonReleased(MOUSE_BUTTON_RIGHT);
|
||||
|
||||
Vec2D<float> mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
|
||||
Vec2D<float> delta = mouse_delta * (-1.0f/camera.zoom);
|
||||
Vec2Df mouse_delta = {GetMouseDelta().x, GetMouseDelta().y};
|
||||
Vec2Df delta = mouse_delta * (-1.0f/camera.zoom);
|
||||
|
||||
auto dragging_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->dragging;});
|
||||
auto connecting_nodes = app.gm.nodes | RANGE_FILTER([](SPTR_Node n) { return n->connecting;});
|
||||
@@ -163,8 +165,8 @@ int main(){
|
||||
select_start = mouse_pos;
|
||||
}
|
||||
if(mouse_down){
|
||||
Vec2D<float> select1 = {mouse_pos.x > select_start.x ? select_start.x : mouse_pos.x, mouse_pos.y > select_start.y ? select_start.y : mouse_pos.y};
|
||||
Vec2D<float> select2 = {mouse_pos.x > select_start.x ? mouse_pos.x - select_start.x : select_start.x - mouse_pos.x, mouse_pos.y > select_start.y ? mouse_pos.y - select_start.y : select_start.y - mouse_pos.y};
|
||||
Vec2Df select1 = {mouse_pos.x > select_start.x ? select_start.x : mouse_pos.x, mouse_pos.y > select_start.y ? select_start.y : mouse_pos.y};
|
||||
Vec2Df select2 = {mouse_pos.x > select_start.x ? mouse_pos.x - select_start.x : select_start.x - mouse_pos.x, mouse_pos.y > select_start.y ? mouse_pos.y - select_start.y : select_start.y - mouse_pos.y};
|
||||
DrawRectangleLines(select1.x, select1.y, select2.x, select2.y, (Color){150,150,150,150});
|
||||
selection = (Rectangle){select1.x, select1.y, select2.x, select2.y};
|
||||
|
||||
@@ -219,9 +221,9 @@ int main(){
|
||||
} else if(IsKeyDown(KEY_LEFT_SHIFT)){
|
||||
float steps = round((dragNode->neighbor->position.dist(mouse_pos)) / app.settings.grid) * app.settings.grid;
|
||||
float pol_r = steps;
|
||||
float pol_theta = Vector2Angle(Vec2D<float>{1,0},(mouse_pos - dragNode->neighbor->position));
|
||||
float pol_theta = Vector2Angle(Vec2Df{1,0},(mouse_pos - dragNode->neighbor->position));
|
||||
|
||||
Vec2D<float> polar = polarToCartesian(pol_r, pol_theta);
|
||||
Vec2Df polar = VMath::polarToCartesian(pol_r, pol_theta);
|
||||
dragNode->position = dragNode->neighbor->position + polar;
|
||||
} else {
|
||||
dragNode->position = mouse_pos + dragNode->drag_offset;
|
||||
@@ -254,7 +256,7 @@ int main(){
|
||||
}
|
||||
case InteractionState::CONNECT_NODE:
|
||||
{
|
||||
Vec2D<float> connector_position = connecting_nodes.front()->position - ((connecting_nodes.front()->position - mouse_pos)).norm() * (connecting_nodes.front()->radius + 14.0f);
|
||||
Vec2Df connector_position = connecting_nodes.front()->position - ((connecting_nodes.front()->position - mouse_pos)).norm() * (connecting_nodes.front()->radius + 14.0f);
|
||||
|
||||
if(connecting_nodes.front()->connecting && mouse_down){
|
||||
DrawLine(connector_position.x, connector_position.y, mouse_pos.x, mouse_pos.y, (Color){229, 181, 103, 255});
|
||||
@@ -312,7 +314,7 @@ int main(){
|
||||
if(!hovering_nodes.empty() && hovering_nodes.front()->getNodeType() == NodeType::MIDINODE) {
|
||||
VEC_SPTR_Node modify_nodes;
|
||||
std::copy_if(selected_nodes.begin(), selected_nodes.end(), std::back_inserter(modify_nodes), [](SPTR_Node n){ return n->getNodeType() == NodeType::MIDINODE;});
|
||||
std::copy_if(hovering_nodes.begin(), hovering_nodes.end(), std::back_inserter(modify_nodes), [modify_nodes](SPTR_Node n){ return n->getNodeType() == NodeType::MIDINODE && !std::ranges::contains(modify_nodes, n);});
|
||||
if(selected_nodes.empty()) std::copy_if(hovering_nodes.begin(), hovering_nodes.end(), std::back_inserter(modify_nodes), [modify_nodes](SPTR_Node n){ return n->getNodeType() == NodeType::MIDINODE && !std::ranges::contains(modify_nodes, n);});
|
||||
|
||||
for(auto n : modify_nodes){
|
||||
std::shared_ptr<MidiNode> midiNode = std::dynamic_pointer_cast<MidiNode>(n);
|
||||
|
||||
+8
-4
@@ -5,7 +5,7 @@
|
||||
#include "raymath.h"
|
||||
#include <map>
|
||||
|
||||
#define R 14.0f
|
||||
#define RADIUS 14.0f
|
||||
|
||||
struct NodeMidiOut{
|
||||
int i;
|
||||
@@ -13,12 +13,14 @@ struct NodeMidiOut{
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(NodeMidiOut, i, name, enabled)
|
||||
|
||||
class MidiNode : public Node{
|
||||
|
||||
public:
|
||||
|
||||
MidiNode() {}
|
||||
MidiNode(Vec2D<float> position) : Node(position) {}
|
||||
MidiNode(Vec2Df position) : Node(position) {}
|
||||
|
||||
NodeType nodeType = NodeType::MIDINODE;
|
||||
|
||||
@@ -81,7 +83,7 @@ class MidiNode : public Node{
|
||||
return midi_gate;
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> mouse, Camera2D cam) override {
|
||||
void draw(Vec2Df mouse, Camera2D cam) override {
|
||||
last = time;
|
||||
time = GetTime();
|
||||
if(time - start >= (float)midi_gate / 1000.0f){
|
||||
@@ -155,7 +157,7 @@ class MidiNode : public Node{
|
||||
}
|
||||
}
|
||||
|
||||
Vec2D<float> connector = position - ((position - mouse)).norm() * (radius + R);
|
||||
Vec2Df connector = position - ((position - mouse)).norm() * (radius + RADIUS);
|
||||
float opacity = 150.0f - Clamp(position.dist(mouse), 0.0f, 150.0f);
|
||||
|
||||
if(hover_connect){
|
||||
@@ -166,3 +168,5 @@ class MidiNode : public Node{
|
||||
if(highlighted) DrawCircleLinesV(position, radius+2, (Color){255, 0, 0, 200});
|
||||
}
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MidiNode, id, nodeType, send_note, send_cc, send_pc, send_pitch_bend, midi_outs, mode, midi_note_channel, midi_note, midi_velocity, midi_gate, midi_cc_channel, midi_cc, midi_cc_value, midi_pc_channel, midi_pc, midi_pc_value, midi_pitch_bend_channel, midi_pitch_bend)
|
||||
|
||||
@@ -127,5 +127,3 @@ class Midi {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
+14
-7
@@ -2,21 +2,22 @@
|
||||
|
||||
#include "datatypes.h"
|
||||
|
||||
|
||||
class Movable{
|
||||
|
||||
public:
|
||||
Movable() {}
|
||||
virtual ~Movable() {}
|
||||
|
||||
Movable(Vec2D<float> p, Vec2D<float> d, float s) : speed(s), position(p), direction(d) {}
|
||||
Movable(Vec2D<float> p, float s) : speed(s), position(p) {}
|
||||
Movable(Vec2Df p, Vec2Df d, float s) : speed(s), position(p), direction(d) {}
|
||||
Movable(Vec2Df p, float s) : speed(s), position(p) {}
|
||||
|
||||
float speed = 1.0f;
|
||||
|
||||
Vec2D<float> position;
|
||||
Vec2D<float> direction;
|
||||
Vec2Df position;
|
||||
Vec2Df direction;
|
||||
|
||||
Vec2D<float> drag_offset;
|
||||
Vec2Df drag_offset;
|
||||
|
||||
bool in_rect = false;
|
||||
|
||||
@@ -31,8 +32,14 @@ class Movable{
|
||||
|
||||
bool erase = false;
|
||||
|
||||
virtual void setPosition(Vec2D<float> _position) {position = _position;}
|
||||
virtual Vec2D<float> getPosition() {return position;};
|
||||
virtual void setPosition(Vec2Df _position) {position = _position;}
|
||||
virtual Vec2Df getPosition() {return position;};
|
||||
virtual void update(double frametime) {};
|
||||
virtual void update() {};
|
||||
|
||||
/*virtual void to_json(json& j, const Movable& M){*/
|
||||
/* j = json{{"position", M.position}, {"direction", M.direction}, {"speed", M.speed}};*/
|
||||
/*}*/
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Movable, position, direction, speed)
|
||||
|
||||
+14
-6
@@ -2,7 +2,8 @@
|
||||
|
||||
#include <raylib.h>
|
||||
|
||||
#include "edge.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "datatypes.h"
|
||||
#include "graph-item.h"
|
||||
#include "moveable.h"
|
||||
@@ -11,17 +12,17 @@ class Node : public Movable, public GraphItem{
|
||||
|
||||
public:
|
||||
Node() {}
|
||||
Node(float x, float y) : Movable(Vec2D<float>(x, y), 0.0f) {}
|
||||
Node(Vec2D<float> p) : Movable(p, 0.0f) {}
|
||||
Node(float x, float y) : Movable(Vec2Df(x, y), 0.0f) {}
|
||||
Node(Vec2Df p) : Movable(p, 0.0f) {}
|
||||
|
||||
NodeType nodeType;
|
||||
NodeType nodeType;
|
||||
|
||||
SPTR_Node neighbor;
|
||||
|
||||
VEC_SPTR_Edge connections;
|
||||
|
||||
Distribution distributionMode = Distribution::GEOMETRIC;
|
||||
|
||||
|
||||
float radius = 15.0f;
|
||||
bool config = false;
|
||||
|
||||
@@ -31,5 +32,12 @@ class Node : public Movable, public GraphItem{
|
||||
virtual int GGate() {return 0;};
|
||||
virtual int GActive() {return 0;};
|
||||
virtual void trigger() {};
|
||||
void draw(Vec2D<float> mouse_pos, Camera2D cam) {}
|
||||
void draw(Vec2Df mouse_pos, Camera2D cam) override {}
|
||||
};
|
||||
|
||||
/*inline void to_json(json& j, const std::shared_ptr<Node>& N){*/
|
||||
/* j = json{{"id", N->id}, {"nodeType",N->nodeType}};*/
|
||||
/*}*/
|
||||
|
||||
//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Node, nodeType, neighbor, connections, distributionMode)
|
||||
//NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Node, id, nodeType, distributionMode)
|
||||
|
||||
@@ -41,7 +41,7 @@ class SignalManager{
|
||||
|
||||
void reset(){
|
||||
for(auto &s : signals){
|
||||
s->position = s->start->position + Vec2D<float>{0.1, 0.1};
|
||||
s->position = s->start->position + Vec2Df{0.1, 0.1};
|
||||
s->next = s->start;
|
||||
s->last = s->start;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class SignalManager{
|
||||
|
||||
void addSignalAtNode(SPTR_Node node){
|
||||
Color c = {(unsigned char)(20 + (rand() % 200)), 100, (unsigned char)(20 + (int)(rand() % 200)), 200};
|
||||
signals.emplace_back(std::make_shared<Signal>(node->position + Vec2D<float>{0.5f, 0.5f}, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
||||
signals.emplace_back(std::make_shared<Signal>(node->position + Vec2Df{0.5f, 0.5f}, 8.0f, 0, c)); // position + 1 or else it does not render. why? no idea!
|
||||
signals.back()->next = node;
|
||||
signals.back()->last = node;
|
||||
signals.back()->start = node;
|
||||
@@ -105,7 +105,7 @@ class SignalManager{
|
||||
}
|
||||
}
|
||||
|
||||
void drawSignals(Vec2D<float> mouse_pos, Camera2D camera){
|
||||
void drawSignals(Vec2Df mouse_pos, Camera2D camera){
|
||||
for(auto s : signals){
|
||||
mutex->lock();
|
||||
s->draw(mouse_pos, camera);
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@ class Signal : public Movable{
|
||||
public:
|
||||
|
||||
Signal();
|
||||
Signal(Vec2D<float> position, float r, float _speed, Color color) : Movable(position, Vec2D<float>(0,0), _speed), radius(r), color(color) {}
|
||||
Signal(Vec2Df position, float r, float _speed, Color color) : Movable(position, Vec2Df(0,0), _speed), radius(r), color(color) {}
|
||||
|
||||
SPTR_Node next;
|
||||
SPTR_Node last;
|
||||
@@ -32,7 +32,7 @@ class Signal : public Movable{
|
||||
position += direction.norm() * speed * multiplier * (float)t_delta / 1000000.0f;
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> mouse, Camera2D cam) {
|
||||
void draw(Vec2Df mouse, Camera2D cam) {
|
||||
DrawCircle(position.x, position.y, radius, color);
|
||||
}
|
||||
};
|
||||
|
||||
+3
-3
@@ -45,7 +45,7 @@ class AppState{
|
||||
}
|
||||
}
|
||||
|
||||
void copyNodesAndConnections(VEC_SPTR_Node nodes, Vec2D<float> position){
|
||||
void copyNodesAndConnections(VEC_SPTR_Node nodes, Vec2Df position){
|
||||
|
||||
VEC_SPTR_Edge copy_connections;
|
||||
for(auto n : nodes){
|
||||
@@ -129,7 +129,7 @@ class AppState{
|
||||
std::erase_if(gm.nodes, [nodes](SPTR_Node n){ return std::ranges::contains(nodes, n);});
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> mouse_pos, Camera2D camera){
|
||||
void draw(Vec2Df mouse_pos, Camera2D camera){
|
||||
mutex.lock();
|
||||
updateMidiPorts();
|
||||
mutex.unlock();
|
||||
@@ -138,7 +138,7 @@ class AppState{
|
||||
sm.drawSignals(mouse_pos, camera);
|
||||
}
|
||||
|
||||
void drawUI(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||
void drawUI(Vec2Df *mouse_pos, Camera2D *camera){
|
||||
mutex.lock();
|
||||
ui.draw(mouse_pos, camera);
|
||||
mutex.unlock();
|
||||
|
||||
@@ -83,7 +83,7 @@ class AppUI{
|
||||
int s_nodes = s_signal + 70 + signal_configs*20;
|
||||
GuiLabel((Rectangle){20, (float)s_nodes + 30, 240, 20}, "NODES");
|
||||
if(GuiButton((Rectangle){20, (float)s_nodes + 60, 240, 20}, "ADD RANDOM NODE")){
|
||||
gm->addMidiNode(Vec2D<float>{200.0f, 200.0f});
|
||||
gm->addMidiNode(Vec2Df{200.0f, 200.0f});
|
||||
}
|
||||
DrawText(std::format("{}", gm->nodes.size()).c_str(), 20, settings->height - 70, 15, VS_COLOR_WHITE);
|
||||
DrawFPS(20, settings->height - 30);
|
||||
@@ -179,7 +179,7 @@ class AppUI{
|
||||
}
|
||||
}
|
||||
|
||||
void draw(Vec2D<float> *mouse_pos, Camera2D *camera){
|
||||
void draw(Vec2Df *mouse_pos, Camera2D *camera){
|
||||
drawSideBar();
|
||||
drawPerNodeConfig(camera);
|
||||
}
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#pragma once
|
||||
|
||||
#include "raylib.h"
|
||||
#include <cmath>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace VMath{
|
||||
|
||||
template<typename T>
|
||||
class Vec2D{
|
||||
public:
|
||||
|
||||
Vec2D() {};
|
||||
Vec2D(T x, T y) : x(x), y(y) {}
|
||||
T x = 0;
|
||||
T y = 0;
|
||||
T dist(Vec2D* v) { return sqrt(pow((v->x - x), 2) + pow((v->y - y), 2));};
|
||||
T dist(Vec2D v) { return sqrt(pow((v.x - x), 2) + pow((v.y - y), 2));};
|
||||
|
||||
T length() { return (T)sqrt(pow(x, 2) + pow(y, 2));};
|
||||
|
||||
T angle(Vec2D v){
|
||||
T angle = atan2(v.y, v.x) - atan2(y,x);
|
||||
if(angle > M_PI) angle -= M_PI_2;
|
||||
if(angle < -M_PI) angle += M_PI_2;
|
||||
return angle;
|
||||
//return acos(dot(v));
|
||||
};
|
||||
|
||||
T angleDeg(Vec2D v){
|
||||
return angle(v) * 180 / M_PI;
|
||||
};
|
||||
|
||||
T dot(Vec2D &v){
|
||||
return (x*v.x) + (y*v.y);
|
||||
};
|
||||
|
||||
T dot(Vec2D v){
|
||||
return (x*v.x) + (y*v.y);
|
||||
};
|
||||
|
||||
operator Vector2() const {
|
||||
return (Vector2){x,y};
|
||||
}
|
||||
|
||||
Vec2D orth(Vec2D &v){
|
||||
return Vec2D(-v.y, v.x);
|
||||
};
|
||||
|
||||
Vec2D orth(){
|
||||
return Vec2D(-y, x);
|
||||
};
|
||||
|
||||
Vec2D norm() { return *this / length();};
|
||||
|
||||
Vec2D center(Vec2D v){
|
||||
return Vec2D<T>{x,y} - (Vec2D<T>{x,y} - v)*0.5f;
|
||||
}
|
||||
|
||||
Vec2D& operator=(const Vec2D& vec){
|
||||
if (this == &vec){
|
||||
return *this;
|
||||
}
|
||||
x = vec.x;
|
||||
y = vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator+=(const Vec2D& vec){
|
||||
this->x += vec.x;
|
||||
this->y += vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator-=(const Vec2D& vec){
|
||||
this->x -= vec.x;
|
||||
this->y -= vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator*=(const Vec2D& vec){
|
||||
this->x *= vec.x;
|
||||
this->y *= vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator/=(const Vec2D& vec){
|
||||
this->x /= vec.x;
|
||||
this->y /= vec.y;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator*=(T scalar){
|
||||
this->x *= scalar;
|
||||
this->y *= scalar;
|
||||
return *this;
|
||||
};
|
||||
|
||||
Vec2D& operator/=(T scalar){
|
||||
this->x /= scalar;
|
||||
this->y /= scalar;
|
||||
return *this;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void to_json(json& j, const Vec2D<T> V){
|
||||
j = json{{"x",V.x},{"y",V.y}};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void from_json(const json& j, Vec2D<T> V){
|
||||
j.at("x").get_to(V.x);
|
||||
j.at("y").get_to(V.y);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator+(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x + right.x, left.y + right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator-(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x - right.x, left.y - right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator*(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x * right.x, left.y * right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator/(const Vec2D<T> left, const Vec2D<T> right){
|
||||
return Vec2D<T>(left.x / right.x, left.y / right.y);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator/(const Vec2D<T> left, T scalar){
|
||||
return Vec2D<T>(left.x / scalar, left.y / scalar);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> operator*(const Vec2D<T> left, T scalar){
|
||||
return Vec2D<T>(left.x * scalar, left.y * scalar);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> cartesianToPolar(T x, T y) {
|
||||
return Vec2D<T>{sqrt(x * x + y * y), atan(y / x)}; // r,theta
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Vec2D<T> polarToCartesian(T r, T q) {
|
||||
return Vec2D<T>{r * cos(q), r * sin(q)};
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user