' Display
' Meta
start:
' Data
' Statics
' Dynamics
' Environment
DIM ForceField
AS Vector
' Gravity ForceField.x = 0
ForceField.y = -.08
' Initialize
ShapeCount = 0
CollisionCount = 0
' Balls (billiard setup)
x0 = -70
y0 = 120
r1 = 15.5
r2 = 2.5
gg = 2 * r1 + 20
xf
= COS(30 * 3.14159 / 180)yf
= SIN(30 * 3.14159 / 180)gx = gg * xf
gy = gg * yf
CALL NewAutoBall
(x0
+ 0 * gx
, y0
+ 0 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 1 * gx
, y0
+ 1 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 1 * gx
, y0
- 1 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
+ 2 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) CALL NewAutoBall
(x0
+ 2 * gx
, y0
+ 0 * gy
, r1
, r2
, INT(RND * 3) + 1, INT(RND * 1) + 2, 0) 'CALL NewAutoBall(x0 + 2 * gx, y0 - 2 * gy, r1, r2, INT(RND * 3) + 1, INT(RND * 1) + 2, 0)
'CALL NewAutoBall(x0 + 3 * gx, y0 + 3 * gy, r1, r2, INT(RND * 3) + 1, INT(RND * 1) + 2, 0)
'CALL NewAutoBall(x0 + 3 * gx, y0 + 1 * gy, r1, r2, INT(RND * 3) + 1, INT(RND * 1) + 2, 0)
'CALL NewAutoBall(x0 + 3 * gx, y0 - 1 * gy, r1, r2, INT(RND * 3) + 1, INT(RND * 1) + 2, 0)
'CALL NewAutoBall(x0 + 3 * gx, y0 - 3 * gy, r1, r2, INT(RND * 3) + 1, INT(RND * 1) + 2, 0)
' Rectangular border
l = 40
w = 10
' Misc. bricks
CALL NewBrickLine
(-100 + 4, 100, 0 + 4, 0, 60, 10) CALL NewBrickLine
(100 - 4, 100, 0 - 4, 0, 60, 10)
'CALL NewAutoBrick(0, -100, 200, 100, 0)
' Main object(s)
ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = 0
Shape(ShapeCount).Collisions = 0
x1 = 0
y1 = -150
i = 0
i = i + 1
r
= 20 + 15 * COS(1.5 * j
) ^ 2 PointChain
(ShapeCount
, i
).x
= x1
+ r
* COS(j
) PointChain
(ShapeCount
, i
).y
= y1
+ r
* SIN(j
)Shape(ShapeCount).Elements = i
CALL CalculateMass
(ShapeCount
, 1) CALL CalculateCentroid
(ShapeCount
) CALL CalculateMOI
(ShapeCount
, Shape
(ShapeCount
).Centroid
) CALL CalculateDiameterMin
(ShapeCount
) CALL CalculateDiameterMax
(ShapeCount
) Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
Shape
(ShapeCount
).Shade
= _RGB(0, 255, 255)
' Prompt
CALL cprintstring
(0, "PRESS ANY KEY TO BEGIN") CALL cprintstring
(-16 * 2, "Arrow keys boost most recently-created object.") CALL cprintstring
(-16 * 3, "Space enters creative mode.") CALL cprintstring
(-16 * 4, "Press 'r' to restart.")
' Main loop
' Keyboard input
CALL cprintstring
(16 * 17, "Drag mouse counter-clockwise to draw a new shape.") CALL cprintstring
(16 * 16, "Make sure centroid is inside body.") 'CALL Graphics
CALL NewMouseShape
(7.5, 75, 25) Shape(ShapeCount).Velocity.y = Shape(ShapeCount).Velocity.y * 1.1 + 2
Shape(ShapeCount).Velocity.y = Shape(ShapeCount).Velocity.y * 0.9 - 2
Shape(ShapeCount).Velocity.x = Shape(ShapeCount).Velocity.x * 0.9 - 2
Shape(ShapeCount).Velocity.x = Shape(ShapeCount).Velocity.x * 1.1 + 2
Shape(k).Velocity.x = .000001
Shape(k).Velocity.y = .000001
Shape(k).Omega = .000001
' Mouse input
mb = 0
mb = 1
vtemp.x = x - Shape(ShapeCount).Centroid.x
vtemp.y = y - Shape(ShapeCount).Centroid.y
CALL TranslateShape
(ShapeCount
, vtemp
) Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
mb = 1
CALL NewAutoBall
(x
, y
, 20, 0, 1, 1, 1)
' Proximity detection
ProximalPairsCount = 0
Shape1 = 0
Shape2 = 0
Shape(j).CollisionSwitch = 0
Shape(j).DeltaO = 0
Shape(j).DeltaV.x = 0
Shape(j).DeltaV.y = 0
Shape(j).PartialNormal.x = 0
Shape(j).PartialNormal.y = 0
FOR k
= j
+ 1 TO ShapeCount
dx = Shape(j).Centroid.x - Shape(k).Centroid.x
dy = Shape(j).Centroid.y - Shape(k).Centroid.y
dr
= SQR(dx
* dx
+ dy
* dy
) IF (dr
< (1.15) * (Shape
(j
).DiameterMax
+ Shape
(k
).DiameterMax
)) THEN ProximalPairsCount = ProximalPairsCount + 1
ProximalPairs(ProximalPairsCount, 1) = j
ProximalPairs(ProximalPairsCount, 2) = k
Shape1 = j
Shape2 = k
IF (ProximalPairsCount
> 0) THEN FOR n
= 1 TO ProximalPairsCount
Shape1 = ProximalPairs(n, 1)
Shape2 = ProximalPairs(n, 2)
' Collision detection
rmin = 999999999
ClosestIndex1 = 0
ClosestIndex2 = 0
FOR j
= 1 TO Shape
(Shape1
).Elements
FOR k
= 1 TO Shape
(Shape2
).Elements
dx = PointChain(Shape1, j).x - PointChain(Shape2, k).x
dy = PointChain(Shape1, j).y - PointChain(Shape2, k).y
r2 = dx * dx + dy * dy
' Normal vector 1
nx1 = CalculateNormalY(Shape1, j)
ny1 = -CalculateNormalX(Shape1, j)
nn
= SQR(nx1
* nx1
+ ny1
* ny1
) nx1 = nx1 / nn
ny1 = ny1 / nn
Shape(Shape1).PartialNormal.x = Shape(Shape1).PartialNormal.x + nx1
Shape(Shape1).PartialNormal.y = Shape(Shape1).PartialNormal.y + ny1
' Normal vector 2
nx2 = CalculateNormalY(Shape2, k)
ny2 = -CalculateNormalX(Shape2, k)
nn
= SQR(nx2
* nx2
+ ny2
* ny2
) nx2 = nx2 / nn
ny2 = ny2 / nn
Shape(Shape2).PartialNormal.x = Shape(Shape2).PartialNormal.x + nx2
Shape(Shape2).PartialNormal.y = Shape(Shape2).PartialNormal.y + ny2
rmin = r2
ClosestIndex1 = j
ClosestIndex2 = k
' Undo previous motion
IF (Shape
(Shape1
).Collisions
= 0) THEN CALL RotShape
(Shape1
, Shape
(Shape1
).Centroid
, -Shape
(Shape1
).Omega
) vtemp.x = -(Shape(Shape1).Velocity.x)
vtemp.y = -(Shape(Shape1).Velocity.y)
CALL TranslateShape
(Shape1
, vtemp
) IF (Shape
(Shape2
).Collisions
= 0) THEN CALL RotShape
(Shape2
, Shape
(Shape2
).Centroid
, -Shape
(Shape2
).Omega
) vtemp.x = -(Shape(Shape2).Velocity.x)
vtemp.y = -(Shape(Shape2).Velocity.y)
CALL TranslateShape
(Shape2
, vtemp
)
IF (Shape
(Shape1
).Collisions
= 0) THEN Shape(Shape1).Velocity.x = Shape(Shape1).Velocity.x * .75
Shape(Shape1).Velocity.y = Shape(Shape1).Velocity.y * .75
IF (Shape
(Shape2
).Collisions
= 0) THEN Shape(Shape2).Velocity.x = Shape(Shape2).Velocity.x * .75
Shape(Shape2).Velocity.y = Shape(Shape2).Velocity.y * .75
CollisionCount = CollisionCount + 1
Shape(Shape1).CollisionSwitch = 1
Shape(Shape2).CollisionSwitch = 1
' Normal vector 1 (nx1, ny1)
nn
= SQR(Shape
(Shape1
).PartialNormal.x
* Shape
(Shape1
).PartialNormal.x
+ Shape
(Shape1
).PartialNormal.y
* Shape
(Shape1
).PartialNormal.y
) nx1 = Shape(Shape1).PartialNormal.x / nn
ny1 = Shape(Shape1).PartialNormal.y / nn
Shape(Shape1).PartialNormal.x = nx1
Shape(Shape1).PartialNormal.y = ny1
' Normal vector 2 (nx2, ny2)
nn
= SQR(Shape
(Shape2
).PartialNormal.x
* Shape
(Shape2
).PartialNormal.x
+ Shape
(Shape2
).PartialNormal.y
* Shape
(Shape2
).PartialNormal.y
) nx2 = Shape(Shape2).PartialNormal.x / nn
ny2 = Shape(Shape2).PartialNormal.y / nn
Shape(Shape2).PartialNormal.x = nx2
Shape(Shape2).PartialNormal.y = ny2
' Contact-centroid differentials 1 (dx1, dy1)
dx1 = PointChain(Shape1, ClosestIndex1).x - Shape(Shape1).Centroid.x
dy1 = PointChain(Shape1, ClosestIndex1).y - Shape(Shape1).Centroid.y
' Contact-centroid differentials 2 (dx2, dy2)
dx2 = PointChain(Shape2, ClosestIndex2).x - Shape(Shape2).Centroid.x
dy2 = PointChain(Shape2, ClosestIndex2).y - Shape(Shape2).Centroid.y
' Perpendicular vector 1 (px1, py1)
px1 = -dy1
py1 = dx1
pp
= SQR(px1
* px1
+ py1
* py1
) px1 = px1 / pp
py1 = py1 / pp
' Perpendicular vector 2 (px2, py2)
px2 = -dy2
py2 = dx2
pp
= SQR(px2
* px2
+ py2
* py2
) px2 = px2 / pp
py2 = py2 / pp
' Angular velocity vector 1 (w1, r1, vx1, vy1)
w1 = Shape(Shape1).Omega
r1
= SQR(dx1
* dx1
+ dy1
* dy1
) vx1 = w1 * r1 * px1
vy1 = w1 * r1 * py1
' Angular velocity vector 2 (w2, r2, vx2, vy2)
w2 = Shape(Shape2).Omega
r2
= SQR(dx2
* dx2
+ dy2
* dy2
) vx2 = w2 * r2 * px2
vy2 = w2 * r2 * py2
' Mass terms (m1, m2, mu)
m1 = Shape(Shape1).Mass
m2 = Shape(Shape2).Mass
mu = 1 / (1 / m1 + 1 / m2)
' Re-Calculate moment of inertia (i1, i2)
vtemp.x = PointChain(Shape1, ClosestIndex1).x
vtemp.y = PointChain(Shape1, ClosestIndex1).y
CALL CalculateMOI
(Shape1
, vtemp
) vtemp.x = PointChain(Shape2, ClosestIndex2).x
vtemp.y = PointChain(Shape2, ClosestIndex2).y
CALL CalculateMOI
(Shape2
, vtemp
) i1 = Shape(Shape1).MOI
i2 = Shape(Shape2).MOI
' Velocity differentials (v1, v2, dvtx, dvty)
vcx1 = Shape(Shape1).Velocity.x
vcy1 = Shape(Shape1).Velocity.y
vcx2 = Shape(Shape2).Velocity.x
vcy2 = Shape(Shape2).Velocity.y
vtx1 = vcx1 + vx1
vty1 = vcy1 + vy1
vtx2 = vcx2 + vx2
vty2 = vcy2 + vy2
v1
= SQR(vtx1
* vtx1
+ vty1
* vty1
) v2
= SQR(vtx2
* vtx2
+ vty2
* vty2
) dvtx = vtx2 - vtx1
dvty = vty2 - vty1
' Geometry (n1dotdvt, n2dotdvt)
n1dotdvt = nx1 * dvtx + ny1 * dvty
n2dotdvt = nx2 * dvtx + ny2 * dvty
' Momentum exchange (qx1, qy1, qx2, qy2)
qx1 = nx1 * 2 * mu * n1dotdvt
qy1 = ny1 * 2 * mu * n1dotdvt
qx2 = nx2 * 2 * mu * n2dotdvt
qy2 = ny2 * 2 * mu * n2dotdvt
' Momentum exchange unit vector
qq
= SQR(qx1
* qx1
+ qy1
* qy1
) qhatx1 = qx1 / qq
qhaty1 = qy1 / qq
qq
= SQR(qx2
* qx2
+ qy2
* qy2
) qhatx2 = qx2 / qq
qhaty2 = qy2 / qq
' Translational impulse
q1dotn1 = qhatx1 * nx1 + qhaty1 * ny1
q2dotn2 = qhatx2 * nx2 + qhaty2 * ny2
n1dotr1hat = (nx1 * dx1 + ny1 * dy1) / r1
n2dotr2hat = (nx2 * dx2 + ny2 * dy2) / r2
f1 = -q1dotn1 * n1dotr1hat
f2 = -q2dotn2 * n2dotr2hat
Shape(Shape1).DeltaV.x = Shape(Shape1).DeltaV.x + f1 * qx1 / m1
Shape(Shape1).DeltaV.y = Shape(Shape1).DeltaV.y + f1 * qy1 / m1
Shape(Shape2).DeltaV.x = Shape(Shape2).DeltaV.x + f2 * qx2 / m2
Shape(Shape2).DeltaV.y = Shape(Shape2).DeltaV.y + f2 * qy2 / m2
' Angular impulse
q1dotp1 = qx1 * px1 + qy1 * py1
q2dotp2 = qx2 * px2 + qy2 * py2
dw1 = r1 * q1dotp1 / i1
dw2 = -r2 * q2dotp2 / i2
Shape(Shape1).DeltaO = Shape(Shape1).DeltaO + dw1
Shape(Shape2).DeltaO = Shape(Shape2).DeltaO + dw2
' Separate along normal
'IF (Shape(Shape1).Collisions = 0) THEN
vtemp.x = -nx1 * 1 * ((v1 + 0) / m1)
vtemp.y = -ny1 * 1 * ((v1 + 0) / m1)
CALL TranslateShape
(Shape1
, vtemp
) 'END IF
'IF (Shape(Shape2).Collisions = 0) THEN
vtemp.x = -nx2 * 1 * ((v2 + 0) / m2)
vtemp.y = -ny2 * 1 * ((v2 + 0) / m2)
CALL TranslateShape
(Shape2
, vtemp
) 'END IF
' External torque
'IF (Shape(Shape1).Collisions > 0) THEN
torque1 = dx1 * ForceField.y - dy1 * ForceField.x
Shape(Shape1).DeltaO = Shape(Shape1).DeltaO - m1 * torque1 / i1
'END IF
'IF (Shape(Shape2).Collisions > 0) THEN
torque2 = dx2 * ForceField.y - dy2 * ForceField.x
Shape(Shape2).DeltaO = Shape(Shape2).DeltaO - m2 * torque2 / i2
'END IF
' Feedback
CALL snd
(100 * (v1
+ v2
) / 2, .5)
'END IF
FOR ShapeIndex
= 1 TO ShapeCount
' Contact update
IF (Shape
(ShapeIndex
).CollisionSwitch
= 1) THEN Shape(ShapeIndex).Collisions = Shape(ShapeIndex).Collisions + 1
Shape(ShapeIndex).Collisions = 0
IF ((Shape
(ShapeIndex
).Fixed
= 0)) THEN
' Angular velocity update
Shape(ShapeIndex).Omega = Shape(ShapeIndex).Omega + Shape(ShapeIndex).DeltaO
' Linear velocity update
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x + Shape(ShapeIndex).DeltaV.x
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y + Shape(ShapeIndex).DeltaV.y
IF (Shape
(ShapeIndex
).Collisions
= 0) THEN ' Freefall (if airborne)
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x + ForceField.x
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y + ForceField.y
' Friction
IF (Shape
(ShapeIndex
).Velocity.x
* Shape
(ShapeIndex
).Velocity.x
) < .05 THEN Shape
(ShapeIndex
).Velocity.x
= 0 IF (Shape
(ShapeIndex
).Velocity.y
* Shape
(ShapeIndex
).Velocity.y
) < .05 THEN Shape
(ShapeIndex
).Velocity.y
= 0 'IF (Shape(ShapeIndex).Omega * Shape(ShapeIndex).Omega) < .001 THEN Shape(ShapeIndex).Omega = 0
' Rotation update
CALL RotShape
(ShapeIndex
, Shape
(ShapeIndex
).Centroid
, Shape
(ShapeIndex
).Omega
)
' Position update
CALL TranslateShape
(ShapeIndex
, Shape
(ShapeIndex
).Velocity
)
' Damping
Shape(ShapeIndex).Velocity.x = Shape(ShapeIndex).Velocity.x * .995
Shape(ShapeIndex).Velocity.y = Shape(ShapeIndex).Velocity.y * .995
'Shape(ShapeIndex).Omega = Shape(ShapeIndex).Omega * (1 - .25 * (Shape(ShapeIndex).DiameterMin / Shape(ShapeIndex).DiameterMax))
FOR ShapeIndex
= 1 TO ShapeCount
'LOCATE 1, 1: PRINT ProximalPairsCount, CollisionCount ', Shape(ShapeCount).Collisions, Shape(ShapeCount - 1).Collisions
FOR i
= 1 TO Shape
(ShapeIndex
).Elements
- 1 CALL cpset
(PointChain
(ShapeIndex
, i
).x
, PointChain
(ShapeIndex
, i
).y
, Shape
(ShapeIndex
).Shade
) CALL cline
(PointChain
(ShapeIndex
, i
).x
, PointChain
(ShapeIndex
, i
).y
, PointChain
(ShapeIndex
, i
+ 1).x
, PointChain
(ShapeIndex
, i
+ 1).y
, Shape
(ShapeIndex
).Shade
) CALL cpset
(PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).x
, PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).y
, Shape
(ShapeIndex
).Shade
) CALL cline
(PointChain
(ShapeIndex
, 1).x
, PointChain
(ShapeIndex
, 1).y
, PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).x
, PointChain
(ShapeIndex
, Shape
(ShapeIndex
).Elements
).y
, Shape
(ShapeIndex
).Shade
) 'CALL cline(Shape(ShapeIndex).Centroid.x, Shape(ShapeIndex).Centroid.y, PointChain(ShapeIndex, 1).x, PointChain(ShapeIndex, 1).y, Shape(ShapeIndex).Shade)
'CALL ccircle(Shape(ShapeIndex).Centroid.x, Shape(ShapeIndex).Centroid.y, 3, _RGB(255, 255, 255))
CALL cpaint
(Shape
(ShapeCount
).Centroid.x
, Shape
(ShapeCount
).Centroid.y
, Shape
(ShapeCount
).Shade
, Shape
(ShapeCount
).Shade
)
li = i - 1
ri = i + 1
IF (i
= 1) THEN li
= Shape
(k
).Elements
IF (i
= Shape
(k
).Elements
) THEN ri
= 1 l.x = PointChain(k, li).x
r.x = PointChain(k, ri).x
dx = r.x - l.x
CalculateNormalX = dx
li = i - 1
ri = i + 1
IF (i
= 1) THEN li
= Shape
(k
).Elements
IF (i
= Shape
(k
).Elements
) THEN ri
= 1 l.y = PointChain(k, li).y
r.y = PointChain(k, ri).y
dy = r.y - l.y
CalculateNormalY = dy
xx = 0
yy = 0
FOR i
= 1 TO Shape
(k
).Elements
xx = xx + PointChain(k, i).x
yy = yy + PointChain(k, i).y
Shape(k).Centroid.x = xx / Shape(k).Elements
Shape(k).Centroid.y = yy / Shape(k).Elements
r2min = 999 ^ 999
FOR i
= 1 TO Shape
(k
).Elements
xx = Shape(k).Centroid.x - PointChain(k, i).x
yy = Shape(k).Centroid.y - PointChain(k, i).y
r2 = xx * xx + yy * yy
r2min = r2
Shape
(k
).DiameterMin
= SQR(r2min
)
r2max = -1
FOR i
= 1 TO Shape
(k
).Elements
xx = Shape(k).Centroid.x - PointChain(k, i).x
yy = Shape(k).Centroid.y - PointChain(k, i).y
r2 = xx * xx + yy * yy
r2max = r2
Shape
(k
).DiameterMax
= SQR(r2max
)
aa = 0
FOR i
= 1 TO Shape
(k
).Elements
- 1 x = (Shape(k).Centroid.x - PointChain(k, i).x)
y = (Shape(k).Centroid.y - PointChain(k, i).y)
dx = (Shape(k).Centroid.x - PointChain(k, i + 1).x) - x
dy = (Shape(k).Centroid.y - PointChain(k, i + 1).y) - y
da = .5 * (x * dy - y * dx)
aa = aa + da
Shape
(k
).Mass
= factor
* SQR(aa
* aa
)
xx = 0
yy = 0
FOR i
= 1 TO Shape
(k
).Elements
a = ctrvec.x - PointChain(k, i).x
b = ctrvec.y - PointChain(k, i).y
xx = xx + a * a
yy = yy + b * b
Shape
(k
).MOI
= SQR((xx
+ yy
) * (xx
+ yy
)) * (Shape
(k
).Mass
/ Shape
(k
).Elements
)
FOR i
= 1 TO Shape
(k
).Elements
PointChain(k, i).x = PointChain(k, i).x + c.x
PointChain(k, i).y = PointChain(k, i).y + c.y
Shape(k).Centroid.x = Shape(k).Centroid.x + c.x
Shape(k).Centroid.y = Shape(k).Centroid.y + c.y
FOR i
= 1 TO Shape
(k
).Elements
xx = PointChain(k, i).x - c.x
yy = PointChain(k, i).y - c.y
PointChain
(k
, i
).x
= c.x
+ xx
* COS(da
) - yy
* SIN(da
) PointChain
(k
, i
).y
= c.y
+ yy
* COS(da
) + xx
* SIN(da
) xx = Shape(k).Centroid.x - c.x
yy = Shape(k).Centroid.y - c.y
Shape
(k
).Centroid.x
= c.x
+ xx
* COS(da
) - yy
* SIN(da
) Shape
(k
).Centroid.y
= c.y
+ yy
* COS(da
) + xx
* SIN(da
)
SUB NewAutoBall
(x1
, y1
, r1
, r2
, pa
, pb
, fx
) ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = fx
Shape(ShapeCount).Collisions = 0
i = 0
i = i + 1
r
= r1
+ r2
* COS(pa
* j
) ^ pb
PointChain
(ShapeCount
, i
).x
= x1
+ r
* COS(j
) PointChain
(ShapeCount
, i
).y
= y1
+ r
* SIN(j
) Shape(ShapeCount).Elements = i
CALL CalculateMass
(ShapeCount
, 1) CALL CalculateMass
(ShapeCount
, 999999) CALL CalculateCentroid
(ShapeCount
) CALL CalculateMOI
(ShapeCount
, Shape
(ShapeCount
).Centroid
) CALL CalculateDiameterMin
(ShapeCount
) CALL CalculateDiameterMax
(ShapeCount
) Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
Shape
(ShapeCount
).Shade
= _RGB(100, 100, 100)
SUB NewAutoBrick
(x1
, y1
, wx
, wy
, ang
) ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = 1
Shape(ShapeCount).Collisions = 0
i = 0
i = i + 1
PointChain(ShapeCount, i).x = x1 + wx / 2
PointChain(ShapeCount, i).y = y1 + j
i = i + 1
PointChain(ShapeCount, i).x = x1 + j
PointChain(ShapeCount, i).y = y1 + wy / 2
i = i + 1
PointChain(ShapeCount, i).x = x1 - wx / 2
PointChain(ShapeCount, i).y = y1 + j
i = i + 1
PointChain(ShapeCount, i).x = x1 + j
PointChain(ShapeCount, i).y = y1 - wy / 2
Shape(ShapeCount).Elements = i
CALL CalculateMass
(ShapeCount
, 99999) CALL CalculateCentroid
(ShapeCount
) CALL CalculateMOI
(ShapeCount
, Shape
(ShapeCount
).Centroid
) CALL CalculateDiameterMin
(ShapeCount
) CALL CalculateDiameterMax
(ShapeCount
) Shape(ShapeCount).MOI = 999 ^ 999
Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
Shape
(ShapeCount
).Shade
= _RGB(100, 100, 100) CALL RotShape
(ShapeCount
, Shape
(ShapeCount
).Centroid
, ang
)
SUB NewBrickLine
(xi
, yi
, xf
, yf
, l
, w
) d1
= SQR((xf
- xi
) ^ 2 + (yf
- yi
) ^ 2) ang
= ATN((yf
- yi
) / (xf
- xi
)) CALL NewAutoBrick
(xi
* (1 - t
) + xf
* t
, yi
* (1 - t
) + yf
* t
, l
, w
, ang
)
'rawresolution = Raw curve resolution.
'targetpoints = Number of points per curve.
'smoothiterations = Magnitude of smooth effect.
ShapeCount = ShapeCount + 1
Shape(ShapeCount).Fixed = 0
Shape(ShapeCount).Collisions = 0
numpoints = 0
' Click+drag mouse button 1 to trace out a curve.
xold = 999999
yold = 999999
delta
= SQR((x
- xold
) ^ 2 + (y
- yold
) ^ 2)
' Collect data only if the new point is sufficiently far away from the previous point.
IF (delta
> rawresolution
) AND (numpoints
< targetpoints
- 1) THEN numpoints = numpoints + 1
PointChain(ShapeCount, numpoints).x = x
PointChain(ShapeCount, numpoints).y = y
xold = x
yold = y
' If the curve contains less than the minimum numer of points, use interpolation to fill in the gaps.
DO WHILE (numpoints
< targetpoints
)
' Determine the pair of neighboring points that have the greatest separation of all pairs.
rad2max = -1
kmax = -1
FOR k
= 1 TO numpoints
- 1 xfac = PointChain(ShapeCount, k).x - PointChain(ShapeCount, k + 1).x
yfac = PointChain(ShapeCount, k).y - PointChain(ShapeCount, k + 1).y
rad2 = xfac ^ 2 + yfac ^ 2
kmax = k
rad2max = rad2
'''
edgecase = 0
xfac = PointChain(ShapeCount, numpoints).x - PointChain(ShapeCount, 1).x
yfac = PointChain(ShapeCount, numpoints).y - PointChain(ShapeCount, 1).y
rad2 = xfac ^ 2 + yfac ^ 2
kmax = numpoints
rad2max = rad2
edgecase = 1
'''
numpoints = numpoints + 1
' Starting next to kmax, create a gap by shifting all other points by one index.
PointChain(ShapeCount, j).x = PointChain(ShapeCount, j - 1).x
PointChain(ShapeCount, j).y = PointChain(ShapeCount, j - 1).y
' Fill the gap with a new point whose position is determined by the average of its neighbors.
PointChain(ShapeCount, kmax + 1).x = (1 / 2) * (PointChain(ShapeCount, kmax).x + PointChain(ShapeCount, kmax + 2).x)
PointChain(ShapeCount, kmax + 1).y = (1 / 2) * (PointChain(ShapeCount, kmax).y + PointChain(ShapeCount, kmax + 2).y)
numpoints = numpoints + 1
xx = PointChain(ShapeCount, numpoints - 1).x
yy = PointChain(ShapeCount, numpoints - 1).y
PointChain(ShapeCount, numpoints).x = (1 / 2) * (PointChain(ShapeCount, 1).x + xx)
PointChain(ShapeCount, numpoints).y = (1 / 2) * (PointChain(ShapeCount, 1).y + yy)
' At this stage, the curve still has all of its sharp edges. Use a relaxation method to smooth.
' The new position of a point is equal to the average position of its neighboring points.
CALL SmoothShape
(ShapeCount
, numpoints
, smoothiterations
)
Shape(ShapeCount).Elements = numpoints
CALL CalculateMass
(ShapeCount
, 1) CALL CalculateCentroid
(ShapeCount
) CALL CalculateMOI
(ShapeCount
, Shape
(ShapeCount
).Centroid
) CALL CalculateDiameterMin
(ShapeCount
) CALL CalculateDiameterMax
(ShapeCount
) Shape(ShapeCount).Velocity.x = 0
Shape(ShapeCount).Velocity.y = 0
Shape(ShapeCount).Omega = 0
TempChain(i, k).x = (1 / 2) * (PointChain(i, k - 1).x + PointChain(i, k + 1).x)
TempChain(i, k).y = (1 / 2) * (PointChain(i, k - 1).y + PointChain(i, k + 1).y)
PointChain(i, k).x = TempChain(i, k).x
PointChain(i, k).y = TempChain(i, k).y