                         node-b-id (vec- (get forces node-b-id [0 0]) force))
                     r)))))
 
+(defn calculate-hinge-force [a b c rest-angle strength]
+    (let [
+        b-to-a (vec- a b)
+        b-to-c (vec- c b)
+        pressure (* (- rest-angle (angle b-to-a b-to-c)) strength)
+        result [
+            (vec* (rot-ccw b-to-a) (/ pressure (magnitude-squared b-to-a)))
+            (vec* (rot-cw b-to-c) (/ pressure (magnitude-squared b-to-c)))
+        ]]
+            result))
+
+(defn calculate-hinge-forces [nodes hinges]
+    (loop [forces {} hinges hinges]
+        (if (empty? hinges) forces
+            (let [
+                [h & r] hinges
+                {:keys [node-a node-b node-c rest-angle strength]} h
+                [force-a force-c] (calculate-hinge-force (:pos (nodes node-a)) (:pos (nodes node-b)) (:pos (nodes node-c)) rest-angle strength)]
+                    (recur
+                        (assoc forces
+                            node-a (vec+ (get forces node-a [0 0]) force-a)
+                            node-b (vec+ (get forces node-b [0 0]) (vec* (vec+ force-a force-c) -1.0))
+                            node-c (vec+ (get forces node-c [0 0]) force-c))
+                        r)))))
+
 (defn calculate-gravity-forces [nodes]
     (zipmap (keys nodes) (repeat [0 (- gravity-strength)])))
 

(def magnitude-squared (comp (partial apply +) (partial map #(* % %))))
(def magnitude (comp Math/sqrt magnitude-squared))
(def normalize (comp (partial apply vec*) (juxt identity (comp (partial / 1.0) magnitude))))

(defn calculate-force [node-a node-b rest-length strength]
    (let [a-b (vec- node-a node-b)

            (update-node-positions
                (update-node-velocities
                    (:nodes state)
                    (calculate-all-node-forces state)
                    tick-step)
                tick-step)))

