Skip to content

Instantly share code, notes, and snippets.

@zeffii
Last active September 5, 2017 10:07
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 zeffii/e94cc9634c1d94f691f22f1a26eec3ef to your computer and use it in GitHub Desktop.
Save zeffii/e94cc9634c1d94f691f22f1a26eec3ef to your computer and use it in GitHub Desktop.
cohesion2.py
"""
in dummy2 s
in dummy s d=2 n=1
out verts v
"""
def setup():
# stuff
from vclasses import Node, DifferentialLine
import math
from math import pi, cos, sin
from math import sqrt as sq
from random import random as rnd
from collections import defaultdict
from mathutils import Vector
TWO_PI = math.pi * 2
# PARAMETERS
_maxForce = 0.2
_maxSpeed = 2
_desiredSeparation = 10
_separationCohesionRation = 1.1
_maxEdgeLen = 5
width = 399
height = 200
# start setup if DifferentialLine
diff_line = DifferentialLine(_maxForce, _maxSpeed, _desiredSeparation, _separationCohesionRation, _maxEdgeLen)
nodesStart = 20
angInc = TWO_PI / nodesStart
rayStart = 10
width = 399
height = 200
num_nodes = int(TWO_PI / angInc)
print(num_nodes)
for a in range(num_nodes):
theta = a * angInc
x = (width/2) + math.cos(theta) * rayStart
y = (height/2) + math.sin(theta) * rayStart
diff_line.addNode(Node(x, y, _maxForce, _maxSpeed))
# end setup
for nn in range(12):
diff_line.run()
verts = [diff_line.renderShape()]
from math import sqrt as sq
from math import cos, sin
from mathutils import Vector
from collections import defaultdict
from random import random as rnd
class PVector():
def __init__(self, x=0, y=0):
self.value = Vector((x, y))
@staticmethod
def random():
return Vector((rnd()*30, rnd()*30))
@property
def x(self):
return self.value.x
@property
def y(self):
return self.value.y
def add(self, other, other2=None):
if other2:
return other.value + other2.value
else:
self.value = self.value + other.value
return self.value
def sub(self, other, other2=None):
if other2:
return other.value - other2.value
else:
self.value = self.value - other.value
return self.value
def limit(self, scalar):
# is this the right analogue?
self.value.magnitude = scalar
return self.value
def mag(self):
return self.value.magnitude
def setMag(self, scalar):
self.value.magnitude = scalar
return self.value
def mult(self, scalar):
self.value = self.value * scalar
return self.value
def div(self, scalar):
self.value = self.value / scalar
return self.value
def dist(self, other, other2=None):
if other2:
return (other.value - other2.value).length
else:
return (self.value - other.value).length
def __repr__(self):
return repr(self.value)
class Node():
def __init__(self, x, y, mF, mS):
self.acceleration = PVector()
self.velocity = PVector.random()
self.position = PVector(x, y)
self.maxSpeed = mF
self.maxForce = mS
def applyForce(self, force):
self.acceleration.add(force)
def update(self):
self.velocity.add(self.acceleration)
self.velocity.limit(self.maxSpeed)
self.position.add(self.velocity)
self.acceleration.mult(0)
def seek(self, target):
desired = PVector.sub(target, self.position)
desired.setMag(self.maxSpeed)
steer = PVector.sub(desired, self.velocity)
steer.limit(self.maxForce)
return steer
class DifferentialLine():
def __init__(self, mF, mS, dS, sCr, eL):
self.nodes = [] # NodeArray()
self.maxSpeed = mF
self.maxForce = mS
self.desiredSeparation = dS
self.sq_desiredSeparation = sq(self.desiredSeparation)
self.separationCohesionRation = sCr
self.maxEdgeLen = eL
def addNode(self, n):
self.nodes.append(n)
def addNodeAt(self, n, index):
self.nodes.insert(index, n) # maybe list is not the appropriate structure
def run(self):
self.differentiate()
self.growth()
def growth(self):
for i in range(len(self.nodes)-1):
n1 = self.nodes[i]
n2 = self.nodes[i+1]
d = PVector.dist(n1.position, n2.position)
# Can add more rules for inserting nodes
if (d > self.maxEdgeLen):
index = self.nodes.index(n2) # indexof? .. is not i+1 ?
middleNode = PVector.add(n1.position, n2.position).div(2)
self.addNodeAt(Node(middleNode.x, middleNode.y, self.maxForce, self.maxSpeed), index)
def differentiate(self):
separationForces = self.getSeparationForces()
cohesionForces = self.getEdgeCohesionForces()
for i in range(len(self.nodes)):
separation = separationForces[i] # a PVector
cohesion = cohesionForces[i] # a PVector
separation.mult(self.separationCohesionRation)
self.nodes[i].applyForce(separation)
self.nodes[i].applyForce(cohesion)
self.nodes[i].update()
def getSeparationForces(self): # PVector[]
n = len(self.nodes)
separateForces = [] # prefil with n elements ?!
nearNodes = defaultdict(int) # int[] nearNodes = new int[n]; (prefil with n elements?)
separateForces = [PVector() for i in range(n)]
for i in range(n):
nodei = self.nodes[i]
for j in range(i+1, n):
nodej = self.nodes[j]
forceij = self.getSeparationForce(nodei, nodej)
if forceij.mag() > 0:
separateForces[i].add(forceij)
separateForces[j].sub(forceij)
nearNodes[i] += 1
nearNodes[j] += 1
if nearNodes[i] > 0:
separateForces[i].div(nearNodes[i])
if separateForces[i].mag() > 0:
separateForces[i].setMag(self.maxSpeed)
separateForces[i].sub(self.nodes[i].velocity)
separateForces[i].limit(self.maxForce)
return separateForces
def getSeparationForce(self, n1, n2):
steer = PVector()
sq_d = sq(n2.position.x-n1.position.x) + sq(n2.position.y-n1.position.y)
if (sq_d > 0 and sq_d < self.sq_desiredSeparation):
diff = PVector.sub(n1.position, n2.position)
diff.normalize()
diff.div(sq(sq_d))
steer.add(diff)
return steer
def getEdgeCohesionForces(self):
n = len(self.nodes)
nodes = self.nodes
cohesionForces = list(range(n))
for i in range(n):
_sum = PVector()
if (i != 0 and i != n-1):
_sum.add(nodes[i-1].position).add(nodes[i+1].position)
elif i == 0:
_sum.add(nodes[n-1].position).add(nodes[i+1].position)
elif i == n-1:
_sum.add(nodes[i-1].position).add(nodes[0].position)
_sum.div(2)
cohesionForces.append(nodes[i].seek(_sum))
return cohesionForces
def renderShape(self):
return [(n.position.x, n.position.y, 0.0) for n in self.nodes]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment