-
Notifications
You must be signed in to change notification settings - Fork 1
/
bond_forces.py
155 lines (116 loc) · 4.58 KB
/
bond_forces.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from bge import logic
from bge import events
from bge import render
from mathutils import Vector
from math import degrees
from molecule import Molecule
gdict = logic.globalDict
def align_p_bonds(this,other):
# aligns nearby pbonds together e.g. in benzene
if ("doubles" in this and len(this["doubles"]) == 1) or ("triple" in this and this["triple"]):
axisvect = other.getAxisVect((0,1,0))
this.alignAxisToVect(axisvect,1,0.1)
def calc_forces(cont):
# first atoms are adjacent
particle = cont.owner
if not particle.molecule:
if particle.name in {"Hydrogen","Bromine"} and "glow" not in particle:
type = particle.name
gdict["free"][type].add(particle)
cont.script = "bond_forces.lone_" + type.lower()
else:
cont.script = "bond_forces.lone_atom"
return
# set total force to zero
particle.reset()
for bond in particle["near_bonds"]:
particle.totalforce -= particle.get_repulsion(bond)
for bond in particle["far_bonds"]:
if particle.getDistanceTo(bond) < 30:
particle.bond.draw_line(bond,[0,1,0])
particle.totalforce -= particle.get_repulsion(bond) * 0.5
bonds = particle.get_bonds()
# SPRINGS
for bond in bonds:
particle.totalforce += particle.spring_force(bond)
if "doubles" in bond:
# P BONDS
if bond["doubles"]:
# p bonds cause a spring
projection = particle.repel_p_bond(bond)
# damps spring
velocity = particle.getLinearVelocity().project(projection)
particle.totalforce += projection * 10 - velocity * 2
bond.applyForce(-projection * 10)
align_p_bonds(particle,bond)
elif "triple" in bond and bond["triple"]:
projection = particle.repel_p_bond2(bond)
velocity = particle.getLinearVelocity().project(projection)
particle.totalforce += projection * 5 - velocity * 100
bond.applyForce(-projection * 5)
align_p_bonds(particle,bond)
lindamp = 0.1 # makes molecules stay still
velocity = particle.getLinearVelocity()
force = particle.totalforce - velocity * lindamp
sensor = cont.sensors["Bonds"]
# check if at rest
if force.magnitude > 0.1:
sensor.frequency = 2
particle.applyForce(force)
else:
particle.worldVelocity = Vector([0,0,0])
sensor.frequency = 20
# don't do anything
def lone_atom(cont):
particle = cont.owner
if particle.molecule:
if particle.name == "Hydrogen" and "glow" in particle:
particle.remove_glow()
type = particle.name
if type == "Hydrogen":
gdict["free"][type].discard(particle)
cont.script = "bond_forces.calc_forces"
# get hydrogens
def lone_hydrogen(cont):
particle = cont.owner
if particle.molecule:
gdict["free"]["Hydrogen"].discard(particle)
bonds = particle["bonds"]
if len(bonds) > 1:
random = next(iter(bonds))
particle.unlink(random)
return
cont.script = "bond_forces.calc_forces"
return
for other in gdict["free"]["Hydrogen"]:
if other is particle:
continue
distance = particle.getDistanceTo(other)
if distance < particle.maxdistance:
particle.link(other)
gdict["free"]["Hydrogen"].remove(particle)
gdict["free"]["Hydrogen"].remove(other)
cont.script = "bond_forces.calc_forces"
return
def lone_bromine(cont):
particle = cont.owner
type = particle.name
if particle.molecule:
bonds = particle["bonds"]
gdict["free"][type].discard(particle)
if len(bonds) > 1:
random = next(iter(bonds))
particle.unlink(random)
return
cont.script = "bond_forces.calc_forces"
return
for other in gdict["free"][type]:
if other is particle:
continue
distance = particle.getDistanceTo(other)
if distance < particle.maxdistance:
particle.link(other)
gdict["free"][type].remove(particle)
gdict["free"][type].remove(other)
cont.script = "bond_forces.calc_forces"
return