summaryrefslogtreecommitdiffstats
path: root/src/fdgl.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/fdgl.hpp')
-rw-r--r--src/fdgl.hpp166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/fdgl.hpp b/src/fdgl.hpp
new file mode 100644
index 0000000..38fded1
--- /dev/null
+++ b/src/fdgl.hpp
@@ -0,0 +1,166 @@
+/* This file is part of Ganv.
+ * Copyright 2007-2015 David Robillard <http://drobilla.net>
+ *
+ * Ganv is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or any later version.
+ *
+ * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Ganv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <float.h>
+#include <math.h>
+
+static const double CHARGE_KE = 4000000.0;
+static const double EDGE_K = 16.0;
+static const double EDGE_LEN = 0.1;
+
+struct Region {
+ Vector pos;
+ Vector area;
+};
+
+inline Vector
+vec_add(const Vector& a, const Vector& b)
+{
+ const Vector result = { a.x + b.x, a.y + b.y };
+ return result;
+}
+
+inline Vector
+vec_sub(const Vector& a, const Vector& b)
+{
+ const Vector result = { a.x - b.x, a.y - b.y };
+ return result;
+}
+
+inline Vector
+vec_mult(const Vector& a, double m)
+{
+ const Vector result = { a.x * m, a.y * m };
+ return result;
+}
+
+inline double
+vec_mult(const Vector& a, const Vector& b)
+{
+ return a.x * b.x + a.y * b.y;
+}
+
+/** Magnitude. */
+inline double
+vec_mag(const Vector& vec)
+{
+ return sqrt(vec.x * vec.x + vec.y * vec.y);
+}
+
+/** Reciprocal of magnitude. */
+inline double
+vec_rmag(const Vector& vec)
+{
+ return 1.0 / sqrt(vec.x * vec.x + vec.y * vec.y);
+}
+
+/** Hooke's law */
+inline Vector
+spring_force(const Vector& a, const Vector& b, double length, double k)
+{
+ const Vector vec = vec_sub(b, a);
+ const double mag = vec_mag(vec);
+ const double displacement = length - mag;
+ return vec_mult(vec, k * displacement * 0.5 / mag);
+}
+
+/** Spring force with a directional force to align with flow direction. */
+static const Vector
+edge_force(const Vector& dir, const Vector& hpos, const Vector& tpos)
+{
+ return vec_add(dir, spring_force(hpos, tpos, EDGE_LEN, EDGE_K));
+}
+
+/** Constant tide force, does not vary with distance. */
+inline Vector
+tide_force(const Vector& a, const Vector& b, double power)
+{
+ static const double G = 0.0000000000667;
+ const Vector vec = vec_sub(a, b);
+ const double mag = vec_mag(vec);
+ return vec_mult(vec, G * power / mag);
+}
+
+inline double
+rect_distance(Vector* vec,
+ const double ax1, const double ay1,
+ const double ax2, const double ay2,
+ const double bx1, const double by1,
+ const double bx2, const double by2)
+{
+ vec->x = 0.0;
+ vec->y = 0.0;
+
+ if (ax2 <= bx1) { // A is completely to the left of B
+ vec->x = ax2 - bx1;
+ if (ay2 <= by1) { // Top Left
+ const double dx = bx1 - ax2;
+ const double dy = by1 - ay2;
+ vec->y = ay2 - by1;
+ return sqrt(dx * dx + dy * dy);
+ } else if (ay1 >= by2) { // Bottom left
+ const double dx = bx1 - ax2;
+ const double dy = ay1 - by2;
+ vec->y = ay1 - by2;
+ return sqrt(dx * dx + dy * dy);
+ } else { // Left
+ return bx1 - ax2;
+ }
+ } else if (ax1 >= bx2) { // A is completely to the right of B
+ vec->x = ax1 - bx2;
+ if (ay2 <= by1) { // Top right
+ const double dx = ax1 - bx2;
+ const double dy = by1 - ay2;
+ vec->y = ay2 - by1;
+ return sqrt(dx * dx + dy * dy);
+ } else if (ay1 >= by2) { // Bottom right
+ const double dx = ax1 - bx2;
+ const double dy = ay1 - by2;
+ vec->y = ay1 - by2;
+ return sqrt(dx * dx + dy * dy);
+ } else { // Right
+ return ax1 - bx2;
+ }
+ } else if (ay2 <= by1) { // Top
+ vec->y = ay2 - by1;
+ return by1 - ay2;
+ } else if (ay1 >= by2) { // Bottom
+ vec->y = ay1 - by2;
+ return ay1 - by2;
+ } else { // Overlap
+ return 0.0;
+ }
+}
+
+/** Repelling charge force, ala Coulomb's law. */
+inline Vector
+repel_force(const Region& a, const Region& b)
+{
+ static const double MIN_DIST = 1.0;
+
+ Vector vec;
+ double dist = rect_distance(
+ &vec,
+ a.pos.x - (a.area.x / 2.0), a.pos.y - (a.area.y / 2.0),
+ a.pos.x + (a.area.x / 2.0), a.pos.y + (a.area.y / 2.0),
+ b.pos.x - (b.area.x / 2.0), b.pos.y - (b.area.y / 2.0),
+ b.pos.x + (b.area.x / 2.0), b.pos.y + (b.area.y / 2.0));
+
+ if (dist <= MIN_DIST) {
+ dist = MIN_DIST;
+ vec = vec_sub(a.pos, b.pos);
+ }
+ return vec_mult(vec, (CHARGE_KE * 0.5 / (vec_mag(vec) * dist * dist)));
+}