Skip to content

Commit 2cc11e5

Browse files
committed
The miracle of git never ceases to infuriate me. See previous commit.
1 parent 57dfb0c commit 2cc11e5

File tree

6 files changed

+444
-95
lines changed

6 files changed

+444
-95
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
'''
2+
A surface filled with one hundred medium to small sized circles.
3+
Each circle has a different size and direction, but moves at the same
4+
slow rate.
5+
6+
Display the instantaneous intersections of the circles
7+
8+
Implemented by Robert Hodgin <http://flight404.com>
9+
6 April 2004
10+
Processing v.68 <http://processing.org>
11+
12+
Port to Processing.py/Processing 2.0 by Ben Alkov 17 July 2014
13+
'''
14+
from circle import Circle
15+
16+
17+
# ****************************************************************************
18+
# INITIALIZE VARIABLES
19+
# ****************************************************************************
20+
sketchX = 600 # self.x dimension of applet
21+
sketchY = 600 # self.y dimension of applet
22+
sketchXMid = sketchX / 2 # self.x midpoint of applet
23+
sketchYMid = sketchY / 2 # self.y midpoint of applet
24+
Circle.TotalCircles = 100 # total number of circles
25+
Circle.Gravity = 0.075 # Strength of gravitational pull
26+
circles = [Circle(i, 0, 0, 0, 0) # Circle object list
27+
for i in range(Circle.TotalCircles)]
28+
29+
30+
# ****************************************************************************
31+
# SETUP FUNCTION
32+
# ****************************************************************************
33+
def setup():
34+
size(600, 600)
35+
background(255)
36+
smooth()
37+
colorMode(RGB, 255)
38+
ellipseMode(RADIUS)
39+
noStroke()
40+
frameRate(30)
41+
createCircles()
42+
43+
44+
# ****************************************************************************
45+
# MAIN LOOP FUNCTION
46+
# ****************************************************************************
47+
def draw():
48+
background(255)
49+
for circle in circles:
50+
circle.behave(circles, sketchXMid, sketchYMid)
51+
52+
53+
def createCircles():
54+
angleOffset = random(360)
55+
for circle in circles:
56+
circle.xPos, circle.yPos = initCirclePos(circle.index, angleOffset,
57+
random(10))
58+
circle.xv = 0
59+
circle.yv = 0
60+
61+
62+
def initCirclePos(index, angleOffset, rand):
63+
initRadius = 150
64+
initAngle = index * 3.6 + angleOffset + rand
65+
initTheta = (-((initAngle) * PI)) / 180
66+
initxv = cos(initTheta) * initRadius
67+
inityv = sin(initTheta) * initRadius
68+
return sketchXMid + initxv, sketchYMid + inityv
69+
70+
71+
def mouseReleased():
72+
createCircles()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
class Circle(object):
2+
NumCollisions = 0 # Number of collisions in one frame
3+
NumConnections = 0 # Total number of collisions
4+
GravityAngle = 1 # Angle to gravity center in degrees
5+
GravityTheta = 1 # Angle to gravity center in radians
6+
TotalCircles = 0
7+
Gravity = 0
8+
CXV = 0
9+
CYV = 0
10+
11+
def __init__(self, index, x, y, xv, yv):
12+
self.index = index
13+
self.x = x
14+
self.y = y
15+
self.radius = 2
16+
self.xv = xv
17+
self.yv = yv
18+
self.mightCollide = [1] * Circle.TotalCircles
19+
self.hasCollided = [1] * Circle.TotalCircles
20+
self.distances = [1] * Circle.TotalCircles
21+
self.angles = [1] * Circle.TotalCircles
22+
self.thetas = [1] * Circle.TotalCircles
23+
24+
def behave(self, circles, sketchXMid, sketchYMid):
25+
self.move()
26+
self.areWeClose(circles)
27+
self.areWeColliding(circles)
28+
self.areWeConnected(circles)
29+
self.applyGravity(sketchXMid, sketchYMid)
30+
self.render(circles)
31+
self.reset()
32+
33+
def areWeClose(self, others):
34+
for other in others:
35+
if self.index != other.index:
36+
if (abs(self.x - other.x) < 50
37+
and abs(self.y - other.y) < 50):
38+
self.mightCollide[other.index] = True
39+
else:
40+
self.mightCollide[other.index] = False
41+
42+
def areWeColliding(self, others):
43+
for other in others:
44+
if (self.mightCollide[other.index]
45+
and self.index != other.index):
46+
self.distances[other.index] = dist(self.x, self.y,
47+
other.x, other.y)
48+
if (self.distances[other.index]
49+
< (self.radius + other.radius) * 1.1):
50+
self.hasCollided[other.index] = True
51+
other.hasCollided[self.index] = True
52+
self.angles[other.index] = Circle.findAngle(self.x, self.y,
53+
other.x, other.y)
54+
self.thetas[other.index] = (-(self.angles[other.index] * PI)) / 180.0
55+
Circle.CXV += (cos(self.thetas[other.index])
56+
* ((other.radius + self.radius) / 2.0))
57+
Circle.CYV += (sin(self.thetas[other.index])
58+
* ((other.radius + self.radius) / 2.0))
59+
Circle.NumCollisions += 1
60+
if Circle.NumCollisions > 0:
61+
self.xv = -Circle.CXV / Circle.NumCollisions
62+
self.yv = -Circle.CYV / Circle.NumCollisions
63+
Circle.CXV = 0.0
64+
Circle.CYV = 0.0
65+
66+
def areWeConnected(self, others):
67+
maxDistance = 150
68+
for other in others:
69+
if (self.hasCollided[other.index]
70+
and self.index != other.index):
71+
self.distances[other.index] = dist(self.x, self.y,
72+
other.x, other.y)
73+
if self.distances[other.index] < maxDistance:
74+
self.angles[other.index] = Circle.findAngle(self.x, self.y,
75+
other.x, other.y)
76+
self.thetas[other.index] = (-(self.angles[other.index] * PI)) / 180.0
77+
Circle.CXV += cos(self.thetas[other.index]) * (self.radius / 8.0)
78+
Circle.CYV += sin(self.thetas[other.index]) * (self.radius / 8.0)
79+
Circle.NumConnections += 1
80+
else:
81+
self.hasCollided[other.index] = False
82+
other.hasCollided[self.index] = False
83+
if Circle.NumConnections > 0:
84+
self.xv += (Circle.CXV / Circle.NumConnections) / 4.0
85+
self.yv += (Circle.CYV / Circle.NumConnections) / 4.0
86+
Circle.CXV = 0.0
87+
Circle.CYV = 0.0
88+
self.radius = Circle.NumConnections * .85 + 2
89+
90+
def applyGravity(self, sketchXMid, sketchYMid):
91+
Circle.GravityAngle = Circle.findAngle(self.x, self.y,
92+
sketchXMid, sketchYMid)
93+
Circle.GravityTheta = (-(Circle.GravityAngle * PI)) / 180
94+
self.xv += cos(Circle.GravityTheta) * Circle.Gravity
95+
self.yv += sin(Circle.GravityTheta) * Circle.Gravity
96+
97+
def move(self):
98+
self.x += self.xv
99+
self.y += self.yv
100+
101+
def render(self, others):
102+
noStroke()
103+
fill(0, 25)
104+
ellipse(self.x, self.y, self.radius, self.radius)
105+
fill(0 + self.radius * 10, 50)
106+
ellipse(self.x, self.y, self.radius * 0.5, self.radius * 0.5)
107+
fill(0 + self.radius * 10)
108+
ellipse(self.x, self.y, self.radius * 0.3, self.radius * 0.3)
109+
if Circle.NumCollisions > 0:
110+
noStroke()
111+
fill(0, 25)
112+
ellipse(self.x, self.y, self.radius, self.radius)
113+
fill(0, 55)
114+
ellipse(self.x, self.y, self.radius * 0.85, self.radius * 0.85)
115+
fill(0)
116+
ellipse(self.x, self.y, self.radius * 0.7, self.radius * 0.7)
117+
for other in others:
118+
if (self.hasCollided[other.index]
119+
and self.index != other.index):
120+
with beginShape(LINE_LOOP):
121+
xdist = self.x - other.x
122+
ydist = self.y - other.y
123+
stroke(0, 150 - self.distances[other.index] * 2.0)
124+
vertex(self.x, self.y)
125+
vertex(self.x - xdist * 0.25 + random(-1.0, 1.0),
126+
self.y - ydist * 0.25 + random(-1.0, 1.0))
127+
vertex(self.x - xdist * 0.5 + random(-3.0, 3.0),
128+
self.y - ydist * 0.5 + random(-3.0, 3.0))
129+
vertex(self.x - xdist * 0.75 + random(-1.0, 1.0),
130+
self.y - ydist * 0.75 + random(-1.0, 1.0))
131+
vertex(other.x, other.y)
132+
line (self.x, self.y, other.x, other.y);
133+
noStroke()
134+
135+
@classmethod
136+
def reset(cls):
137+
Circle.NumCollisions = 0
138+
Circle.NumConnections = 0
139+
140+
@classmethod
141+
def findAngle(cls, x1, y1, x2, y2):
142+
return 180 + (-(180 * (atan2(y1 - y2, x1 - x2))) / PI)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
class Circle(object):
2+
def __init__(self, index, x, y, radius, xspeed, yspeed):
3+
self.index = index
4+
self.x = x
5+
self.y = y
6+
self.radius = radius
7+
self.rSqr = radius**2
8+
self.xspeed = xspeed
9+
self.yspeed = yspeed
10+
11+
def update(self, circles):
12+
for circle in circles:
13+
if circle.index != self.index:
14+
self.intersect(circle)
15+
16+
def drawSelf(self):
17+
stroke(102)
18+
noFill()
19+
ellipse(self.x, self.y, self.radius * 2, self.radius * 2)
20+
21+
def move(self):
22+
self.x += self.xspeed
23+
self.y += self.yspeed
24+
# Wrap.
25+
if self.xspeed == 0 or self.yspeed == 0:
26+
return
27+
constrainedX = constrain(self.x, -self.radius, width + self.radius)
28+
constrainedY = constrain(self.y, -self.radius, height + self.radius)
29+
if constrainedX != self.x:
30+
if self.x < 0:
31+
self.x = width + self.radius
32+
else:
33+
self.x = -self.radius
34+
if constrainedY != self.y:
35+
if self.y < 0:
36+
self.y = height + self.radius
37+
else:
38+
self.y = -self.radius
39+
40+
def intersect(self, other):
41+
distance = dist(self.x, self.y, other.x, other.y)
42+
if (distance > self.radius + other.radius
43+
or distance < abs(self.radius - other.radius)):
44+
return # No solution.
45+
a = (self.rSqr - other.rSqr + distance**2) / (2 * distance)
46+
hyp = sqrt(self.rSqr - a**2)
47+
midpointX = Circle.calc2(self.x, '+', a, Circle.calc1(other.x, self.x, distance))
48+
midpointY = Circle.calc2(self.y, '+', a, Circle.calc1(other.y, self.y, distance))
49+
pointAX = Circle.calc2(midpointX, '+', hyp, Circle.calc1(other.y, self.y, distance))
50+
pointAY = Circle.calc2(midpointY, '-', hyp, Circle.calc1(other.x, self.x, distance))
51+
pointBX = Circle.calc2(midpointX, '-', hyp, Circle.calc1(other.y, self.y, distance))
52+
pointBY = Circle.calc2(midpointY, '+', hyp, Circle.calc1(other.x, self.x, distance))
53+
Circle.renderIntersect(midpointX, midpointY, pointAX, pointAY, pointBX, pointBY)
54+
55+
@classmethod
56+
def renderIntersect(cls, midpointX, midpointY, pointAX, pointAY, pointBX, pointBY):
57+
stroke(0, 12)
58+
line(pointAX, pointAY, pointBX, pointBY)
59+
60+
@classmethod
61+
def calc1(cls, first, second, distance):
62+
return (first - second) / distance
63+
64+
@classmethod
65+
def calc2(cls, first, operation, second, function):
66+
if operation == '+':
67+
return first + second * function
68+
elif operation == '-':
69+
return first - second * function
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
class Circle(object):
2+
def __init__(self, index, x, y, radius, xspeed, yspeed):
3+
self.index = index
4+
self.x = x
5+
self.y = y
6+
self.radius = radius
7+
self.rSqr = radius**2
8+
self.xspeed = xspeed
9+
self.yspeed = yspeed
10+
11+
def update(self, circles):
12+
for circle in circles:
13+
if circle.index != self.index:
14+
self.intersect(circle)
15+
16+
def drawSelf(self):
17+
stroke(102)
18+
noFill()
19+
ellipse(self.x, self.y, self.radius * 2, self.radius * 2)
20+
21+
def move(self):
22+
self.x += self.xspeed
23+
self.y += self.yspeed
24+
# Wrap.
25+
if self.xspeed == 0 or self.yspeed == 0:
26+
return
27+
constrainedX = constrain(self.x, -self.radius, width + self.radius)
28+
constrainedY = constrain(self.y, -self.radius, height + self.radius)
29+
if constrainedX != self.x:
30+
if self.x < 0:
31+
self.x = width + self.radius
32+
else:
33+
self.x = -self.radius
34+
if constrainedY != self.y:
35+
if self.y < 0:
36+
self.y = height + self.radius
37+
else:
38+
self.y = -self.radius
39+
40+
def intersect(self, other):
41+
distance = dist(self.x, self.y, other.x, other.y)
42+
if (distance > self.radius + other.radius
43+
or distance < abs(self.radius - other.radius)):
44+
return # No solution.
45+
a = (self.rSqr - other.rSqr + distance**2) / (2 * distance)
46+
hyp = sqrt(self.rSqr - a**2)
47+
midpointX = Circle.calc2(self.x, '+', a, Circle.calc1(other.x, self.x, distance))
48+
midpointY = Circle.calc2(self.y, '+', a, Circle.calc1(other.y, self.y, distance))
49+
pointAX = Circle.calc2(midpointX, '+', hyp, Circle.calc1(other.y, self.y, distance))
50+
pointAY = Circle.calc2(midpointY, '-', hyp, Circle.calc1(other.x, self.x, distance))
51+
pointBX = Circle.calc2(midpointX, '-', hyp, Circle.calc1(other.y, self.y, distance))
52+
pointBY = Circle.calc2(midpointY, '+', hyp, Circle.calc1(other.x, self.x, distance))
53+
Circle.renderIntersect(midpointX, midpointY, pointAX, pointAY, pointBX, pointBY)
54+
55+
@classmethod
56+
def renderIntersect(cls, midpointX, midpointY, pointAX, pointAY, pointBX, pointBY):
57+
stroke(0)
58+
line(pointAX, pointAY, pointBX, pointBY)
59+
60+
@classmethod
61+
def calc1(cls, first, second, distance):
62+
return (first - second) / distance
63+
64+
@classmethod
65+
def calc2(cls, first, operation, second, function):
66+
if operation == '+':
67+
return first + second * function
68+
elif operation == '-':
69+
return first - second * function

0 commit comments

Comments
 (0)