diff options
author | Robert Adams | 2012-11-06 17:58:55 -0800 |
---|---|---|
committer | Robert Adams | 2012-11-06 18:16:35 -0800 |
commit | 76cc3030314b3302da46bfe4078f076ba1b3d8a1 (patch) | |
tree | defc41af21d4542789c00a93452d5793ec7f896d | |
parent | BulletSim: remove limit on taints that can happen before a step. Remove some ... (diff) | |
download | opensim-SC-76cc3030314b3302da46bfe4078f076ba1b3d8a1.zip opensim-SC-76cc3030314b3302da46bfe4078f076ba1b3d8a1.tar.gz opensim-SC-76cc3030314b3302da46bfe4078f076ba1b3d8a1.tar.bz2 opensim-SC-76cc3030314b3302da46bfe4078f076ba1b3d8a1.tar.xz |
BulletSim: Add ZeroAngularMotion method to physical objects. Add inTaint flag to ZeroMotion method. Update the references to those functions.
4 files changed, 82 insertions, 28 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 2a5397e..f33c124 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -103,7 +103,7 @@ public sealed class BSCharacter : BSPhysObject | |||
103 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 103 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() |
104 | { | 104 | { |
105 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 105 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
106 | // New body and shape into BSBody and BSShape | 106 | // New body and shape into PhysBody and PhysShape |
107 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); | 107 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); |
108 | 108 | ||
109 | SetPhysicalProperties(); | 109 | SetPhysicalProperties(); |
@@ -126,7 +126,7 @@ public sealed class BSCharacter : BSPhysObject | |||
126 | { | 126 | { |
127 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | 127 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); |
128 | 128 | ||
129 | ZeroMotion(); | 129 | ZeroMotion(true); |
130 | ForcePosition = _position; | 130 | ForcePosition = _position; |
131 | // Set the velocity and compute the proper friction | 131 | // Set the velocity and compute the proper friction |
132 | ForceVelocity = _velocity; | 132 | ForceVelocity = _velocity; |
@@ -218,18 +218,31 @@ public sealed class BSCharacter : BSPhysObject | |||
218 | // Do it to the properties so the values get set in the physics engine. | 218 | // Do it to the properties so the values get set in the physics engine. |
219 | // Push the setting of the values to the viewer. | 219 | // Push the setting of the values to the viewer. |
220 | // Called at taint time! | 220 | // Called at taint time! |
221 | public override void ZeroMotion() | 221 | public override void ZeroMotion(bool inTaintTime) |
222 | { | 222 | { |
223 | _velocity = OMV.Vector3.Zero; | 223 | _velocity = OMV.Vector3.Zero; |
224 | _acceleration = OMV.Vector3.Zero; | 224 | _acceleration = OMV.Vector3.Zero; |
225 | _rotationalVelocity = OMV.Vector3.Zero; | 225 | _rotationalVelocity = OMV.Vector3.Zero; |
226 | 226 | ||
227 | // Zero some other properties directly into the physics engine | 227 | // Zero some other properties directly into the physics engine |
228 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 228 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
229 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 229 | { |
230 | BulletSimAPI.SetInterpolationVelocity2(PhysBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | 230 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); |
231 | BulletSimAPI.ClearForces2(PhysBody.ptr); | 231 | }); |
232 | } | 232 | } |
233 | public override void ZeroAngularMotion(bool inTaintTime) | ||
234 | { | ||
235 | _rotationalVelocity = OMV.Vector3.Zero; | ||
236 | |||
237 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | ||
238 | { | ||
239 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
240 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
241 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
242 | BulletSimAPI.ClearForces2(PhysBody.ptr); | ||
243 | }); | ||
244 | } | ||
245 | |||
233 | 246 | ||
234 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | 247 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } |
235 | 248 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index d2387fb..c855fda 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -184,7 +184,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
184 | private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) | 184 | private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) |
185 | { | 185 | { |
186 | // Zero motion for children so they don't interpolate | 186 | // Zero motion for children so they don't interpolate |
187 | childPrim.ZeroMotion(); | 187 | childPrim.ZeroMotion(true); |
188 | 188 | ||
189 | // Relative position normalized to the root prim | 189 | // Relative position normalized to the root prim |
190 | // Essentually a vector pointing from center of rootPrim to center of childPrim | 190 | // Essentually a vector pointing from center of rootPrim to center of childPrim |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 7127aaf..e803072 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -34,9 +34,17 @@ using OpenSim.Region.Physics.Manager; | |||
34 | 34 | ||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | // Class to wrap all objects. | 37 | /* |
38 | // The rest of BulletSim doesn't need to keep checking for avatars or prims | 38 | * Class to wrap all objects. |
39 | // unless the difference is significant. | 39 | * The rest of BulletSim doesn't need to keep checking for avatars or prims |
40 | * unless the difference is significant. | ||
41 | * | ||
42 | * Variables in the physicsl objects are in three forms: | ||
43 | * VariableName: used by the simulator and performs taint operations, etc | ||
44 | * RawVariableName: direct reference to the BulletSim storage for the variable value | ||
45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. | ||
46 | * The last two (and certainly the last one) should be referenced only in taint-time. | ||
47 | */ | ||
40 | public abstract class BSPhysObject : PhysicsActor | 48 | public abstract class BSPhysObject : PhysicsActor |
41 | { | 49 | { |
42 | protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName) | 50 | protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName) |
@@ -67,6 +75,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
67 | // Set the raw mass but also update physical mass properties (inertia, ...) | 75 | // Set the raw mass but also update physical mass properties (inertia, ...) |
68 | public abstract void UpdatePhysicalMassProperties(float mass); | 76 | public abstract void UpdatePhysicalMassProperties(float mass); |
69 | 77 | ||
78 | // The last value calculated for the prim's inertia | ||
79 | public OMV.Vector3 Inertia { get; set; } | ||
80 | |||
70 | // Reference to the physical body (btCollisionObject) of this object | 81 | // Reference to the physical body (btCollisionObject) of this object |
71 | public BulletBody PhysBody; | 82 | public BulletBody PhysBody; |
72 | // Reference to the physical shape (btCollisionShape) of this object | 83 | // Reference to the physical shape (btCollisionShape) of this object |
@@ -96,7 +107,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
96 | public abstract bool IsStatic { get; } | 107 | public abstract bool IsStatic { get; } |
97 | 108 | ||
98 | // Stop all physical motion. | 109 | // Stop all physical motion. |
99 | public abstract void ZeroMotion(); | 110 | public abstract void ZeroMotion(bool inTaintTime); |
111 | public abstract void ZeroAngularMotion(bool inTaintTime); | ||
100 | 112 | ||
101 | // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. | 113 | // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. |
102 | public virtual void StepVehicle(float timeStep) { } | 114 | public virtual void StepVehicle(float timeStep) { } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index aaa0d93..14eb505 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -25,8 +25,6 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | // Uncomment this it enable code to do all shape an body memory management | ||
29 | // in the C# code. | ||
30 | using System; | 28 | using System; |
31 | using System.Reflection; | 29 | using System.Reflection; |
32 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
@@ -236,14 +234,27 @@ public sealed class BSPrim : BSPhysObject | |||
236 | // Do it to the properties so the values get set in the physics engine. | 234 | // Do it to the properties so the values get set in the physics engine. |
237 | // Push the setting of the values to the viewer. | 235 | // Push the setting of the values to the viewer. |
238 | // Called at taint time! | 236 | // Called at taint time! |
239 | public override void ZeroMotion() | 237 | public override void ZeroMotion(bool inTaintTime) |
240 | { | 238 | { |
241 | _velocity = OMV.Vector3.Zero; | 239 | _velocity = OMV.Vector3.Zero; |
242 | _acceleration = OMV.Vector3.Zero; | 240 | _acceleration = OMV.Vector3.Zero; |
243 | _rotationalVelocity = OMV.Vector3.Zero; | 241 | _rotationalVelocity = OMV.Vector3.Zero; |
244 | 242 | ||
245 | // Zero some other properties in the physics engine | 243 | // Zero some other properties in the physics engine |
246 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 244 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
245 | { | ||
246 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
247 | }); | ||
248 | } | ||
249 | public override void ZeroAngularMotion(bool inTaintTime) | ||
250 | { | ||
251 | _rotationalVelocity = OMV.Vector3.Zero; | ||
252 | // Zero some other properties in the physics engine | ||
253 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | ||
254 | { | ||
255 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
256 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
257 | }); | ||
247 | } | 258 | } |
248 | 259 | ||
249 | public override void LockAngularMotion(OMV.Vector3 axis) | 260 | public override void LockAngularMotion(OMV.Vector3 axis) |
@@ -371,17 +382,18 @@ public sealed class BSPrim : BSPhysObject | |||
371 | { | 382 | { |
372 | if (IsStatic) | 383 | if (IsStatic) |
373 | { | 384 | { |
374 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, OMV.Vector3.Zero); | 385 | Inertia = OMV.Vector3.Zero; |
386 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); | ||
375 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | 387 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); |
376 | } | 388 | } |
377 | else | 389 | else |
378 | { | 390 | { |
379 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | 391 | Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); |
380 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | 392 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); |
393 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
381 | // center of mass is at the zero of the object | 394 | // center of mass is at the zero of the object |
382 | BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); | 395 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); |
383 | // BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); | 396 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); |
384 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, localInertia); | ||
385 | } | 397 | } |
386 | } | 398 | } |
387 | 399 | ||
@@ -582,7 +594,7 @@ public sealed class BSPrim : BSPhysObject | |||
582 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 594 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
583 | SetObjectDynamic(true); | 595 | SetObjectDynamic(true); |
584 | // whether phys-to-static or static-to-phys, the object is not moving. | 596 | // whether phys-to-static or static-to-phys, the object is not moving. |
585 | ZeroMotion(); | 597 | ZeroMotion(true); |
586 | }); | 598 | }); |
587 | } | 599 | } |
588 | } | 600 | } |
@@ -648,6 +660,7 @@ public sealed class BSPrim : BSPhysObject | |||
648 | // Recompute any linkset parameters. | 660 | // Recompute any linkset parameters. |
649 | // When going from non-physical to physical, this re-enables the constraints that | 661 | // When going from non-physical to physical, this re-enables the constraints that |
650 | // had been automatically disabled when the mass was set to zero. | 662 | // had been automatically disabled when the mass was set to zero. |
663 | // For compound based linksets, this enables and disables interactions of the children. | ||
651 | Linkset.Refresh(this); | 664 | Linkset.Refresh(this); |
652 | 665 | ||
653 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | 666 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", |
@@ -666,9 +679,9 @@ public sealed class BSPrim : BSPhysObject | |||
666 | // Become a Bullet 'static' object type | 679 | // Become a Bullet 'static' object type |
667 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 680 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
668 | // Stop all movement | 681 | // Stop all movement |
669 | ZeroMotion(); | 682 | ZeroMotion(true); |
670 | // Center of mass is at the center of the object | 683 | // Center of mass is at the center of the object |
671 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | 684 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); |
672 | // Mass is zero which disables a bunch of physics stuff in Bullet | 685 | // Mass is zero which disables a bunch of physics stuff in Bullet |
673 | UpdatePhysicalMassProperties(0f); | 686 | UpdatePhysicalMassProperties(0f); |
674 | // Set collision detection parameters | 687 | // Set collision detection parameters |
@@ -704,7 +717,7 @@ public sealed class BSPrim : BSPhysObject | |||
704 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 717 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
705 | 718 | ||
706 | // Center of mass is at the center of the object | 719 | // Center of mass is at the center of the object |
707 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | 720 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); |
708 | 721 | ||
709 | // A dynamic object has mass | 722 | // A dynamic object has mass |
710 | UpdatePhysicalMassProperties(RawMass); | 723 | UpdatePhysicalMassProperties(RawMass); |
@@ -958,6 +971,16 @@ public sealed class BSPrim : BSPhysObject | |||
958 | }); | 971 | }); |
959 | } | 972 | } |
960 | 973 | ||
974 | public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) | ||
975 | { | ||
976 | OMV.Vector3 applyImpulse = impulse; | ||
977 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() | ||
978 | { | ||
979 | DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | ||
980 | BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); | ||
981 | }); | ||
982 | } | ||
983 | |||
961 | private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); | 984 | private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); |
962 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 985 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
963 | AddAngularForce(force, pushforce, false); | 986 | AddAngularForce(force, pushforce, false); |
@@ -1001,7 +1024,6 @@ public sealed class BSPrim : BSPhysObject | |||
1001 | OMV.Vector3 applyImpulse = impulse; | 1024 | OMV.Vector3 applyImpulse = impulse; |
1002 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1025 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1003 | { | 1026 | { |
1004 | DetailLog("{0},BSPrim.ApplyTorqueImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | ||
1005 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | 1027 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); |
1006 | }); | 1028 | }); |
1007 | } | 1029 | } |
@@ -1315,9 +1337,10 @@ public sealed class BSPrim : BSPhysObject | |||
1315 | // If this prim is part of a linkset, we must remove and restore the physical | 1337 | // If this prim is part of a linkset, we must remove and restore the physical |
1316 | // links if the body is rebuilt. | 1338 | // links if the body is rebuilt. |
1317 | bool needToRestoreLinkset = false; | 1339 | bool needToRestoreLinkset = false; |
1340 | bool needToRestoreVehicle = false; | ||
1318 | 1341 | ||
1319 | // Create the correct physical representation for this type of object. | 1342 | // Create the correct physical representation for this type of object. |
1320 | // Updates BSBody and BSShape with the new information. | 1343 | // Updates PhysBody and PhysShape with the new information. |
1321 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1344 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1322 | // Returns 'true' if either the body or the shape was changed. | 1345 | // Returns 'true' if either the body or the shape was changed. |
1323 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1346 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
@@ -1326,6 +1349,7 @@ public sealed class BSPrim : BSPhysObject | |||
1326 | // Remove all the physical dependencies on the old body. | 1349 | // Remove all the physical dependencies on the old body. |
1327 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | 1350 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) |
1328 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 1351 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); |
1352 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | ||
1329 | }); | 1353 | }); |
1330 | 1354 | ||
1331 | if (needToRestoreLinkset) | 1355 | if (needToRestoreLinkset) |
@@ -1333,6 +1357,11 @@ public sealed class BSPrim : BSPhysObject | |||
1333 | // If physical body dependencies were removed, restore them | 1357 | // If physical body dependencies were removed, restore them |
1334 | Linkset.RestoreBodyDependencies(this); | 1358 | Linkset.RestoreBodyDependencies(this); |
1335 | } | 1359 | } |
1360 | if (needToRestoreVehicle) | ||
1361 | { | ||
1362 | // If physical body dependencies were removed, restore them | ||
1363 | _vehicle.RestoreBodyDependencies(this); | ||
1364 | } | ||
1336 | 1365 | ||
1337 | // Make sure the properties are set on the new object | 1366 | // Make sure the properties are set on the new object |
1338 | UpdatePhysicalParameters(); | 1367 | UpdatePhysicalParameters(); |